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,98 @@
1
+ """Identity-aware reducer for a ConversationItem surface.
2
+
3
+ This reducer deliberately does not deduplicate by author or text. Providers
4
+ may emit the same content in two different items, and both are user-visible
5
+ truth. Reconnect de-duplication is limited to a previously applied source
6
+ event for the same item.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from collections import OrderedDict
12
+
13
+ from ksadk.conversations.contracts import ConversationItem
14
+
15
+
16
+ class ConversationItemReducer:
17
+ """Apply append/replace/completed operations while preserving item identity."""
18
+
19
+ def __init__(self) -> None:
20
+ self._items: OrderedDict[str, ConversationItem] = OrderedDict()
21
+ self._source_events: set[tuple[str, str]] = set()
22
+
23
+ def apply(self, item: ConversationItem) -> bool:
24
+ """Apply one item operation and return whether this changed the view."""
25
+
26
+ keys = {(item.item_id, source_id) for source_id in item.source_event_ids}
27
+ if keys and keys.issubset(self._source_events):
28
+ return False
29
+
30
+ existing = self._items.get(item.item_id)
31
+ if existing is not None and _terminal(existing) and not _terminal(item):
32
+ # A reconnect may replay an older delta after the terminal snapshot
33
+ # has already arrived on the live connection. Remember its event
34
+ # identity, but never regress a completed item back to streaming or
35
+ # append the stale delta a second time.
36
+ self._source_events.update(keys)
37
+ return False
38
+ if existing is None:
39
+ merged = item
40
+ elif item.operation == "append":
41
+ merged = item.model_copy(
42
+ update={
43
+ "payload": _append_payload(existing.payload, item.payload),
44
+ "source_event_ids": _merge_sources(
45
+ existing.source_event_ids,
46
+ item.source_event_ids,
47
+ ),
48
+ }
49
+ )
50
+ else:
51
+ merged = item.model_copy(
52
+ update={
53
+ "source_event_ids": _merge_sources(
54
+ existing.source_event_ids,
55
+ item.source_event_ids,
56
+ )
57
+ }
58
+ )
59
+ self._items[item.item_id] = merged
60
+ self._source_events.update(keys)
61
+ return True
62
+
63
+ def items(self) -> tuple[ConversationItem, ...]:
64
+ """Return presentation items in first-seen order."""
65
+
66
+ return tuple(self._items.values())
67
+
68
+
69
+ def _append_payload(
70
+ existing: dict[str, object],
71
+ update: dict[str, object],
72
+ ) -> dict[str, object]:
73
+ merged = dict(existing)
74
+ for key, value in update.items():
75
+ previous = merged.get(key)
76
+ if key == "text" and isinstance(previous, str) and isinstance(value, str):
77
+ merged[key] = previous + value
78
+ elif key in {"data", "operations"} and isinstance(previous, list) and isinstance(
79
+ value, list
80
+ ):
81
+ merged[key] = [*previous, *value]
82
+ else:
83
+ merged[key] = value
84
+ return merged
85
+
86
+
87
+ def _merge_sources(
88
+ current: tuple[str, ...],
89
+ incoming: tuple[str, ...],
90
+ ) -> tuple[str, ...]:
91
+ return tuple(dict.fromkeys((*current, *incoming)))
92
+
93
+
94
+ def _terminal(item: ConversationItem) -> bool:
95
+ return item.lifecycle in {"completed", "failed"}
96
+
97
+
98
+ __all__ = ["ConversationItemReducer"]
@@ -370,6 +370,8 @@ def _project_item_completed(
370
370
  if text_projection or event.item_kind in {"message", "reasoning"}:
371
371
  return text_projection
372
372
  if event.item_kind == "data":
373
+ if event.source.metadata.get("operation_batch") is True:
374
+ return ()
373
375
  ref = _a2ui_surface_ref(event, context)
374
376
  if ref is None:
375
377
  return ()
@@ -48,6 +48,7 @@ from ksadk.events.canonical import (
48
48
  ContinuationCreated,
49
49
  ContinuationResumed,
50
50
  ErrorInfo,
51
+ InteractionRequested,
51
52
  ItemCompleted,
52
53
  ItemFailed,
53
54
  ItemStarted,
@@ -56,10 +57,12 @@ from ksadk.events.canonical import (
56
57
  RunCanceled,
57
58
  RunCompleted,
58
59
  RunFailed,
60
+ RunInterrupted,
59
61
  RunProgress,
60
62
  RunStarted,
61
63
  RuntimeEvent,
62
64
  SourceRef,
65
+ StructuredInputRequest,
63
66
  UsageReported,
64
67
  )
65
68
  from ksadk.events.content import (
@@ -191,6 +194,20 @@ class CodexEventAdapter(_CodexInteractionMixin):
191
194
  return self._map_server_request_resolved(
192
195
  params=params, context=context, cursor=cursor, timestamp=timestamp
193
196
  )
197
+ if method == "a2ui/surface":
198
+ return self._map_a2ui_surface(
199
+ params=params,
200
+ context=context,
201
+ cursor=cursor,
202
+ timestamp=timestamp,
203
+ )
204
+ if method == "a2ui/interaction":
205
+ return self._map_a2ui_interaction(
206
+ params=params,
207
+ context=context,
208
+ cursor=cursor,
209
+ timestamp=timestamp,
210
+ )
194
211
  if method in _CONTROL_INTERACTION_METHODS:
195
212
  return self._map_control_interaction_request(
196
213
  message=message,
@@ -255,6 +272,179 @@ class CodexEventAdapter(_CodexInteractionMixin):
255
272
  )
256
273
  _fail("unsupported_method", "method", f"Unsupported Codex app-server method: {method}")
257
274
 
275
+ @staticmethod
276
+ def _a2ui_scope(
277
+ params: Mapping[str, Any],
278
+ context: CodexAdapterContext,
279
+ *,
280
+ surface_id: str,
281
+ ) -> tuple[str, str, str]:
282
+ thread_value = params.get("threadId", params.get("thread_id"))
283
+ turn_value = params.get("turnId", params.get("turn_id"))
284
+ thread_id = (
285
+ _required_string(thread_value, "params.threadId")
286
+ if thread_value is not None
287
+ else f"runtime:{context.run_id}"
288
+ )
289
+ turn_id = (
290
+ _required_string(turn_value, "params.turnId")
291
+ if turn_value is not None
292
+ else "a2ui"
293
+ )
294
+ return thread_id, turn_id, stable_scope_id("codex", thread_id, turn_id, surface_id)
295
+
296
+ @staticmethod
297
+ def _a2ui_source(
298
+ *,
299
+ method: str,
300
+ cursor: str,
301
+ thread_id: str,
302
+ turn_id: str,
303
+ native_item_id: str,
304
+ surface_id: str,
305
+ metadata: Mapping[str, Any] | None = None,
306
+ ) -> SourceRef:
307
+ source = _protocol_source(
308
+ method=method,
309
+ cursor=cursor,
310
+ thread_id=thread_id,
311
+ turn_id=turn_id,
312
+ native_item_id=native_item_id,
313
+ native_event_id=native_item_id,
314
+ )
315
+ return source.model_copy(
316
+ update={
317
+ "protocol": "a2ui",
318
+ "metadata": {
319
+ **source.metadata,
320
+ "surface_id": surface_id,
321
+ **dict(metadata or {}),
322
+ },
323
+ }
324
+ )
325
+
326
+ def _map_a2ui_surface(
327
+ self,
328
+ *,
329
+ params: Mapping[str, Any],
330
+ context: CodexAdapterContext,
331
+ cursor: str,
332
+ timestamp: float,
333
+ ) -> tuple[RuntimeEvent, ...]:
334
+ """Map one complete A2UI surface description as an immutable operation batch."""
335
+
336
+ surface_id = _required_string(params.get("surface_id"), "params.surface_id")
337
+ surface = _mapping(params.get("surface"), "params.surface")
338
+ thread_id, turn_id, scope_id = self._a2ui_scope(
339
+ params, context, surface_id=surface_id
340
+ )
341
+ item_id = stable_item_id("codex", scope_id, "a2ui-surface", surface_id)
342
+ source = self._a2ui_source(
343
+ method="a2ui/surface",
344
+ cursor=cursor,
345
+ thread_id=thread_id,
346
+ turn_id=turn_id,
347
+ native_item_id=surface_id,
348
+ surface_id=surface_id,
349
+ metadata={
350
+ "operation_batch": True,
351
+ "surface_lifecycle": "begin",
352
+ "catalog_id": str(surface.get("catalog_id") or surface.get("catalogId") or ""),
353
+ },
354
+ )
355
+ snapshot = ContentSnapshot(
356
+ parts=(
357
+ DataContent(
358
+ part_id="a2ui-surface",
359
+ data={"surface_id": surface_id, **_json_value(surface)},
360
+ ),
361
+ )
362
+ )
363
+ env = _envelope(context, cursor, timestamp)
364
+ return (
365
+ ItemStarted(
366
+ **env(scope_id, item_id, "item.started", "a2ui-surface", source),
367
+ item_id=item_id,
368
+ item_kind="data",
369
+ initial=snapshot,
370
+ ),
371
+ ItemCompleted(
372
+ **env(scope_id, item_id, "item.completed", "a2ui-surface", source),
373
+ item_id=item_id,
374
+ item_kind="data",
375
+ snapshot=snapshot,
376
+ ),
377
+ )
378
+
379
+ def _map_a2ui_interaction(
380
+ self,
381
+ *,
382
+ params: Mapping[str, Any],
383
+ context: CodexAdapterContext,
384
+ cursor: str,
385
+ timestamp: float,
386
+ ) -> tuple[RuntimeEvent, ...]:
387
+ """Map the client-owned A2UI input request without changing its live call id."""
388
+
389
+ surface_id = _required_string(params.get("surface_id"), "params.surface_id")
390
+ interaction_id = _required_string(
391
+ params.get("interaction_id"), "params.interaction_id"
392
+ )
393
+ kind = _required_string(params.get("kind"), "params.kind")
394
+ schema = _mapping(params.get("input_schema"), "params.input_schema")
395
+ is_blocking = params.get("is_blocking", True)
396
+ if not isinstance(is_blocking, bool):
397
+ _fail(
398
+ "invalid_interaction_request",
399
+ "params.is_blocking",
400
+ "A2UI is_blocking must be a boolean",
401
+ )
402
+ thread_id, turn_id, scope_id = self._a2ui_scope(
403
+ params, context, surface_id=surface_id
404
+ )
405
+ source = self._a2ui_source(
406
+ method="a2ui/interaction",
407
+ cursor=cursor,
408
+ thread_id=thread_id,
409
+ turn_id=turn_id,
410
+ native_item_id=interaction_id,
411
+ surface_id=surface_id,
412
+ metadata={"kind": kind, "is_blocking": is_blocking},
413
+ )
414
+ env = _envelope(context, cursor, timestamp)
415
+ requested = InteractionRequested(
416
+ **env(
417
+ scope_id,
418
+ interaction_id,
419
+ "interaction.requested",
420
+ "structured_input",
421
+ source,
422
+ ),
423
+ interaction_id=interaction_id,
424
+ interaction_kind="structured_input",
425
+ request=StructuredInputRequest(prompt=None, schema=_json_value(schema)),
426
+ )
427
+ if not is_blocking:
428
+ return (requested,)
429
+ return (
430
+ requested,
431
+ RunInterrupted(
432
+ **env(
433
+ scope_id,
434
+ turn_id,
435
+ "run.interrupted",
436
+ interaction_id,
437
+ source,
438
+ ),
439
+ status="interrupted",
440
+ reason="Codex requires user interaction",
441
+ interaction_id=interaction_id,
442
+ continuation_id=self._thread_continuations.setdefault(
443
+ thread_id, _thread_continuation_identity(thread_id)[1]
444
+ ),
445
+ ),
446
+ )
447
+
258
448
  def _map_token_usage(
259
449
  self,
260
450
  *,
ksadk/harness/__init__.py CHANGED
@@ -1,35 +1,45 @@
1
- """HarnessApp — 统一 Runtime 的可部署交付物 / composition root (goal-08)。"""
2
-
3
- from ksadk.harness.app import HarnessApp, HarnessCapabilities, HarnessPlugin
4
- from ksadk.harness.config import (
5
- HarnessConfig,
6
- HarnessConfigError,
7
- McpToolSpec,
8
- SandboxPolicy,
9
- )
10
- from ksadk.harness.reasoner import (
11
- HarnessReasoner,
12
- HarnessReasoningTurn,
13
- HarnessToolCall,
14
- LiteLLMHarnessReasoner,
15
- )
16
- from ksadk.harness.runtime import HarnessRuntime, HarnessRuntimeAdapter
17
- from ksadk.harness.sandbox import HarnessSandboxExecutor, SandboxPolicyDenied
18
-
19
- __all__ = [
20
- "HarnessApp",
21
- "HarnessCapabilities",
22
- "HarnessConfig",
23
- "HarnessConfigError",
24
- "HarnessPlugin",
25
- "HarnessReasoner",
26
- "HarnessRuntime",
27
- "HarnessRuntimeAdapter",
28
- "HarnessReasoningTurn",
29
- "HarnessSandboxExecutor",
30
- "HarnessToolCall",
31
- "LiteLLMHarnessReasoner",
32
- "McpToolSpec",
33
- "SandboxPolicy",
34
- "SandboxPolicyDenied",
35
- ]
1
+ """Public Harness surface without eagerly requiring an ADK runtime.
2
+
3
+ Studio must be usable for Codex and DSH Providers from a base ``ksadk``
4
+ installation. Harness keeps ADK as an optional execution dependency, so
5
+ importing its configuration types cannot import the full Harness runtime.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from importlib import import_module
11
+ from typing import Any
12
+
13
+ _EXPORTS = {
14
+ "HarnessApp": ("ksadk.harness.app", "HarnessApp"),
15
+ "HarnessCapabilities": ("ksadk.harness.app", "HarnessCapabilities"),
16
+ "HarnessPlugin": ("ksadk.harness.app", "HarnessPlugin"),
17
+ "HarnessConfig": ("ksadk.harness.config", "HarnessConfig"),
18
+ "HarnessConfigError": ("ksadk.harness.config", "HarnessConfigError"),
19
+ "McpToolSpec": ("ksadk.harness.config", "McpToolSpec"),
20
+ "SandboxPolicy": ("ksadk.harness.config", "SandboxPolicy"),
21
+ "HarnessReasoner": ("ksadk.harness.reasoner", "HarnessReasoner"),
22
+ "HarnessReasoningTurn": ("ksadk.harness.reasoner", "HarnessReasoningTurn"),
23
+ "HarnessToolCall": ("ksadk.harness.reasoner", "HarnessToolCall"),
24
+ "LiteLLMHarnessReasoner": ("ksadk.harness.reasoner", "LiteLLMHarnessReasoner"),
25
+ "HarnessRuntime": ("ksadk.harness.runtime", "HarnessRuntime"),
26
+ "HarnessRuntimeAdapter": ("ksadk.harness.runtime", "HarnessRuntimeAdapter"),
27
+ "HarnessSandboxExecutor": ("ksadk.harness.sandbox", "HarnessSandboxExecutor"),
28
+ "SandboxPolicyDenied": ("ksadk.harness.sandbox", "SandboxPolicyDenied"),
29
+ }
30
+
31
+ __all__ = list(_EXPORTS)
32
+
33
+
34
+ def __getattr__(name: str) -> Any:
35
+ try:
36
+ module_name, attribute = _EXPORTS[name]
37
+ except KeyError:
38
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
39
+ value = getattr(import_module(module_name), attribute)
40
+ globals()[name] = value
41
+ return value
42
+
43
+
44
+ def __dir__() -> list[str]:
45
+ return sorted({*globals(), *__all__})
ksadk/harness/runtime.py CHANGED
@@ -72,6 +72,19 @@ class _HarnessRun:
72
72
  done: bool = False
