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
@@ -30,7 +30,15 @@ def materialize_generated_runtime_source(
30
30
  """
31
31
 
32
32
  runtime = draft.spec.runtime
33
- if runtime is None or runtime.type == "codex" or not runtime.project_path:
33
+ # Only the two legacy Python-framework runtimes own generated source.
34
+ # Harness and externally installed AgentProviders are bundle compositions;
35
+ # treating either as the ``else`` branch here would silently generate a
36
+ # LangGraph project and change the selected provider's execution model.
37
+ if (
38
+ runtime is None
39
+ or runtime.type not in {"adk", "langgraph"}
40
+ or not runtime.project_path
41
+ ):
34
42
  return
35
43
  root = workspace.resolve(runtime.project_path)
36
44
  marker = root / _GENERATED_MARKER
@@ -0,0 +1,374 @@
1
+ """Build-pinned AgentKernel runtimes owned by the local Studio scheduler.
2
+
3
+ The ordinary Studio conversation path may keep using its historical direct
4
+ RuntimeExecutor or an independently enabled HTTP Kernel. Scheduler Lite owns
5
+ neither of those lifecycles. Instead it lazily starts one in-process Kernel
6
+ runtime for each immutable Build referenced by a local scheduled task.
7
+
8
+ This is intentionally a registry rather than another process-global Kernel:
9
+ one AgentKernelWorker has one concrete RuntimeAdapter factory, so reusing a
10
+ single global worker for multiple Studio Builds can execute the wrong Agent.
11
+ The registry keeps ``Build -> instance -> Runtime`` exact and dispatches every
12
+ occurrence through that runtime's AgentControl Inbox and canonical
13
+ SessionEvent log.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import asyncio
19
+ import hashlib
20
+ from collections.abc import Callable
21
+ from dataclasses import dataclass
22
+ from uuid import uuid4
23
+
24
+ from ksadk.kernel.bootstrap import (
25
+ AgentKernelRuntime,
26
+ AgentKernelRuntimeConfig,
27
+ build_agent_kernel_runtime,
28
+ )
29
+ from ksadk.kernel.contracts import (
30
+ AgentControlCommand,
31
+ AgentControlPermit,
32
+ AgentControlReceipt,
33
+ SessionEventSubscription,
34
+ )
35
+ from ksadk.kernel.ingress import trusted_context
36
+ from ksadk.runtime import RuntimeAdapter
37
+ from ksadk.scheduler.contracts import ScheduledTaskTarget, ScheduleOccurrence
38
+ from ksadk.sessions.base import BaseSessionService
39
+ from ksadk.studio.run_service import StudioRunSpec
40
+
41
+ ResolveBuild = Callable[[str], StudioRunSpec]
42
+ ResolveAdapterProvider = Callable[
43
+ [StudioRunSpec], Callable[[], RuntimeAdapter]
44
+ ]
45
+
46
+
47
+ class StudioSchedulerRuntimeError(RuntimeError):
48
+ """Stable local scheduling failure safe to persist on an occurrence."""
49
+
50
+ def __init__(self, code: str, message: str) -> None:
51
+ super().__init__(message)
52
+ self.code = code
53
+
54
+
55
+ @dataclass(frozen=True)
56
+ class StudioScheduledRuntimeTarget:
57
+ """Server-owned immutable routing facts persisted on ScheduledTask/v1."""
58
+
59
+ build_id: str
60
+ agent_id: str
61
+ tenant_id: str
62
+ agent_instance_id: str
63
+
64
+
65
+ @dataclass
66
+ class _RuntimeEntry:
67
+ target: StudioScheduledRuntimeTarget
68
+ spec: StudioRunSpec
69
+ runtime: AgentKernelRuntime
70
+
71
+
72
+ class StudioScheduledKernelRegistry:
73
+ """Own exact per-Build Kernel runtimes for one Studio process.
74
+
75
+ The registry does not register anything in ``ksadk.kernel.ingress`` and
76
+ therefore cannot redirect normal conversations or hosted HTTP traffic.
77
+ Scheduler dispatch uses :meth:`submit` and :meth:`read_events` directly,
78
+ while still crossing the frozen AgentControl permit/admission boundary.
79
+ """
80
+
81
+ def __init__(
82
+ self,
83
+ *,
84
+ resolve_build: ResolveBuild,
85
+ resolve_adapter_provider: ResolveAdapterProvider,
86
+ session_service: BaseSessionService,
87
+ runtime_executor: object | None = None,
88
+ tenant_id: str = "local-studio",
89
+ workspace_id: str = "studio-scheduler",
90
+ poll_interval: float = 0.05,
91
+ lease_ttl_seconds: float = 30.0,
92
+ ) -> None:
93
+ self._resolve_build = resolve_build
94
+ self._resolve_adapter_provider = resolve_adapter_provider
95
+ self._session_service = session_service
96
+ self._runtime_executor = runtime_executor
97
+ self._tenant_id = tenant_id
98
+ self._workspace_id = workspace_id
99
+ self._poll_interval = poll_interval
100
+ self._lease_ttl_seconds = lease_ttl_seconds
101
+ self._owner_id = uuid4().hex
102
+ self._entries_by_build: dict[str, _RuntimeEntry] = {}
103
+ self._build_by_instance: dict[str, str] = {}
104
+ self._lock = asyncio.Lock()
105
+ self._started = False
106
+
107
+ @property
108
+ def started(self) -> bool:
109
+ return self._started
110
+
111
+ @property
112
+ def active_runtime_count(self) -> int:
113
+ return len(self._entries_by_build)
114
+
115
+ async def start(self) -> None:
116
+ self._started = True
117
+
118
+ async def ensure_build(
119
+ self,
120
+ build_id: str,
121
+ *,
122
+ expected_agent_id: str | None = None,
123
+ ) -> StudioScheduledRuntimeTarget:
124
+ """Start or return the exact Runtime owned by one immutable Build."""
125
+
126
+ normalized = str(build_id).strip()
127
+ if not normalized:
128
+ raise StudioSchedulerRuntimeError(
129
+ "SCHEDULER_BUILD_REQUIRED",
130
+ "定时任务缺少不可变 Build 标识",
131
+ )
132
+ if not self._started:
133
+ raise StudioSchedulerRuntimeError(
134
+ "SCHEDULER_RUNTIME_NOT_STARTED",
135
+ "Studio Scheduler Runtime 尚未启动",
136
+ )
137
+ existing = self._entries_by_build.get(normalized)
138
+ if existing is not None:
139
+ self._require_agent(existing.spec, expected_agent_id)
140
+ return existing.target
141
+
142
+ async with self._lock:
143
+ existing = self._entries_by_build.get(normalized)
144
+ if existing is not None:
145
+ self._require_agent(existing.spec, expected_agent_id)
146
+ return existing.target
147
+ try:
148
+ spec = self._resolve_build(normalized)
149
+ except Exception as error:
150
+ raise StudioSchedulerRuntimeError(
151
+ "SCHEDULER_BUILD_UNAVAILABLE",
152
+ f"定时任务绑定的 Build {normalized!r} 不可用",
153
+ ) from error
154
+ if spec.build_id != normalized:
155
+ raise StudioSchedulerRuntimeError(
156
+ "SCHEDULER_BUILD_MISMATCH",
157
+ "Build 解析结果与定时任务绑定不一致",
158
+ )
159
+ self._require_agent(spec, expected_agent_id)
160
+ try:
161
+ adapter_provider = self._resolve_adapter_provider(spec)
162
+ except Exception as error:
163
+ raise StudioSchedulerRuntimeError(
164
+ "SCHEDULER_PROVIDER_UNAVAILABLE",
165
+ f"Build {normalized!r} 的 AgentProvider 不可用",
166
+ ) from error
167
+
168
+ # ``build_agent_kernel_runtime`` asks the provider once to snapshot
169
+ # capabilities. Retain that exact adapter for the first worker or
170
+ # recovery acquisition instead of constructing and discarding a
171
+ # resource-owning Codex/Harness adapter during registration.
172
+ retained_first_adapter: RuntimeAdapter | None = None
173
+ first_adapter_borrowed = False
174
+
175
+ def checked_adapter_provider() -> RuntimeAdapter:
176
+ nonlocal retained_first_adapter, first_adapter_borrowed
177
+ if retained_first_adapter is not None and not first_adapter_borrowed:
178
+ first_adapter_borrowed = True
179
+ adapter = retained_first_adapter
180
+ retained_first_adapter = None
181
+ return adapter
182
+ adapter = adapter_provider()
183
+ if not isinstance(adapter, RuntimeAdapter):
184
+ raise StudioSchedulerRuntimeError(
185
+ "SCHEDULER_PROVIDER_INVALID",
186
+ "AgentProvider 没有返回 RuntimeAdapter",
187
+ )
188
+ if retained_first_adapter is None and not first_adapter_borrowed:
189
+ retained_first_adapter = adapter
190
+ return adapter
191
+
192
+ instance_id = self._instance_id(normalized)
193
+ config = AgentKernelRuntimeConfig(
194
+ agent_instance_id=instance_id,
195
+ authority_mode="local",
196
+ driver="memory",
197
+ durability_tier="ephemeral",
198
+ adapter_provider=checked_adapter_provider,
199
+ session_service=self._session_service,
200
+ runtime_executor=self._runtime_executor,
201
+ launch_context=spec.launch_context,
202
+ start_request_defaults=self._start_defaults(spec),
203
+ tenant_id=self._tenant_id,
204
+ workspace_id=self._workspace_id,
205
+ poll_interval=self._poll_interval,
206
+ lease_ttl_seconds=self._lease_ttl_seconds,
207
+ activation_id=f"studio-scheduler:{self._owner_id}:{instance_id}",
208
+ runtime_type=spec.launch_context.runtime_type,
209
+ bundle_digest=spec.manifest_sha256 or normalized,
210
+ )
211
+ runtime = build_agent_kernel_runtime(config)
212
+ try:
213
+ await runtime.start()
214
+ except Exception:
215
+ await runtime.close()
216
+ raise
217
+ target = StudioScheduledRuntimeTarget(
218
+ build_id=normalized,
219
+ agent_id=spec.agent_id,
220
+ tenant_id=self._tenant_id,
221
+ agent_instance_id=instance_id,
222
+ )
223
+ self._entries_by_build[normalized] = _RuntimeEntry(
224
+ target=target,
225
+ spec=spec,
226
+ runtime=runtime,
227
+ )
228
+ self._build_by_instance[instance_id] = normalized
229
+ return target
230
+
231
+ async def ensure_target(
232
+ self, target: ScheduledTaskTarget
233
+ ) -> StudioScheduledRuntimeTarget:
234
+ build_id = str(target.agent_version_ref or "").strip()
235
+ exact = await self.ensure_build(
236
+ build_id,
237
+ expected_agent_id=target.agent_id,
238
+ )
239
+ if (
240
+ target.tenant_id != exact.tenant_id
241
+ or target.agent_instance_id != exact.agent_instance_id
242
+ ):
243
+ raise StudioSchedulerRuntimeError(
244
+ "SCHEDULER_TARGET_MISMATCH",
245
+ "定时任务目标与不可变 Build 的 Kernel 身份不一致",
246
+ )
247
+ return exact
248
+
249
+ def runtime_for_build(self, build_id: str) -> AgentKernelRuntime:
250
+ entry = self._entries_by_build.get(str(build_id))
251
+ if entry is None:
252
+ raise StudioSchedulerRuntimeError(
253
+ "SCHEDULER_TARGET_UNAVAILABLE",
254
+ "定时任务目标 Kernel 未注册",
255
+ )
256
+ return entry.runtime
257
+
258
+ async def submit(
259
+ self,
260
+ command: AgentControlCommand,
261
+ permit: AgentControlPermit,
262
+ ) -> AgentControlReceipt:
263
+ entry = self._entry_for_instance(command.agent_instance_id)
264
+ if command.tenant_id != entry.target.tenant_id:
265
+ raise StudioSchedulerRuntimeError(
266
+ "SCHEDULER_TARGET_MISMATCH",
267
+ "AgentControl tenant 与 Build Kernel 不一致",
268
+ )
269
+ if await self._session_service.get_session(command.session_id) is None:
270
+ await self._session_service.create_session(
271
+ agent_id=entry.target.agent_id,
272
+ user_id=command.tenant_id,
273
+ session_id=command.session_id,
274
+ )
275
+ return await entry.runtime.kernel.submit(command, permit=permit)
276
+
277
+ async def read_events(
278
+ self, occurrence: ScheduleOccurrence
279
+ ) -> tuple[tuple[int, object], ...]:
280
+ target = occurrence.target
281
+ if target is None:
282
+ return ()
283
+ await self.ensure_target(target)
284
+ entry = self._entry_for_instance(target.agent_instance_id)
285
+ trusted = trusted_context(
286
+ source_kind="scheduler",
287
+ source_ref=occurrence.occurrence_id,
288
+ tenant_id=target.tenant_id,
289
+ agent_instance_id=target.agent_instance_id,
290
+ session_id=occurrence.session_id,
291
+ operations=("subscribe_events",),
292
+ )
293
+ cursor = occurrence.last_event_seq
294
+ if cursor is None:
295
+ cursor = occurrence.accepted_seq or 0
296
+ subscription = SessionEventSubscription(
297
+ tenant_id=trusted.tenant_id,
298
+ agent_instance_id=trusted.agent_instance_id,
299
+ session_id=occurrence.session_id,
300
+ authorization_ref=trusted.permit.permit_id,
301
+ after_seq=cursor,
302
+ )
303
+ result: list[tuple[int, object]] = []
304
+ stream = entry.runtime.kernel.subscribe(
305
+ subscription,
306
+ permit=trusted.permit,
307
+ timeout=0.05,
308
+ )
309
+ try:
310
+ async for envelope in stream:
311
+ result.append((int(envelope.seq), envelope))
312
+ if len(result) >= 100:
313
+ break
314
+ finally:
315
+ await stream.aclose()
316
+ return tuple(result)
317
+
318
+ async def close(self) -> None:
319
+ async with self._lock:
320
+ entries = list(self._entries_by_build.values())
321
+ self._entries_by_build.clear()
322
+ self._build_by_instance.clear()
323
+ self._started = False
324
+ first_error: BaseException | None = None
325
+ for entry in reversed(entries):
326
+ try:
327
+ await entry.runtime.close()
328
+ except BaseException as error: # cleanup must continue for other Builds
329
+ if first_error is None:
330
+ first_error = error
331
+ if first_error is not None:
332
+ raise first_error
333
+
334
+ def _entry_for_instance(self, instance_id: str) -> _RuntimeEntry:
335
+ build_id = self._build_by_instance.get(str(instance_id))
336
+ entry = self._entries_by_build.get(build_id or "")
337
+ if entry is None:
338
+ raise StudioSchedulerRuntimeError(
339
+ "SCHEDULER_TARGET_UNAVAILABLE",
340
+ "定时任务目标 Kernel 未注册",
341
+ )
342
+ return entry
343
+
344
+ def _instance_id(self, build_id: str) -> str:
345
+ digest = hashlib.sha256(build_id.encode("utf-8")).hexdigest()[:24]
346
+ return f"studio-schedule-{digest}"
347
+
348
+ @staticmethod
349
+ def _require_agent(spec: StudioRunSpec, expected_agent_id: str | None) -> None:
350
+ if expected_agent_id and spec.agent_id != expected_agent_id:
351
+ raise StudioSchedulerRuntimeError(
352
+ "SCHEDULER_AGENT_MISMATCH",
353
+ "定时任务 Agent 与不可变 Build 不一致",
354
+ )
355
+
356
+ @staticmethod
357
+ def _start_defaults(spec: StudioRunSpec) -> dict[str, object]:
358
+ defaults: dict[str, object] = {
359
+ "agent_id": spec.agent_id,
360
+ "config": dict(spec.request_config),
361
+ }
362
+ if spec.model:
363
+ defaults["model"] = spec.model
364
+ defaults["allowed_models"] = [spec.model]
365
+ return defaults
366
+
367
+
368
+ __all__ = [
369
+ "ResolveAdapterProvider",
370
+ "ResolveBuild",
371
+ "StudioScheduledKernelRegistry",
372
+ "StudioScheduledRuntimeTarget",
373
+ "StudioSchedulerRuntimeError",
374
+ ]
@@ -0,0 +1,211 @@
1
+ """Studio-facing lifecycle for the local Scheduler Lite backend.
2
+
3
+ This service owns only local scheduling intent and occurrence history. It
4
+ does not silently start a second runtime or submit prompts directly: when the
5
+ local AgentKernel route is unavailable it reports that condition explicitly.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from datetime import datetime, timezone
11
+ from typing import TYPE_CHECKING
12
+
13
+ from ksadk.kernel.ingress import kernel_route_active
14
+ from ksadk.scheduler import (
15
+ AgentControlSchedulerDispatcher,
16
+ SchedulerDispatchError,
17
+ SchedulerEngine,
18
+ SchedulerSQLiteStore,
19
+ next_schedule_time,
20
+ )
21
+ from ksadk.scheduler.contracts import ScheduledTask, ScheduledTaskTarget, ScheduleOccurrence
22
+ from ksadk.studio.errors import StudioError, not_found
23
+ from ksadk.studio.workspace import Workspace
24
+
25
+ if TYPE_CHECKING:
26
+ from ksadk.studio.scheduler_runtime import StudioScheduledKernelRegistry
27
+
28
+
29
+ class StudioSchedulerService:
30
+ """CRUD and explicit local process lifecycle for ``ScheduledTask/v1``."""
31
+
32
+ def __init__(
33
+ self,
34
+ workspace: Workspace,
35
+ *,
36
+ runtime_registry: StudioScheduledKernelRegistry | None = None,
37
+ ) -> None:
38
+ self.workspace = workspace
39
+ self.runtime_registry = runtime_registry
40
+ self.store = SchedulerSQLiteStore(
41
+ workspace.resolve(".agentkit/scheduler/scheduler.sqlite3")
42
+ )
43
+ dispatcher = (
44
+ AgentControlSchedulerDispatcher(
45
+ runtime_registry.submit,
46
+ event_reader=runtime_registry.read_events,
47
+ target_preparer=self._prepare_target,
48
+ )
49
+ if runtime_registry is not None
50
+ else AgentControlSchedulerDispatcher()
51
+ )
52
+ self.engine = SchedulerEngine(
53
+ self.store,
54
+ dispatcher,
55
+ # Keep the local monitor alive when Studio starts before a Runtime.
56
+ # It observes availability on every scan and never claims work while
57
+ # the trusted Kernel route is absent.
58
+ tick_guard=self._runtime_available,
59
+ )
60
+
61
+ def availability(self) -> dict[str, object]:
62
+ active = self._runtime_available()
63
+ engine = self.engine.status()
64
+ return {
65
+ "available": active,
66
+ "scope": "local_studio_process",
67
+ "alwaysOn": False,
68
+ "reason": "agent_kernel_route_inactive" if not active else None,
69
+ "triggerActive": bool(active and engine["running"]),
70
+ "store": "sqlite",
71
+ **engine,
72
+ }
73
+
74
+ def list_tasks(self) -> list[ScheduledTask]:
75
+ return [task for task, _generation in self.store.list_tasks()]
76
+
77
+ def get_task(self, task_id: str) -> ScheduledTask:
78
+ item = self.store.get_task(task_id)
79
+ if item is None:
80
+ raise not_found("schedule", task_id)
81
+ return item[0]
82
+
83
+ def list_occurrences(self, task_id: str, *, limit: int = 50) -> list[ScheduleOccurrence]:
84
+ # A deleted task intentionally retains occurrence history, so query the
85
+ # history table directly rather than requiring a live task row.
86
+ return self.store.list_occurrences(task_id, limit=limit)
87
+
88
+ def list_all_occurrences(self, *, limit: int = 200) -> list[ScheduleOccurrence]:
89
+ return self.store.list_all_occurrences(limit=limit)
90
+
91
+ def create_task(self, task: ScheduledTask) -> ScheduledTask:
92
+ if self.store.get_task(task.task_id) is not None:
93
+ raise StudioError(
94
+ "SCHEDULE_ALREADY_EXISTS",
95
+ "该定时任务已存在",
96
+ status_code=409,
97
+ details={"id": task.task_id},
98
+ )
99
+ prepared = self._prepare(task)
100
+ self.store.put_task(prepared, generation=1)
101
+ return prepared
102
+
103
+ def update_task(self, task_id: str, task: ScheduledTask) -> ScheduledTask:
104
+ if task.task_id != task_id:
105
+ raise StudioError(
106
+ "SCHEDULE_ID_IMMUTABLE",
107
+ "定时任务 ID 不可修改",
108
+ status_code=422,
109
+ field="taskId",
110
+ )
111
+ existing = self.store.get_task(task_id)
112
+ if existing is None:
113
+ raise not_found("schedule", task_id)
114
+ old, generation = existing
115
+ prepared = self._prepare(
116
+ task.model_copy(update={"created_at": old.created_at}),
117
+ reset_next_run=True,
118
+ )
119
+ self.store.put_task(prepared, generation=generation + 1)
120
+ return prepared
121
+
122
+ def delete_task(self, task_id: str) -> None:
123
+ if not self.store.delete_task(task_id):
124
+ raise not_found("schedule", task_id)
125
+
126
+ async def run_now(self, task_id: str) -> ScheduleOccurrence:
127
+ self._require_kernel_route()
128
+ try:
129
+ return await self.engine.run_now(task_id)
130
+ except KeyError as exc:
131
+ raise not_found("schedule", task_id) from exc
132
+ except SchedulerDispatchError as exc:
133
+ raise StudioError(
134
+ exc.code,
135
+ exc.detail,
136
+ status_code=409 if exc.code in {"TASK_DISABLED", "CONCURRENCY_FORBID"} else 422,
137
+ ) from exc
138
+
139
+ async def tick(self) -> list[ScheduleOccurrence]:
140
+ self._require_kernel_route()
141
+ return await self.engine.tick()
142
+
143
+ async def start_if_available(self) -> bool:
144
+ # The monitor is process-local and cheap. Starting it unconditionally
145
+ # is what lets a Runtime launched after Studio startup begin scheduling
146
+ # without a daemon restart. The engine's tick_guard is the fail-closed
147
+ # admission boundary while no Kernel route exists.
148
+ if self.runtime_registry is not None:
149
+ await self.runtime_registry.start()
150
+ await self.engine.start()
151
+ return self._runtime_available()
152
+
153
+ async def stop(self) -> None:
154
+ try:
155
+ await self.engine.stop()
156
+ finally:
157
+ if self.runtime_registry is not None:
158
+ await self.runtime_registry.close()
159
+
160
+ def _prepare(self, task: ScheduledTask, *, reset_next_run: bool = False) -> ScheduledTask:
161
+ now = datetime.now(timezone.utc)
162
+ next_run_at = task.next_run_at
163
+ if reset_next_run or next_run_at is None:
164
+ next_run_at = next_schedule_time(
165
+ task.schedule,
166
+ after=now,
167
+ anchor_at=task.created_at,
168
+ )
169
+ if task.enabled and next_run_at is None:
170
+ raise StudioError(
171
+ "SCHEDULE_NOT_FUTURE",
172
+ "启用的单次任务必须指定未来的触发时间",
173
+ status_code=422,
174
+ field="schedule.at",
175
+ )
176
+ return task.model_copy(update={"next_run_at": next_run_at, "updated_at": now})
177
+
178
+ def _runtime_available(self) -> bool:
179
+ if self.runtime_registry is not None:
180
+ return self.runtime_registry.started
181
+ return kernel_route_active()
182
+
183
+ def _require_kernel_route(self) -> None:
184
+ if not self._runtime_available():
185
+ raise StudioError(
186
+ "SCHEDULER_RUNTIME_UNAVAILABLE",
187
+ "本地 Agent Kernel 未启用,定时任务不会伪装为已运行",
188
+ status_code=409,
189
+ )
190
+
191
+ async def _prepare_target(self, target: ScheduledTaskTarget) -> object:
192
+ """Resolve the build-pinned Kernel target, preserving typed failures.
193
+
194
+ StudioScheduledKernelRegistry.ensure_target raises
195
+ StudioSchedulerRuntimeError (for example SCHEDULER_BUILD_UNAVAILABLE
196
+ when agent_version_ref is not a real immutable Build id). Without this
197
+ adapter the SchedulerEngine generic except Exception collapses every such
198
+ failure into an opaque DISPATCH_FAILED occurrence, hiding the real reason.
199
+ Re-raise it as a SchedulerDispatchError so the durable occurrence keeps
200
+ the actionable error code instead of the catch-all.
201
+ """
202
+
203
+ from ksadk.studio.scheduler_runtime import StudioSchedulerRuntimeError
204
+
205
+ try:
206
+ return await self.runtime_registry.ensure_target(target) # type: ignore[union-attr]
207
+ except StudioSchedulerRuntimeError as error:
208
+ raise SchedulerDispatchError(error.code, str(error)) from error
209
+
210
+
211
+ __all__ = ["StudioSchedulerService"]