agentengine-sdk-python 0.8.2__py3-none-any.whl → 0.8.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +18 -25
  2. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +224 -169
  3. ksadk/_build_provenance.json +1 -0
  4. ksadk/agui/_agent_helpers.py +4 -0
  5. ksadk/api/client.py +3 -0
  6. ksadk/builders/managed_runtime_builder.py +3 -0
  7. ksadk/cli/__init__.py +6 -0
  8. ksadk/cli/cmd_plugin.py +657 -0
  9. ksadk/codex/runtime.py +50 -8
  10. ksadk/configs/env_registry.py +31 -3
  11. ksadk/configs/settings.py +9 -0
  12. ksadk/context_engine/contributors.py +73 -8
  13. ksadk/conversations/__init__.py +19 -0
  14. ksadk/conversations/context.py +104 -24
  15. ksadk/conversations/contracts.py +266 -0
  16. ksadk/conversations/message_projection.py +19 -1
  17. ksadk/conversations/projector.py +616 -0
  18. ksadk/conversations/reducer.py +98 -0
  19. ksadk/events/_v1_compat/projection.py +2 -0
  20. ksadk/events/adapters/codex.py +190 -0
  21. ksadk/harness/__init__.py +45 -35
  22. ksadk/harness/runtime.py +60 -1
  23. ksadk/kernel/contract_fingerprints.py +5 -4
  24. ksadk/kernel/contracts.py +8 -0
  25. ksadk/kernel/control.py +1 -0
  26. ksadk/kernel/ingress.py +21 -0
  27. ksadk/kernel/memory_store.py +1 -0
  28. ksadk/kernel/postgres_store.py +1 -0
  29. ksadk/kernel/sqlite_store.py +1 -0
  30. ksadk/kernel/worker.py +11 -0
  31. ksadk/memory/providers/local_sqlite.py +7 -0
  32. ksadk/plugins/__init__.py +167 -0
  33. ksadk/plugins/bridges/__init__.py +45 -0
  34. ksadk/plugins/bridges/codex.py +552 -0
  35. ksadk/plugins/bridges/dsh.py +1116 -0
  36. ksadk/plugins/builtins.py +747 -0
  37. ksadk/plugins/bundle.py +246 -0
  38. ksadk/plugins/bundle_security.py +167 -0
  39. ksadk/plugins/composition.py +529 -0
  40. ksadk/plugins/context_contributor.py +437 -0
  41. ksadk/plugins/contracts.py +451 -0
  42. ksadk/plugins/dsh_toolchain.py +935 -0
  43. ksadk/plugins/ecosystem_bridge.py +1105 -0
  44. ksadk/plugins/ecosystem_probe.py +191 -0
  45. ksadk/plugins/host.py +724 -0
  46. ksadk/plugins/providers/__init__.py +85 -0
  47. ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
  48. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
  49. ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
  50. ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
  51. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
  52. ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
  53. ksadk/plugins/providers/codex.py +722 -0
  54. ksadk/plugins/providers/codex_dsh.py +83 -0
  55. ksadk/plugins/providers/dsh.py +951 -0
  56. ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
  57. ksadk/plugins/providers/harness.py +627 -0
  58. ksadk/plugins/providers/harness_dsh.py +91 -0
  59. ksadk/plugins/providers/legacy.py +215 -0
  60. ksadk/plugins/providers/legacy_catalog.py +100 -0
  61. ksadk/plugins/providers/shipped_dsh.py +370 -0
  62. ksadk/plugins/resolver.py +331 -0
  63. ksadk/plugins/subagent_providers/__init__.py +12 -0
  64. ksadk/plugins/subagent_providers/codex.py +443 -0
  65. ksadk/plugins/subagents.py +333 -0
  66. ksadk/runtime/_runner_adapter/stream_mapping.py +51 -42
  67. ksadk/runtime/adapter.py +1 -0
  68. ksadk/runtime/factory.py +76 -2
  69. ksadk/runtime/framework_adapters.py +18 -0
  70. ksadk/runtime/runner_adapter.py +5 -0
  71. ksadk/sandbox/__init__.py +2 -1
  72. ksadk/sandbox/factory.py +72 -0
  73. ksadk/scheduler/__init__.py +18 -0
  74. ksadk/scheduler/calendar.py +102 -0
  75. ksadk/scheduler/contracts.py +254 -0
  76. ksadk/scheduler/dispatcher.py +129 -0
  77. ksadk/scheduler/engine.py +416 -0
  78. ksadk/scheduler/sqlite_store.py +563 -0
  79. ksadk/server/static/assets/{ArtifactsPanel-DSU1sWD_.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
  80. ksadk/server/static/assets/{CodeBlock-DOH6MVcn.js → CodeBlock-BXk1l-G1.js} +1 -1
  81. ksadk/server/static/assets/{MathMessageMarkdown-BL8my1R2.js → MathMessageMarkdown-D9uB55Oh.js} +1 -1
  82. ksadk/server/static/assets/{MermaidBlock-Dz4IP-Tx.js → MermaidBlock--OEYoXIJ.js} +6 -6
  83. ksadk/server/static/assets/{NativeTerminalPanel-DUrK0JpZ.js → NativeTerminalPanel-DrEe1syq.js} +1 -1
  84. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-g20pFzNV.js → abnfDiagram-VCTEODGH-eeTFJLvo.js} +1 -1
  85. ksadk/server/static/assets/{arc-C4FzinUA.js → arc-S3ZNbIAd.js} +1 -1
  86. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
  87. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-DpIqL5h4.js → architectureDiagram-5GKGNRK7-CRjgEJDX.js} +1 -1
  88. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-BjkljTNz.js → blockDiagram-NRAW4CY4-C7bsBoNH.js} +1 -1
  89. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-Dk_ieq2X.js → c4Diagram-UCG6FXSJ-BX3c33Ob.js} +1 -1
  90. ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
  91. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
  92. ksadk/server/static/assets/{chunk-5VM5RSS4-BVHAchFb.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
  93. ksadk/server/static/assets/{chunk-F27PBJKO-C-ipQzuS.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
  94. ksadk/server/static/assets/{chunk-G27WJ6UU-C2EyJbIK.js → chunk-G27WJ6UU-CZwF3oUP.js} +1 -1
  95. ksadk/server/static/assets/{chunk-JWPE2WC7-vYvVJb_M.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
  96. ksadk/server/static/assets/{chunk-LCL6LL3I-BcI6ysPT.js → chunk-LCL6LL3I-CnorGV5q.js} +1 -1
  97. ksadk/server/static/assets/{chunk-POPQ4Y6H-C030x_Z1.js → chunk-POPQ4Y6H-CexntQA-.js} +1 -1
  98. ksadk/server/static/assets/{chunk-RHFEMEQ7-yyGpsz4n.js → chunk-RHFEMEQ7-CHTC7UxA.js} +1 -1
  99. ksadk/server/static/assets/{chunk-SVP7TREG-BLTlmMU7.js → chunk-SVP7TREG-BC1EWt_-.js} +1 -1
  100. ksadk/server/static/assets/{chunk-XXDRQBXY-C_32ArgP.js → chunk-XXDRQBXY-BTG24xN0.js} +1 -1
  101. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
  102. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
  103. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-9YQYwdl0.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
  104. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
  105. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-ErLF5N13.js → cynefinDiagram-5FMLGOSQ-DEOCBe15.js} +1 -1
  106. ksadk/server/static/assets/{dagre-3AP2YEHR-DFiQF-6f.js → dagre-3AP2YEHR-DBThPuLa.js} +1 -1
  107. ksadk/server/static/assets/{dagre-BuhGnRI1.js → dagre-ClTPrTht.js} +1 -1
  108. ksadk/server/static/assets/{diagram-S7CK7UJ4-Bt1v8-GC.js → diagram-S7CK7UJ4-DsZHrnpJ.js} +1 -1
  109. ksadk/server/static/assets/{diagram-UQ7AKVKN-DSCxJdBK.js → diagram-UQ7AKVKN-BJR4nhVr.js} +1 -1
  110. ksadk/server/static/assets/{diagram-VSXAHHWV-DHfYwp_9.js → diagram-VSXAHHWV-xzcERX0a.js} +1 -1
  111. ksadk/server/static/assets/{diagram-VX7I27RA-DdzD-4Le.js → diagram-VX7I27RA-tn2xM1xu.js} +1 -1
  112. ksadk/server/static/assets/{diagram-Z3DM3KII-Du-nAJ9F.js → diagram-Z3DM3KII-BZPGBkw5.js} +1 -1
  113. ksadk/server/static/assets/{dist-ClxGviKw.js → dist-4zN1_tq5.js} +1 -1
  114. ksadk/server/static/assets/{dist-BE7bu-DL.js → dist-8VWI-2bZ.js} +1 -1
  115. ksadk/server/static/assets/{dist-BX8z72IC.js → dist-B-46q3Hk.js} +1 -1
  116. ksadk/server/static/assets/{dist-BjU6y-A2.js → dist-B0gdk4rl.js} +1 -1
  117. ksadk/server/static/assets/{dist-C_wsv-Qd.js → dist-B1oWRmrH.js} +1 -1
  118. ksadk/server/static/assets/{dist-ngtN0DJB.js → dist-BI1qQH4n.js} +1 -1
  119. ksadk/server/static/assets/{dist-dydu68Fl.js → dist-BJLUwH6W.js} +1 -1
  120. ksadk/server/static/assets/{dist-Dq9gLD7L.js → dist-Bbwqa8TG.js} +1 -1
  121. ksadk/server/static/assets/{dist-CttYUqzS.js → dist-Btyo4vX4.js} +1 -1
  122. ksadk/server/static/assets/{dist-CXYYBw3_.js → dist-C71CsujO.js} +1 -1
  123. ksadk/server/static/assets/{dist-dDdADKFA.js → dist-CXpH_Rdd.js} +1 -1
  124. ksadk/server/static/assets/{dist-CSh_DE14.js → dist-Cq4OL6nO.js} +1 -1
  125. ksadk/server/static/assets/{dist-8hqcx0sU.js → dist-D1V3f1B4.js} +1 -1
  126. ksadk/server/static/assets/{dist-BVDffZ0U.js → dist-DJmCPRVB.js} +1 -1
  127. ksadk/server/static/assets/{dist-DnfXs8Vn.js → dist-DQAB0qn_.js} +1 -1
  128. ksadk/server/static/assets/{dist-DNp6rLRA.js → dist-DUwKa_l6.js} +1 -1
  129. ksadk/server/static/assets/{dist-B7seoj3d.js → dist-DdRBIceA.js} +1 -1
  130. ksadk/server/static/assets/{dist-BytlxIDT.js → dist-DfGFrb0v.js} +1 -1
  131. ksadk/server/static/assets/{dist-Bf2M8m3N.js → dist-DjhwGUgZ.js} +1 -1
  132. ksadk/server/static/assets/{dist-W-TIVntx.js → dist-DyqV4fL4.js} +1 -1
  133. ksadk/server/static/assets/{dist-DUX-id_F.js → dist-M67Hwu0n.js} +1 -1
  134. ksadk/server/static/assets/{dist-DmldrHd_.js → dist-u8tVH5Ak.js} +1 -1
  135. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Da9C9NO1.js → ebnfDiagram-PWID7BFC-DVfMsLge.js} +1 -1
  136. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-EAGqqR79.js → erDiagram-SSCWMZ5O-CWEZSYaw.js} +1 -1
  137. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
  138. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
  139. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DqJsKb59.js → ganttDiagram-EL5Y4UJY-TWIxoyYL.js} +1 -1
  140. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
  141. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-B6g4dtDi.js → gitGraphDiagram-WWUBYQGX-DDh2hd2S.js} +1 -1
  142. ksadk/server/static/assets/index-B2k_urY8.js +241 -0
  143. ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
  144. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
  145. ksadk/server/static/assets/{infoDiagram-RXCK75RN-Djm_nbd5.js → infoDiagram-RXCK75RN-CgoyWiDR.js} +1 -1
  146. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-DWya9SG2.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +1 -1
  147. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DutxhSNI.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +1 -1
  148. ksadk/server/static/assets/{kanban-definition-3QL26DDD-DJdOF8Fm.js → kanban-definition-3QL26DDD-CNP3ui66.js} +1 -1
  149. ksadk/server/static/assets/{katex-vFWytM5c.js → katex-DWEzQy1d.js} +1 -1
  150. ksadk/server/static/assets/{linear-BHjG8b-J.js → linear-C-qHp7d2.js} +1 -1
  151. ksadk/server/static/assets/{mermaid-parser.core-KGSy4jWT.js → mermaid-parser.core-Cl-K943T.js} +2 -2
  152. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-9-HC88D4.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +1 -1
  153. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
  154. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-DrEZd4fD.js → pegDiagram-XKGWAZYB-BQVc9ia_.js} +1 -1
  155. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
  156. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-DpjqOFFp.js → pieDiagram-E7YTZNPT-B6UCAvtY.js} +1 -1
  157. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BiNhgOXX.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +1 -1
  158. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
  159. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
  160. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
  161. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
  162. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
  163. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-_Y3Ojg6G.js → railroadDiagram-O6MQD6OU-Dt3FFDmK.js} +1 -1
  164. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-DeCFdg9K.js → requirementDiagram-EFPCY7ZU-Cz_vQtgF.js} +1 -1
  165. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-CPH75rhw.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +1 -1
  166. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-OEpQQdr4.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +1 -1
  167. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-heUErzhI.js → sizeCapture-X5ZJPWSS-DXX54iyO.js} +1 -1
  168. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DvA3jSMB.js → stateDiagram-HBIQ2CUA-Dp_lw9II.js} +1 -1
  169. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
  170. ksadk/server/static/assets/{swimlanes-XN3QIQJK-CR-dfN_t.js → swimlanes-XN3QIQJK-D8O5UlLG.js} +1 -1
  171. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
  172. ksadk/server/static/assets/{timeline-definition-24CTP7MA-DAVJf1TX.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +1 -1
  173. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
  174. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
  175. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-DwM8eDkh.js → vennDiagram-4TSXK5OY-EnNl0DE7.js} +1 -1
  176. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
  177. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DZL-Zz2t.js → wardleyDiagram-VM6X3IG4-DBu5fbYr.js} +1 -1
  178. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js → xychartDiagram-S5SC5T6Z-BSVXs4IY.js} +1 -1
  179. ksadk/server/static/index.html +2 -2
  180. ksadk/skills/service_client.py +48 -0
  181. ksadk/studio/agent_lifecycle.py +26 -20
  182. ksadk/studio/api.py +513 -71
  183. ksadk/studio/api_catalog_routes.py +5 -0
  184. ksadk/studio/api_contracts.py +34 -1
  185. ksadk/studio/api_plugin_routes.py +480 -0
  186. ksadk/studio/attachment_store.py +187 -0
  187. ksadk/studio/authoring.py +10 -4
  188. ksadk/studio/authoring_coordinator.py +12 -2
  189. ksadk/studio/builder.py +123 -43
  190. ksadk/studio/cloud.py +4 -0
  191. ksadk/studio/codex_agent_service.py +12 -1
  192. ksadk/studio/codex_builder.py +54 -15
  193. ksadk/studio/codex_manifest.py +21 -1
  194. ksadk/studio/codex_run.py +16 -4
  195. ksadk/studio/compatibility_report.py +445 -0
  196. ksadk/studio/compiler.py +6 -1
  197. ksadk/studio/contracts.py +123 -4
  198. ksadk/studio/dsh_provider_registration.py +768 -0
  199. ksadk/studio/event_store.py +54 -6
  200. ksadk/studio/framework_run.py +37 -4
  201. ksadk/studio/hosted_kernel.py +1 -1
  202. ksadk/studio/operations.py +12 -2
  203. ksadk/studio/plugin_composition.py +301 -0
  204. ksadk/studio/plugin_kernel_adapter.py +128 -0
  205. ksadk/studio/plugin_runtime.py +652 -0
  206. ksadk/studio/resource_catalog.py +6 -1
  207. ksadk/studio/run_service.py +713 -75
  208. ksadk/studio/runtime_source.py +9 -1
  209. ksadk/studio/scheduler_runtime.py +374 -0
  210. ksadk/studio/scheduler_service.py +211 -0
  211. ksadk/studio/service.py +672 -82
  212. ksadk/studio/shared_web.py +167 -28
  213. ksadk/studio/soul.py +52 -0
  214. ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
  215. ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
  216. ksadk/studio/static/index.html +2 -2
  217. ksadk/studio/validator.py +1 -1
  218. ksadk/studio/workspace.py +1 -0
  219. ksadk/version.py +1 -1
  220. ksadk_runtime_common/workspace_files/path_utils.py +41 -0
  221. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +0 -1
  222. ksadk/server/static/assets/channel-4cQHKtx1.js +0 -1
  223. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +0 -1
  224. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +0 -1
  225. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +0 -1
  226. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +0 -1
  227. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +0 -1
  228. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +0 -1
  229. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +0 -1
  230. ksadk/server/static/assets/index-8ipRcQ-M.js +0 -240
  231. ksadk/server/static/assets/index-ByFCqjlh.css +0 -2
  232. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +0 -1
  233. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +0 -1
  234. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +0 -1
  235. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +0 -1
  236. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +0 -1
  237. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +0 -1
  238. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +0 -1
  239. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +0 -1
  240. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +0 -1
  241. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +0 -8
  242. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +0 -1
  243. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +0 -1
  244. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +0 -1
  245. ksadk/studio/static/assets/index-BLpcdrgW.css +0 -1
  246. ksadk/studio/static/assets/index-CYekR2Xv.js +0 -260
  247. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
  248. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
  249. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
  250. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,416 @@