73
73
 
74
74
 
75
+ @dataclass
76
+ class _HarnessSession:
77
+ """Process-local transcript and serialization boundary for one Session.
78
+
79
+ The public capability matrix deliberately advertises process-scoped,
80
+ non-durable continuity. Keeping this state on the adapter makes that
81
+ declaration true without pretending that a restart can recover it.
82
+ """
83
+
84
+ messages: list[dict[str, Any]]
85
+ lock: asyncio.Lock
86
+
87
+
75
88
  class HarnessRuntimeAdapter(RuntimeAdapter):
76
89
  """Execute a YAML Harness config directly as RuntimeEvent streams."""
77
90
 
@@ -95,6 +108,7 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
95
108
  self._tools: tuple[HarnessTool, ...] | None = None
96
109
  self._tool_lock = asyncio.Lock()
97
110
  self._mcp_toolsets: list[Any] = []
111
+ self._sessions: dict[tuple[str, str, str], _HarnessSession] = {}
98
112
 
99
113
  @property
100
114
  def harness_config(self) -> HarnessConfig:
@@ -167,16 +181,43 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
167
181
  if not self._runs:
168
182
  await self._close_tools()
169
183
 
184
+ async def close_all(self) -> None:
185
+ """Dispose every process-local run owned by this adapter instance."""
186
+
187
+ for run_id, run in list(self._runs.items()):
188
+ await self.close(
189
+ RunHandle(
190
+ run_id=run_id,
191
+ session_id=run.request.session_id,
192
+ runtime_type="harness",
193
+ native_ref={
194
+ "user_id": run.request.user_id,
195
+ "agent_id": run.request.agent_id,
196
+ },
197
+ )
198
+ )
199
+
170
200
  def is_handle_attached(self, handle: RunHandle) -> bool:
