agentengine-sdk-python 0.8.2__py3-none-any.whl → 0.8.4__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 (563) hide show
  1. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.4.dist-info}/METADATA +22 -28
  2. agentengine_sdk_python-0.8.4.dist-info/RECORD +1070 -0
  3. ksadk/_build_provenance.json +1 -0
  4. ksadk/agui/_agent_helpers.py +4 -0
  5. ksadk/api/client.py +108 -91
  6. ksadk/builders/code_builder.py +36 -9
  7. ksadk/builders/framework_requirements.py +2 -1
  8. ksadk/builders/ks3_uploader.py +36 -7
  9. ksadk/builders/managed_runtime_builder.py +4 -0
  10. ksadk/cli/__init__.py +38 -3
  11. ksadk/cli/cmd_managed_runtime.py +13 -1
  12. ksadk/cli/cmd_plugin.py +662 -0
  13. ksadk/cli/cmd_web.py +2 -5
  14. ksadk/cli/runtime_bootstrap.py +23 -1
  15. ksadk/codex/client.py +424 -96
  16. ksadk/codex/projection.py +24 -0
  17. ksadk/codex/runtime.py +83 -283
  18. ksadk/common/auth.py +16 -10
  19. ksadk/configs/env_registry.py +59 -3
  20. ksadk/configs/settings.py +9 -0
  21. ksadk/context_engine/contributors.py +73 -8
  22. ksadk/conversations/__init__.py +19 -0
  23. ksadk/conversations/context.py +104 -24
  24. ksadk/conversations/contracts.py +266 -0
  25. ksadk/conversations/message_projection.py +154 -15
  26. ksadk/conversations/projector.py +614 -0
  27. ksadk/conversations/reducer.py +98 -0
  28. ksadk/conversations/runtime_invocation.py +5 -0
  29. ksadk/conversations/runtime_payloads.py +1 -0
  30. ksadk/conversations/runtime_preparation.py +30 -27
  31. ksadk/conversations/runtime_resume.py +50 -2
  32. ksadk/conversations/runtime_stream_events.py +5 -0
  33. ksadk/conversations/runtime_streaming.py +25 -7
  34. ksadk/deployment/env_forward.py +2 -2
  35. ksadk/deployment/providers/serverless.py +1 -1
  36. ksadk/events/_v1_compat/projection.py +2 -0
  37. ksadk/events/adapters/_codex_validators.py +18 -7
  38. ksadk/events/adapters/codex.py +190 -0
  39. ksadk/events/adapters/langgraph.py +15 -1
  40. ksadk/events/canonical_store.py +3 -1
  41. ksadk/events/projections.py +1 -1
  42. ksadk/harness/__init__.py +45 -35
  43. ksadk/harness/config.py +2 -2
  44. ksadk/harness/runtime.py +75 -16
  45. ksadk/harness/tools.py +38 -13
  46. ksadk/interaction/provider.py +1 -0
  47. ksadk/interaction/providers/langgraph.py +1 -0
  48. ksadk/kernel/bootstrap.py +28 -4
  49. ksadk/kernel/contract_fingerprints.py +5 -4
  50. ksadk/kernel/contracts.py +8 -0
  51. ksadk/kernel/control.py +1 -0
  52. ksadk/kernel/ingress.py +36 -2
  53. ksadk/kernel/memory_store.py +1 -0
  54. ksadk/kernel/postgres_store.py +1 -0
  55. ksadk/kernel/sqlite_store.py +28 -0
  56. ksadk/kernel/store.py +3 -0
  57. ksadk/kernel/worker.py +76 -10
  58. ksadk/knowledge_base/client.py +57 -27
  59. ksadk/mcp_runtime/__init__.py +12 -4
  60. ksadk/memory/adk/backends/sdk_ltm_backend.py +161 -41
  61. ksadk/memory/adk/resilient_session_service.py +25 -17
  62. ksadk/memory/adk/short_term_memory.py +26 -9
  63. ksadk/memory/models.py +7 -4
  64. ksadk/memory/provider_resolver.py +3 -0
  65. ksadk/memory/providers/local_sqlite.py +7 -0
  66. ksadk/model_proxy/server.py +10 -5
  67. ksadk/plugins/__init__.py +171 -0
  68. ksadk/plugins/artifacts.py +275 -0
  69. ksadk/plugins/bridges/__init__.py +47 -0
  70. ksadk/plugins/bridges/codex.py +659 -0
  71. ksadk/plugins/bridges/dsh.py +1300 -0
  72. ksadk/plugins/builtins.py +746 -0
  73. ksadk/plugins/bundle.py +246 -0
  74. ksadk/plugins/bundle_security.py +191 -0
  75. ksadk/plugins/codex_manifest.py +983 -0
  76. ksadk/plugins/composition.py +537 -0
  77. ksadk/plugins/context_contributor.py +437 -0
  78. ksadk/plugins/contracts.py +569 -0
  79. ksadk/plugins/delivery.py +153 -0
  80. ksadk/plugins/dsh_installation_digest.py +71 -0
  81. ksadk/plugins/dsh_toolchain.py +1024 -0
  82. ksadk/plugins/ecosystem_bridge.py +1105 -0
  83. ksadk/plugins/ecosystem_probe.py +191 -0
  84. ksadk/plugins/host.py +787 -0
  85. ksadk/plugins/kernel_adapter.py +205 -0
  86. ksadk/plugins/providers/__init__.py +108 -0
  87. ksadk/plugins/providers/bundles/dsh-knowledge/cordis.patch.yml +3 -0
  88. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +53 -0
  89. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +16 -0
  90. ksadk/plugins/providers/bundles/dsh-memory/cordis.patch.yml +3 -0
  91. ksadk/plugins/providers/bundles/dsh-memory/index.mjs +175 -0
  92. ksadk/plugins/providers/bundles/dsh-memory/package.json +16 -0
  93. ksadk/plugins/providers/bundles/dsh-platform-resources/client.mjs +166 -0
  94. ksadk/plugins/providers/bundles/dsh-platform-resources/cordis.patch.yml +3 -0
  95. ksadk/plugins/providers/bundles/dsh-platform-resources/index.mjs +9 -0
  96. ksadk/plugins/providers/bundles/dsh-platform-resources/package.json +12 -0
  97. ksadk/plugins/providers/bundles/dsh-skill-center/cordis.patch.yml +3 -0
  98. ksadk/plugins/providers/bundles/dsh-skill-center/index.mjs +125 -0
  99. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +16 -0
  100. ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
  101. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
  102. ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
  103. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/cordis.patch.yml +3 -0
  104. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +870 -0
  105. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +27 -0
  106. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +92 -0
  107. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +15 -0
  108. ksadk/plugins/providers/bundles/ksadk-dsh-studio/package.json +7 -0
  109. ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
  110. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
  111. ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
  112. ksadk/plugins/providers/codex.py +988 -0
  113. ksadk/plugins/providers/codex_dsh.py +83 -0
  114. ksadk/plugins/providers/codex_native.py +368 -0
  115. ksadk/plugins/providers/codex_turn.py +301 -0
  116. ksadk/plugins/providers/dsh.py +951 -0
  117. ksadk/plugins/providers/dsh_capabilities.py +1389 -0
  118. ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
  119. ksadk/plugins/providers/dsh_mcp.py +467 -0
  120. ksadk/plugins/providers/harness.py +632 -0
  121. ksadk/plugins/providers/harness_dsh.py +91 -0
  122. ksadk/plugins/providers/legacy.py +215 -0
  123. ksadk/plugins/providers/legacy_catalog.py +100 -0
  124. ksadk/plugins/providers/mcp_projection.py +150 -0
  125. ksadk/plugins/providers/platform_resources.py +657 -0
  126. ksadk/plugins/providers/shipped_dsh.py +370 -0
  127. ksadk/plugins/resolver.py +338 -0
  128. ksadk/plugins/subagent_providers/__init__.py +12 -0
  129. ksadk/plugins/subagent_providers/codex.py +443 -0
  130. ksadk/plugins/subagents.py +333 -0
  131. ksadk/resource_runtime/__init__.py +4 -0
  132. ksadk/resource_runtime/broker.py +616 -0
  133. ksadk/resource_runtime/build_artifacts.py +165 -0
  134. ksadk/resource_runtime/contracts.py +138 -0
  135. ksadk/resource_runtime/discovery_receipts.py +100 -0
  136. ksadk/resource_runtime/discovery_skills.py +172 -0
  137. ksadk/resource_runtime/errors.py +6 -0
  138. ksadk/resource_runtime/ipc.py +142 -0
  139. ksadk/resource_runtime/kernel_approval.py +165 -0
  140. ksadk/resource_runtime/knowledge.py +114 -0
  141. ksadk/resource_runtime/langgraph.py +94 -0
  142. ksadk/resource_runtime/leases.py +191 -0
  143. ksadk/resource_runtime/managed_projection.py +186 -0
  144. ksadk/resource_runtime/mcp_server.py +138 -0
  145. ksadk/resource_runtime/memory_provider.py +318 -0
  146. ksadk/resource_runtime/memory_receipts.py +34 -0
  147. ksadk/resource_runtime/operation_ledger.py +211 -0
  148. ksadk/resource_runtime/plugin_config.py +48 -0
  149. ksadk/resource_runtime/policy_authorization.py +54 -0
  150. ksadk/resource_runtime/process.py +110 -0
  151. ksadk/resource_runtime/skill_artifacts.py +153 -0
  152. ksadk/resource_runtime/skill_runtime.py +42 -0
  153. ksadk/resource_runtime/skill_workspace.py +118 -0
  154. ksadk/resource_runtime/skills.py +215 -0
  155. ksadk/resource_runtime/snapshots.py +180 -0
  156. ksadk/resource_runtime/socket_server.py +103 -0
  157. ksadk/resource_runtime/supervisor.py +380 -0
  158. ksadk/resource_runtime/worker.py +504 -0
  159. ksadk/runners/_langgraph_runner_streams.py +74 -6
  160. ksadk/runners/adk_runner.py +149 -11
  161. ksadk/runners/base_runner.py +29 -1
  162. ksadk/runners/langgraph_runner.py +475 -145
  163. ksadk/runtime/_runner_adapter/stream_mapping.py +193 -60
  164. ksadk/runtime/adapter.py +3 -0
  165. ksadk/runtime/conversation_execution.py +92 -16
  166. ksadk/runtime/executor.py +78 -2
  167. ksadk/runtime/factory.py +30 -200
  168. ksadk/runtime/framework_adapters.py +41 -0
  169. ksadk/runtime/preprocessing.py +10 -2
  170. ksadk/runtime/runner_adapter.py +78 -14
  171. ksadk/runtime_context.py +40 -2
  172. ksadk/sandbox/__init__.py +2 -1
  173. ksadk/sandbox/backends/e2b.py +52 -11
  174. ksadk/sandbox/backends/local_process.py +9 -0
  175. ksadk/sandbox/base.py +2 -0
  176. ksadk/sandbox/e2b_connection.py +66 -0
  177. ksadk/sandbox/factory.py +72 -0
  178. ksadk/scheduler/__init__.py +18 -0
  179. ksadk/scheduler/calendar.py +102 -0
  180. ksadk/scheduler/contracts.py +254 -0
  181. ksadk/scheduler/dispatcher.py +129 -0
  182. ksadk/scheduler/engine.py +416 -0
  183. ksadk/scheduler/sqlite_store.py +581 -0
  184. ksadk/server/composition.py +2 -0
  185. ksadk/server/factory.py +5 -0
  186. ksadk/server/persistence_capability.py +516 -0
  187. ksadk/server/routes/control.py +210 -46
  188. ksadk/server/routes/dependencies.py +15 -0
  189. ksadk/server/routes/models.py +47 -4
  190. ksadk/server/routes/projection.py +252 -12
  191. ksadk/server/routes/sessions.py +284 -107
  192. ksadk/server/routes/streaming.py +43 -9
  193. ksadk/server/static/assets/{ArtifactsPanel-DSU1sWD_.js → ArtifactsPanel-CGbWlMNh.js} +1 -1
  194. ksadk/server/static/assets/{CodeBlock-DOH6MVcn.js → CodeBlock-b4C7upmO.js} +3 -3
  195. ksadk/server/static/assets/{MathMessageMarkdown-BL8my1R2.js → MathMessageMarkdown-DbdW5A4_.js} +4 -4
  196. ksadk/server/static/assets/{MermaidBlock-Dz4IP-Tx.js → MermaidBlock-BEBN4Ksz.js} +6 -6
  197. ksadk/server/static/assets/{NativeTerminalPanel-DUrK0JpZ.js → NativeTerminalPanel-zvL-WpAn.js} +1 -1
  198. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-g20pFzNV.js → abnfDiagram-VCTEODGH-BYafW7Za.js} +1 -1
  199. ksadk/server/static/assets/{arc-C4FzinUA.js → arc-bTohInsS.js} +1 -1
  200. ksadk/server/static/assets/architecture-7GRP2DOG-BW5UtSnx.js +1 -0
  201. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-DpIqL5h4.js → architectureDiagram-5GKGNRK7-Ch5Lbzsi.js} +1 -1
  202. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-BjkljTNz.js → blockDiagram-NRAW4CY4-kqF4MDOG.js} +1 -1
  203. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-Dk_ieq2X.js → c4Diagram-UCG6FXSJ-8uSRIODv.js} +1 -1
  204. ksadk/server/static/assets/channel-CF5Up3hQ.js +1 -0
  205. ksadk/server/static/assets/chunk-2Q5K7J3B-KkXX47WI.js +1 -0
  206. ksadk/server/static/assets/{chunk-5VM5RSS4-BVHAchFb.js → chunk-5VM5RSS4-DkhehZDr.js} +1 -1
  207. ksadk/server/static/assets/{chunk-F27PBJKO-C-ipQzuS.js → chunk-F27PBJKO-BdXhtPe9.js} +1 -1
  208. ksadk/server/static/assets/{chunk-G27WJ6UU-C2EyJbIK.js → chunk-G27WJ6UU-DPTpvpwi.js} +1 -1
  209. ksadk/server/static/assets/{chunk-JWPE2WC7-vYvVJb_M.js → chunk-JWPE2WC7-Pqoh38el.js} +1 -1
  210. ksadk/server/static/assets/{chunk-LCL6LL3I-BcI6ysPT.js → chunk-LCL6LL3I-DeU00qC-.js} +1 -1
  211. ksadk/server/static/assets/{chunk-POPQ4Y6H-C030x_Z1.js → chunk-POPQ4Y6H-CzxScFkr.js} +1 -1
  212. ksadk/server/static/assets/{chunk-RHFEMEQ7-yyGpsz4n.js → chunk-RHFEMEQ7-DpqMx-ux.js} +1 -1
  213. ksadk/server/static/assets/{chunk-SVP7TREG-BLTlmMU7.js → chunk-SVP7TREG-C6t0SypQ.js} +1 -1
  214. ksadk/server/static/assets/{chunk-XXDRQBXY-C_32ArgP.js → chunk-XXDRQBXY-DVaeafZk.js} +1 -1
  215. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Cz81acRQ.js +1 -0
  216. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Cz81acRQ.js +1 -0
  217. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-9YQYwdl0.js → cose-bilkent-JH36ORCC-Bf9D3tzJ.js} +1 -1
  218. ksadk/server/static/assets/cynefin-OW5HDTMX-DVWs8a2t.js +1 -0
  219. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-ErLF5N13.js → cynefinDiagram-5FMLGOSQ-B9cY3iTz.js} +1 -1
  220. ksadk/server/static/assets/{dagre-3AP2YEHR-DFiQF-6f.js → dagre-3AP2YEHR-CSwlx3CB.js} +1 -1
  221. ksadk/server/static/assets/{dagre-BuhGnRI1.js → dagre-UBpgon5q.js} +1 -1
  222. ksadk/server/static/assets/{diagram-S7CK7UJ4-Bt1v8-GC.js → diagram-S7CK7UJ4-C9akhN9a.js} +1 -1
  223. ksadk/server/static/assets/{diagram-UQ7AKVKN-DSCxJdBK.js → diagram-UQ7AKVKN-CgedhTPI.js} +1 -1
  224. ksadk/server/static/assets/{diagram-VSXAHHWV-DHfYwp_9.js → diagram-VSXAHHWV-Cjucz5BY.js} +1 -1
  225. ksadk/server/static/assets/{diagram-VX7I27RA-DdzD-4Le.js → diagram-VX7I27RA-Dd4Vleyn.js} +1 -1
  226. ksadk/server/static/assets/{diagram-Z3DM3KII-Du-nAJ9F.js → diagram-Z3DM3KII-CZ2jGtYW.js} +1 -1
  227. ksadk/server/static/assets/{dist-B7seoj3d.js → dist-B2_CVgKv.js} +1 -1
  228. ksadk/server/static/assets/{dist-CSh_DE14.js → dist-B3FR1SKK.js} +1 -1
  229. ksadk/server/static/assets/{dist-DUX-id_F.js → dist-BIr4DSRq.js} +1 -1
  230. ksadk/server/static/assets/{dist-C_wsv-Qd.js → dist-BgV_owcB.js} +1 -1
  231. ksadk/server/static/assets/{dist-W-TIVntx.js → dist-Bj730Ib4.js} +1 -1
  232. ksadk/server/static/assets/{dist-BytlxIDT.js → dist-BnaTiyzN.js} +1 -1
  233. ksadk/server/static/assets/{dist-CXYYBw3_.js → dist-C1NMAY5a.js} +1 -1
  234. ksadk/server/static/assets/{dist-dDdADKFA.js → dist-C5_ZAZsG.js} +1 -1
  235. ksadk/server/static/assets/{dist-BVDffZ0U.js → dist-CB9iJrvg.js} +1 -1
  236. ksadk/server/static/assets/{dist-Bf2M8m3N.js → dist-CFzsn6BG.js} +1 -1
  237. ksadk/server/static/assets/{dist-ngtN0DJB.js → dist-Cf125P_m.js} +1 -1
  238. ksadk/server/static/assets/{dist-BE7bu-DL.js → dist-ClYUxfeK.js} +1 -1
  239. ksadk/server/static/assets/{dist-DNp6rLRA.js → dist-DFD6Qa6T.js} +1 -1
  240. ksadk/server/static/assets/{dist-BX8z72IC.js → dist-DVCOWtha.js} +1 -1
  241. ksadk/server/static/assets/{dist-dydu68Fl.js → dist-D_ctSS2i.js} +1 -1
  242. ksadk/server/static/assets/{dist-ClxGviKw.js → dist-DiixqL0J.js} +1 -1
  243. ksadk/server/static/assets/{dist-BjU6y-A2.js → dist-DoVSwoDb.js} +1 -1
  244. ksadk/server/static/assets/{dist-Dq9gLD7L.js → dist-DvFK7p5S.js} +1 -1
  245. ksadk/server/static/assets/{dist-8hqcx0sU.js → dist-QfkEHOlb.js} +1 -1
  246. ksadk/server/static/assets/{dist-CttYUqzS.js → dist-btbmmX5O.js} +1 -1
  247. ksadk/server/static/assets/{dist-DmldrHd_.js → dist-fBO2v5Kt.js} +1 -1
  248. ksadk/server/static/assets/{dist-DnfXs8Vn.js → dist-ufY3F5p6.js} +1 -1
  249. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Da9C9NO1.js → ebnfDiagram-PWID7BFC-Ci8NqqZu.js} +1 -1
  250. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-EAGqqR79.js → erDiagram-SSCWMZ5O-CCIOhLZG.js} +1 -1
  251. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CQqR2hg3.js +1 -0
  252. ksadk/server/static/assets/flowDiagram-A5DVABFB-DDRRbGPm.js +1 -0
  253. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DqJsKb59.js → ganttDiagram-EL5Y4UJY-Cp_r9Hb6.js} +1 -1
  254. ksadk/server/static/assets/gitGraph-4MIJSDKK-fgWEf7UD.js +1 -0
  255. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-B6g4dtDi.js → gitGraphDiagram-WWUBYQGX-Dlhc8Wr8.js} +1 -1
  256. ksadk/server/static/assets/index-DcTML1Up.css +2 -0
  257. ksadk/server/static/assets/index-Dh2XHqPK.js +244 -0
  258. ksadk/server/static/assets/info-A6RAGUB7-BUecLTdt.js +1 -0
  259. ksadk/server/static/assets/{infoDiagram-RXCK75RN-Djm_nbd5.js → infoDiagram-RXCK75RN-CO0rRTRA.js} +1 -1
  260. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-DWya9SG2.js → ishikawaDiagram-5VMMS53U-CHiaedSS.js} +1 -1
  261. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DutxhSNI.js → journeyDiagram-EYS64GPL-CHcCIB09.js} +1 -1
  262. ksadk/server/static/assets/{kanban-definition-3QL26DDD-DJdOF8Fm.js → kanban-definition-3QL26DDD-CJ_ebBZf.js} +1 -1
  263. ksadk/server/static/assets/{katex-vFWytM5c.js → katex-B4weu383.js} +1 -1
  264. ksadk/server/static/assets/{linear-BHjG8b-J.js → linear-V-MgYHW1.js} +1 -1
  265. ksadk/server/static/assets/{mermaid-parser.core-KGSy4jWT.js → mermaid-parser.core-CBijEX_c.js} +2 -2
  266. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-9-HC88D4.js → mindmap-definition-FBJOCRG2-Bc-pQvpp.js} +1 -1
  267. ksadk/server/static/assets/packet-AYTQ26CC-BeW-btFv.js +1 -0
  268. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-DrEZd4fD.js → pegDiagram-XKGWAZYB-D7genGLl.js} +1 -1
  269. ksadk/server/static/assets/pie-WAS4IAKB-X0xh4SaT.js +1 -0
  270. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-DpjqOFFp.js → pieDiagram-E7YTZNPT-Bxj32zwD.js} +1 -1
  271. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BiNhgOXX.js → quadrantDiagram-AXDQQJYC-BURv2mGh.js} +1 -1
  272. ksadk/server/static/assets/radar-RG4KPBEZ-DzRMSqjd.js +1 -0
  273. ksadk/server/static/assets/railroad-74A4TZTK-Cc44icX-.js +1 -0
  274. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-D6S4BdV-.js +1 -0
  275. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-vD3aVE2o.js +1 -0
  276. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CYbW_b4T.js +1 -0
  277. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-_Y3Ojg6G.js → railroadDiagram-O6MQD6OU-CCsh3avW.js} +1 -1
  278. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-DeCFdg9K.js → requirementDiagram-EFPCY7ZU-_FRRBKEd.js} +1 -1
  279. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-CPH75rhw.js → sankeyDiagram-P5KCCOFB-C-gr2o9M.js} +1 -1
  280. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-OEpQQdr4.js → sequenceDiagram-WJ2MYXX4-D97NmfKg.js} +1 -1
  281. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-heUErzhI.js → sizeCapture-X5ZJPWSS-DjrPC5FX.js} +1 -1
  282. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DvA3jSMB.js → stateDiagram-HBIQ2CUA-DzMNg1hh.js} +1 -1
  283. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BIcjKFhF.js +1 -0
  284. ksadk/server/static/assets/{swimlanes-XN3QIQJK-CR-dfN_t.js → swimlanes-XN3QIQJK-Cssf_CsU.js} +1 -1
  285. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-tq3K3Ybl.js +8 -0
  286. ksadk/server/static/assets/{timeline-definition-24CTP7MA-DAVJf1TX.js → timeline-definition-24CTP7MA-BWTHzyS1.js} +1 -1
  287. ksadk/server/static/assets/treeView-Q6P3EWNA-DBXt3GdU.js +1 -0
  288. ksadk/server/static/assets/treemap-WGGIJYW6-DrCy4E_l.js +1 -0
  289. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-DwM8eDkh.js → vennDiagram-4TSXK5OY-BSKgJsmR.js} +1 -1
  290. ksadk/server/static/assets/wardley-WFR3VGLG-CefhOliM.js +1 -0
  291. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DZL-Zz2t.js → wardleyDiagram-VM6X3IG4-eflHNoaZ.js} +1 -1
  292. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js → xychartDiagram-S5SC5T6Z-eYqrQ-v4.js} +1 -1
  293. ksadk/server/static/index.html +2 -2
  294. ksadk/session_context.py +66 -0
  295. ksadk/sessions/__init__.py +11 -21
  296. ksadk/sessions/_local_service_sync.py +263 -1
  297. ksadk/sessions/base.py +176 -0
  298. ksadk/sessions/errors.py +4 -0
  299. ksadk/sessions/in_memory.py +309 -19
  300. ksadk/sessions/local_service.py +83 -1
  301. ksadk/sessions/persistence.py +275 -0
  302. ksadk/sessions/postgres_service.py +358 -0
  303. ksadk/sessions/resilience.py +8 -0
  304. ksadk/sessions/resilient.py +362 -4
  305. ksadk/sessions/topology.py +135 -0
  306. ksadk/skills/models.py +26 -4
  307. ksadk/skills/package_store.py +186 -38
  308. ksadk/skills/runtime/agent.py +31 -6
  309. ksadk/skills/runtime/artifact_delivery.py +139 -0
  310. ksadk/skills/runtime/backends/e2b.py +98 -6
  311. ksadk/skills/runtime/backends/local.py +73 -8
  312. ksadk/skills/runtime/base.py +3 -0
  313. ksadk/skills/runtime/executor.py +2 -0
  314. ksadk/skills/runtime/loader.py +10 -2
  315. ksadk/skills/runtime/pinned.py +114 -0
  316. ksadk/skills/runtime/request.py +31 -0
  317. ksadk/skills/service_client.py +211 -24
  318. ksadk/studio/agent_lifecycle.py +26 -20
  319. ksadk/studio/api.py +714 -90
  320. ksadk/studio/api_catalog_routes.py +23 -0
  321. ksadk/studio/api_contracts.py +34 -1
  322. ksadk/studio/api_plugin_routes.py +911 -0
  323. ksadk/studio/api_resource_connections.py +183 -0
  324. ksadk/studio/attachment_store.py +187 -0
  325. ksadk/studio/authoring.py +10 -4
  326. ksadk/studio/authoring_coordinator.py +31 -16
  327. ksadk/studio/builder.py +199 -43
  328. ksadk/studio/cloud.py +346 -104
  329. ksadk/studio/cloud_shared_web.py +565 -0
  330. ksadk/studio/codex_agent_service.py +140 -27
  331. ksadk/studio/codex_builder.py +294 -16
  332. ksadk/studio/codex_credentials.py +90 -0
  333. ksadk/studio/codex_manifest.py +51 -4
  334. ksadk/studio/codex_plugin_store.py +746 -0
  335. ksadk/studio/codex_provider_build.py +231 -0
  336. ksadk/studio/codex_run.py +200 -29
  337. ksadk/studio/compatibility_report.py +456 -0
  338. ksadk/studio/compiler.py +84 -15
  339. ksadk/studio/contracts.py +249 -4
  340. ksadk/studio/dsh_application.py +137 -0
  341. ksadk/studio/dsh_capability_service.py +1107 -0
  342. ksadk/studio/dsh_models.py +59 -0
  343. ksadk/studio/dsh_provider_registration.py +1075 -0
  344. ksadk/studio/event_store.py +54 -6
  345. ksadk/studio/framework_run.py +37 -4
  346. ksadk/studio/hosted_kernel.py +89 -14
  347. ksadk/studio/mcp_runtime.py +11 -3
  348. ksadk/studio/model_client.py +2 -2
  349. ksadk/studio/operations.py +12 -2
  350. ksadk/studio/plugin_composition.py +468 -0
  351. ksadk/studio/plugin_kernel_adapter.py +28 -0
  352. ksadk/studio/plugin_runtime.py +831 -0
  353. ksadk/studio/resource_authority.py +637 -0
  354. ksadk/studio/resource_binding_validation.py +77 -0
  355. ksadk/studio/resource_build_admission.py +196 -0
  356. ksadk/studio/resource_build_materializer.py +149 -0
  357. ksadk/studio/resource_catalog.py +149 -3
  358. ksadk/studio/resource_connections.py +220 -0
  359. ksadk/studio/run_service.py +1144 -96
  360. ksadk/studio/runtime_source.py +24 -8
  361. ksadk/studio/scheduler_assistant.py +317 -0
  362. ksadk/studio/scheduler_runtime.py +383 -0
  363. ksadk/studio/scheduler_service.py +214 -0
  364. ksadk/studio/service.py +1131 -95
  365. ksadk/studio/shared_web.py +610 -87
  366. ksadk/studio/soul.py +52 -0
  367. ksadk/studio/static/assets/CodeBlock-DCUUY0PL-BLjA7kbS.js +41 -0
  368. ksadk/studio/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  369. ksadk/studio/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  370. ksadk/studio/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  371. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  372. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  373. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  374. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  375. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  376. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  377. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  378. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  379. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  380. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  381. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  382. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  383. ksadk/studio/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  384. ksadk/studio/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  385. ksadk/studio/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  386. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  387. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  388. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  389. ksadk/studio/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  390. ksadk/studio/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  391. ksadk/studio/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  392. ksadk/studio/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  393. ksadk/studio/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  394. ksadk/studio/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  395. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  396. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  397. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  398. ksadk/studio/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  399. ksadk/studio/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  400. ksadk/studio/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  401. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  402. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  403. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  404. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  405. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  406. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  407. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  408. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  409. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  410. ksadk/studio/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  411. ksadk/studio/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  412. ksadk/studio/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  413. ksadk/studio/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  414. ksadk/studio/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  415. ksadk/studio/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  416. ksadk/studio/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  417. ksadk/studio/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  418. ksadk/studio/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  419. ksadk/studio/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  420. ksadk/studio/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  421. ksadk/studio/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  422. ksadk/studio/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  423. ksadk/studio/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  424. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  425. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  426. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  427. ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--BEOyPC3w.css +1 -0
  428. ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--CUYIXwgI.js +8 -0
  429. ksadk/studio/static/assets/MermaidBlock-DBFTztfQ-BTYKWEbD.js +44 -0
  430. ksadk/studio/static/assets/PrismRenderer-wiXRHURw.js +3 -0
  431. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-CLETGjKq.js +1 -0
  432. ksadk/studio/static/assets/arc-Pry-7G1_.js +1 -0
  433. ksadk/studio/static/assets/architecture-7GRP2DOG-hXMiO_AU.js +1 -0
  434. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-B5EQysk6.js +36 -0
  435. ksadk/studio/static/assets/array-BifhSqXX.js +1 -0
  436. ksadk/studio/static/assets/blockDiagram-I7D4REHJ-CFmPl1de.js +129 -0
  437. ksadk/studio/static/assets/c4Diagram-7LVT6UL2-BRrGu8qt.js +38 -0
  438. ksadk/studio/static/assets/channel-BqO-gtEw.js +1 -0
  439. ksadk/studio/static/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  440. ksadk/studio/static/assets/chunk-4HAMMTFA-D220vUtq.js +62 -0
  441. ksadk/studio/static/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  442. ksadk/studio/static/assets/chunk-75Z2AOVW-C8lLv_qc.js +2 -0
  443. ksadk/studio/static/assets/chunk-DU6HZSFF-C4DtVpCu.js +128 -0
  444. ksadk/studio/static/assets/chunk-F27PBJKO-Cpw14SNG.js +1 -0
  445. ksadk/studio/static/assets/chunk-FOHPRMQF-DHwB1DNv.js +161 -0
  446. ksadk/studio/static/assets/chunk-GMAD6QVW-DiQA-u2N.js +72 -0
  447. ksadk/studio/static/assets/chunk-GVQU2GXP-DUdNBUCi.js +1 -0
  448. ksadk/studio/static/assets/chunk-IMKFNOWR-BSlbjT_b.js +231 -0
  449. ksadk/studio/static/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  450. ksadk/studio/static/assets/chunk-L3NEJ4N5-Db8Ab22W.js +1 -0
  451. ksadk/studio/static/assets/chunk-OSK3NFVY-M2m6G3j4.js +10 -0
  452. ksadk/studio/static/assets/chunk-P2QGCYS3-DezaQxiK.js +1 -0
  453. ksadk/studio/static/assets/chunk-POPQ4Y6H-DOpufJ3t.js +1 -0
  454. ksadk/studio/static/assets/chunk-PWAF6VOD-CfLb1gSc.js +1 -0
  455. ksadk/studio/static/assets/chunk-SHT3W25Y-DAyIVp5H.js +168 -0
  456. ksadk/studio/static/assets/chunk-SVP7TREG-DulomOrS.js +88 -0
  457. ksadk/studio/static/assets/chunk-TICWLB2K-bHJYoflj.js +206 -0
  458. ksadk/studio/static/assets/chunk-XXDRQBXY-7PcdR2B1.js +1 -0
  459. ksadk/studio/static/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  460. ksadk/studio/static/assets/classDiagram-ZZMXUADV-D_bW8JjA.js +1 -0
  461. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-D_bW8JjA.js +1 -0
  462. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-snL88wkX.js +1 -0
  463. ksadk/studio/static/assets/cynefin-OW5HDTMX-Bd1YhRo1.js +1 -0
  464. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-BBrIG_mI.js +62 -0
  465. ksadk/studio/static/assets/cytoscape.esm-CGd-uY3x.js +321 -0
  466. ksadk/studio/static/assets/dagre-GXQ25YYZ-DtF1nGdY.js +4 -0
  467. ksadk/studio/static/assets/dagre-PrKaheQc.js +1 -0
  468. ksadk/studio/static/assets/defaultLocale-BFoDCU3G.js +1 -0
  469. ksadk/studio/static/assets/diagram-S7CK7UJ4-0BZ98mya.js +30 -0
  470. ksadk/studio/static/assets/diagram-UQ7AKVKN-6mLKEo6L.js +41 -0
  471. ksadk/studio/static/assets/diagram-VSXAHHWV-CJBIaiZ2.js +3 -0
  472. ksadk/studio/static/assets/diagram-VX7I27RA-BohLEE1C.js +24 -0
  473. ksadk/studio/static/assets/diagram-Z3DM3KII-D8KIGonG.js +24 -0
  474. ksadk/studio/static/assets/dist-v5Q1xZ2K.js +1 -0
  475. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-C99HU61t.js +1 -0
  476. ksadk/studio/static/assets/erDiagram-RLTQ6QDP-DLGry2Ap.js +99 -0
  477. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-B1_5Ac8j.js +1 -0
  478. ksadk/studio/static/assets/flowDiagram-HODETNUW-DD5hmicn.js +1 -0
  479. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BPJrVLSG.js +292 -0
  480. ksadk/studio/static/assets/gitGraph-4MIJSDKK-Cy_ZQBGi.js +1 -0
  481. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-CZCUz4MT.js +106 -0
  482. ksadk/studio/static/assets/graphlib-DS17s2tU.js +1 -0
  483. ksadk/studio/static/assets/index-CeHL9ARV.css +2 -0
  484. ksadk/studio/static/assets/index-D9QEcVpL.js +320 -0
  485. ksadk/studio/static/assets/info-A6RAGUB7-DBzDQB_I.js +1 -0
  486. ksadk/studio/static/assets/infoDiagram-27XIBGKW-B-sq07Hi.js +2 -0
  487. ksadk/studio/static/assets/init-C-OQMol4.js +1 -0
  488. ksadk/studio/static/assets/ishikawaDiagram-5VMMS53U-CljI2wyf.js +70 -0
  489. ksadk/studio/static/assets/journeyDiagram-3NMN7TZE-D50Fo2sL.js +139 -0
  490. ksadk/studio/static/assets/kanban-definition-UXKFOSKX-DimfOTam.js +89 -0
  491. ksadk/studio/static/assets/katex-DhON-x74.js +257 -0
  492. ksadk/studio/static/assets/line-CX5BOOUP.js +1 -0
  493. ksadk/studio/static/assets/linear-BCxN9JLv.js +1 -0
  494. ksadk/studio/static/assets/mermaid-parser.core-BdCz8fkS.js +7 -0
  495. ksadk/studio/static/assets/mindmap-definition-YA3MSWOX-Bizzqy5R.js +96 -0
  496. ksadk/studio/static/assets/ordinal-BDEzSJ7C.js +1 -0
  497. ksadk/studio/static/assets/packet-AYTQ26CC-gPln-_kG.js +1 -0
  498. ksadk/studio/static/assets/path-fybaL0A-.js +1 -0
  499. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-Dy3fB-gW.js +1 -0
  500. ksadk/studio/static/assets/pie-WAS4IAKB-qZdHMr7B.js +1 -0
  501. ksadk/studio/static/assets/pieDiagram-E7YTZNPT-B9mrFSDF.js +39 -0
  502. ksadk/studio/static/assets/quadrantDiagram-AXDQQJYC-NzUfCbMR.js +7 -0
  503. ksadk/studio/static/assets/radar-RG4KPBEZ-BZlnaea9.js +1 -0
  504. ksadk/studio/static/assets/railroad-74A4TZTK-Ce3__H9c.js +1 -0
  505. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-DqQn7EzD.js +1 -0
  506. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-B55kCA8F.js +1 -0
  507. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-DfQnvkHd.js +1 -0
  508. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-DnhMjZCk.js +1 -0
  509. ksadk/studio/static/assets/requirementDiagram-BXWQKSXE-BF3d103U.js +84 -0
  510. ksadk/studio/static/assets/rolldown-runtime-Dy4uBu1J-DK3Fl9T5.js +1 -0
  511. ksadk/studio/static/assets/rough.esm-Dy-Kn_BL.js +1 -0
  512. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-Bo-JTwt0.js +40 -0
  513. ksadk/studio/static/assets/sequenceDiagram-WJ2MYXX4-Dh4wZtUm.js +162 -0
  514. ksadk/studio/static/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  515. ksadk/studio/static/assets/src-SFn9St9H.js +1 -0
  516. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DH774G6d.js +1 -0
  517. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-DZvVWPBo.js +1 -0
  518. ksadk/studio/static/assets/swimlanes-42K2YHIH-Bl13OvTX.js +1 -0
  519. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-BnFOTALJ.js +8 -0
  520. ksadk/studio/static/assets/timeline-definition-24CTP7MA-DxmSSjRB.js +120 -0
  521. ksadk/studio/static/assets/treeView-Q6P3EWNA-D5Nn9Swz.js +1 -0
  522. ksadk/studio/static/assets/treemap-WGGIJYW6-CgHgnQhE.js +1 -0
  523. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-B9QEXcJq.js +34 -0
  524. ksadk/studio/static/assets/wardley-WFR3VGLG-DXrK2RRY.js +1 -0
  525. ksadk/studio/static/assets/wardleyDiagram-VM6X3IG4-Ba1AOWoe.js +78 -0
  526. ksadk/studio/static/assets/xychartDiagram-S5SC5T6Z-Cr5pt5Y-.js +7 -0
  527. ksadk/studio/static/index.html +2 -2
  528. ksadk/studio/validator.py +1 -1
  529. ksadk/studio/workspace.py +1 -0
  530. ksadk/version.py +1 -1
  531. ksadk_runtime_common/workspace_files/path_utils.py +41 -0
  532. agentengine_sdk_python-0.8.2.dist-info/RECORD +0 -778
  533. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +0 -1
  534. ksadk/server/static/assets/channel-4cQHKtx1.js +0 -1
  535. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +0 -1
  536. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +0 -1
  537. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +0 -1
  538. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +0 -1
  539. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +0 -1
  540. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +0 -1
  541. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +0 -1
  542. ksadk/server/static/assets/index-8ipRcQ-M.js +0 -240
  543. ksadk/server/static/assets/index-ByFCqjlh.css +0 -2
  544. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +0 -1
  545. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +0 -1
  546. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +0 -1
  547. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +0 -1
  548. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +0 -1
  549. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +0 -1
  550. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +0 -1
  551. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +0 -1
  552. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +0 -1
  553. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +0 -8
  554. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +0 -1
  555. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +0 -1
  556. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +0 -1
  557. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +0 -3
  558. ksadk/studio/static/assets/index-BLpcdrgW.css +0 -1
  559. ksadk/studio/static/assets/index-CYekR2Xv.js +0 -260
  560. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.4.dist-info}/WHEEL +0 -0
  561. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.4.dist-info}/entry_points.txt +0 -0
  562. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.4.dist-info}/licenses/LICENSE +0 -0
  563. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.4.dist-info}/top_level.txt +0 -0