1
+ """Explicitly started local Scheduler Lite engine.
2
+
3
+ There is intentionally no import-time loop and no Studio lifespan hook here.
4
+ Local schedules run only while a caller starts this engine; deployment-wide
5
+ always-on scheduling belongs to the Server/Operator phase, not this component.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ from collections.abc import Callable, Sequence
12
+ from datetime import datetime, timedelta, timezone
13
+ from typing import Protocol
14
+ from uuid import uuid4
15
+
16
+ from ksadk.scheduler.calendar import next_schedule_time
17
+ from ksadk.scheduler.contracts import ScheduledTask, ScheduleOccurrence
18
+ from ksadk.scheduler.sqlite_store import SchedulerSQLiteStore
19
+
20
+
21
+ class SchedulerEventReader(Protocol):
22
+ """Read canonical SessionEvents for one accepted occurrence."""
23
+
24
+ async def read_events(self, occurrence: ScheduleOccurrence) -> Sequence[tuple[int, object]]: ...
25
+
26
+
27
+ class SchedulerDispatchReceipt(str):
28
+ """A backward-compatible dispatcher result with an event-log cursor.
29
+
30
+ It remains a ``str`` so existing local dispatcher implementations keep
31
+ working. The new ``accepted_seq`` lets the scheduler resume from exactly
32
+ the AgentControl admission fact rather than guessing from wall-clock time.
33
+ """
34
+
35
+ accepted_seq: int | None
36
+
37
+ def __new__(cls, command_id: str, *, accepted_seq: int | None = None):
38
+ value = super().__new__(cls, command_id)
39
+ value.accepted_seq = accepted_seq
40
+ return value
41
+
42
+
43
+ class SchedulerDispatchError(RuntimeError):
44
+ """A typed dispatcher failure safe to persist in occurrence history."""
45
+
46
+ def __init__(self, code: str, detail: str) -> None:
47
+ super().__init__(detail)
48
+ self.code = code
49
+ self.detail = detail
50
+
51
+
52
+ class SchedulerDispatcher(Protocol):
53
+ """The one execution seam. Implementations must submit AgentControl only."""
54
+
55
+ async def dispatch(self, task: ScheduledTask, occurrence: ScheduleOccurrence) -> str:
56
+ """Return AgentControl's accepted command ID, or raise a typed error."""
57
+
58
+
59
+ Clock = Callable[[], datetime]
60
+ TickGuard = Callable[[], bool]
61
+
62
+
63
+ class SchedulerEngine:
64
+ def __init__(
65
+ self,
66
+ store: SchedulerSQLiteStore,
67
+ dispatcher: SchedulerDispatcher,
68
+ *,
69
+ owner_id: str | None = None,
70
+ clock: Clock | None = None,
71
+ tick_guard: TickGuard | None = None,
72
+ lease_seconds: int = 30,
73
+ ) -> None:
74
+ self.store = store
75
+ self.dispatcher = dispatcher
76
+ self.owner_id = owner_id or f"studio-{uuid4().hex}"
77
+ self.clock = clock or (lambda: datetime.now(timezone.utc))
78
+ self.tick_guard = tick_guard
79
+ self.lease_seconds = lease_seconds
80
+ self._task: asyncio.Task[None] | None = None
81
+ self._stop = asyncio.Event()
82
+ self._poll_seconds: float | None = None
83
+ self._last_scan_at: datetime | None = None
84
+ self._last_scan_result: str | None = None
85
+ self._last_scan_detail: str | None = None
86
+ self._next_scan_at: datetime | None = None
87
+
88
+ @property
89
+ def running(self) -> bool:
90
+ return self._task is not None and not self._task.done()
91
+
92
+ def status(self) -> dict[str, object]:
93
+ """Return a UI-safe snapshot of the local trigger process.
94
+
95
+ This is operational state, not a claim that every configured task is
96
+ executable. ``waiting_runtime`` deliberately means the monitor is
97
+ alive but will not claim due work until its trusted Kernel route is
98
+ available again.
99
+ """
100
+
101
+ return {
102
+ "running": self.running,
103
+ "ownerId": self.owner_id,
104
+ "pollSeconds": self._poll_seconds,
105
+ "lastScanAt": self._last_scan_at,
106
+ "lastScanResult": self._last_scan_result,
107
+ "lastScanDetail": self._last_scan_detail,
108
+ "nextScanAt": self._next_scan_at,
109
+ }
110
+
111
+ async def tick(self) -> list[ScheduleOccurrence]:
112
+ """Claim every due occurrence once and submit it through AgentControl."""
113
+
114
+ now = self.clock().astimezone(timezone.utc)
115
+ self._last_scan_at = now
116
+ if self.tick_guard is not None and not self.tick_guard():
117
+ self._last_scan_result = "waiting_runtime"
118
+ self._last_scan_detail = "agent_kernel_route_inactive"
119
+ return []
120
+ owns_lease = await asyncio.to_thread(
121
+ self.store.acquire_lease,
122
+ owner_id=self.owner_id,
123
+ now=now,
124
+ ttl_seconds=self.lease_seconds,
125
+ )
126
+ if not owns_lease:
127
+ self._last_scan_result = "lease_not_owned"
128
+ self._last_scan_detail = "another_local_scheduler_owns_the_lease"
129
+ return []
130
+ await self.reconcile()
131
+ due = await asyncio.to_thread(self.store.list_due, now)
132
+ result: list[ScheduleOccurrence] = []
133
+ for task, generation in due:
134
+ occurrence = await self._claim_scheduled(task, generation, now)
135
+ if occurrence is None:
136
+ continue
137
+ result.append(occurrence)
138
+ if occurrence.state == "skipped":
139
+ continue
140
+ try:
141
+ dispatch = await self.dispatcher.dispatch(task, occurrence)
142
+ except SchedulerDispatchError as exc:
143
+ result[-1] = await asyncio.to_thread(
144
+ self.store.finish,
145
+ occurrence.occurrence_id,
146
+ succeeded=False,
147
+ error_code=exc.code,
148
+ detail=exc.detail,
149
+ )
150
+ except Exception as exc: # noqa: BLE001 - normalize boundary errors
151
+ result[-1] = await asyncio.to_thread(
152
+ self.store.finish,
153
+ occurrence.occurrence_id,
154
+ succeeded=False,
155
+ error_code="DISPATCH_FAILED",
156
+ detail=str(exc)[:1024],
157
+ )
158
+ else:
159
+ result[-1] = await asyncio.to_thread(
160
+ self.store.mark_accepted,
161
+ occurrence.occurrence_id,
162
+ str(dispatch),
163
+ accepted_seq=getattr(dispatch, "accepted_seq", None),
164
+ )
165
+ self._last_scan_result = "ok"
166
+ self._last_scan_detail = f"claimed={len(result)}"
167
+ return result
168
+
169
+ async def _claim_scheduled(
170
+ self,
171
+ task: ScheduledTask,
172
+ generation: int,
173
+ now: datetime,
174
+ ) -> ScheduleOccurrence | None:
175
+ assert task.next_run_at is not None
176
+ missed = task.next_run_at < now
177
+ next_run_at = next_schedule_time(
178
+ task.schedule,
179
+ after=now if missed else task.next_run_at,
180
+ anchor_at=task.created_at,
181
+ )
182
+ if missed and task.schedule.misfire_policy == "skip":
183
+ return await asyncio.to_thread(
184
+ self.store.claim_and_advance,
185
+ task,
186
+ generation=generation,
187
+ next_run_at=next_run_at,
188
+ state="skipped",
189
+ detail="misfire_skipped",
190
+ claimed_at=now,
191
+ )
192
+ if task.concurrency_policy == "forbid" and await asyncio.to_thread(
193
+ self.store.has_active_occurrence, task.task_id
194
+ ):
195
+ return await asyncio.to_thread(
196
+ self.store.claim_and_advance,
197
+ task,
198
+ generation=generation,
199
+ next_run_at=next_run_at,
200
+ state="skipped",
201
+ detail="concurrency_forbid_active_occurrence",
202
+ claimed_at=now,
203
+ )
204
+ return await asyncio.to_thread(
205
+ self.store.claim_and_advance,
206
+ task,
207
+ generation=generation,
208
+ next_run_at=next_run_at,
209
+ claimed_at=now,
210
+ )
211
+
212
+ async def run_now(self, task_id: str) -> ScheduleOccurrence:
213
+ """Explicit user action; it still uses the dispatcher and durable log."""
214
+
215
+ value = await asyncio.to_thread(self.store.get_task, task_id)
216
+ if value is None:
217
+ raise KeyError(task_id)
218
+ task, generation = value
219
+ if not task.enabled:
220
+ raise SchedulerDispatchError("TASK_DISABLED", "scheduled task is disabled")
221
+ if task.concurrency_policy == "forbid" and await asyncio.to_thread(
222
+ self.store.has_active_occurrence, task.task_id
223
+ ):
224
+ raise SchedulerDispatchError(
225
+ "CONCURRENCY_FORBID", "an earlier occurrence is still active"
226
+ )
227
+ # Run-now has a separate manual occurrence identity. It is intentionally
228
+ # not an implicit reschedule and does not advance the natural next time.
229
+ now = self.clock().astimezone(timezone.utc)
230
+ occurrence = await asyncio.to_thread(
231
+ self.store.claim_manual,
232
+ task,
233
+ generation=generation,
234
+ now=now,
235
+ )
236
+ if occurrence is None:
237
+ raise SchedulerDispatchError("TASK_CHANGED", "task changed while starting manually")
238
+ try:
239
+ dispatch = await self.dispatcher.dispatch(task, occurrence)
240
+ except SchedulerDispatchError as exc:
241
+ return await asyncio.to_thread(
242
+ self.store.finish,
243
+ occurrence.occurrence_id,
244
+ succeeded=False,
245
+ error_code=exc.code,
246
+ detail=exc.detail,
247
+ )
248
+ except Exception as exc: # noqa: BLE001
249
+ return await asyncio.to_thread(
250
+ self.store.finish,
251
+ occurrence.occurrence_id,
252
+ succeeded=False,
253
+ error_code="DISPATCH_FAILED",
254
+ detail=str(exc)[:1024],
255
+ )
256
+ return await asyncio.to_thread(
257
+ self.store.mark_accepted,
258
+ occurrence.occurrence_id,
259
+ str(dispatch),
260
+ accepted_seq=getattr(dispatch, "accepted_seq", None),
261
+ )
262
+
263
+ async def reconcile(self) -> list[ScheduleOccurrence]:
264
+ """Settle accepted work only from correlated canonical runtime facts.
265
+
266
+ ``AgentControlReceipt.accepted`` means the command entered Inbox; it
267
+ is deliberately not a success signal. The control run-transition
268
+ event carries the originating command id, then the matching runtime
269
+ terminal event decides the immutable occurrence outcome.
270
+ """
271
+
272
+ reader = getattr(self.dispatcher, "read_events", None)
273
+ if not callable(reader):
274
+ return []
275
+ changed: list[ScheduleOccurrence] = []
276
+ for occurrence in await asyncio.to_thread(self.store.list_active_occurrences):
277
+ if not occurrence.command_id or occurrence.target is None:
278
+ # Legacy local records lack the new immutable target snapshot.
279
+ # Preserve their accepted status rather than guessing a target.
280
+ continue
281
+ try:
282
+ events = await reader(occurrence)
283
+ except Exception: # noqa: BLE001 - retain accepted state for a later poll
284
+ continue
285
+ current = occurrence
286
+ for seq, envelope in events:
287
+ current = await self._reconcile_event(current, seq=seq, envelope=envelope)
288
+ if current.state in {"succeeded", "failed", "skipped", "cancelled"}:
289
+ break
290
+ if current != occurrence:
291
+ changed.append(current)
292
+ return changed
293
+
294
+ async def _reconcile_event(
295
+ self, occurrence: ScheduleOccurrence, *, seq: int, envelope: object
296
+ ) -> ScheduleOccurrence:
297
+ event_type = str(getattr(envelope, "event_type", ""))
298
+ event_run_id = str(getattr(envelope, "run_id", "") or "")
299
+ causation_id = str(getattr(envelope, "causation_id", "") or "")
300
+ payload = getattr(envelope, "payload", {}) or {}
301
+ if not isinstance(payload, dict):
302
+ payload = {}
303
+
304
+ if event_type == "control.run_transition" and causation_id == occurrence.command_id:
305
+ run_id = event_run_id or str(payload.get("run_id") or "")
306
+ if run_id:
307
+ run_state = str(payload.get("state") or "")
308
+ if run_state not in {"running", "paused", "waiting"}:
309
+ return await asyncio.to_thread(
310
+ self.store.bind_run,
311
+ occurrence.occurrence_id,
312
+ run_id=run_id,
313
+ last_event_seq=seq,
314
+ )
315
+ return await asyncio.to_thread(
316
+ self.store.mark_running,
317
+ occurrence.occurrence_id,
318
+ run_id=run_id,
319
+ last_event_seq=seq,
320
+ )
321
+ if occurrence.run_id and event_run_id == occurrence.run_id:
322
+ if event_type == "run.completed":
323
+ return await asyncio.to_thread(
324
+ self.store.finish,
325
+ occurrence.occurrence_id,
326
+ succeeded=True,
327
+ detail="runtime_completed",
328
+ )
329
+ if event_type in {"run.failed", "run.canceled", "run.interrupted"}:
330
+ error = payload.get("error")
331
+ code = (
332
+ str(error.get("code") or "RUNTIME_FAILED")
333
+ if isinstance(error, dict)
334
+ else event_type.upper().replace(".", "_")
335
+ )
336
+ detail = (
337
+ str(error.get("message") or event_type)
338
+ if isinstance(error, dict)
339
+ else event_type
340
+ )
341
+ return await asyncio.to_thread(
342
+ self.store.finish,
343
+ occurrence.occurrence_id,
344
+ succeeded=False,
345
+ error_code=code[:128],
346
+ detail=detail[:1024],
347
+ )
348
+ return await asyncio.to_thread(
349
+ self.store.advance_reconciliation_cursor,
350
+ occurrence.occurrence_id,
351
+ last_event_seq=seq,
352
+ )
353
+
354
+ async def settle(
355
+ self,
356
+ occurrence_id: str,
357
+ *,
358
+ succeeded: bool,
359
+ error_code: str | None = None,
360
+ detail: str | None = None,
361
+ ) -> ScheduleOccurrence:
362
+ """Called by the runtime-event reconciler, never by receipt handling."""
363
+
364
+ return await asyncio.to_thread(
365
+ self.store.finish,
366
+ occurrence_id,
367
+ succeeded=succeeded,
368
+ error_code=error_code,
369
+ detail=detail,
370
+ )
371
+
372
+ async def start(self, *, poll_seconds: float = 5.0) -> None:
373
+ if poll_seconds <= 0:
374
+ raise ValueError("poll_seconds must be positive")
375
+ if self._task is not None and not self._task.done():
376
+ return
377
+ # asyncio primitives bind to the loop that first waits on them. Studio
378
+ # tests and embedded hosts may start/stop the same service through a
379
+ # fresh event loop, so never reuse the previous loop's Event.
380
+ self._stop = asyncio.Event()
381
+ self._poll_seconds = poll_seconds
382
+
383
+ async def loop() -> None:
384
+ while not self._stop.is_set():
385
+ try:
386
+ await self.tick()
387
+ except Exception as exc: # noqa: BLE001 - keep the monitor alive
388
+ self._last_scan_at = self.clock().astimezone(timezone.utc)
389
+ self._last_scan_result = "error"
390
+ self._last_scan_detail = f"{type(exc).__name__}: {exc}"[:512]
391
+ self._next_scan_at = self.clock().astimezone(timezone.utc) + timedelta(
392
+ seconds=poll_seconds
393
+ )
394
+ try:
395
+ await asyncio.wait_for(self._stop.wait(), timeout=poll_seconds)
396
+ except TimeoutError:
397
+ pass
398
+
399
+ self._task = asyncio.create_task(loop(), name="ksadk-local-scheduler")
400
+
401
+ async def stop(self) -> None:
402
+ self._stop.set()
403
+ if self._task is None:
404
+ return
405
+ await self._task
406
+ self._task = None
407
+ self._next_scan_at = None
408
+
409
+
410
+ __all__ = [
411
+ "SchedulerDispatchError",
412
+ "SchedulerDispatchReceipt",
413
+ "SchedulerDispatcher",
414
+ "SchedulerEngine",
415
+ "SchedulerEventReader",
416
+ ]