171
201
  return handle.run_id in self._runs
172
202
 
173
203
  async def execute_request(self, request: StartRequest) -> dict[str, Any]:
204
+ session = self._session_for(request)
205
+ async with session.lock:
206
+ return await self._execute_session_request(request, session)
207
+
208
+ async def _execute_session_request(
209
+ self,
210
+ request: StartRequest,
211
+ session: _HarnessSession,
212
+ ) -> dict[str, Any]:
174
213
  tools = await self._ensure_tools()
175
214
  model, prompt = self._effective(request)
176
215
  messages: list[dict[str, Any]] = [
177
216
  {"role": "system", "content": prompt},
178
- {"role": "user", "content": str(request.input or "")},
217
+ *[dict(message) for message in session.messages],
179
218
  ]
219
+ user_message = {"role": "user", "content": str(request.input or "")}
220
+ messages.append(user_message)
180
221
  execution_log: list[dict[str, Any]] = []
181
222
 
182
223
  for _turn_number in range(_MAX_REASONING_TURNS):
@@ -235,6 +276,12 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
235
276
  raise RuntimeError(
236
277
  "Harness reasoner returned neither a final response nor a tool call"
237
278
  )
279
+ final_message = {"role": "assistant", "content": turn.final_text}
280
+ messages.append(final_message)
281
+ # Failed or cancelled turns never commit a partial transcript.
282
+ # A successful turn atomically replaces the process-local history
283
+ # while the per-session lock is still held.
284
+ session.messages[:] = [dict(message) for message in messages[1:]]
238
285
  return {
239
286
  "output": turn.final_text,
240
287
  "model": model,
@@ -244,6 +291,18 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
244
291
  }