ksadk/studio/service.py CHANGED
@@ -4,15 +4,20 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import hashlib
7
+ import json
7
8
  import logging
8
9
  import os
10
+ import zipfile
11
+ from collections.abc import AsyncIterator, Awaitable, Mapping, Sequence
12
+ from contextlib import asynccontextmanager
9
13
  from dataclasses import dataclass
10
14
  from pathlib import Path
11
- from typing import Any, Callable, Literal, cast
15
+ from typing import Any, Callable, Literal, TypeVar, cast
12
16
  from urllib.parse import urlparse
13
17
  from uuid import uuid4
14
18
 
15
19
  from ksadk.api import AgentEngineClient
20
+ from ksadk.conversations.contracts import ConversationCapability, ConversationSurface
16
21
  from ksadk.evaluation import (
17
22
  EvaluationConfig as PublicEvaluationConfig,
18
23
  )
@@ -39,10 +44,23 @@ from ksadk.evaluation.studio_build_adapter import (
39
44
  from ksadk.events.store import RuntimeEventStore
40
45
  from ksadk.observability.session_log import SessionLogError, export_session_log
41
46
  from ksadk.observability.trajectory import encode_sse, project_trajectory_event
47
+ from ksadk.plugins.bundle_security import BundleSecurityError
48
+ from ksadk.plugins.contracts import PluginManifest
49
+ from ksadk.plugins.providers.legacy import LegacyHarnessSource
50
+ from ksadk.plugins.providers.legacy_catalog import (
51
+ KSADK_HARNESS_AGENT_PROVIDER_PLUGIN_ID,
52
+ )
42
53
  from ksadk.runtime import RuntimeExecutor, build_default_runtime_registry
54
+ from ksadk.scheduler.contracts import (
55
+ ScheduleCommandTemplate,
56
+ ScheduledTask,
57
+ ScheduledTaskTarget,
58
+ ScheduleSpec,
59
+ )
43
60
  from ksadk.sessions.local_service import LocalSessionService
44
61
  from ksadk.studio.agent_avatar_assets import AgentAvatarAssetStore
45
62
  from ksadk.studio.agent_lifecycle import delete_framework_agent
63
+ from ksadk.studio.attachment_store import ConversationAttachmentStore
46
64
  from ksadk.studio.authoring_coordinator import StudioAuthoringCoordinator
47
65
  from ksadk.studio.builder import AgentBundleBuilder
48
66
  from ksadk.studio.capabilities import builtin_tool_contracts
@@ -66,6 +84,8 @@ from ksadk.studio.codex_manifest import (
66
84
  CodexAgentManifest,
67
85
  CodexManifestRepository,
68
86
  )
87
+ from ksadk.studio.codex_plugin_store import CodexPluginSnapshotStore
88
+ from ksadk.studio.codex_provider_build import CodexProviderBuildManager
69
89
  from ksadk.studio.codex_run import CodexRunSpecResolver
70
90
  from ksadk.studio.compiler import AgentCompiler
71
91
  from ksadk.studio.contracts import (
@@ -76,7 +96,10 @@ from ksadk.studio.contracts import (
76
96
  AgentTemplateComposeRequest,
77
97
  AgentTemplateComposition,
78
98
  BuildStatus,
99
+ BundleManifest,
79
100
  DeploymentRequest,
101
+ Diagnostic,
102
+ DiagnosticSeverity,
80
103
  Operation,
81
104
  OperationKind,
82
105
  RunEvent,
@@ -84,6 +107,13 @@ from ksadk.studio.contracts import (
84
107
  RuntimeRef,
85
108
  ToolContract,
86
109
  )
110
+ from ksadk.studio.dsh_capability_service import (
111
+ StudioDshCapabilityService,
112
+ )
113
+ from ksadk.studio.dsh_provider_registration import (
114
+ StudioDshProviderRegistrationError,
115
+ StudioDshProviderRegistrationManager,
116
+ )
87
117
  from ksadk.studio.errors import StudioError
88
118
  from ksadk.studio.event_store import RunEventStore
89
119
  from ksadk.studio.framework_run import FrameworkRunSpecResolver
@@ -91,11 +121,29 @@ from ksadk.studio.mcp_runtime import MCPRuntimeAdapter
91
121
  from ksadk.studio.model_client import CredentialResolver, OpenAICompatibleModelClient
92
122
  from ksadk.studio.model_profile_service import test_model_profile_connection
93
123
  from ksadk.studio.operations import OperationManager
124
+ from ksadk.studio.plugin_composition import StudioPluginCompositionCompiler
125
+ from ksadk.studio.plugin_runtime import StudioPluginRuntime
94
126
  from ksadk.studio.repository import AgentDraftRepository, BuildRepository, load_yaml_file
127
+ from ksadk.studio.resource_authority import (
128
+ ResourceAuthorityPolicy,
129
+ SignedKnowledgeResourceAuthority,
130
+ resource_authority_policy_from_environment,
131
+ )
132
+ from ksadk.studio.resource_build_admission import (
133
+ admit_resource_build,
134
+ resource_build_required,
135
+ )
95
136
  from ksadk.studio.resource_catalog import LocalResourceCatalog
96
- from ksadk.studio.run_service import StudioRunService
137
+ from ksadk.studio.resource_connections import ResourceConnectionRepository
138
+ from ksadk.studio.run_service import StudioRunService, StudioRunSpec
97
139
  from ksadk.studio.runtime_catalog import inspect_runtime_catalog
98
140
  from ksadk.studio.runtime_source import materialize_generated_runtime_source
141
+ from ksadk.studio.scheduler_runtime import (
142
+ StudioScheduledKernelRegistry,
143
+ StudioSchedulerRuntimeError,
144
+ )
145
+ from ksadk.studio.scheduler_service import StudioSchedulerService
146
+ from ksadk.studio.soul import soul_digest
99
147
  from ksadk.studio.templates import (
100
148
  compose_blank_agent,
101
149
  compose_research_agent,
@@ -105,6 +153,8 @@ from ksadk.studio.templates import (
105
153
  from ksadk.studio.validator import AgentValidator
106
154
  from ksadk.studio.workspace import Workspace
107
155
 
156
+ _T = TypeVar("_T")
157
+
108
158
  _TRAJECTORY_KEEPALIVE_SECONDS = 15.0
109
159
  _EVALUATION_TARGET_LABELS = {
110
160
  TargetKind.A2A: "A2A Agent",
@@ -129,14 +179,78 @@ class StudioService:
129
179
  cloud_gateway: CloudDeploymentGateway | None = None,
130
180
  codex_runtime_inspector: RuntimeInspector | None = None,
131
181
  runtime_executor: RuntimeExecutor | None = None,
182
+ harness_reasoner: Any | None = None,
183
+ plugin_provider_manifests: Mapping[str, PluginManifest] | None = None,
184
+ plugin_provider_factories: Mapping[str, Any] | None = None,
185
+ legacy_harness_sources: Sequence[LegacyHarnessSource] = (),
186
+ dsh_provider_registration_manager: StudioDshProviderRegistrationManager | None = None,
187
+ dsh_capability_service: StudioDshCapabilityService | None = None,
188
+ resource_authority_policy: ResourceAuthorityPolicy | None = None,
132
189
  ) -> None:
190
+ provider_manifests = dict(plugin_provider_manifests or {})
191
+ provider_factories = dict(plugin_provider_factories or {})
192
+ if provider_manifests.keys() != provider_factories.keys():
193
+ raise ValueError(
194
+ "plugin provider manifests and factories must use the same exact references"
195
+ )
133
196
  self.workspace = Workspace(root)
134
197
  self.workspace.initialize()
198
+ self._startup_provider_manifests = provider_manifests
199
+ self._startup_provider_factories = provider_factories
200
+ self._active_provider_manifests = dict(provider_manifests)
201
+ self._dsh_provider_registration_manager = (
202
+ dsh_provider_registration_manager
203
+ or StudioDshProviderRegistrationManager.discover_or_create_workspace_default(
204
+ self.workspace.root
205
+ )
206
+ )
207
+ self.dsh_capabilities = (
208
+ dsh_capability_service
209
+ or StudioDshCapabilityService.discover_or_create_workspace_default(self.workspace.root)
210
+ )
211
+ if dsh_capability_service is not None or os.environ.get(
212
+ "KSADK_DSH_HOME", ""
213
+ ).strip() or os.environ.get("KSADK_DSH_PROFILE", "").strip():
214
+ self._resource_dsh_provider_registration_manager = None
215
+ self.resource_dsh_capabilities = self.dsh_capabilities
216
+ else:
217
+ self._resource_dsh_provider_registration_manager = (
218
+ StudioDshProviderRegistrationManager.create_workspace_resource_default(
219
+ self.workspace.root
220
+ )
221
+ )
222
+ self.resource_dsh_capabilities = (
223
+ StudioDshCapabilityService.create_workspace_resource_default(
224
+ self.workspace.root
225
+ )
226
+ )
227
+ self._start_lock = asyncio.Lock()
228
+ self._started = False
229
+ self._closed = False
135
230
  self._apply_persisted_settings()
136
231
  self.avatar_assets = AgentAvatarAssetStore(self.workspace)
232
+ self.conversation_attachments = ConversationAttachmentStore(self.workspace)
137
233
  self.drafts = AgentDraftRepository(self.workspace)
138
234
  self.catalog = LocalResourceCatalog(self.workspace)
139
235
  self.builds = BuildRepository(self.workspace)
236
+ self.credentials = (
237
+ credential_resolver
238
+ or getattr(model_client, "credential_resolver", None)
239
+ or CredentialResolver(self.workspace)
240
+ )
241
+ self.resource_connections = ResourceConnectionRepository(self.workspace, self.credentials)
242
+ effective_resource_policy = (
243
+ resource_authority_policy
244
+ if resource_authority_policy is not None
245
+ else resource_authority_policy_from_environment()
246
+ )
247
+ self.resource_authority = (
248
+ SignedKnowledgeResourceAuthority(
249
+ self.resource_connections, effective_resource_policy
250
+ )
251
+ if effective_resource_policy is not None
252
+ else None
253
+ )
140
254
  self.validator = AgentValidator()
141
255
  self.builder = AgentBundleBuilder(
142
256
  self.workspace,
@@ -147,12 +261,19 @@ class StudioService:
147
261
  ),
148
262
  repository=self.builds,
149
263
  )
264
+ self.plugin_compositions = StudioPluginCompositionCompiler(
265
+ self.workspace,
266
+ self.catalog,
267
+ provider_manifests=provider_manifests,
268
+ )
150
269
  self.event_store = RunEventStore(self.workspace)
151
270
  self.session_service = LocalSessionService(project_dir=str(self.workspace.root))
152
271
  self.runtime_events = RuntimeEventStore(self.session_service)
153
272
  self.codex_manifests = CodexManifestRepository(self.workspace)
154
273
  self.codex_builds = CodexBuildRepository(self.workspace)
155
274
  self.codex_drafts = CodexDraftRepository(self.workspace)
275
+ self.codex_plugin_snapshots = CodexPluginSnapshotStore(self.workspace)
276
+ self.codex_provider_builds = CodexProviderBuildManager(self)
156
277
  codex_builder_kwargs = {}
157
278
  if codex_runtime_inspector is not None:
158
279
  codex_builder_kwargs["runtime_inspector"] = codex_runtime_inspector
@@ -162,6 +283,10 @@ class StudioService:
162
283
  build_repository=self.codex_builds,
163
284
  resource_catalog=self.catalog,
164
285
  draft_repository=self.codex_drafts,
286
+ plugin_snapshot_store=self.codex_plugin_snapshots,
287
+ resource_connections=self.resource_connections,
288
+ provider_build=self.codex_provider_builds.prepare,
289
+ provider_validate=self.codex_provider_builds.bundle_root,
165
290
  **codex_builder_kwargs,
166
291
  )
167
292
  self.runtime_executor = runtime_executor or RuntimeExecutor(
@@ -174,17 +299,15 @@ class StudioService:
174
299
  session_service=self.session_service,
175
300
  runtime_events=self.runtime_events,
176
301
  )
177
- self.credentials = (
178
- credential_resolver
179
- or getattr(model_client, "credential_resolver", None)
180
- or CredentialResolver(self.workspace)
181
- )
182
302
  self.codex_runs = CodexRunSpecResolver(
183
303
  self.workspace,
184
304
  build_repository=self.codex_builds,
185
305
  manifest_repository=self.codex_manifests,
186
306
  credential_resolver=self.credentials,
187
307
  resource_catalog=self.catalog,
308
+ draft_repository=self.codex_drafts,
309
+ plugin_snapshot_store=self.codex_plugin_snapshots,
310
+ provider_bundle_resolver=self.codex_provider_builds.bundle_root,
188
311
  )
189
312
  self.framework_runs = FrameworkRunSpecResolver(
190
313
  self.workspace,
@@ -194,6 +317,38 @@ class StudioService:
194
317
  credential_resolver=self.credentials
195
318
  )
196
319
  self.model_client = runtime_model_client
320
+ self.plugin_runs = StudioPluginRuntime(
321
+ self.workspace,
322
+ build_repository=self.builds,
323
+ session_service=self.session_service,
324
+ model_client=self.model_client,
325
+ secret_resolver=self.credentials,
326
+ codex_local_launch_resolver=self.codex_provider_builds.native_launch,
327
+ runtime_executor=self.runtime_executor,
328
+ harness_reasoner=harness_reasoner,
329
+ provider_manifests=provider_manifests,
330
+ provider_factories=provider_factories,
331
+ legacy_harness_sources=legacy_harness_sources,
332
+ dsh_capability_service=self.dsh_capabilities,
333
+ resource_dsh_capability_service=self.resource_dsh_capabilities,
334
+ resource_authority=self.resource_authority,
335
+ resource_connections=self.resource_connections,
336
+ resource_actor_ref="local-user",
337
+ )
338
+ self.run_service.plugin_runtime = self.plugin_runs
339
+ self.scheduler_runtimes = StudioScheduledKernelRegistry(
340
+ resolve_build=self.resolve_run_spec,
341
+ resolve_adapter_provider=self._scheduler_adapter_provider,
342
+ session_service=self.session_service,
343
+ runtime_executor=self.runtime_executor,
344
+ )
345
+ self.scheduler = StudioSchedulerService(
346
+ self.workspace,
347
+ runtime_registry=self.scheduler_runtimes,
348
+ )
349
+ from ksadk.studio.scheduler_assistant import StudioScheduleAssistant
350
+
351
+ self.run_service.schedule_assistant = StudioScheduleAssistant(self)
197
352
  self.mcp_runtime = MCPRuntimeAdapter(self.workspace, credentials=self.credentials)
198
353
  self._cloud_gateway_override = cloud_gateway
199
354
  self.cloud = CloudDeploymentService(
@@ -202,15 +357,772 @@ class StudioService:
202
357
  build_repository=self.builds,
203
358
  )
204
359
  self.operations = OperationManager(self.workspace)
205
- self.evaluation_storage = EvaluationStorage(
206
- self.workspace.resolve(".agentkit/evaluations")
207
- )
360
+ self.evaluation_storage = EvaluationStorage(self.workspace.resolve(".agentkit/evaluations"))
208
361
  self.authoring = StudioAuthoringCoordinator(self)
209
362
  self.codex_agents = CodexAgentService(self)
210
363
 
364
+ async def start(self) -> None:
365
+ """Bind ready managed DSH registrations before build or execution."""
366
+
367
+ async with self._start_lock:
368
+ self._ensure_open()
369
+ if self._started:
370
+ return
371
+ await self._bootstrap_official_dsh_defaults()
372
+ manifests, factories, manager_refs = await self._provider_snapshot(refresh=False)
373
+ self.plugin_compositions.replace_provider_registrations(manifests)
374
+ self.plugin_runs.replace_provider_registrations(manifests, factories)
375
+ self._active_provider_manifests = manifests
376
+ manager = self._dsh_provider_registration_manager
377
+ if manager is not None and manager_refs is not None:
378
+ manager.mark_bound(manager_refs)
379
+ self._started = True
380
+
381
+ async def refresh_dsh_provider_registrations(self) -> None:
382
+ """Rebind the exact current DSH Profile and release stale activations."""
383
+
384
+ async with self._start_lock:
385
+ self._ensure_open()
386
+ safe_to_resume = False
387
+ try:
388
+ await self.plugin_runs.suspend_admission()
389
+ await self.reset_dsh_capability_state()
390
+ await self._bind_dsh_provider_registrations_locked(refresh=True)
391
+ await self._refresh_dsh_catalog_resource(required=False)
392
+ safe_to_resume = True
393
+ finally:
394
+ if safe_to_resume:
395
+ await self.plugin_runs.resume_admission()
396
+
397
+ async def reconfigure_dsh_profile(
398
+ self,
399
+ operation: Callable[[], Awaitable[_T]],
400
+ ) -> _T:
401
+ """Run one Profile mutation while all Agent admission is suspended."""
402
+
403
+ async with self._start_lock:
404
+ self._ensure_open()
405
+ safe_to_resume = False
406
+ try:
407
+ await self.plugin_runs.suspend_admission()
408
+ await self.reset_dsh_capability_state()
409
+ try:
410
+ result = await operation()
411
+ except BaseException as mutation_error:
412
+ if (
413
+ isinstance(mutation_error, StudioError)
414
+ and mutation_error.code == "DSH_PROFILE_RECOVERY_REQUIRED"
415
+ ):
416
+ raise
417
+ try:
418
+ await self._bind_dsh_provider_registrations_locked(refresh=True)
419
+ await self._refresh_dsh_catalog_resource(required=False)
420
+ safe_to_resume = True
421
+ except Exception as recovery_error: # noqa: BLE001
422
+ logging.getLogger(__name__).warning(
423
+ "DSH provider recovery after mutation failure skipped: %s",
424
+ recovery_error,
425
+ )
426
+ raise
427
+ await self._bind_dsh_provider_registrations_locked(refresh=True)
428
+ await self._refresh_dsh_catalog_resource(required=False)
429
+ safe_to_resume = True
430
+ return result
431
+ finally:
432
+ if safe_to_resume:
433
+ await self.plugin_runs.resume_admission()
434
+
435
+ async def _bind_dsh_provider_registrations_locked(self, *, refresh: bool) -> None:
436
+ if self._dsh_provider_registration_manager is None:
437
+ self._dsh_provider_registration_manager = (
438
+ StudioDshProviderRegistrationManager.discover_or_create_workspace_default(
439
+ self.workspace.root
440
+ )
441
+ )
442
+ await self._bootstrap_official_dsh_defaults()
443
+ manifests, factories, manager_refs = await self._provider_snapshot(refresh=refresh)
444
+ self.plugin_compositions.replace_provider_registrations(manifests)
445
+ self.plugin_runs.replace_provider_registrations(manifests, factories)
446
+ self._active_provider_manifests = manifests
447
+ manager = self._dsh_provider_registration_manager
448
+ if manager is not None and manager_refs is not None:
449
+ manager.mark_bound(manager_refs)
450
+ self._started = True
451
+
452
+ async def reset_dsh_capability_state(self) -> None:
453
+ """Drop the current DSH capability/Core generation."""
454
+
455
+ self.catalog.clear_dsh_profile_mcp()
456
+ await self.dsh_capabilities.refresh()
457
+
458
+ async def refresh_dsh_catalog_resource(self): # type: ignore[no-untyped-def]
459
+ """Validate and publish the current DSH Profile as a bindable MCP."""
460
+
461
+ _snapshot, resource = await self.dsh_capability_catalog_snapshot()
462
+ return resource
463
+
464
+ async def dsh_capability_catalog_snapshot(self): # type: ignore[no-untyped-def]
465
+ """Atomically snapshot and publish one current DSH generation."""
466
+
467
+ async with self._start_lock:
468
+ self._ensure_open()
469
+ snapshot = await self.dsh_capabilities.capability_snapshot()
470
+ resource = self.catalog.replace_dsh_profile_mcp(snapshot.descriptor)
471
+ return snapshot, resource
472
+
473
+ async def ensure_dsh_catalog_available(self) -> None:
474
+ """Publish an explicitly enabled DSH Profile for the generic selector.
475
+
476
+ The normal Studio startup remains side-effect free for legacy users.
477
+ The generic MCP catalog request performs only a profile metadata check;
478
+ it starts the managed capability host when the user has already enabled
479
+ at least one DSH plugin.
480
+ """
481
+
482
+ async with self._start_lock:
483
+ self._ensure_open()
484
+ existing = self.catalog.list(kind="mcp", source="provider", limit=200)
485
+ if any(item.contract.get("materialization") == "dsh-profile" for item in existing):
486
+ return
487
+ checker = getattr(self.dsh_capabilities, "has_enabled_profile_plugins", None)
488
+ if checker is None:
489
+ return
490
+ try:
491
+ enabled = await checker()
492
+ except Exception as error: # noqa: BLE001 - optional ecosystem boundary
493
+ logging.getLogger(__name__).warning("DSH catalog discovery skipped: %s", error)
494
+ return
495
+ if enabled:
496
+ await self._refresh_dsh_catalog_resource(required=False)
497
+
498
+ @asynccontextmanager
499
+ async def dsh_profile_read_transaction(self) -> AsyncIterator[None]:
500
+ """Fence a UI grant read against Profile mutation and shutdown."""
501
+
502
+ async with self._start_lock:
503
+ self._ensure_open()
504
+ yield
505
+
506
+ async def _refresh_dsh_catalog_resource(self, *, required: bool): # type: ignore[no-untyped-def]
507
+ try:
508
+ snapshot = await self.dsh_capabilities.capability_snapshot()
509
+ return self.catalog.replace_dsh_profile_mcp(snapshot.descriptor)
510
+ except Exception as error: # noqa: BLE001 - optional ecosystem boundary
511
+ self.catalog.clear_dsh_profile_mcp()
512
+ if required:
513
+ raise
514
+ logging.getLogger(__name__).warning(
515
+ "DSH capability catalog publication skipped: %s", error
516
+ )
517
+ return None
518
+
519
+ async def _bootstrap_official_dsh_defaults(self) -> None:
520
+ manager = self._dsh_provider_registration_manager
521
+ if manager is None:
522
+ return
523
+ try:
524
+ result = await manager.bootstrap_official_codex_provider()
525
+ except Exception as error: # optional DSH must fail closed to legacy paths
526
+ logging.getLogger(__name__).warning(
527
+ "official DSH provider bootstrap skipped: %s", error
528
+ )
529
+ else:
530
+ if result in {"installed", "already_enabled"}:
531
+ logging.getLogger(__name__).info(
532
+ "official Codex DSH provider bootstrap: %s", result
533
+ )
534
+ try:
535
+ resource_result = await manager.bootstrap_official_resource_plugins()
536
+ except Exception as error: # optional DSH must fail closed to legacy paths
537
+ logging.getLogger(__name__).warning(
538
+ "official DSH resource bootstrap skipped: %s", error
539
+ )
540
+ else:
541
+ if resource_result in {"installed", "already_enabled"}:
542
+ logging.getLogger(__name__).info(
543
+ "official platform resource DSH bootstrap: %s", resource_result
544
+ )
545
+ resource_manager = self._resource_dsh_provider_registration_manager
546
+ if resource_manager is None:
547
+ return
548
+ try:
549
+ resource_result = await resource_manager.bootstrap_official_resource_plugins()
550
+ except Exception as error:
551
+ logging.getLogger(__name__).warning(
552
+ "official resource execution Profile bootstrap skipped: %s", error
553
+ )
554
+ else:
555
+ if resource_result in {"installed", "already_enabled"}:
556
+ logging.getLogger(__name__).info(
557
+ "official resource execution Profile bootstrap: %s", resource_result
558
+ )
559
+
560
+ async def _provider_snapshot(
561
+ self, *, refresh: bool
562
+ ) -> tuple[dict[str, PluginManifest], dict[str, Any], tuple[str, ...] | None]:
563
+ manifests = dict(self._startup_provider_manifests)
564
+ factories = dict(self._startup_provider_factories)
565
+ manager = self._dsh_provider_registration_manager
566
+ if manager is None:
567
+ return manifests, factories, None
568
+ try:
569
+ registrations = await (manager.refresh() if refresh else manager.start())
570
+ except StudioDshProviderRegistrationError as error:
571
+ logging.getLogger(__name__).warning(
572
+ "DSH AgentProvider discovery failed closed: %s", error.code
573
+ )
574
+ return manifests, factories, None
575
+ if registrations.manifests.keys() != registrations.factories.keys():
576
+ logging.getLogger(__name__).warning(
577
+ "DSH AgentProvider discovery returned a partial registration set"
578
+ )
579
+ return manifests, factories, None
580
+ for provider_ref, manifest in registrations.manifests.items():
581
+ if provider_ref in manifests and (
582
+ manifests[provider_ref] != manifest
583
+ or factories[provider_ref] is not registrations.factories[provider_ref]
584
+ ):
585
+ logging.getLogger(__name__).warning(
586
+ "DSH AgentProvider registration conflicts with startup provider: %s",
587
+ provider_ref,
588
+ )
589
+ return (
590
+ dict(self._startup_provider_manifests),
591
+ dict(self._startup_provider_factories),
592
+ None,
593
+ )
594
+ manifests[provider_ref] = manifest
595
+ factories[provider_ref] = registrations.factories[provider_ref]
596
+ return manifests, factories, tuple(registrations.manifests)
597
+
598
+ def agent_provider_catalog(self) -> list[dict[str, Any]]:
599
+ """Return only external providers that reached Studio's bound selector."""
600
+
601
+ reserved = {
602
+ KSADK_HARNESS_AGENT_PROVIDER_PLUGIN_ID,
603
+ }
604
+ package_by_ref: dict[str, str] = {}
605
+ display_name_by_ref: dict[str, str] = {}
606
+ manager = self._dsh_provider_registration_manager
607
+ if manager is not None:
608
+ package_by_ref = {
609
+ item.provider_ref: item.package_name
610
+ for item in manager.inventory.packages
611
+ if item.state == "bound" and item.provider_ref is not None
612
+ }
613
+ display_name_by_ref = {
614
+ item.provider_ref: item.display_name
615
+ for item in manager.inventory.packages
616
+ if item.state == "bound" and item.provider_ref is not None and item.display_name
617
+ }
618
+ items = []
619
+ for provider_ref, manifest in sorted(self._active_provider_manifests.items()):
620
+ if manifest.metadata.id in reserved:
621
+ continue
622
+ items.append(
623
+ {
624
+ "providerRef": provider_ref,
625
+ "pluginId": package_by_ref.get(provider_ref, manifest.metadata.id),
626
+ "resolvedVersion": manifest.metadata.version,
627
+ "displayName": display_name_by_ref.get(provider_ref, manifest.metadata.id),
628
+ "state": "enabled",
629
+ "compatible": True,
630
+ "selectable": True,
631
+ "reason": None,
632
+ "permissions": list(manifest.spec.permissions),
633
+ "isolation": manifest.spec.isolation,
634
+ "configSchemaDeclared": manifest.spec.config_schema is not None,
635
+ "secretFields": list(manifest.spec.secret_fields),
636
+ }
637
+ )
638
+ return items
639
+
640
+ def dsh_provider_runtime_state(self, package_name: str) -> dict[str, Any] | None:
641
+ """Project one manager-owned package lifecycle state for plugin APIs."""
642
+
643
+ manager = self._dsh_provider_registration_manager
644
+ if manager is None:
645
+ return None
646
+ status = next(
647
+ (item for item in manager.inventory.packages if item.package_name == package_name),
648
+ None,
649
+ )
650
+ if status is None:
651
+ return None
652
+ return {
653
+ "state": status.state,
654
+ "providerRef": status.provider_ref,
655
+ "errorCode": status.error_code,
656
+ }
657
+
211
658
  def runtime_catalog(self) -> list[dict]:
212
659
  return inspect_runtime_catalog(self.runtime_executor)
213
660
 
661
+ def _scheduler_adapter_provider(self, spec: StudioRunSpec): # type: ignore[no-untyped-def]
662
+ if spec.plugin_bundle_root is not None:
663
+ return self.plugin_runs.kernel_adapter_provider(spec)
664
+ return lambda: self.runtime_executor.create_adapter(spec.launch_context)
665
+
666
+ def resolve_run_spec(
667
+ self,
668
+ build_id: str,
669
+ *,
670
+ model: str | None = None,
671
+ sandbox: str | None = None,
672
+ approval_mode: str | None = None,
673
+ ) -> StudioRunSpec:
674
+ """Resolve one immutable Build through its only compatible resolver."""
675
+
676
+ try:
677
+ self.codex_builds.get(build_id)
678
+ except Exception as exc:
679
+ if getattr(exc, "status_code", None) != 404:
680
+ raise
681
+ else:
682
+ # The record exists in the Codex repository. Any later resolution
683
+ # error belongs to that Build and must remain actionable; a nested
684
+ # 404 (for example a missing plugin snapshot) is not evidence that
685
+ # this is a framework Build.
686
+ return self.codex_runs.resolve(
687
+ build_id,
688
+ model=model,
689
+ sandbox=sandbox,
690
+ approval_mode=approval_mode,
691
+ )
692
+ framework_build = self.builds.get(build_id)
693
+ runtime_type = framework_build.runtime_type.strip().lower()
694
+ if runtime_type in {"harness", "plugin"}:
695
+ return self.plugin_runs.resolve(
696
+ build_id,
697
+ model=model,
698
+ approval_mode=approval_mode,
699
+ )
700
+ return self.framework_runs.resolve(
701
+ build_id,
702
+ model=model,
703
+ approval_mode=approval_mode,
704
+ )
705
+
706
+ def validate_schedule_build(
707
+ self,
708
+ build_ref: str | None,
709
+ *,
710
+ agent_id: str | None = None,
711
+ ) -> None:
712
+ """Reject a ScheduledTask target build that is not a real immutable Build.
713
+
714
+ The agent-scoped authoring path resolves the Build server-side via
715
+ :meth:`ensure_current_build`, so this guard is primarily for the raw
716
+ ``/api/v1/schedules`` surface that accepts a caller-supplied
717
+ ``agent_version_ref``. A version name or tag (for example "v1") is
718
+ not an immutable Build id and must fail at admission with an actionable
719
+ error instead of collapsing into a later opaque DISPATCH_FAILED.
720
+ """
721
+ ref = (build_ref or "").strip()
722
+ if not ref:
723
+ raise StudioError(
724
+ "SCHEDULE_BUILD_REQUIRED",
725
+ "定时任务必须绑定一个已成功构建的 Build id(不能为空或使用版本名)",
726
+ status_code=422,
727
+ field="target.agentVersionRef",
728
+ )
729
+ try:
730
+ spec = self.resolve_run_spec(ref)
731
+ except StudioError as error:
732
+ if error.status_code == 404:
733
+ raise StudioError(
734
+ "SCHEDULE_BUILD_UNAVAILABLE",
735
+ f"定时任务绑定的 Build {ref!r} 不可用:请使用已成功构建的 Build id,而非版本名",
736
+ status_code=422,
737
+ field="target.agentVersionRef",
738
+ details={"buildId": ref},
739
+ ) from error
740
+ raise
741
+ except Exception as error:
742
+ raise StudioError(
743
+ "SCHEDULE_BUILD_UNAVAILABLE",
744
+ f"定时任务绑定的 Build {ref!r} 不可用:{error}",
745
+ status_code=422,
746
+ field="target.agentVersionRef",
747
+ details={"buildId": ref},
748
+ ) from error
749
+ if agent_id and spec.agent_id != agent_id:
750
+ raise StudioError(
751
+ "SCHEDULE_AGENT_MISMATCH",
752
+ "定时任务绑定的 Build 与所选 Agent 不一致",
753
+ status_code=422,
754
+ field="target.agentVersionRef",
755
+ details={"buildId": ref, "agentId": agent_id},
756
+ )
757
+
758
+ def conversation_surface(
759
+ self,
760
+ build_id: str,
761
+ *,
762
+ session_id: str,
763
+ ) -> ConversationSurface:
764
+ """Describe the actual local composer contract for one Build/session.
765
+
766
+ This is intentionally conservative. It derives the declaration from
767
+ the resolved Build, rather than guessing support from a model name or
768
+ sending provider-specific fields to every Runtime.
769
+ """
770
+
771
+ spec = self.resolve_run_spec(build_id)
772
+ runtime_type = spec.launch_context.runtime_type.strip().lower()
773
+ runtime_mode: Literal["native", "translated"] = (
774
+ "native" if runtime_type == "codex" else "translated"
775
+ )
776
+ inputs = [ConversationCapability(name="text", mode="native")]
777
+ if spec.model:
778
+ inputs.append(ConversationCapability(name="model.select", mode=runtime_mode))
779
+ inputs.append(ConversationCapability(name="approval", mode=runtime_mode))
780
+ if runtime_type == "codex":
781
+ inputs.extend(
782
+ (
783
+ # Studio projects image data URLs to native Codex ImageInput.
784
+ ConversationCapability(name="attachment.image", mode="native"),
785
+ # Bounded UTF-8/code attachments are made model-visible as
786
+ # deterministic text parts by the Responses compatibility
787
+ # adapter. Binary files remain unavailable in Phase 2.
788
+ ConversationCapability(name="attachment.file", mode="translated"),
789
+ ConversationCapability(name="reasoning.effort", mode="native"),
790
+ ConversationCapability(name="goal", mode="native"),
791
+ ConversationCapability(name="plan", mode="native"),
792
+ )
793
+ )
794
+
795
+ outputs = [
796
+ ConversationCapability(name="text", mode="native"),
797
+ ConversationCapability(name="streaming", mode=runtime_mode),
798
+ ]
799
+ if runtime_type == "codex":
800
+ outputs.extend(
801
+ (
802
+ ConversationCapability(name="reasoning", mode="native"),
803
+ ConversationCapability(name="tool.inspect", mode="native"),
804
+ ConversationCapability(name="approval", mode="native"),
805
+ ConversationCapability(name="goal", mode="native"),
806
+ ConversationCapability(name="plan", mode="native"),
807
+ ConversationCapability(name="cancel", mode="native"),
808
+ )
809
+ )
810
+ return ConversationSurface(
811
+ surface_id=f"studio.build.{spec.build_id}",
812
+ session_id=session_id,
813
+ provider_ref=f"studio.runtime.{runtime_type}",
814
+ inputs=tuple(inputs),
815
+ outputs=tuple(outputs),
816
+ )
817
+
818
+ async def ensure_current_build(self, agent_id: str):
819
+ """Return the Build that is eligible for a local Studio turn.
820
+
821
+ This is deliberately one shared resolver for Web chat and Scheduler
822
+ authoring. A Scheduler must never select a mutable Draft or a stale
823
+ Codex manifest merely because a UI happened to show it as an Agent.
824
+ """
825
+
826
+ await self.start()
827
+ if self.is_codex_agent(agent_id):
828
+ self.codex_agent_detail(agent_id)
829
+ builds = [
830
+ record
831
+ for record in self.codex_builds.list()
832
+ if record.agent_name == agent_id and self.codex_builder.is_current(record)
833
+ ]
834
+ if builds:
835
+ return builds[0]
836
+ return await asyncio.to_thread(self.codex_builder.build, agent_id)
837
+ draft = self.drafts.get(agent_id)
838
+ composition_required = self.plugin_compositions.required_for(draft)
839
+ resources_required = resource_build_required(draft)
840
+ for record in self.builds.list_for_agent(agent_id):
841
+ if record.status == BuildStatus.SUCCEEDED:
842
+ if (composition_required or resources_required) and (
843
+ record.source_revision != draft.metadata.revision
844
+ or (composition_required and not self._build_has_composition(record))
845
+ or (resources_required and not self._build_has_resources(record))
846
+ ):
847
+ continue
848
+ if composition_required:
849
+ composition = self.plugin_compositions.compile_if_required(draft)
850
+ if composition is None: # pragma: no cover - guarded by required_for
851
+ raise StudioError(
852
+ "PLUGIN_COMPOSITION_REQUIRED",
853
+ "当前 Agent 需要插件组合,但无法生成 Composition",
854
+ status_code=409,
855
+ )
856
+ self.plugin_compositions.bind_build(
857
+ composition,
858
+ agent_id=draft.metadata.id,
859
+ build_id=record.id,
860
+ )
861
+ return record
862
+ if draft.spec.model is None and not draft.spec.bindings.model_profile_id:
863
+ raise StudioError(
864
+ "AGENT_MODEL_REQUIRED",
865
+ "当前 Agent 未绑定 Model Profile,请先在 Agent 配置中选择模型;"
866
+ "API Key 只提供访问凭证,不会自动绑定模型。",
867
+ status_code=422,
868
+ field="spec.bindings.modelProfileId",
869
+ )
870
+ return await asyncio.to_thread(self._build_agent_bundle, draft)
871
+
872
+ def _build_agent_bundle(self, draft: AgentDraft):
873
+ composition = self.plugin_compositions.compile_if_required(draft)
874
+ resource_build = None
875
+ if resource_build_required(draft):
876
+ dsh_profile = self.resource_dsh_capabilities.capture_resource_build_snapshot()
877
+ resource_build = admit_resource_build(
878
+ draft,
879
+ authority=self.resource_authority,
880
+ connections=self.resource_connections,
881
+ dsh_profile=dsh_profile,
882
+ )
883
+ try:
884
+ record = self.builder.build(
885
+ draft,
886
+ composition=composition,
887
+ resource_build=resource_build,
888
+ )
889
+ except BundleSecurityError as error:
890
+ first = error.findings[0]
891
+ reason = {
892
+ "literal-secret-field": "明文凭证",
893
+ "url-credentials": "含账号信息的 URL",
894
+ "local-home-path": "本机用户目录路径",
895
+ "invalid-structured-input": "无法解析的结构化数据",
896
+ }.get(first.kind, "敏感内容")
897
+ raise StudioError(
898
+ "BUNDLE_SECURITY_REJECTED",
899
+ f"AgentBundle 安全检查未通过:{first.path} 检测到{reason}",
900
+ status_code=422,
901
+ details={
902
+ "securityFindings": [
903
+ {
904
+ "path": finding.path,
905
+ "kind": finding.kind,
906
+ "field": finding.field,
907
+ }
908
+ for finding in error.findings
909
+ ]
910
+ },
911
+ ) from error
912
+ if composition is not None:
913
+ self.plugin_compositions.bind_build(
914
+ composition,
915
+ agent_id=draft.metadata.id,
916
+ build_id=record.id,
917
+ )
918
+ return record
919
+
920
+ def _build_has_composition(self, record: Any) -> bool:
921
+ """Reject stale pre-Phase-2 builds for a composed runtime.
922
+
923
+ This check is intentionally scoped to Harness/plugin runtimes. Legacy
924
+ ADK/LangGraph build selection retains its existing behavior.
925
+ """
926
+
927
+ if not record.artifact_path:
928
+ return False
929
+ try:
930
+ archive = self.workspace.resolve(record.artifact_path, must_exist=True)
931
+ with zipfile.ZipFile(archive) as bundle:
932
+ manifest = json.loads(bundle.read("manifest.json"))
933
+ names = frozenset(bundle.namelist())
934
+ return bool(
935
+ isinstance(manifest, dict)
936
+ and manifest.get("compositionProfileDigest")
937
+ and "composition-profile.json" in names
938
+ and "plugin-lock.json" in names
939
+ )
940
+ except (KeyError, OSError, UnicodeError, ValueError, zipfile.BadZipFile):
941
+ return False
942
+
943
+ def _build_has_resources(self, record: Any) -> bool:
944
+ if (
945
+ not record.artifact_path
946
+ or not record.resource_build_digest
947
+ or not record.resource_snapshot_digest
948
+ ):
949
+ return False
950
+ try:
951
+ archive = self.workspace.resolve(record.artifact_path, must_exist=True)
952
+ with zipfile.ZipFile(archive) as bundle:
953
+ manifest = BundleManifest.model_validate_json(bundle.read("manifest.json"))
954
+ names = frozenset(bundle.namelist())
955
+ return bool(
956
+ manifest.resource_build_digest == record.resource_build_digest
957
+ and manifest.resource_snapshot_digest == record.resource_snapshot_digest
958
+ and "platform-resources/resource-build.json" in names
959
+ )
960
+ except (KeyError, OSError, UnicodeError, ValueError, zipfile.BadZipFile):
961
+ return False
962
+
963
+ async def create_agent_schedule(
964
+ self,
965
+ agent_id: str,
966
+ *,
967
+ display_name: str,
968
+ prompt: str,
969
+ schedule: ScheduleSpec,
970
+ enabled: bool = True,
971
+ continuity: Literal["new_session", "continue_session"] = "new_session",
972
+ session_id: str | None = None,
973
+ ) -> ScheduledTask:
974
+ """Create a local-only schedule for the Kernel Runtime that owns it.
975
+
976
+ The browser provides only human intent (prompt/calendar/continuity).
977
+ The trusted Studio process resolves the immutable Build and concrete
978
+ Kernel instance. Thus a task cannot be pointed at another Agent
979
+ Instance, smuggle a permit reference, or claim cloud scheduling.
980
+ """
981
+
982
+ await self.start()
983
+ build = await self.ensure_current_build(agent_id)
984
+ spec = self.resolve_run_spec(build.id)
985
+ await self.scheduler_runtimes.start()
986
+ try:
987
+ target = await self.scheduler_runtimes.ensure_build(
988
+ build.id,
989
+ expected_agent_id=agent_id,
990
+ )
991
+ runtime = self.scheduler_runtimes.runtime_for_build(build.id)
992
+ except StudioSchedulerRuntimeError as error:
993
+ raise StudioError(
994
+ error.code,
995
+ str(error),
996
+ status_code=409,
997
+ details={"agentId": agent_id, "buildId": build.id},
998
+ ) from error
999
+ if continuity == "continue_session" and not session_id:
1000
+ raise StudioError(
1001
+ "SCHEDULE_SESSION_REQUIRED",
1002
+ "继续会话的定时任务必须选择一个已有会话。",
1003
+ status_code=422,
1004
+ field="sessionId",
1005
+ )
1006
+ if continuity == "continue_session":
1007
+ await self._require_schedule_session_owner(agent_id, session_id)
1008
+ self._require_schedule_continuation(runtime, spec.launch_context.runtime_type)
1009
+ task = ScheduledTask(
1010
+ task_id=f"sched-{uuid4().hex[:20]}",
1011
+ display_name=display_name,
1012
+ target=ScheduledTaskTarget(
1013
+ agent_id=agent_id,
1014
+ tenant_id=target.tenant_id,
1015
+ agent_instance_id=target.agent_instance_id,
1016
+ agent_version_ref=str(build.id),
1017
+ session_id=session_id,
1018
+ # This is an opaque local authority marker, never a browser
1019
+ # supplied credential. The dispatcher obtains a short-lived
1020
+ # in-process permit at the AgentControl ingress boundary.
1021
+ authorization_ref="runtime://local-kernel-ingress",
1022
+ ),
1023
+ schedule=schedule,
1024
+ command=ScheduleCommandTemplate(payload={"content": prompt}),
1025
+ enabled=enabled,
1026
+ continuity=continuity,
1027
+ )
1028
+ return self.scheduler.create_task(task)
1029
+
1030
+ async def _require_schedule_session_owner(self, agent_id: str, session_id: str | None) -> None:
1031
+ session = (
1032
+ await self.session_service.get_session_metadata(session_id) if session_id else None
1033
+ )
1034
+ if session is None or session.agent_id != agent_id:
1035
+ raise StudioError(
1036
+ "SCHEDULE_SESSION_INVALID",
1037
+ "请选择该智能体已有的会话。",
1038
+ status_code=422,
1039
+ field="sessionId",
1040
+ )
1041
+
1042
+ async def validate_schedule_session(
1043
+ self, agent_id: str, continuity: str, session_id: str | None, build_id: str | None
1044
+ ) -> None:
1045
+ if continuity != "continue_session":
1046
+ return
1047
+ await self._require_schedule_session_owner(agent_id, session_id)
1048
+ await self.scheduler_runtimes.ensure_build(build_id, expected_agent_id=agent_id)
1049
+ runtime = self.scheduler_runtimes.runtime_for_build(build_id)
1050
+ spec = self.resolve_run_spec(build_id)
1051
+ self._require_schedule_continuation(runtime, spec.launch_context.runtime_type)
1052
+
1053
+ @staticmethod
1054
+ def _require_schedule_continuation(runtime: Any, runtime_type: str) -> None:
1055
+ """Fail closed unless the bound Provider can preserve one conversation.
1056
+
1057
+ Harness owns process-local Session history without exposing the generic
1058
+ checkpoint ``resume`` verb. Codex and external adapters must declare
1059
+ the typed resume capability. An older Runtime that lacks either proof
1060
+ remains usable for normal conversations and ``new_session`` schedules;
1061
+ only the optional follow-up mode is rejected.
1062
+ """
1063
+
1064
+ if runtime_type.strip().lower() == "harness":
1065
+ return
1066
+ kernel = getattr(runtime, "kernel", None)
1067
+ describe = getattr(kernel, "capabilities", None)
1068
+ matrix = describe() if callable(describe) else None
1069
+ resume = getattr(matrix, "resume", None)
1070
+ if not bool(getattr(resume, "supported", False)):
1071
+ raise StudioError(
1072
+ "SCHEDULE_CONTINUATION_UNAVAILABLE",
1073
+ "当前 Runtime 未声明可恢复的会话续接能力;可改用新会话定时任务。",
1074
+ status_code=409,
1075
+ field="continuity",
1076
+ details={"runtimeType": runtime_type},
1077
+ )
1078
+
1079
+ def list_agent_schedules(self, agent_id: str) -> list[ScheduledTask]:
1080
+ return [task for task in self.scheduler.list_tasks() if task.target.agent_id == agent_id]
1081
+
1082
+ def get_agent_schedule(self, agent_id: str, task_id: str) -> ScheduledTask:
1083
+ task = self.scheduler.get_task(task_id)
1084
+ if task.target.agent_id != agent_id:
1085
+ from ksadk.studio.errors import not_found
1086
+
1087
+ raise not_found("schedule", task_id)
1088
+ return task
1089
+
1090
+ def update_agent_schedule(
1091
+ self,
1092
+ agent_id: str,
1093
+ task_id: str,
1094
+ *,
1095
+ display_name: str,
1096
+ prompt: str,
1097
+ schedule: ScheduleSpec,
1098
+ enabled: bool,
1099
+ continuity: Literal["new_session", "continue_session"],
1100
+ session_id: str | None,
1101
+ ) -> ScheduledTask:
1102
+ existing = self.get_agent_schedule(agent_id, task_id)
1103
+ if continuity == "continue_session" and not session_id:
1104
+ raise StudioError(
1105
+ "SCHEDULE_SESSION_REQUIRED",
1106
+ "继续会话的定时任务必须选择一个已有会话。",
1107
+ status_code=422,
1108
+ field="sessionId",
1109
+ )
1110
+ task = existing.model_copy(
1111
+ update={
1112
+ "display_name": display_name,
1113
+ "schedule": schedule,
1114
+ "command": ScheduleCommandTemplate(payload={"content": prompt}),
1115
+ "enabled": enabled,
1116
+ "continuity": continuity,
1117
+ "target": existing.target.model_copy(update={"session_id": session_id}),
1118
+ }
1119
+ )
1120
+ return self.scheduler.update_task(task_id, task)
1121
+
1122
+ async def run_agent_schedule_now(self, agent_id: str, task_id: str):
1123
+ self.get_agent_schedule(agent_id, task_id)
1124
+ return await self.scheduler.run_now(task_id)
1125
+
214
1126
  def codex_manifest_state(self, agent_id: str | None = None) -> dict:
215
1127
  return self.codex_agents.manifest_state(agent_id)
216
1128
 
@@ -306,7 +1218,8 @@ class StudioService:
306
1218
  from ksadk.studio.errors import not_found
307
1219
 
308
1220
  runs = self.event_store.list_runs(session_id=session_id)
309
- if not runs:
1221
+ session = await self.session_service.get_session_metadata(session_id)
1222
+ if not runs and session is None:
310
1223
  raise not_found("session", session_id)
311
1224
  if any(run.status == RunStatus.RUNNING for run in runs):
312
1225
  raise StudioError(
@@ -315,9 +1228,54 @@ class StudioService:
315
1228
  status_code=409,
316
1229
  details={"sessionId": session_id},
317
1230
  )
1231
+ await self.plugin_runs.close_session(session_id)
318
1232
  await self.session_service.delete_session(session_id)
319
1233
  self.event_store.delete_session(session_id)
320
1234
 
1235
+ async def aclose(self) -> None:
1236
+ """Release local provider activations and supervised plugin processes."""
1237
+
1238
+ async with self._start_lock:
1239
+ if self._closed:
1240
+ return
1241
+ self._closed = True
1242
+ cleanup = asyncio.create_task(self._close_owned_plugin_services())
1243
+ interrupted = False
1244
+ while not cleanup.done():
1245
+ try:
1246
+ await asyncio.shield(cleanup)
1247
+ except asyncio.CancelledError:
1248
+ interrupted = True
1249
+ cleanup.result()
1250
+ if interrupted:
1251
+ raise asyncio.CancelledError
1252
+
1253
+ async def _close_owned_plugin_services(self) -> None:
1254
+ first_error: BaseException | None = None
1255
+ owned = [self.plugin_runs.aclose, self.dsh_capabilities.aclose]
1256
+ if self.resource_dsh_capabilities is not self.dsh_capabilities:
1257
+ owned.append(self.resource_dsh_capabilities.aclose)
1258
+ if self._dsh_provider_registration_manager is not None:
1259
+ owned.append(self._dsh_provider_registration_manager.aclose)
1260
+ if self._resource_dsh_provider_registration_manager is not None:
1261
+ owned.append(self._resource_dsh_provider_registration_manager.aclose)
1262
+ for close in owned:
1263
+ try:
1264
+ await close()
1265
+ except BaseException as error: # cleanup must continue
1266
+ if first_error is None:
1267
+ first_error = error
1268
+ if first_error is not None:
1269
+ raise first_error
1270
+
1271
+ def _ensure_open(self) -> None:
1272
+ if self._closed:
1273
+ raise StudioError(
1274
+ "STUDIO_SERVICE_CLOSED",
1275
+ "Studio service 已关闭",
1276
+ status_code=503,
1277
+ )
1278
+
321
1279
  async def _require_runtime_session(self, session_id: str) -> None:
322
1280
  if await self.session_service.get_session_metadata(session_id) is None:
323
1281
  raise StudioError(
@@ -842,12 +1800,36 @@ class StudioService:
842
1800
 
843
1801
  def agent_detail(self, agent_id: str) -> dict:
844
1802
  if self.is_codex_agent(agent_id):
845
- return self.codex_agent_detail(agent_id)
1803
+ detail = self.codex_agent_detail(agent_id)
1804
+ detail["soulProjection"] = self._soul_projection(detail["draft"])
1805
+ return detail
846
1806
  draft = self.drafts.get(agent_id)
847
1807
  return {
848
1808
  "draft": draft,
849
1809
  "builds": self.builds.list_for_agent(agent_id)[:10],
850
1810
  "validation": self.validator.validate(draft),
1811
+ "soulProjection": self._soul_projection(draft),
1812
+ }
1813
+
1814
+ @staticmethod
1815
+ def _soul_projection(draft: AgentDraft) -> dict[str, object]:
1816
+ """Describe the reviewed Soul source without claiming runtime learning."""
1817
+
1818
+ soul = draft.spec.soul
1819
+ runtime_type = draft.spec.runtime.type if draft.spec.runtime is not None else ""
1820
+ compile_target = {
1821
+ "codex": "managed-runtime.base_instructions",
1822
+ "plugin": "instructions/soul.md",
1823
+ }.get(runtime_type, "resolved-agent-spec.instructions.system")
1824
+ return {
1825
+ "present": soul is not None,
1826
+ "source": "AgentSpec.soul",
1827
+ "sourceRevision": draft.metadata.revision,
1828
+ "schemaVersion": soul.schema_version if soul is not None else "agentkit.soul/v1",
1829
+ "digest": soul_digest(soul) if soul is not None else None,
1830
+ "digestAlgorithm": "sha256-canonical-json",
1831
+ "compileTarget": compile_target,
1832
+ "compileOrder": "before-instructions.system",
851
1833
  }
852
1834
 
853
1835
  def create_studio_agent(
@@ -993,6 +1975,83 @@ class StudioService:
993
1975
  return detail["validation"]
994
1976
  return self.validator.validate(draft, level=level)
995
1977
 
1978
+ async def resource_binding_status(self, agent_id: str, *, activation_id: str) -> dict:
1979
+ # Check workspace ownership, but never project the mutable draft as runtime state.
1980
+ await asyncio.to_thread(self.agent_detail, agent_id)
1981
+ status = await self.dsh_capabilities.resource_runtime_status(
1982
+ agent_id=agent_id, activation_id=activation_id,
1983
+ )
1984
+ if status is None:
1985
+ raise StudioError(
1986
+ "RESOURCE_ACTIVATION_NOT_FOUND", "未找到此 Agent 的资源运行实例",
1987
+ status_code=404,
1988
+ )
1989
+ return status
1990
+
1991
+ def validate_resource_bindings(self, agent_id: str, *, expected_revision: int) -> dict:
1992
+ from ksadk.resource_runtime.plugin_config import resource_plugin_config
1993
+ from ksadk.studio.resource_binding_validation import resource_binding_diagnostics
1994
+
1995
+ draft = self.agent_detail(agent_id)["draft"]
1996
+ if draft.metadata.revision != expected_revision:
1997
+ raise StudioError(
1998
+ "AGENT_REVISION_CONFLICT", "资源校验版本与当前 Agent 不一致", status_code=409,
1999
+ )
2000
+ diagnostics = resource_binding_diagnostics(
2001
+ draft.spec.bindings.plugins, draft.spec.memory, self.resource_connections,
2002
+ )
2003
+ configs = [
2004
+ (index, config)
2005
+ for index, binding in enumerate(draft.spec.bindings.plugins)
2006
+ if binding.enabled
2007
+ for config in [
2008
+ resource_plugin_config(
2009
+ binding.plugin_ref,
2010
+ binding.ecosystem,
2011
+ binding.config,
2012
+ enabled=True,
2013
+ )
2014
+ ]
2015
+ if config is not None
2016
+ ]
2017
+ verified = []
2018
+ if (
2019
+ self.resource_authority is not None
2020
+ and configs
2021
+ and not any(item.severity == DiagnosticSeverity.ERROR for item in diagnostics)
2022
+ ):
2023
+ for index, config in configs:
2024
+ try:
2025
+ verified.append(self.resource_authority.admit(config))
2026
+ except StudioError as error:
2027
+ diagnostics.append(
2028
+ Diagnostic(
2029
+ severity=DiagnosticSeverity.ERROR,
2030
+ code=error.code,
2031
+ message=error.message,
2032
+ field=error.field
2033
+ or f"spec.bindings.plugins[{index}].config.binding",
2034
+ )
2035
+ )
2036
+ current = self.agent_detail(agent_id)["draft"]
2037
+ if current.metadata.revision != draft.metadata.revision:
2038
+ raise StudioError(
2039
+ "AGENT_REVISION_CONFLICT",
2040
+ "资源校验期间 Agent 已变更,请刷新后重试",
2041
+ status_code=409,
2042
+ )
2043
+ authorization_verified = bool(configs) and len(verified) == len(configs)
2044
+ if authorization_verified:
2045
+ diagnostics = [
2046
+ item for item in diagnostics if item.code != "RESOURCE_AUTHORITY_UNVERIFIED"
2047
+ ]
2048
+ return {
2049
+ "revision": draft.metadata.revision,
2050
+ "valid": not any(item.severity == "error" for item in diagnostics),
2051
+ "authorizationVerified": authorization_verified,
2052
+ "diagnostics": [item.model_dump(by_alias=True, mode="json") for item in diagnostics],
2053
+ }
2054
+
996
2055
  def submit_studio_build(
997
2056
  self,
998
2057
  agent_id: str,
@@ -1000,32 +2059,11 @@ class StudioService:
1000
2059
  revision: int,
1001
2060
  idempotency_key: str,
1002
2061
  ) -> Operation:
1003
- runtime_type = self.agent_runtime_type(agent_id)
1004
- runtime = next(
1005
- (item for item in self.runtime_catalog() if item["runtimeType"] == runtime_type),
1006
- None,
1007
- )
1008
- if runtime is None:
1009
- from ksadk.studio.errors import StudioError
1010
-
1011
- raise StudioError(
1012
- "RUNTIME_NOT_REGISTERED",
1013
- "Agent 引用的 RuntimeAdapter 未注册",
1014
- status_code=422,
1015
- details={"runtimeType": runtime_type},
1016
- )
1017
- if runtime["status"] != "ready":
1018
- from ksadk.studio.errors import StudioError
1019
-
1020
- raise StudioError(
1021
- "RUNTIME_DEPENDENCY_MISSING",
1022
- f"{runtime['displayName']} Runtime 依赖未安装",
1023
- status_code=422,
1024
- details={
1025
- "runtimeType": runtime_type,
1026
- "installCommand": runtime["installCommand"],
1027
- },
1028
- )
2062
+ # Codex build admission already runs the injected runtime inspector and
2063
+ # pins its result into the immutable build. Checking package metadata
2064
+ # first would reject an explicitly supplied RuntimeExecutor/inspector
2065
+ # (including an out-of-process Codex runtime) merely because the local
2066
+ # Studio interpreter does not have the optional wheel installed.
1029
2067
  if self.is_codex_agent(agent_id):
1030
2068
  detail = self.agent_detail(agent_id)
1031
2069
  if revision != detail["draft"].metadata.revision:
@@ -1040,6 +2078,12 @@ class StudioService:
1040
2078
  idempotency_key=idempotency_key,
1041
2079
  agent_id=agent_id,
1042
2080
  )
2081
+
2082
+ # A framework Build compiles and seals source/configuration only. Its
2083
+ # optional Runtime dependency belongs to run preflight, and may live in
2084
+ # a different process or deployment image. Rejecting the Build from
2085
+ # this Studio interpreter's package metadata would make portable
2086
+ # bundles impossible and incorrectly couple authoring to execution.
1043
2087
  return self.submit_build(
1044
2088
  agent_id,
1045
2089
  revision=revision,
@@ -1271,8 +2315,7 @@ class StudioService:
1271
2315
  resolved.model_profile_ids = [
1272
2316
  resource_id
1273
2317
  for resource_id in resolved.model_profile_ids
1274
- if resource_id in known
1275
- or resource_id not in current.model_profile_ids
2318
+ if resource_id in known or resource_id not in current.model_profile_ids
1276
2319
  ]
1277
2320
  resolved.skills = selected_for_materialization(
1278
2321
  candidate.skills,
@@ -1356,7 +2399,7 @@ class StudioService:
1356
2399
  snapshot = draft.model_copy(deep=True)
1357
2400
 
1358
2401
  async def runner(_operation_id: str):
1359
- return await asyncio.to_thread(self.builder.build, snapshot)
2402
+ return await asyncio.to_thread(self._build_agent_bundle, snapshot)
1360
2403
 
1361
2404
  return self.operations.submit(
1362
2405
  kind=OperationKind.BUILD,
@@ -1420,21 +2463,13 @@ class StudioService:
1420
2463
  ):
1421
2464
  """Execute any immutable Studio Build through the canonical executor."""
1422
2465
 
1423
- try:
1424
- spec = self.codex_runs.resolve(
1425
- build_id,
1426
- model=model,
1427
- sandbox=sandbox,
1428
- approval_mode=approval_mode,
1429
- )
1430
- except Exception as exc:
1431
- if getattr(exc, "status_code", None) != 404:
1432
- raise
1433
- spec = self.framework_runs.resolve(
1434
- build_id,
1435
- model=model,
1436
- approval_mode=approval_mode,
1437
- )
2466
+ await self.start()
2467
+ spec = self.resolve_run_spec(
2468
+ build_id,
2469
+ model=model,
2470
+ sandbox=sandbox,
2471
+ approval_mode=approval_mode,
2472
+ )
1438
2473
  if collaboration_mode or goal_objective or reasoning_effort:
1439
2474
  from dataclasses import replace
1440
2475
 
@@ -1660,12 +2695,14 @@ class StudioService:
1660
2695
  evalset = load_evalset(path)
1661
2696
  except (EvalSetParseError, OSError):
1662
2697
  continue
1663
- evalsets.append({
1664
- "path": path.relative_to(self.workspace.root).as_posix(),
1665
- "name": evalset.name,
1666
- "caseCount": len(evalset.cases),
1667
- "contentDigest": evalset.content_digest,
1668
- })
2698
+ evalsets.append(
2699
+ {
2700
+ "path": path.relative_to(self.workspace.root).as_posix(),
2701
+ "name": evalset.name,
2702
+ "caseCount": len(evalset.cases),
2703
+ "contentDigest": evalset.content_digest,
2704
+ }
2705
+ )
1669
2706
  evalsets.sort(key=lambda item: item["path"])
1670
2707
  return {"builds": builds, "evalsets": evalsets}
1671
2708
 
@@ -1840,9 +2877,7 @@ class StudioService:
1840
2877
  # this outbound control-plane request only, never in the Build or
1841
2878
  # deployment receipt.
1842
2879
  launch = self.codex_runs.resolve(build_id)
1843
- runtime_environment = dict(
1844
- (launch.launch_context.config or {}).get("env") or {}
1845
- )
2880
+ runtime_environment = dict((launch.launch_context.config or {}).get("env") or {})
1846
2881
  # Retrying a YAML deployment must update the Agent that the prior
1847
2882
  # receipt already created. CreateAgent can have succeeded before
1848
2883
  # a downstream Runtime-Service start failed; creating again would
@@ -1894,6 +2929,12 @@ class StudioService:
1894
2929
  runner=managed_runtime_runner,
1895
2930
  )
1896
2931
 
2932
+ # Do not turn a stale URL or a deleted Agent's Build into an accepted
2933
+ # operation that can only fail later in the worker. The Codex lookup
2934
+ # above intentionally falls back to framework builds, so establish
2935
+ # that the fallback record exists before returning HTTP 202.
2936
+ self.builds.get(build_id)
2937
+
1897
2938
  async def runner(_operation_id: str):
1898
2939
  return await self.cloud.deploy(build_id, request)
1899
2940
 
@@ -2026,14 +3067,10 @@ class StudioService:
2026
3067
 
2027
3068
  workspace_identity = str(self.workspace.root.resolve())
2028
3069
  region = (
2029
- os.environ.get("AGENTENGINE_REGION")
2030
- or os.environ.get("KSYUN_REGION")
2031
- or "cn-beijing-6"
3070
+ os.environ.get("AGENTENGINE_REGION") or os.environ.get("KSYUN_REGION") or "cn-beijing-6"
2032
3071
  ).strip()
2033
3072
  access_key = (
2034
- os.environ.get("KSYUN_ACCESS_KEY")
2035
- or os.environ.get("KS3_ACCESS_KEY")
2036
- or "unsigned"
3073
+ os.environ.get("KSYUN_ACCESS_KEY") or os.environ.get("KS3_ACCESS_KEY") or "unsigned"
2037
3074
  ).strip()
2038
3075
 
2039
3076
  def opaque(value: str) -> str:
@@ -2053,36 +3090,26 @@ class StudioService:
2053
3090
  except Exception:
2054
3091
  data = {}
2055
3092
  defaults = {
2056
- "sandbox": os.environ.get("KSADK_CODEX_SANDBOX", "read_only"),
3093
+ "sandbox": os.environ.get("KSADK_CODEX_SANDBOX", "workspace-write-auto"),
2057
3094
  "buildAfterCreate": True,
2058
3095
  "codexProxy": current_proxy_mode(),
2059
3096
  "cloudRegion": os.environ.get(
2060
3097
  "AGENTENGINE_REGION", os.environ.get("KSYUN_REGION", "cn-beijing-6")
2061
3098
  ),
2062
3099
  "cloudBucket": os.environ.get("KS3_BUCKET", ""),
2063
- "cloudAccountId": (
2064
- os.environ.get("KSYUN_ACCOUNT_ID", "").strip()
2065
- ),
3100
+ "cloudAccountId": (os.environ.get("KSYUN_ACCOUNT_ID", "").strip()),
2066
3101
  # AK/SK 不回显(避免本地 UI 回传 secret);只暴露配置状态。
2067
3102
  # 已配置 = 启动环境或已持久化 settings 里 AK+SK 齐全。
2068
3103
  "cloudAccountConfigured": bool(
2069
- (
2070
- os.environ.get("KSYUN_ACCESS_KEY")
2071
- or os.environ.get("KS3_ACCESS_KEY", "")
2072
- ).strip()
3104
+ (os.environ.get("KSYUN_ACCESS_KEY") or os.environ.get("KS3_ACCESS_KEY", "")).strip()
2073
3105
  and (
2074
- os.environ.get("KSYUN_SECRET_KEY")
2075
- or os.environ.get("KS3_SECRET_KEY", "")
3106
+ os.environ.get("KSYUN_SECRET_KEY") or os.environ.get("KS3_SECRET_KEY", "")
2076
3107
  ).strip()
2077
3108
  ),
2078
3109
  "cloudSignedAccountConfigured": bool(
2079
- (
2080
- os.environ.get("KSYUN_ACCESS_KEY")
2081
- or os.environ.get("KS3_ACCESS_KEY", "")
2082
- ).strip()
3110
+ (os.environ.get("KSYUN_ACCESS_KEY") or os.environ.get("KS3_ACCESS_KEY", "")).strip()
2083
3111
  and (
2084
- os.environ.get("KSYUN_SECRET_KEY")
2085
- or os.environ.get("KS3_SECRET_KEY", "")
3112
+ os.environ.get("KSYUN_SECRET_KEY") or os.environ.get("KS3_SECRET_KEY", "")
2086
3113
  ).strip()
2087
3114
  ),
2088
3115
  "traceContent": os.environ.get("KSADK_STUDIO_TRACE_CONTENT", "1") != "0",
@@ -2191,26 +3218,34 @@ class StudioService:
2191
3218
  secret_key = (
2192
3219
  os.environ.get("KSYUN_SECRET_KEY") or os.environ.get("KS3_SECRET_KEY", "")
2193
3220
  ).strip()
2194
- region = os.environ.get(
3221
+ configured_region = os.environ.get(
2195
3222
  "AGENTENGINE_REGION", os.environ.get("KSYUN_REGION", "")
2196
3223
  ).strip()
2197
- if not all((access_key, secret_key, region)):
3224
+ environment_region = os.environ.get("KSYUN_REGION", "").strip()
3225
+ logical_region = (
3226
+ "pre-online"
3227
+ if environment_region.lower() == "pre-online"
3228
+ else configured_region
3229
+ )
3230
+ if not all((access_key, secret_key, logical_region)):
2198
3231
  return UnavailableCloudGateway()
2199
3232
  control_client = AgentEngineClient(
2200
- region=region,
3233
+ region=logical_region,
2201
3234
  access_key=access_key,
2202
3235
  secret_key=secret_key,
2203
3236
  )
3237
+ is_preonline = logical_region.lower() == "pre-online"
2204
3238
  stream_base_url = os.environ.get("AGENTENGINE_STREAM_SERVER_URL", "").strip()
2205
- if not stream_base_url and region.lower() == "pre-online":
3239
+ if not stream_base_url and is_preonline:
2206
3240
  # The pre-online KOP response path currently buffers SSE until
2207
- # EOF. Its internal Server ingress validates the same V4
2208
- # signature and preserves the RunAgent streaming response.
3241
+ # EOF, and KOP may not yet publish newly deployed native Action
3242
+ # names. Its internal Server ingress validates the same V4
3243
+ # signature for RunAgent, ManagedRuntime, and plugin delivery.
2209
3244
  stream_base_url = "http://agent-api-pre.kspmas-internal.ksyun.com"
2210
3245
  stream_client = (
2211
3246
  AgentEngineClient(
2212
3247
  base_url=stream_base_url,
2213
- region=region,
3248
+ region=logical_region,
2214
3249
  access_key=access_key,
2215
3250
  secret_key=secret_key,
2216
3251
  )
@@ -2218,9 +3253,10 @@ class StudioService:
2218
3253
  else control_client
2219
3254
  )
2220
3255
  return DirectAgentEngineCloudDeploymentGateway(
2221
- region=region,
3256
+ region=logical_region,
2222
3257
  client=control_client,
2223
3258
  stream_client=stream_client,
3259
+ managed_runtime_client=stream_client if is_preonline else None,
2224
3260
  bucket=os.environ.get("KS3_BUCKET", "").strip() or None,
2225
3261
  ks3_credentials={
2226
3262
  "access_key": access_key,