245
292
  raise RuntimeError(f"Harness reasoning exceeded {_MAX_REASONING_TURNS} turns")
246
293
 
294
+ def _session_for(self, request: StartRequest) -> _HarnessSession:
295
+ key = (
296
+ str(request.agent_id or self._agent_name),
297
+ str(request.user_id),
298
+ str(request.session_id),
299
+ )
300
+ session = self._sessions.get(key)
301
+ if session is None:
302
+ session = _HarnessSession(messages=[], lock=asyncio.Lock())
303
+ self._sessions[key] = session
304
+ return session
305
+
247
306
  def _effective(self, request: StartRequest) -> tuple[str, str]:
248
307
  metadata = request.metadata or {}
249
308
  model = str(
@@ -15,7 +15,7 @@ from typing import Any
15
15
 
16
16
  AGENT_KERNEL_V1_CONTRACT_SET = "agent-kernel/v1"
17
17
  AGENT_KERNEL_V1_AGGREGATE_DIGEST = (
18
- "47e1003e03d97abeba232cc3e03a14b9cbcf78b1109870ccd2ce371f073b6211"
18
+ "b610a25aae957306b9f84a2cc2c948b30d1ce6218585cfd2a91f96736b92d102"
19
19
  )
20
20
 
21
21
 
@@ -23,12 +23,13 @@ def runtime_capability_matrix_wire_value(matrix: Any) -> dict[str, Any]:
23
23
  """Serialize the additive matrix without materializing absent v2 modes.
24
24
 
25
25
  Pydantic includes optional ``None`` defaults in ``model_dump``. Omitting
26
- those three top-level keys preserves the exact pre-extension wire value and
27
- capability digest for runtimes that do not publish goal/loop/plan.
26
+ those additive top-level keys preserves the exact pre-extension wire value
27
+ and capability digest for runtimes that do not publish execution controls
28
+ or an interaction delivery mode.
28
29
  """
29
30
 
30
31
  dump = matrix.model_dump(mode="json")
31
- for key in ("goal", "loop", "plan"):
32
+ for key in ("interaction_mode", "goal", "loop", "plan"):
32
33
  if dump.get(key) is None:
33
34
  dump.pop(key, None)
34
35
  return dump
ksadk/kernel/contracts.py CHANGED
@@ -309,6 +309,14 @@ class RuntimeCapabilityMatrix(WireModel):
309
309
  inject: RuntimeCapability
310
310
  checkpoint: RuntimeCapability
311
311
  durable_restore: RuntimeCapability
312
+ # Interaction delivery is deliberately separate from the verb matrix:
313
+ # ``submit_interaction`` alone does not tell a caller whether the reply
314
+ # reaches a live process, resumes a checkpoint, or has no native route.
315
+ # It remains optional so a v1 consumer can read records emitted before
316
+ # this additive declaration without inventing support.
317
+ interaction_mode: Literal[
318
+ "live_submit", "durable_resume", "unavailable"
319
+ ] | None = None
312
320
  # Runtime v2 execution controls are additive optional capabilities. Older
313
321
  # runtimes omit them; a runtime must never infer support from UI presence.
314
322
  # ``loop`` specifically means an externally bounded, eval-driven
ksadk/kernel/control.py CHANGED
@@ -57,6 +57,7 @@ def default_capability_matrix() -> RuntimeCapabilityMatrix:
57
57
  inject=_unavailable("runtime_no_native_inject"),
58
58
  checkpoint=_unavailable(),
59
59
  durable_restore=_unavailable(),
60
+ interaction_mode="unavailable",
60
61
  )
61
62
 
62
63
 
ksadk/kernel/ingress.py CHANGED
@@ -421,6 +421,26 @@ def map_studio_request(
421
421
  )
422
422
 
423
423
 
424
+ def map_scheduler_request(
425
+ *,
426
+ session_id: str,
427
+ idempotency_key: str,
428
+ content: Any,
429
+ occurrence_id: str,
430
+ trusted: TrustedRuntimeContext,
431
+ ) -> AgentControlCommand:
432
+ """Scheduler occurrence -> enqueue with durable source and correlation IDs."""
433
+
434
+ return _command(
435
+ trusted=trusted,
436
+ command_type="enqueue",
437
+ session_id=session_id,
438
+ idempotency_key=idempotency_key,
439
+ payload={"content": content},
440
+ correlation_id=occurrence_id,
441
+ )
442
+
443
+
424
444
  def map_control_request(
425
445
  *,
426
446
  command_type: str,
@@ -1091,6 +1111,7 @@ __all__ = [
1091
1111
  "map_control_request",
1092
1112
  "map_responses_request",
1093
1113
  "map_run_request",
1114
+ "map_scheduler_request",
1094
1115
  "map_studio_request",
1095
1116
  "receipt_error_payload",
1096
1117
  "receipt_http_status",
@@ -1124,6 +1124,7 @@ class InMemoryAgentKernelStore:
1124
1124
  "fencing_token": int(expected_fence),
1125
1125
  },
1126
1126
  run_id=run.run_id,
1127
+ causation_id=str(run.metadata.get("command_id") or "") or None,
1127
1128
  ),
1128
1129
  activation_row=activation,
1129
1130
  )
@@ -1647,6 +1647,7 @@ class PostgresAgentKernelStore:
1647
1647
  "fencing_token": int(expected_fence),
1648
1648
  },
1649
1649
  run_id=run.run_id,
1650
+ causation_id=str(run.metadata.get("command_id") or "") or None,
1650
1651
  ),
1651
1652
  activation,
1652
1653
  expected_fence,
@@ -1400,6 +1400,7 @@ class SQLiteAgentKernelStore:
1400
1400
  "fencing_token": int(expected_fence),
1401
1401
  },
1402
1402
  run_id=run.run_id,
1403
+ causation_id=str(run.metadata.get("command_id") or "") or None,
1403
1404
  ),
1404
1405
  activation,
1405
1406
  expected_fence,
ksadk/kernel/worker.py CHANGED
@@ -356,6 +356,17 @@ class AgentKernelWorker:
356
356
  agent_instance_id=command.agent_instance_id,
357
357
  session_id=command.session_id,
358
358
  state=RunState.PENDING,
359
+ # Keep the admitted control identity on the durable run. This is
360
+ # not user-supplied metadata: it is copied from the trusted
361
+ # command that the worker actually claimed. Consumers such as the
362
+ # local Scheduler can therefore reconcile a runtime terminal fact
363
+ # back to one occurrence without matching text or wall-clock time.
364
+ metadata={
365
+ "command_id": str(command.command_id),
366
+ "source_kind": command.source.kind,
367
+ "source_ref": command.source.ref,
368
+ "correlation_id": command.correlation_id,
369
+ },
359
370
  )
360
371
  created = await self._store.save_run_transition(pending, expected_fence=fence)
361
372
  continuation_metadata = await self._session_continuation_metadata(command.session_id)
@@ -141,6 +141,13 @@ class SqliteMemoryProvider:
141
141
  workspace_id: str = "local",
142
142
  ) -> None:
143
143
  self._db_path = str(db_path)
144
+ if self._db_path != ":memory:":
145
+ # A fresh local Studio has not created its session directory yet.
146
+ # SQLite creates the database file, but not missing parents.
147
+ Path(self._db_path).expanduser().resolve().parent.mkdir(
148
+ parents=True,
149
+ exist_ok=True,
150
+ )
144
151
  self._tenant_id = tenant_id
145
152
  self._workspace_id = workspace_id
146
153
  self._lock = threading.Lock()