agentengine-sdk-python 0.8.4__py3-none-any.whl → 0.8.6__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 (1221) hide show
  1. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/METADATA +17 -10
  2. agentengine_sdk_python-0.8.6.dist-info/RECORD +1731 -0
  3. ksadk/_async_iterators.py +79 -0
  4. ksadk/_build_provenance.json +1 -1
  5. ksadk/_model_anthropic.py +49 -0
  6. ksadk/_model_input.py +86 -0
  7. ksadk/_model_json.py +40 -0
  8. ksadk/_model_reasoning.py +17 -0
  9. ksadk/_model_refusal.py +20 -0
  10. ksadk/_model_sse.py +163 -0
  11. ksadk/_process.py +83 -0
  12. ksadk/_str_enum.py +17 -0
  13. ksadk/a2a/__init__.py +157 -167
  14. ksadk/a2a/_invocation_state.py +86 -0
  15. ksadk/a2a/_space_client_events.py +33 -22
  16. ksadk/a2a/adk.py +194 -0
  17. ksadk/a2a/adk_invocation_context.py +242 -0
  18. ksadk/a2a/adk_runtime.py +126 -0
  19. ksadk/a2a/adk_tools.py +319 -0
  20. ksadk/a2a/bootstrap.py +149 -23
  21. ksadk/a2a/build_validation.py +147 -0
  22. ksadk/a2a/card.py +23 -15
  23. ksadk/a2a/codex.py +160 -0
  24. ksadk/a2a/codex_checkpoint.py +111 -0
  25. ksadk/a2a/codex_recovery.py +96 -0
  26. ksadk/a2a/codex_recovery_events.py +123 -0
  27. ksadk/a2a/codex_runtime.py +198 -0
  28. ksadk/a2a/codex_session_checkpoint.py +162 -0
  29. ksadk/a2a/composition.py +88 -0
  30. ksadk/a2a/context_store.py +118 -19
  31. ksadk/a2a/control_plane.py +108 -106
  32. ksadk/a2a/event_adapter.py +92 -193
  33. ksadk/a2a/executor.py +257 -85
  34. ksadk/a2a/exposure.py +106 -0
  35. ksadk/a2a/external_transport.py +3 -4
  36. ksadk/a2a/identity.py +106 -12
  37. ksadk/a2a/ids.py +14 -3
  38. ksadk/a2a/inbound_kernel.py +133 -0
  39. ksadk/a2a/interaction_wire.py +76 -0
  40. ksadk/a2a/invocation_checkpoint.py +274 -0
  41. ksadk/a2a/invocation_policy.py +87 -0
  42. ksadk/a2a/invocation_publication.py +210 -0
  43. ksadk/a2a/invocation_service.py +972 -0
  44. ksadk/a2a/invocation_types.py +459 -0
  45. ksadk/a2a/kernel_task_adapter.py +259 -0
  46. ksadk/a2a/langgraph.py +20 -7
  47. ksadk/a2a/langgraph_invocation_context.py +136 -0
  48. ksadk/a2a/langgraph_managed.py +150 -0
  49. ksadk/a2a/langgraph_recovery.py +32 -0
  50. ksadk/a2a/langgraph_runtime.py +89 -0
  51. ksadk/a2a/langgraph_tool_runtime.py +132 -0
  52. ksadk/a2a/langgraph_tools.py +63 -0
  53. ksadk/a2a/message_digest.py +40 -0
  54. ksadk/a2a/platform.py +389 -0
  55. ksadk/a2a/policy_refs.py +13 -0
  56. ksadk/a2a/presentation.py +402 -0
  57. ksadk/a2a/product_kernel_facts.py +177 -0
  58. ksadk/a2a/product_key.py +99 -0
  59. ksadk/a2a/protocol_errors.py +116 -0
  60. ksadk/a2a/result_text.py +49 -0
  61. ksadk/a2a/resume_store.py +93 -3
  62. ksadk/a2a/routes.py +6 -1
  63. ksadk/a2a/runtime_approval.py +198 -0
  64. ksadk/a2a/runtime_input.py +151 -0
  65. ksadk/a2a/server.py +16 -7
  66. ksadk/a2a/space_client.py +101 -16
  67. ksadk/a2a/task_adapter.py +19 -5
  68. ksadk/a2a/task_event_dispatcher.py +39 -2
  69. ksadk/a2a/task_event_outbox.py +215 -0
  70. ksadk/a2a/task_event_outbox_owned.py +130 -0
  71. ksadk/a2a/task_store.py +37 -0
  72. ksadk/a2a/tool_activity.py +176 -0
  73. ksadk/a2a/workload_tokens.py +134 -0
  74. ksadk/a2ui/core.py +3 -3
  75. ksadk/api/client.py +38 -79
  76. ksadk/api/sse_stream.py +96 -0
  77. ksadk/builders/code_builder.py +121 -118
  78. ksadk/builders/container_builder.py +11 -29
  79. ksadk/builders/framework_requirements.py +22 -2
  80. ksadk/builders/managed_runtime_builder.py +12 -0
  81. ksadk/builders/source_provenance.py +87 -0
  82. ksadk/cli/__init__.py +36 -0
  83. ksadk/cli/cmd_a2a.py +43 -0
  84. ksadk/cli/cmd_build.py +9 -0
  85. ksadk/cli/cmd_config.py +4 -4
  86. ksadk/cli/cmd_create.py +12 -12
  87. ksadk/cli/cmd_deploy.py +27 -2
  88. ksadk/cli/cmd_hermes.py +24 -2
  89. ksadk/cli/cmd_invoke.py +64 -88
  90. ksadk/cli/cmd_openclaw.py +26 -1
  91. ksadk/cli/cmd_plugin.py +70 -12
  92. ksadk/cli/cmd_studio.py +69 -17
  93. ksadk/cli/cmd_web.py +2 -0
  94. ksadk/cli/hosted_invoke.py +206 -0
  95. ksadk/cli/invoke_content.py +60 -0
  96. ksadk/cli/openclaw_env.py +1 -1
  97. ksadk/cli/resource_common.py +26 -0
  98. ksadk/cli/runtime_bootstrap.py +27 -5
  99. ksadk/codex/_expert_request_reader.py +48 -0
  100. ksadk/codex/a2a_tools.py +140 -0
  101. ksadk/codex/async_approval.py +169 -0
  102. ksadk/codex/async_client.py +938 -0
  103. ksadk/codex/async_proxy.py +216 -0
  104. ksadk/codex/base_runtime.py +25 -0
  105. ksadk/codex/client.py +3 -1047
  106. ksadk/codex/client_payloads.py +85 -0
  107. ksadk/codex/rollout_checkpoint.py +264 -0
  108. ksadk/codex/runtime.py +290 -54
  109. ksadk/common/auth.py +2 -2
  110. ksadk/common/cloud_headers.py +36 -0
  111. ksadk/common/diagnostics.py +34 -0
  112. ksadk/common/kop_client.py +2 -1
  113. ksadk/configs/__init__.py +1 -1
  114. ksadk/configs/env_registry.py +216 -143
  115. ksadk/configs/env_registry_a2a.py +173 -0
  116. ksadk/configs/env_registry_studio.py +134 -0
  117. ksadk/configs/global_config.py +2 -1
  118. ksadk/configs/settings.py +9 -3
  119. ksadk/connector/__init__.py +17 -0
  120. ksadk/connector/channel.py +477 -0
  121. ksadk/context_engine/assembler.py +9 -0
  122. ksadk/context_engine/capabilities.py +52 -4
  123. ksadk/context_engine/contributors.py +80 -17
  124. ksadk/context_engine/instruction_authority.py +18 -0
  125. ksadk/conversations/attachment_storage.py +10 -3
  126. ksadk/conversations/attachments.py +69 -20
  127. ksadk/conversations/contracts.py +28 -9
  128. ksadk/conversations/message_projection.py +51 -155
  129. ksadk/conversations/message_projection_blocks.py +137 -0
  130. ksadk/conversations/model_context.py +11 -3
  131. ksadk/conversations/normalize.py +28 -10
  132. ksadk/conversations/projector.py +63 -0
  133. ksadk/conversations/runtime_baseline.py +37 -0
  134. ksadk/conversations/runtime_compaction.py +7 -2
  135. ksadk/conversations/runtime_input.py +16 -4
  136. ksadk/conversations/runtime_invocation.py +17 -4
  137. ksadk/conversations/runtime_observability.py +39 -10
  138. ksadk/conversations/runtime_payloads.py +12 -0
  139. ksadk/conversations/runtime_persistence.py +296 -32
  140. ksadk/conversations/runtime_preparation.py +98 -13
  141. ksadk/conversations/runtime_projection.py +217 -0
  142. ksadk/conversations/runtime_resume.py +141 -70
  143. ksadk/conversations/runtime_stream_events.py +29 -35
  144. ksadk/conversations/runtime_streaming.py +8 -0
  145. ksadk/conversations/tool_receipt_resume.py +387 -0
  146. ksadk/conversations/tool_receipts.py +32 -0
  147. ksadk/deployment/env_forward.py +5 -0
  148. ksadk/deployment/manager.py +15 -6
  149. ksadk/deployment/providers/serverless.py +76 -136
  150. ksadk/deployment/providers/serverless_payloads.py +122 -0
  151. ksadk/evaluation/agent_eval_client.py +2 -1
  152. ksadk/evaluation/contracts.py +78 -3
  153. ksadk/evaluation/evaluators.py +166 -1
  154. ksadk/evaluation/evidence.py +271 -4
  155. ksadk/evaluation/local_adapter.py +76 -12
  156. ksadk/evaluation/studio_build_adapter.py +73 -9
  157. ksadk/events/adapters/_a2a_checkpoint.py +151 -0
  158. ksadk/events/adapters/_a2a_snapshot.py +18 -14
  159. ksadk/events/adapters/_a2a_support.py +15 -3
  160. ksadk/events/adapters/_a2a_tool_activity.py +123 -0
  161. ksadk/events/adapters/_codex_errors.py +49 -0
  162. ksadk/events/adapters/_codex_items.py +16 -8
  163. ksadk/events/adapters/_langgraph_support.py +46 -1
  164. ksadk/events/adapters/a2a.py +54 -26
  165. ksadk/events/adapters/adk.py +188 -30
  166. ksadk/events/adapters/codex.py +33 -7
  167. ksadk/events/adapters/langgraph.py +16 -6
  168. ksadk/events/canonical.py +5 -0
  169. ksadk/events/canonical_store.py +200 -4
  170. ksadk/events/reducer.py +82 -0
  171. ksadk/events/run_authority.py +176 -0
  172. ksadk/events/session_event.py +2 -2
  173. ksadk/harness/__init__.py +18 -0
  174. ksadk/harness/app.py +11 -0
  175. ksadk/harness/artifact_adapters/__init__.py +1 -0
  176. ksadk/harness/artifact_adapters/native_page_budget.py +172 -0
  177. ksadk/harness/artifact_adapters/native_search.py +249 -0
  178. ksadk/harness/artifact_adapters/native_search_budget.py +134 -0
  179. ksadk/harness/artifact_adapters/native_store.py +115 -0
  180. ksadk/harness/artifact_adapters/native_tool.py +222 -0
  181. ksadk/harness/artifact_store.py +230 -0
  182. ksadk/harness/browser_adapters/__init__.py +6 -0
  183. ksadk/harness/browser_adapters/native_browser_tool.py +92 -0
  184. ksadk/harness/browser_adapters/native_dom_snapshot.py +187 -0
  185. ksadk/harness/browser_adapters/native_playwright.py +953 -0
  186. ksadk/harness/browser_adapters/native_vision.py +295 -0
  187. ksadk/harness/capabilities.py +115 -0
  188. ksadk/harness/capability_adapters/__init__.py +1 -0
  189. ksadk/harness/capability_adapters/native_dsh.py +289 -0
  190. ksadk/harness/capability_runtime.py +332 -0
  191. ksadk/harness/closure_contract.py +92 -0
  192. ksadk/harness/compaction_record.py +153 -0
  193. ksadk/harness/compiler.py +284 -0
  194. ksadk/harness/config.py +28 -5
  195. ksadk/harness/conformance/__init__.py +33 -0
  196. ksadk/harness/conformance/contract.py +504 -0
  197. ksadk/harness/conformance/fixtures.py +102 -0
  198. ksadk/harness/context_engine.py +388 -0
  199. ksadk/harness/context_maintenance.py +259 -0
  200. ksadk/harness/context_manifest.py +188 -0
  201. ksadk/harness/context_sections.py +397 -0
  202. ksadk/harness/context_tuning.py +168 -0
  203. ksadk/harness/diagnostic_adapters/__init__.py +1 -0
  204. ksadk/harness/diagnostic_adapters/contracts.py +70 -0
  205. ksadk/harness/diagnostic_adapters/lsp_rpc.py +210 -0
  206. ksadk/harness/diagnostic_adapters/native_lsp.py +286 -0
  207. ksadk/harness/draft_runtime.py +322 -0
  208. ksadk/harness/engine/__init__.py +40 -0
  209. ksadk/harness/engine/base.py +122 -0
  210. ksadk/harness/engine/budgets.py +108 -0
  211. ksadk/harness/engine/capability_declarations.py +59 -0
  212. ksadk/harness/engine/completion_guard.py +57 -0
  213. ksadk/harness/engine/context_pipeline.py +1351 -0
  214. ksadk/harness/engine/graph_builder.py +352 -0
  215. ksadk/harness/engine/hooked_reasoner.py +380 -0
  216. ksadk/harness/engine/langgraph.py +1049 -0
  217. ksadk/harness/engine/mcp_disclosure.py +701 -0
  218. ksadk/harness/engine/phases/__init__.py +6 -0
  219. ksadk/harness/engine/phases/context.py +48 -0
  220. ksadk/harness/engine/phases/interaction.py +31 -0
  221. ksadk/harness/engine/phases/reason.py +552 -0
  222. ksadk/harness/engine/phases/tools.py +638 -0
  223. ksadk/harness/engine/policy_runtime.py +81 -0
  224. ksadk/harness/engine/postgres_checkpointer.py +386 -0
  225. ksadk/harness/engine/run_control_bridge.py +100 -0
  226. ksadk/harness/engine/run_types.py +98 -0
  227. ksadk/harness/engine/skill_disclosure.py +275 -0
  228. ksadk/harness/engine/spans.py +41 -0
  229. ksadk/harness/engine/steering.py +177 -0
  230. ksadk/harness/engine/subagents.py +360 -0
  231. ksadk/harness/engine/thread_ids.py +112 -0
  232. ksadk/harness/engine/tool_dispatch.py +249 -0
  233. ksadk/harness/event_tree.py +212 -0
  234. ksadk/harness/events.py +498 -0
  235. ksadk/harness/execution_policy.py +104 -0
  236. ksadk/harness/hooks.py +259 -0
  237. ksadk/harness/insights.py +210 -0
  238. ksadk/harness/lifecycle.py +578 -0
  239. ksadk/harness/lifecycle_conformance.py +233 -0
  240. ksadk/harness/lifecycle_local_plane.py +104 -0
  241. ksadk/harness/loop/__init__.py +44 -0
  242. ksadk/harness/loop/reason.py +699 -0
  243. ksadk/harness/loop/tools.py +907 -0
  244. ksadk/harness/managed_runtime.py +1044 -0
  245. ksadk/harness/mcp_disclosure_contract.py +85 -0
  246. ksadk/harness/mcp_matrix.py +474 -0
  247. ksadk/harness/mcp_result_policy.py +44 -0
  248. ksadk/harness/mcp_runtime.py +504 -0
  249. ksadk/harness/memory_consolidation.py +157 -0
  250. ksadk/harness/memory_loop.py +156 -0
  251. ksadk/harness/memory_runtime.py +541 -0
  252. ksadk/harness/metrics.py +90 -0
  253. ksadk/harness/micro_compact.py +69 -0
  254. ksadk/harness/model_adapters/__init__.py +1 -0
  255. ksadk/harness/model_adapters/native_mcp_media.py +100 -0
  256. ksadk/harness/model_adapters/native_mcp_result.py +36 -0
  257. ksadk/harness/model_adapters/native_openai.py +703 -0
  258. ksadk/harness/model_capability.py +468 -0
  259. ksadk/harness/model_provider.py +430 -0
  260. ksadk/harness/multimodal.py +57 -0
  261. ksadk/harness/native/__init__.py +1 -0
  262. ksadk/harness/native/activation_contract.py +25 -0
  263. ksadk/harness/native/activation_recovery.py +29 -0
  264. ksadk/harness/native/adapters.py +291 -0
  265. ksadk/harness/native/artifact_contract.py +14 -0
  266. ksadk/harness/native/artifact_partial_read_capacity.py +171 -0
  267. ksadk/harness/native/artifact_read_capacity.py +182 -0
  268. ksadk/harness/native/artifact_read_contract.py +27 -0
  269. ksadk/harness/native/artifact_runtime.py +408 -0
  270. ksadk/harness/native/artifact_search_capacity.py +206 -0
  271. ksadk/harness/native/artifact_search_contract.py +40 -0
  272. ksadk/harness/native/artifact_single_read_capacity.py +170 -0
  273. ksadk/harness/native/browser_contract.py +229 -0
  274. ksadk/harness/native/browser_recovery.py +183 -0
  275. ksadk/harness/native/capabilities.py +204 -0
  276. ksadk/harness/native/child_approval.py +60 -0
  277. ksadk/harness/native/child_budget.py +136 -0
  278. ksadk/harness/native/child_cancellation.py +80 -0
  279. ksadk/harness/native/child_input.py +98 -0
  280. ksadk/harness/native/child_input_runtime.py +59 -0
  281. ksadk/harness/native/child_interruption.py +81 -0
  282. ksadk/harness/native/child_lifecycle.py +246 -0
  283. ksadk/harness/native/child_lifecycle_contract.py +91 -0
  284. ksadk/harness/native/child_notifications.py +75 -0
  285. ksadk/harness/native/child_promotion.py +66 -0
  286. ksadk/harness/native/command_runtime.py +99 -0
  287. ksadk/harness/native/completion.py +302 -0
  288. ksadk/harness/native/completion_text.py +116 -0
  289. ksadk/harness/native/context.py +358 -0
  290. ksadk/harness/native/context_artifact_page.py +75 -0
  291. ksadk/harness/native/context_compaction_projection.py +131 -0
  292. ksadk/harness/native/context_contributions.py +320 -0
  293. ksadk/harness/native/context_contributor_contract.py +133 -0
  294. ksadk/harness/native/context_driver.py +820 -0
  295. ksadk/harness/native/context_fresh_tools.py +49 -0
  296. ksadk/harness/native/context_history.py +272 -0
  297. ksadk/harness/native/context_microcompact.py +61 -0
  298. ksadk/harness/native/context_partial_summary.py +58 -0
  299. ksadk/harness/native/context_partition.py +492 -0
  300. ksadk/harness/native/context_pruning.py +275 -0
  301. ksadk/harness/native/context_reduction.py +60 -0
  302. ksadk/harness/native/context_replay.py +148 -0
  303. ksadk/harness/native/context_request_projection.py +526 -0
  304. ksadk/harness/native/context_runtime.py +976 -0
  305. ksadk/harness/native/context_runtime_contracts.py +409 -0
  306. ksadk/harness/native/context_search.py +112 -0
  307. ksadk/harness/native/context_source_fragments.py +188 -0
  308. ksadk/harness/native/context_source_progress.py +119 -0
  309. ksadk/harness/native/context_summary_planning.py +788 -0
  310. ksadk/harness/native/context_summary_recovery.py +105 -0
  311. ksadk/harness/native/delivery_review.py +331 -0
  312. ksadk/harness/native/delivery_review_contract.py +54 -0
  313. ksadk/harness/native/effect_admission.py +82 -0
  314. ksadk/harness/native/effect_control.py +318 -0
  315. ksadk/harness/native/effect_receipts.py +729 -0
  316. ksadk/harness/native/effect_runtime.py +303 -0
  317. ksadk/harness/native/effective_configuration.py +28 -0
  318. ksadk/harness/native/engine.py +945 -0
  319. ksadk/harness/native/final_output.py +34 -0
  320. ksadk/harness/native/final_submission.py +58 -0
  321. ksadk/harness/native/finalization_workspace.py +96 -0
  322. ksadk/harness/native/fork.py +151 -0
  323. ksadk/harness/native/guidance.py +91 -0
  324. ksadk/harness/native/history.py +381 -0
  325. ksadk/harness/native/hook_executor.py +205 -0
  326. ksadk/harness/native/hook_runtime_contract.py +282 -0
  327. ksadk/harness/native/interaction_observation.py +117 -0
  328. ksadk/harness/native/lease.py +103 -0
  329. ksadk/harness/native/machine.py +974 -0
  330. ksadk/harness/native/mcp_result_governance.py +156 -0
  331. ksadk/harness/native/model.py +570 -0
  332. ksadk/harness/native/model_feedback.py +63 -0
  333. ksadk/harness/native/model_input.py +30 -0
  334. ksadk/harness/native/model_recovery_contract.py +35 -0
  335. ksadk/harness/native/model_replay.py +128 -0
  336. ksadk/harness/native/model_request.py +133 -0
  337. ksadk/harness/native/model_runtime.py +196 -0
  338. ksadk/harness/native/model_takeover.py +419 -0
  339. ksadk/harness/native/model_tool_batch.py +40 -0
  340. ksadk/harness/native/observed_progress.py +46 -0
  341. ksadk/harness/native/operator_guidance.py +201 -0
  342. ksadk/harness/native/output_contract.py +80 -0
  343. ksadk/harness/native/output_recovery.py +24 -0
  344. ksadk/harness/native/ports.py +749 -0
  345. ksadk/harness/native/precompact_hook_runtime.py +171 -0
  346. ksadk/harness/native/replay_context.py +149 -0
  347. ksadk/harness/native/request_media.py +112 -0
  348. ksadk/harness/native/restore_contract.py +16 -0
  349. ksadk/harness/native/run_clock.py +120 -0
  350. ksadk/harness/native/state.py +436 -0
  351. ksadk/harness/native/steering.py +170 -0
  352. ksadk/harness/native/stop_hook_runtime.py +151 -0
  353. ksadk/harness/native/studio_admission.py +29 -0
  354. ksadk/harness/native/subagents.py +86 -0
  355. ksadk/harness/native/task_policy.py +99 -0
  356. ksadk/harness/native/task_progress.py +86 -0
  357. ksadk/harness/native/terminal_verification.py +43 -0
  358. ksadk/harness/native/tool_argument_feedback.py +178 -0
  359. ksadk/harness/native/tool_budget.py +253 -0
  360. ksadk/harness/native/tool_error_streak.py +89 -0
  361. ksadk/harness/native/tool_hook_runtime.py +343 -0
  362. ksadk/harness/native/tool_input_validation.py +58 -0
  363. ksadk/harness/native/tool_interruption.py +96 -0
  364. ksadk/harness/native/tool_observation.py +259 -0
  365. ksadk/harness/native/tool_progress.py +223 -0
  366. ksadk/harness/native/tool_recovery.py +25 -0
  367. ksadk/harness/native/tool_scheduling.py +33 -0
  368. ksadk/harness/native/tool_schema.py +126 -0
  369. ksadk/harness/native/transitions.py +151 -0
  370. ksadk/harness/native/turn_control.py +98 -0
  371. ksadk/harness/native/user_document.py +98 -0
  372. ksadk/harness/native/user_document_capture.py +49 -0
  373. ksadk/harness/native/user_input.py +87 -0
  374. ksadk/harness/native/verification.py +432 -0
  375. ksadk/harness/native/verification_binding.py +40 -0
  376. ksadk/harness/native/verification_runtime.py +233 -0
  377. ksadk/harness/native/verification_workspace.py +67 -0
  378. ksadk/harness/native_driver_failure.py +123 -0
  379. ksadk/harness/native_facade.py +977 -0
  380. ksadk/harness/native_factory.py +244 -0
  381. ksadk/harness/native_projection.py +503 -0
  382. ksadk/harness/native_runtime.py +621 -0
  383. ksadk/harness/native_shadow.py +250 -0
  384. ksadk/harness/native_shadow_inputs.py +146 -0
  385. ksadk/harness/observability/__init__.py +29 -0
  386. ksadk/harness/observability/inspection.py +528 -0
  387. ksadk/harness/observability/metrics.py +167 -0
  388. ksadk/harness/observability/otel_exporter.py +218 -0
  389. ksadk/harness/progress_adapters/__init__.py +5 -0
  390. ksadk/harness/progress_adapters/native_todo.py +75 -0
  391. ksadk/harness/prompt_cache.py +132 -0
  392. ksadk/harness/public_activity.py +213 -0
  393. ksadk/harness/public_output.py +30 -0
  394. ksadk/harness/public_summary.py +36 -0
  395. ksadk/harness/readiness.py +249 -0
  396. ksadk/harness/reasoner.py +779 -17
  397. ksadk/harness/release_readiness.py +140 -0
  398. ksadk/harness/resource_ref.py +69 -0
  399. ksadk/harness/rpc.py +200 -0
  400. ksadk/harness/run_control.py +773 -0
  401. ksadk/harness/runtime.py +157 -113
  402. ksadk/harness/runtime_capabilities.py +228 -0
  403. ksadk/harness/runtime_server.py +514 -0
  404. ksadk/harness/sandbox_adapters.py +739 -0
  405. ksadk/harness/sandbox_backend.py +733 -0
  406. ksadk/harness/sandbox_conformance.py +288 -0
  407. ksadk/harness/sandbox_lease.py +77 -0
  408. ksadk/harness/sandbox_lease_conformance.py +259 -0
  409. ksadk/harness/sandbox_matrix.py +170 -0
  410. ksadk/harness/sandbox_reconciliation.py +140 -0
  411. ksadk/harness/sandbox_recovery.py +586 -0
  412. ksadk/harness/sandbox_recovery_conformance.py +246 -0
  413. ksadk/harness/sdk.py +153 -0
  414. ksadk/harness/session_store.py +589 -0
  415. ksadk/harness/skill_adapters/__init__.py +1 -0
  416. ksadk/harness/skill_adapters/native_bundle.py +148 -0
  417. ksadk/harness/skill_adapters/native_disclosure.py +306 -0
  418. ksadk/harness/skill_composition.py +212 -0
  419. ksadk/harness/skill_feedback.py +123 -0
  420. ksadk/harness/skill_intent.py +47 -0
  421. ksadk/harness/skill_matrix.py +233 -0
  422. ksadk/harness/skill_runtime.py +317 -0
  423. ksadk/harness/spec.py +342 -0
  424. ksadk/harness/state.py +155 -0
  425. ksadk/harness/stores/__init__.py +14 -0
  426. ksadk/harness/stores/native_command_settlement.py +65 -0
  427. ksadk/harness/stores/native_contract.py +311 -0
  428. ksadk/harness/stores/native_memory.py +326 -0
  429. ksadk/harness/stores/native_memory_archive.py +70 -0
  430. ksadk/harness/stores/native_migration_cli.py +91 -0
  431. ksadk/harness/stores/native_outbox.py +56 -0
  432. ksadk/harness/stores/native_sqlite.py +782 -0
  433. ksadk/harness/stores/native_sqlite_audit.py +29 -0
  434. ksadk/harness/stores/native_sqlite_migration.py +252 -0
  435. ksadk/harness/strategies.py +149 -0
  436. ksadk/harness/subagent.py +263 -0
  437. ksadk/harness/subagent_adapters/checkpoint_recovery.py +120 -0
  438. ksadk/harness/subagent_adapters/native_background_child.py +803 -0
  439. ksadk/harness/subagent_adapters/native_child.py +819 -0
  440. ksadk/harness/subagent_adapters/native_child_approval.py +128 -0
  441. ksadk/harness/subagent_adapters/native_child_continuation.py +51 -0
  442. ksadk/harness/subagent_adapters/native_child_result.py +392 -0
  443. ksadk/harness/subagent_adapters/prepared_recovery.py +120 -0
  444. ksadk/harness/tool_display.py +75 -0
  445. ksadk/harness/tool_display_contract.py +134 -0
  446. ksadk/harness/tool_output.py +141 -0
  447. ksadk/harness/tool_policy.py +134 -0
  448. ksadk/harness/tool_receipts.py +96 -0
  449. ksadk/harness/tool_reliability.py +81 -0
  450. ksadk/harness/tool_result_policy.py +216 -0
  451. ksadk/harness/tools.py +52 -0
  452. ksadk/harness/user_errors.py +69 -0
  453. ksadk/harness/working_context.py +81 -0
  454. ksadk/harness/working_context_patch.py +99 -0
  455. ksadk/harness/workspace_adapters/__init__.py +6 -0
  456. ksadk/harness/workspace_adapters/native_directory.py +180 -0
  457. ksadk/harness/workspace_adapters/native_git.py +208 -0
  458. ksadk/harness/workspace_adapters/native_isolation.py +350 -0
  459. ksadk/identity/resolver.py +18 -0
  460. ksadk/interaction/__init__.py +1 -1
  461. ksadk/interaction/ledger.py +1 -1
  462. ksadk/interaction/provider.py +1 -1
  463. ksadk/interaction/providers/__init__.py +3 -1
  464. ksadk/interaction/providers/adk.py +1 -1
  465. ksadk/interaction/providers/codex.py +1 -1
  466. ksadk/interaction/providers/harness.py +50 -0
  467. ksadk/interaction/providers/langgraph.py +9 -2
  468. ksadk/kernel/__init__.py +10 -0
  469. ksadk/kernel/approval_presentation.py +91 -0
  470. ksadk/kernel/authorization.py +1 -1
  471. ksadk/kernel/bootstrap.py +220 -252
  472. ksadk/kernel/contract_fingerprints.py +45 -1
  473. ksadk/kernel/contracts.py +30 -0
  474. ksadk/kernel/control.py +180 -29
  475. ksadk/kernel/execution_grants.py +428 -0
  476. ksadk/kernel/execution_grants_memory.py +252 -0
  477. ksadk/kernel/execution_grants_postgres.py +395 -0
  478. ksadk/kernel/execution_grants_sqlite.py +435 -0
  479. ksadk/kernel/execution_host_ingress.py +1071 -0
  480. ksadk/kernel/history_projection.py +120 -0
  481. ksadk/kernel/ingress.py +139 -226
  482. ksadk/kernel/ingress_bootstrap.py +268 -0
  483. ksadk/kernel/legacy_history.py +179 -0
  484. ksadk/kernel/mapping.py +1 -1
  485. ksadk/kernel/memory_store.py +61 -58
  486. ksadk/kernel/memory_store_projection.py +63 -0
  487. ksadk/kernel/postgres_event_log.py +181 -0
  488. ksadk/kernel/postgres_store.py +230 -231
  489. ksadk/kernel/readiness.py +125 -0
  490. ksadk/kernel/recovery.py +166 -16
  491. ksadk/kernel/recovery_projection.py +124 -0
  492. ksadk/kernel/runtime_checkpoint.py +34 -0
  493. ksadk/kernel/sql/001_agent_kernel.sql +28 -0
  494. ksadk/kernel/sqlite_schema.py +100 -0
  495. ksadk/kernel/sqlite_store.py +410 -200
  496. ksadk/kernel/state.py +2 -3
  497. ksadk/kernel/store.py +104 -5
  498. ksadk/kernel/teams_artifact_tools.py +392 -0
  499. ksadk/kernel/teams_effects.py +851 -0
  500. ksadk/kernel/teams_execution_context.py +408 -0
  501. ksadk/kernel/teams_host_http.py +237 -0
  502. ksadk/kernel/teams_material_transport.py +245 -0
  503. ksadk/kernel/teams_materials.py +318 -0
  504. ksadk/kernel/teams_runtime_bootstrap.py +604 -0
  505. ksadk/kernel/teams_tool_runtime.py +273 -0
  506. ksadk/kernel/teams_workspace.py +259 -0
  507. ksadk/kernel/worker.py +369 -340
  508. ksadk/kernel/worker_controls.py +454 -0
  509. ksadk/kernel/worker_history.py +72 -0
  510. ksadk/kernel/worker_identity.py +74 -0
  511. ksadk/kernel/worker_interactions.py +197 -0
  512. ksadk/knowledge_base/client.py +15 -1
  513. ksadk/managed_runtime.py +29 -2
  514. ksadk/memory/adk/backends/http_ltm_backend.py +2 -1
  515. ksadk/memory/adk/backends/sdk_ltm_backend.py +15 -1
  516. ksadk/memory/adk/bounded_database_session_service.py +232 -0
  517. ksadk/memory/adk/resilient_session_service.py +115 -15
  518. ksadk/memory/adk/short_term_memory.py +8 -9
  519. ksadk/memory/coordinator.py +22 -6
  520. ksadk/memory/extraction.py +159 -7
  521. ksadk/memory/models.py +77 -1
  522. ksadk/memory/provider_resolver.py +5 -0
  523. ksadk/memory/providers/local_candidates.py +183 -0
  524. ksadk/memory/providers/local_postgres.py +200 -0
  525. ksadk/memory/providers/local_sqlite.py +280 -67
  526. ksadk/memory/resolved_policy.py +12 -7
  527. ksadk/memory/retrieval.py +189 -0
  528. ksadk/memory/store_adapter.py +150 -0
  529. ksadk/model_gateway/__init__.py +29 -0
  530. ksadk/model_gateway/client.py +253 -0
  531. ksadk/model_gateway/events.py +113 -0
  532. ksadk/model_gateway/matrix.py +297 -0
  533. ksadk/model_policy.py +2 -2
  534. ksadk/model_proxy/compat.py +670 -0
  535. ksadk/model_proxy/detect.py +254 -0
  536. ksadk/model_proxy/server.py +14 -9
  537. ksadk/model_proxy/transform.py +72 -6
  538. ksadk/plugins/__init__.py +1 -1
  539. ksadk/plugins/bridges/dsh.py +29 -20
  540. ksadk/plugins/bridges/dsh_profile_manifest.py +36 -0
  541. ksadk/plugins/builtin_resources.py +199 -0
  542. ksadk/plugins/builtins.py +417 -185
  543. ksadk/plugins/companion_artifacts.py +83 -0
  544. ksadk/plugins/companions.py +368 -0
  545. ksadk/plugins/context_contributor.py +15 -4
  546. ksadk/plugins/contracts.py +1 -1
  547. ksadk/plugins/dsh_channels.py +156 -0
  548. ksadk/plugins/dsh_dependency_policy.py +41 -0
  549. ksadk/plugins/dsh_home.py +140 -0
  550. ksadk/plugins/dsh_teams.py +105 -0
  551. ksadk/plugins/dsh_toolchain.py +92 -21
  552. ksadk/plugins/execution_host.py +107 -0
  553. ksadk/plugins/host.py +73 -5
  554. ksadk/plugins/kernel_adapter.py +44 -1
  555. ksadk/plugins/memory_provider.py +180 -0
  556. ksadk/plugins/providers/_process_group.py +50 -0
  557. ksadk/plugins/providers/bundles/dsh-channels-client/client.js +19 -0
  558. ksadk/plugins/providers/bundles/dsh-channels-client/cordis.patch.yml +3 -0
  559. ksadk/plugins/providers/bundles/dsh-channels-client/index.mjs +7 -0
  560. ksadk/plugins/providers/bundles/dsh-channels-client/package.json +12 -0
  561. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +24 -2
  562. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +1 -1
  563. ksadk/plugins/providers/bundles/dsh-memory/package.json +1 -1
  564. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +1 -1
  565. ksadk/plugins/providers/bundles/dsh-teams-client/client.js +29 -0
  566. ksadk/plugins/providers/bundles/dsh-teams-client/cordis.patch.yml +3 -0
  567. ksadk/plugins/providers/bundles/dsh-teams-client/index.mjs +11 -0
  568. ksadk/plugins/providers/bundles/dsh-teams-client/package.json +35 -0
  569. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/cordis.patch.yml +3 -0
  570. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/index.mjs +13 -0
  571. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/package.json +27 -0
  572. ksadk/plugins/providers/bundles/dsh-teams-profile/cordis.patch.yml +3 -0
  573. ksadk/plugins/providers/bundles/dsh-teams-profile/index.mjs +12 -0
  574. ksadk/plugins/providers/bundles/dsh-teams-profile/package.json +26 -0
  575. ksadk/plugins/providers/bundles/dsh-teams-router/cordis.patch.yml +3 -0
  576. ksadk/plugins/providers/bundles/dsh-teams-router/index.mjs +16 -0
  577. ksadk/plugins/providers/bundles/dsh-teams-router/package.json +27 -0
  578. ksadk/plugins/providers/bundles/dsh-teams-tasks/cordis.patch.yml +3 -0
  579. ksadk/plugins/providers/bundles/dsh-teams-tasks/index.mjs +16 -0
  580. ksadk/plugins/providers/bundles/dsh-teams-tasks/package.json +27 -0
  581. ksadk/plugins/providers/bundles/dsh-teams-tools/cordis.patch.yml +3 -0
  582. ksadk/plugins/providers/bundles/dsh-teams-tools/index.mjs +25 -0
  583. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +29 -0
  584. ksadk/plugins/providers/bundles/dsh-teams-tools/tools.json +235 -0
  585. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +1 -1
  586. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +51 -1
  587. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +2 -2
  588. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/client.mjs +133 -0
  589. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/index.mjs +14 -0
  590. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +27 -4
  591. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +9 -5
  592. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +1 -1
  593. ksadk/plugins/providers/codex.py +52 -40
  594. ksadk/plugins/providers/codex_native.py +20 -0
  595. ksadk/plugins/providers/codex_skills.py +46 -0
  596. ksadk/plugins/providers/dsh_capabilities.py +49 -143
  597. ksadk/plugins/providers/dsh_connector_lease.py +225 -0
  598. ksadk/plugins/providers/dsh_mcp.py +163 -1
  599. ksadk/plugins/providers/harness.py +413 -52
  600. ksadk/plugins/providers/harness_context.py +61 -0
  601. ksadk/plugins/providers/harness_contributions.py +241 -0
  602. ksadk/plugins/providers/harness_delegation.py +670 -0
  603. ksadk/plugins/providers/harness_hooks.py +121 -0
  604. ksadk/plugins/providers/harness_managed.py +550 -0
  605. ksadk/plugins/providers/harness_tools.py +455 -0
  606. ksadk/plugins/providers/legacy_catalog.py +1 -1
  607. ksadk/plugins/providers/mcp_projection.py +100 -3
  608. ksadk/plugins/providers/platform_resources.py +16 -6
  609. ksadk/plugins/providers/shipped_dsh.py +4 -1
  610. ksadk/plugins/subagent_providers/codex.py +28 -6
  611. ksadk/plugins/teams/__init__.py +5 -0
  612. ksadk/plugins/teams/api.py +405 -0
  613. ksadk/plugins/teams/application.py +540 -0
  614. ksadk/plugins/teams/artifacts.py +60 -0
  615. ksadk/plugins/teams/build_artifacts.py +460 -0
  616. ksadk/plugins/teams/cloud_contract_fingerprints.py +22 -0
  617. ksadk/plugins/teams/cloud_contracts.py +928 -0
  618. ksadk/plugins/teams/cloud_permits.py +250 -0
  619. ksadk/plugins/teams/context.py +96 -0
  620. ksadk/plugins/teams/contracts.py +136 -0
  621. ksadk/plugins/teams/domain.py +1480 -0
  622. ksadk/plugins/teams/domain_values.py +24 -0
  623. ksadk/plugins/teams/effect_contracts.py +255 -0
  624. ksadk/plugins/teams/errors.py +13 -0
  625. ksadk/plugins/teams/execution_projection.py +255 -0
  626. ksadk/plugins/teams/leader_decisions.py +106 -0
  627. ksadk/plugins/teams/migration.py +311 -0
  628. ksadk/plugins/teams/migration_cli.py +322 -0
  629. ksadk/plugins/teams/postgres_store.py +352 -0
  630. ksadk/plugins/teams/release_contracts.py +60 -0
  631. ksadk/plugins/teams/runtime.py +853 -0
  632. ksadk/plugins/teams/source_projection.py +84 -0
  633. ksadk/plugins/teams/store.py +519 -0
  634. ksadk/plugins/teams/task_decisions.py +436 -0
  635. ksadk/plugins/teams/tool_service.py +152 -0
  636. ksadk/plugins/teams/transport.py +96 -0
  637. ksadk/plugins/teams/workspaces.py +255 -0
  638. ksadk/resource_runtime/skill_runtime.py +3 -0
  639. ksadk/resource_runtime/socket_server.py +11 -0
  640. ksadk/resource_runtime/worker.py +28 -4
  641. ksadk/runners/_adk_a2a_stream.py +122 -0
  642. ksadk/runners/_adk_canonical_stream.py +474 -0
  643. ksadk/runners/_langgraph_canonical_streams.py +527 -0
  644. ksadk/runners/_langgraph_runner_streams.py +83 -401
  645. ksadk/runners/_langgraph_state_reader.py +106 -0
  646. ksadk/runners/_langgraph_tool_projection.py +86 -0
  647. ksadk/runners/_langgraph_tools_transformer.py +27 -0
  648. ksadk/runners/_session_identity.py +285 -0
  649. ksadk/runners/adk_runner.py +220 -350
  650. ksadk/runners/base_runner.py +6 -5
  651. ksadk/runners/langgraph_runner.py +208 -195
  652. ksadk/runners/patch_langchain.py +47 -0
  653. ksadk/runners/usage_accumulator.py +11 -3
  654. ksadk/runners/utils/loader.py +28 -14
  655. ksadk/runtime/_runner_adapter/a2ui_surface.py +145 -0
  656. ksadk/runtime/_runner_adapter/gateway_approvals.py +93 -0
  657. ksadk/runtime/_runner_adapter/stream_mapping.py +134 -129
  658. ksadk/runtime/adapter.py +40 -3
  659. ksadk/runtime/conversation_execution.py +29 -3
  660. ksadk/runtime/executor.py +105 -7
  661. ksadk/runtime/factory.py +45 -3
  662. ksadk/runtime/framework_adapters.py +184 -10
  663. ksadk/runtime/hosted_finalizer.py +4 -6
  664. ksadk/runtime/launch.py +2 -0
  665. ksadk/runtime/preprocessing.py +11 -3
  666. ksadk/runtime/runner_adapter.py +160 -21
  667. ksadk/runtime/skill_eval_result.py +36 -0
  668. ksadk/runtime/timing.py +46 -0
  669. ksadk/runtime/usage.py +49 -18
  670. ksadk/runtime_context.py +105 -1
  671. ksadk/sandbox/backends/e2b.py +272 -24
  672. ksadk/sandbox/backends/local_process.py +73 -39
  673. ksadk/sandbox/base.py +62 -1
  674. ksadk/sandbox/diagnostics.py +82 -0
  675. ksadk/sandbox/e2b_connection.py +9 -1
  676. ksadk/sandbox/local_controls.py +776 -0
  677. ksadk/sandbox/local_launcher.py +124 -0
  678. ksadk/scheduler/dispatcher.py +1 -1
  679. ksadk/server/factory.py +178 -25
  680. ksadk/server/history_deadline.py +158 -0
  681. ksadk/server/history_page_cache.py +129 -0
  682. ksadk/server/invocation_identity.py +118 -0
  683. ksadk/server/routes/checkpoint_audit.py +88 -0
  684. ksadk/server/routes/checkpoint_listing.py +294 -0
  685. ksadk/server/routes/checkpoint_resolution.py +73 -20
  686. ksadk/server/routes/common.py +32 -3
  687. ksadk/server/routes/control.py +112 -9
  688. ksadk/server/routes/dependencies.py +2 -1
  689. ksadk/server/routes/display_projection.py +154 -0
  690. ksadk/server/routes/kernel_ingress.py +26 -3
  691. ksadk/server/routes/misc.py +331 -33
  692. ksadk/server/routes/models.py +28 -4
  693. ksadk/server/routes/openai_compat.py +82 -13
  694. ksadk/server/routes/projection.py +159 -216
  695. ksadk/server/routes/run.py +112 -37
  696. ksadk/server/routes/sessions.py +493 -358
  697. ksadk/server/routes/streaming.py +68 -15
  698. ksadk/server/routes/tool_receipt_claim_routes.py +107 -0
  699. ksadk/server/routes/workspace.py +135 -23
  700. ksadk/server/static/assets/{ArtifactsPanel-CGbWlMNh.js → ArtifactsPanel-CILaW-fC.js} +1 -1
  701. ksadk/server/static/assets/{CodeBlock-b4C7upmO.js → CodeBlock-BVrNVtJC.js} +10 -7
  702. ksadk/server/static/assets/MathMessageMarkdown-Dp7c4wWD.js +8 -0
  703. ksadk/server/static/assets/{MermaidBlock-BEBN4Ksz.js → MermaidBlock-Dxop8Rd7.js} +9 -9
  704. ksadk/server/static/assets/{NativeTerminalPanel-zvL-WpAn.js → NativeTerminalPanel-Cjjz8B30.js} +1 -1
  705. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-BYafW7Za.js → abnfDiagram-VCTEODGH-ckWDmOzw.js} +1 -1
  706. ksadk/server/static/assets/{arc-bTohInsS.js → arc-DqxJede-.js} +1 -1
  707. ksadk/server/static/assets/architecture-7GRP2DOG-pn_DuLy6.js +1 -0
  708. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-Ch5Lbzsi.js → architectureDiagram-5GKGNRK7-SEQA4bVi.js} +1 -1
  709. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-kqF4MDOG.js → blockDiagram-NRAW4CY4-pM0B-6NJ.js} +1 -1
  710. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-8uSRIODv.js → c4Diagram-UCG6FXSJ-m2tuCNVq.js} +1 -1
  711. ksadk/server/static/assets/channel-fySsnkft.js +1 -0
  712. ksadk/server/static/assets/chunk-2Q5K7J3B-BheGxKRQ.js +1 -0
  713. ksadk/server/static/assets/{chunk-5VM5RSS4-DkhehZDr.js → chunk-5VM5RSS4-GJHDr9Ww.js} +1 -1
  714. ksadk/server/static/assets/{chunk-F27PBJKO-BdXhtPe9.js → chunk-F27PBJKO-CbAN45AV.js} +1 -1
  715. ksadk/server/static/assets/{chunk-G27WJ6UU-DPTpvpwi.js → chunk-G27WJ6UU-D5ngbbzF.js} +1 -1
  716. ksadk/server/static/assets/{chunk-JWPE2WC7-Pqoh38el.js → chunk-JWPE2WC7-Cc5IwuYC.js} +1 -1
  717. ksadk/server/static/assets/{chunk-LCL6LL3I-DeU00qC-.js → chunk-LCL6LL3I-CprgDDdJ.js} +1 -1
  718. ksadk/server/static/assets/{chunk-POPQ4Y6H-CzxScFkr.js → chunk-POPQ4Y6H-CDZhSy82.js} +1 -1
  719. ksadk/server/static/assets/{chunk-RHFEMEQ7-DpqMx-ux.js → chunk-RHFEMEQ7-CZchUNro.js} +1 -1
  720. ksadk/server/static/assets/{chunk-SVP7TREG-C6t0SypQ.js → chunk-SVP7TREG-BVruqk6T.js} +1 -1
  721. ksadk/server/static/assets/{chunk-XXDRQBXY-DVaeafZk.js → chunk-XXDRQBXY-4ld9SxPN.js} +1 -1
  722. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DSfLtNYm.js +1 -0
  723. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DSfLtNYm.js +1 -0
  724. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-Bf9D3tzJ.js → cose-bilkent-JH36ORCC-Dmyyk_Vp.js} +1 -1
  725. ksadk/server/static/assets/cynefin-OW5HDTMX-PFWIGtvA.js +1 -0
  726. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-B9cY3iTz.js → cynefinDiagram-5FMLGOSQ-BIyq3EJb.js} +1 -1
  727. ksadk/server/static/assets/{dagre-3AP2YEHR-CSwlx3CB.js → dagre-3AP2YEHR-eBw08Qdk.js} +1 -1
  728. ksadk/server/static/assets/{dagre-UBpgon5q.js → dagre-DfvnEf45.js} +1 -1
  729. ksadk/server/static/assets/{diagram-S7CK7UJ4-C9akhN9a.js → diagram-S7CK7UJ4-CUSrE3Mg.js} +1 -1
  730. ksadk/server/static/assets/{diagram-UQ7AKVKN-CgedhTPI.js → diagram-UQ7AKVKN-Dq5Zw2gy.js} +1 -1
  731. ksadk/server/static/assets/{diagram-VSXAHHWV-Cjucz5BY.js → diagram-VSXAHHWV-DyUHfNwT.js} +1 -1
  732. ksadk/server/static/assets/{diagram-VX7I27RA-Dd4Vleyn.js → diagram-VX7I27RA-CREmM89O.js} +1 -1
  733. ksadk/server/static/assets/{diagram-Z3DM3KII-CZ2jGtYW.js → diagram-Z3DM3KII-Dw9zhHUK.js} +1 -1
  734. ksadk/server/static/assets/{dist-Bj730Ib4.js → dist-0uJ4tdx6.js} +1 -1
  735. ksadk/server/static/assets/{dist-BnaTiyzN.js → dist-AEv-vXf-.js} +1 -1
  736. ksadk/server/static/assets/{dist-BgV_owcB.js → dist-B49GzZDb.js} +1 -1
  737. ksadk/server/static/assets/{dist-D_ctSS2i.js → dist-B8Myiet9.js} +1 -1
  738. ksadk/server/static/assets/{dist-ufY3F5p6.js → dist-BBsYarrI.js} +2 -2
  739. ksadk/server/static/assets/{dist-ClYUxfeK.js → dist-BQMrUwdI.js} +1 -1
  740. ksadk/server/static/assets/{dist-CFzsn6BG.js → dist-BX_-FENW.js} +1 -1
  741. ksadk/server/static/assets/{dist-B3FR1SKK.js → dist-CD4L6ymH.js} +1 -1
  742. ksadk/server/static/assets/{dist-Cf125P_m.js → dist-CHpW1BHj.js} +1 -1
  743. ksadk/server/static/assets/{dist-DVCOWtha.js → dist-CVPau3tn.js} +1 -1
  744. ksadk/server/static/assets/{dist-DFD6Qa6T.js → dist-C_qdxcSH.js} +1 -1
  745. ksadk/server/static/assets/{dist-BIr4DSRq.js → dist-Co68Apq4.js} +1 -1
  746. ksadk/server/static/assets/{dist-DiixqL0J.js → dist-Cp2PaOMY.js} +1 -1
  747. ksadk/server/static/assets/{dist-fBO2v5Kt.js → dist-CuR5Bgme.js} +1 -1
  748. ksadk/server/static/assets/{dist-DoVSwoDb.js → dist-DDSyLEOX.js} +1 -1
  749. ksadk/server/static/assets/{dist-C5_ZAZsG.js → dist-DUxO0R99.js} +1 -1
  750. ksadk/server/static/assets/{dist-C1NMAY5a.js → dist-QzbGrED_.js} +1 -1
  751. ksadk/server/static/assets/dist-bupkyEBZ.js +1 -0
  752. ksadk/server/static/assets/{dist-DvFK7p5S.js → dist-cxTGfdqx.js} +1 -1
  753. ksadk/server/static/assets/{dist-CB9iJrvg.js → dist-hL5p1til.js} +1 -1
  754. ksadk/server/static/assets/{dist-btbmmX5O.js → dist-lOy23y43.js} +1 -1
  755. ksadk/server/static/assets/{dist-QfkEHOlb.js → dist-pq-nD33R.js} +1 -1
  756. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Ci8NqqZu.js → ebnfDiagram-PWID7BFC-BS5LdNoR.js} +1 -1
  757. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CCIOhLZG.js → erDiagram-SSCWMZ5O-Bv1QtiY-.js} +1 -1
  758. ksadk/server/static/assets/eventmodeling-NTZA5JFV-DsM4upQX.js +1 -0
  759. ksadk/server/static/assets/flowDiagram-A5DVABFB-D5NA16k9.js +1 -0
  760. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-Cp_r9Hb6.js → ganttDiagram-EL5Y4UJY-musi-e0G.js} +1 -1
  761. ksadk/server/static/assets/gitGraph-4MIJSDKK-DUCVz-ih.js +1 -0
  762. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-Dlhc8Wr8.js → gitGraphDiagram-WWUBYQGX-DH37EGkG.js} +1 -1
  763. ksadk/server/static/assets/index-CZdkAvsv.js +244 -0
  764. ksadk/server/static/assets/index-CvXdHgF3.css +2 -0
  765. ksadk/server/static/assets/info-A6RAGUB7-rw0ZNHZp.js +1 -0
  766. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CO0rRTRA.js → infoDiagram-RXCK75RN-C1kEtv2y.js} +1 -1
  767. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CHiaedSS.js → ishikawaDiagram-5VMMS53U-BCNPyMka.js} +1 -1
  768. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-CHcCIB09.js → journeyDiagram-EYS64GPL--cDbKnjP.js} +1 -1
  769. ksadk/server/static/assets/{kanban-definition-3QL26DDD-CJ_ebBZf.js → kanban-definition-3QL26DDD-R1rAVw2f.js} +1 -1
  770. ksadk/server/static/assets/{katex-B4weu383.js → katex-BT-X-V7U.js} +1 -1
  771. ksadk/server/static/assets/{linear-V-MgYHW1.js → linear-DTR631iG.js} +1 -1
  772. ksadk/server/static/assets/{mermaid-parser.core-CBijEX_c.js → mermaid-parser.core-DfFzJhX8.js} +2 -2
  773. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-Bc-pQvpp.js → mindmap-definition-FBJOCRG2-D4by_rmk.js} +1 -1
  774. ksadk/server/static/assets/packet-AYTQ26CC-Ca4Hvki9.js +1 -0
  775. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-D7genGLl.js → pegDiagram-XKGWAZYB-xWXPEh0c.js} +1 -1
  776. ksadk/server/static/assets/pie-WAS4IAKB-hwiz6fbw.js +1 -0
  777. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-Bxj32zwD.js → pieDiagram-E7YTZNPT-BudBDlCI.js} +1 -1
  778. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BURv2mGh.js → quadrantDiagram-AXDQQJYC-DXZ0PCJF.js} +1 -1
  779. ksadk/server/static/assets/radar-RG4KPBEZ-BR1oZXLM.js +1 -0
  780. ksadk/server/static/assets/railroad-74A4TZTK-DfgEISfX.js +1 -0
  781. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-CWOC3rdk.js +1 -0
  782. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CiRvHCLY.js +1 -0
  783. ksadk/server/static/assets/railroad-peg-WCYAUIDC-DSDDyJ2f.js +1 -0
  784. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-CCsh3avW.js → railroadDiagram-O6MQD6OU-BdAYRYB8.js} +1 -1
  785. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-_FRRBKEd.js → requirementDiagram-EFPCY7ZU-CBBmaL70.js} +1 -1
  786. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-C-gr2o9M.js → sankeyDiagram-P5KCCOFB-Doc3rdwp.js} +1 -1
  787. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-D97NmfKg.js → sequenceDiagram-WJ2MYXX4-0J8R8hWW.js} +1 -1
  788. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DjrPC5FX.js → sizeCapture-X5ZJPWSS-CfFLlWsK.js} +1 -1
  789. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DzMNg1hh.js → stateDiagram-HBIQ2CUA-jBwkjtTy.js} +1 -1
  790. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-Cw1fPb5w.js +1 -0
  791. ksadk/server/static/assets/{swimlanes-XN3QIQJK-Cssf_CsU.js → swimlanes-XN3QIQJK-B0WxTQf8.js} +1 -1
  792. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-Cc3JMBAF.js +8 -0
  793. ksadk/server/static/assets/{timeline-definition-24CTP7MA-BWTHzyS1.js → timeline-definition-24CTP7MA-BfCT_75A.js} +1 -1
  794. ksadk/server/static/assets/treeView-Q6P3EWNA-C05SJHxo.js +1 -0
  795. ksadk/server/static/assets/treemap-WGGIJYW6-BqNLAhc3.js +1 -0
  796. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-BSKgJsmR.js → vennDiagram-4TSXK5OY-9gX1VMDC.js} +1 -1
  797. ksadk/server/static/assets/wardley-WFR3VGLG-DokNktqB.js +1 -0
  798. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-eflHNoaZ.js → wardleyDiagram-VM6X3IG4-sEs_BP6O.js} +1 -1
  799. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-eYqrQ-v4.js → xychartDiagram-S5SC5T6Z-Ll4jvUN9.js} +1 -1
  800. ksadk/server/static/index.html +2 -2
  801. ksadk/server/terminal_sessions.py +34 -2
  802. ksadk/sessions/__init__.py +8 -1
  803. ksadk/sessions/_checkpoint_resume_audit.py +44 -0
  804. ksadk/sessions/_in_memory_query.py +112 -0
  805. ksadk/sessions/_local_service_sync.py +157 -156
  806. ksadk/sessions/_local_state_sync.py +152 -0
  807. ksadk/sessions/_local_tables.py +2 -0
  808. ksadk/sessions/_postgres_checkpoint_read.py +323 -0
  809. ksadk/sessions/_postgres_checkpoint_stats.py +330 -0
  810. ksadk/sessions/_postgres_history_read.py +678 -0
  811. ksadk/sessions/_postgres_schema.py +44 -2
  812. ksadk/sessions/_postgres_tables.py +2 -0
  813. ksadk/sessions/_postgres_tool_receipts.py +169 -0
  814. ksadk/sessions/_resilient_read.py +630 -0
  815. ksadk/sessions/_tool_receipt_sync.py +119 -0
  816. ksadk/sessions/agent_identity.py +16 -0
  817. ksadk/sessions/base.py +278 -0
  818. ksadk/sessions/db_budget.py +332 -0
  819. ksadk/sessions/errors.py +12 -0
  820. ksadk/sessions/history_budget.py +36 -0
  821. ksadk/sessions/history_identity.py +27 -0
  822. ksadk/sessions/in_memory.py +376 -113
  823. ksadk/sessions/invocation_identity.py +235 -0
  824. ksadk/sessions/local_service.py +345 -0
  825. ksadk/sessions/postgres_service.py +515 -549
  826. ksadk/sessions/resilience.py +21 -14
  827. ksadk/sessions/resilient.py +611 -504
  828. ksadk/skills/__init__.py +26 -0
  829. ksadk/skills/events.py +464 -0
  830. ksadk/skills/loader.py +44 -2
  831. ksadk/skills/manifest_cache.py +263 -0
  832. ksadk/skills/mcp_server/__init__.py +0 -0
  833. ksadk/skills/mcp_server/_registry.py +33 -0
  834. ksadk/skills/mcp_server/_routing.py +26 -0
  835. ksadk/skills/mcp_server/_workspace_files.py +160 -0
  836. ksadk/skills/mcp_server/register.py +415 -0
  837. ksadk/skills/mcp_server/server.py +218 -0
  838. ksadk/skills/models.py +11 -0
  839. ksadk/skills/observability.py +132 -0
  840. ksadk/skills/package_store.py +75 -2
  841. ksadk/skills/runtime/agent.py +38 -5
  842. ksadk/skills/runtime/artifacts.py +87 -0
  843. ksadk/skills/runtime/backends/e2b.py +400 -56
  844. ksadk/skills/runtime/backends/local.py +621 -119
  845. ksadk/skills/runtime/base.py +78 -7
  846. ksadk/skills/runtime/executor.py +266 -1
  847. ksadk/skills/runtime/loader.py +108 -3
  848. ksadk/skills/runtime/request.py +18 -0
  849. ksadk/skills/service_client.py +6 -1
  850. ksadk/skills/tool_defs.py +108 -3
  851. ksadk/studio/a2a_bindings.py +407 -0
  852. ksadk/studio/a2a_orchestration.py +178 -0
  853. ksadk/studio/active_run_output.py +92 -0
  854. ksadk/studio/activity_records.py +542 -0
  855. ksadk/studio/agent_configuration.py +173 -0
  856. ksadk/studio/api.py +784 -419
  857. ksadk/studio/api_a2a_routes.py +93 -0
  858. ksadk/studio/api_catalog_routes.py +13 -0
  859. ksadk/studio/api_cloud_chat_routes.py +382 -0
  860. ksadk/studio/api_contracts.py +31 -2
  861. ksadk/studio/api_plugin_routes.py +39 -12
  862. ksadk/studio/api_resource_connections.py +79 -41
  863. ksadk/studio/attachment_store.py +14 -2
  864. ksadk/studio/authoring.py +12 -6
  865. ksadk/studio/authoring_coordinator.py +4 -2
  866. ksadk/studio/build_resolution.py +117 -0
  867. ksadk/studio/build_singleflight.py +37 -0
  868. ksadk/studio/builder.py +32 -2
  869. ksadk/studio/capabilities.py +31 -9
  870. ksadk/studio/channel_connections.py +333 -0
  871. ksadk/studio/cloud.py +113 -387
  872. ksadk/studio/cloud_gateways.py +424 -0
  873. ksadk/studio/cloud_shared_web.py +82 -2
  874. ksadk/studio/codex_agent_service.py +19 -2
  875. ksadk/studio/codex_builder.py +1 -1
  876. ksadk/studio/codex_manifest.py +5 -1
  877. ksadk/studio/codex_provider_build.py +65 -0
  878. ksadk/studio/codex_run.py +6 -1
  879. ksadk/studio/compiler.py +112 -6
  880. ksadk/studio/configuration.py +182 -0
  881. ksadk/studio/contract_base.py +19 -0
  882. ksadk/studio/contracts.py +260 -202
  883. ksadk/studio/dsh_application.py +183 -27
  884. ksadk/studio/dsh_capability_service.py +302 -189
  885. ksadk/studio/dsh_lifecycle.py +58 -0
  886. ksadk/studio/dsh_mcp_transport.py +191 -0
  887. ksadk/studio/dsh_provider_registration.py +55 -16
  888. ksadk/studio/entry.py +53 -0
  889. ksadk/studio/event_store.py +53 -5
  890. ksadk/studio/execution_host.py +598 -0
  891. ksadk/studio/framework_run.py +50 -10
  892. ksadk/studio/hosted_kernel.py +1 -1
  893. ksadk/studio/interaction_submission.py +265 -0
  894. ksadk/studio/kernel_registry.py +429 -0
  895. ksadk/studio/kernel_sqlite_migration.py +181 -0
  896. ksadk/studio/lifecycle_status.py +43 -0
  897. ksadk/studio/model_buffered_wire.py +227 -0
  898. ksadk/studio/model_chat_tools.py +143 -0
  899. ksadk/studio/model_client.py +1939 -345
  900. ksadk/studio/model_content_stream.py +129 -0
  901. ksadk/studio/model_credentials.py +196 -0
  902. ksadk/studio/model_profile_service.py +89 -40
  903. ksadk/studio/model_request_projection.py +284 -0
  904. ksadk/studio/model_responses_content.py +296 -0
  905. ksadk/studio/model_usage.py +109 -0
  906. ksadk/studio/model_wire_failure.py +110 -0
  907. ksadk/studio/model_wire_identity.py +138 -0
  908. ksadk/studio/model_wire_snapshot.py +45 -0
  909. ksadk/studio/model_wire_tools.py +283 -0
  910. ksadk/studio/native_acceptance.py +68 -0
  911. ksadk/studio/native_approval.py +111 -0
  912. ksadk/studio/native_browser_port.py +861 -0
  913. ksadk/studio/native_child_mcp.py +87 -0
  914. ksadk/studio/native_child_publication.py +68 -0
  915. ksadk/studio/native_child_skills.py +72 -0
  916. ksadk/studio/native_child_workspace.py +176 -0
  917. ksadk/studio/native_command_policy.py +53 -0
  918. ksadk/studio/native_context_port.py +326 -0
  919. ksadk/studio/native_context_registration.py +54 -0
  920. ksadk/studio/native_document_input.py +88 -0
  921. ksadk/studio/native_documents.py +172 -0
  922. ksadk/studio/native_final_shape.py +852 -0
  923. ksadk/studio/native_gateway_stream.py +69 -0
  924. ksadk/studio/native_hook_port.py +145 -0
  925. ksadk/studio/native_hook_registration.py +70 -0
  926. ksadk/studio/native_inventory_disclosure.py +223 -0
  927. ksadk/studio/native_kernel_admission.py +84 -0
  928. ksadk/studio/native_language_diagnostics.py +320 -0
  929. ksadk/studio/native_mcp_disclosure.py +198 -0
  930. ksadk/studio/native_mcp_tool_port.py +219 -0
  931. ksadk/studio/native_memory_acceptance.py +362 -0
  932. ksadk/studio/native_memory_context.py +266 -0
  933. ksadk/studio/native_memory_flush.py +174 -0
  934. ksadk/studio/native_memory_sources.py +80 -0
  935. ksadk/studio/native_memory_tool_port.py +360 -0
  936. ksadk/studio/native_memory_turn.py +183 -0
  937. ksadk/studio/native_model_port.py +765 -0
  938. ksadk/studio/native_model_recovery.py +126 -0
  939. ksadk/studio/native_options.py +75 -0
  940. ksadk/studio/native_output_fields.py +58 -0
  941. ksadk/studio/native_planning.py +156 -0
  942. ksadk/studio/native_product.py +988 -0
  943. ksadk/studio/native_read_budget.py +426 -0
  944. ksadk/studio/native_recovery.py +171 -0
  945. ksadk/studio/native_scope.py +35 -0
  946. ksadk/studio/native_session_context_port.py +141 -0
  947. ksadk/studio/native_session_engine.py +14 -0
  948. ksadk/studio/native_skill_source.py +74 -0
  949. ksadk/studio/native_subagent_port.py +700 -0
  950. ksadk/studio/native_terminal_recovery.py +95 -0
  951. ksadk/studio/native_test_action.py +610 -0
  952. ksadk/studio/native_tool_port.py +477 -0
  953. ksadk/studio/native_user_input.py +60 -0
  954. ksadk/studio/native_verification_presentation.py +65 -0
  955. ksadk/studio/native_workspace_diagnostics.py +183 -0
  956. ksadk/studio/native_workspace_port.py +43 -0
  957. ksadk/studio/operations.py +34 -9
  958. ksadk/studio/plugin_composition.py +39 -12
  959. ksadk/studio/plugin_kernel_adapter.py +89 -0
  960. ksadk/studio/plugin_lifecycle.py +80 -0
  961. ksadk/studio/plugin_native_activation.py +163 -0
  962. ksadk/studio/plugin_runtime.py +832 -99
  963. ksadk/studio/plugin_runtime_admission.py +57 -0
  964. ksadk/studio/presentation.py +92 -0
  965. ksadk/studio/provider_recovery.py +59 -0
  966. ksadk/studio/public_output_store.py +69 -0
  967. ksadk/studio/recovery_page.py +70 -0
  968. ksadk/studio/resource_authority.py +69 -34
  969. ksadk/studio/resource_catalog.py +14 -12
  970. ksadk/studio/run_activity.py +848 -0
  971. ksadk/studio/run_controls.py +185 -0
  972. ksadk/studio/run_documents.py +127 -0
  973. ksadk/studio/run_service.py +1220 -335
  974. ksadk/studio/run_submission_receipts.py +68 -0
  975. ksadk/studio/runtime_catalog.py +73 -11
  976. ksadk/studio/runtime_prewarm.py +22 -0
  977. ksadk/studio/runtime_source.py +1 -1
  978. ksadk/studio/scheduler_assistant.py +4 -1
  979. ksadk/studio/scheduler_runtime.py +32 -289
  980. ksadk/studio/service.py +615 -246
  981. ksadk/studio/service_settings.py +229 -0
  982. ksadk/studio/shared_web.py +518 -181
  983. ksadk/studio/shared_web_response_events.py +180 -0
  984. ksadk/studio/shared_web_run_state.py +133 -0
  985. ksadk/studio/skill_discovery.py +305 -3
  986. ksadk/studio/static/assets/ChannelsPage-xX5HlMId.js +8 -0
  987. ksadk/studio/static/assets/CodeBlock-DMIf4h33-CkufcPYo.js +44 -0
  988. ksadk/studio/static/assets/ExecutionTree-v3HexvPo-Bk8wzGSy.js +1 -0
  989. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-DYG1Wzbx.js +8 -0
  990. ksadk/studio/static/assets/MermaidBlock-H_0qzQDf-BdXtxug_.js +11 -0
  991. ksadk/studio/static/assets/MessageMarkdown-CwMTvgFj-BeyLyQHu.js +59 -0
  992. ksadk/studio/static/assets/PrismRenderer-5pK6tUdb.js +3 -0
  993. ksadk/studio/static/assets/TeamsPage-CCaaGaVp.js +3 -0
  994. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-Bnb1O3tA.js +1 -0
  995. ksadk/studio/static/assets/architecture-7GRP2DOG-BMOPAkUC.js +1 -0
  996. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-5Zn1gqJv.js +36 -0
  997. ksadk/studio/static/assets/{blockDiagram-I7D4REHJ-CFmPl1de.js → blockDiagram-I7D4REHJ-CLB4L11u.js} +6 -6
  998. ksadk/studio/static/assets/{c4Diagram-7LVT6UL2-BRrGu8qt.js → c4Diagram-7LVT6UL2-BOma_Z_F.js} +7 -7
  999. ksadk/studio/static/assets/channel-r8itPEik.js +1 -0
  1000. ksadk/studio/static/assets/chunk-2E4U76K2-BFf_huql.js +2 -0
  1001. ksadk/studio/static/assets/chunk-2ZTRR5NV-C2qZJila.js +2 -0
  1002. ksadk/studio/static/assets/chunk-3Z5EZCMW-DMniOlPd.js +1 -0
  1003. ksadk/studio/static/assets/{chunk-4HAMMTFA-D220vUtq.js → chunk-4HAMMTFA-DVtDP4rm.js} +7 -7
  1004. ksadk/studio/static/assets/chunk-5V3GS4D5-i-ZDOEnP.js +1 -0
  1005. ksadk/studio/static/assets/chunk-6AZGARVD-BB6FqMl-.js +1 -0
  1006. ksadk/studio/static/assets/chunk-6EIED4P4-DdUJkP0f.js +1 -0
  1007. ksadk/studio/static/assets/chunk-6K3QC6MW-CqVsVn-y.js +1 -0
  1008. ksadk/studio/static/assets/chunk-6TQVIW2G-DKlLbNIP.js +1 -0
  1009. ksadk/studio/static/assets/chunk-747NJXEK-BFkZPlab.js +2 -0
  1010. ksadk/studio/static/assets/chunk-75Z2AOVW-BZNhM4vB.js +2 -0
  1011. ksadk/studio/static/assets/chunk-CLGD4ZFX-D-GTtyKs.js +1 -0
  1012. ksadk/studio/static/assets/{chunk-DU6HZSFF-C4DtVpCu.js → chunk-DU6HZSFF-CpEZCUgg.js} +1 -1
  1013. ksadk/studio/static/assets/chunk-F27PBJKO-D7pvKf0C.js +1 -0
  1014. ksadk/studio/static/assets/{chunk-GMAD6QVW-DiQA-u2N.js → chunk-GMAD6QVW-DE_8H717.js} +6 -6
  1015. ksadk/studio/static/assets/chunk-GVQU2GXP-BfEB0lNv.js +1 -0
  1016. ksadk/studio/static/assets/chunk-I5DQTOEV-Hm2LfiYI.js +1 -0
  1017. ksadk/studio/static/assets/chunk-ICYGCRZG-749o-pGJ.js +1 -0
  1018. ksadk/studio/static/assets/chunk-IH6LHLGP-CC6I9F3i.js +1 -0
  1019. ksadk/studio/static/assets/{chunk-IMKFNOWR-BSlbjT_b.js → chunk-IMKFNOWR-D38axYOR.js} +5 -5
  1020. ksadk/studio/static/assets/chunk-KI3K4JFJ-Rma-0k_M.js +1 -0
  1021. ksadk/studio/static/assets/chunk-L3NEJ4N5-Dq5xn7aL.js +1 -0
  1022. ksadk/studio/static/assets/chunk-LNGE3PJU-DWpGwHrW.js +34 -0
  1023. ksadk/studio/static/assets/{chunk-OSK3NFVY-M2m6G3j4.js → chunk-OSK3NFVY-DiCQjx9b.js} +5 -5
  1024. ksadk/studio/static/assets/chunk-OUJLGHUK-D0j2JRSg.js +2 -0
  1025. ksadk/studio/static/assets/{chunk-P2QGCYS3-DezaQxiK.js → chunk-P2QGCYS3-VdhKmfYq.js} +1 -1
  1026. ksadk/studio/static/assets/chunk-POPQ4Y6H-C1_rzO5M.js +1 -0
  1027. ksadk/studio/static/assets/chunk-PWAF6VOD-B45HvflI.js +1 -0
  1028. ksadk/studio/static/assets/{chunk-SHT3W25Y-DAyIVp5H.js → chunk-SHT3W25Y-DsCFnRVE.js} +9 -9
  1029. ksadk/studio/static/assets/{chunk-SVP7TREG-DulomOrS.js → chunk-SVP7TREG-DljApgRX.js} +1 -1
  1030. ksadk/studio/static/assets/{chunk-TICWLB2K-bHJYoflj.js → chunk-TICWLB2K-DWqRtyqa.js} +6 -6
  1031. ksadk/studio/static/assets/chunk-TLUHSLCS-DUeGgnD5.js +2 -0
  1032. ksadk/studio/static/assets/chunk-UY3FDG6J-CnmaAkG5.js +1 -0
  1033. ksadk/studio/static/assets/chunk-XHIXRSVI-BFQ6B8BE.js +1 -0
  1034. ksadk/studio/static/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
  1035. ksadk/studio/static/assets/classDiagram-ZZMXUADV-DjeMNJmu.js +1 -0
  1036. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-DjeMNJmu.js +1 -0
  1037. ksadk/studio/static/assets/clsx-DB0hHKMi.js +1 -0
  1038. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-om8AY0Mc.js +1 -0
  1039. ksadk/studio/static/assets/createLucideIcon-DR0LGTP5.js +1 -0
  1040. ksadk/studio/static/assets/cynefin-OW5HDTMX-7tP7QfM3.js +1 -0
  1041. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-6BrmK52S.js +62 -0
  1042. ksadk/studio/static/assets/dagre-GXQ25YYZ-buZBRlwz.js +4 -0
  1043. ksadk/studio/static/assets/{diagram-S7CK7UJ4-0BZ98mya.js → diagram-S7CK7UJ4-C6aH78c4.js} +3 -3
  1044. ksadk/studio/static/assets/diagram-UQ7AKVKN-DY_tQ6C_.js +41 -0
  1045. ksadk/studio/static/assets/diagram-VSXAHHWV-DX9p5cQT.js +3 -0
  1046. ksadk/studio/static/assets/diagram-VX7I27RA-DB2WSH8X.js +24 -0
  1047. ksadk/studio/static/assets/diagram-Z3DM3KII-Ce1BJwHE.js +24 -0
  1048. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-Daukxwqf.js +1 -0
  1049. ksadk/studio/static/assets/{erDiagram-RLTQ6QDP-DLGry2Ap.js → erDiagram-RLTQ6QDP-CGthTMmJ.js} +6 -6
  1050. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-BR2FzK4R.js +1 -0
  1051. ksadk/studio/static/assets/flowDiagram-HODETNUW-CZ1tEenp.js +1 -0
  1052. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BfoAZW9X.js +292 -0
  1053. ksadk/studio/static/assets/gitGraph-4MIJSDKK-DYlXv_yJ.js +1 -0
  1054. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-S985OIJF.js +106 -0
  1055. ksadk/studio/static/assets/iconfont-4HN3C9Pg.woff2 +0 -0
  1056. ksadk/studio/static/assets/index-C7DNDik2.css +2 -0
  1057. ksadk/studio/static/assets/index-Cy68gTlH.js +265 -0
  1058. ksadk/studio/static/assets/index.dom-BQenBtFm.js +1 -0
  1059. ksadk/studio/static/assets/info-A6RAGUB7-BlU-8_xu.js +1 -0
  1060. ksadk/studio/static/assets/infoDiagram-27XIBGKW-CO3W8tFn.js +2 -0
  1061. ksadk/studio/static/assets/{ishikawaDiagram-5VMMS53U-CljI2wyf.js → ishikawaDiagram-5VMMS53U-BUGEl8cO.js} +2 -2
  1062. ksadk/studio/static/assets/{journeyDiagram-3NMN7TZE-D50Fo2sL.js → journeyDiagram-3NMN7TZE-Ch2ZYxvr.js} +6 -6
  1063. ksadk/studio/static/assets/{kanban-definition-UXKFOSKX-DimfOTam.js → kanban-definition-UXKFOSKX-Da-Fp4vC.js} +3 -3
  1064. ksadk/studio/static/assets/kingsoft-cloud-BOcLiQ3e.ico +0 -0
  1065. ksadk/studio/static/assets/{line-CX5BOOUP.js → line-BDaeq300.js} +1 -1
  1066. ksadk/studio/static/assets/linear-DmucvK78.js +1 -0
  1067. ksadk/studio/static/assets/mermaid-parser.core-Cj5mYdBi.js +4 -0
  1068. ksadk/studio/static/assets/{mindmap-definition-YA3MSWOX-Bizzqy5R.js → mindmap-definition-YA3MSWOX-CvlsVQ38.js} +1 -1
  1069. ksadk/studio/static/assets/packet-AYTQ26CC-BSJEH9Lb.js +1 -0
  1070. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-BuHuNgT5.js +1 -0
  1071. ksadk/studio/static/assets/pie-WAS4IAKB-qxv01Y8W.js +1 -0
  1072. ksadk/studio/static/assets/{pieDiagram-E7YTZNPT-B9mrFSDF.js → pieDiagram-E7YTZNPT-DlrWiSOv.js} +1 -1
  1073. ksadk/studio/static/assets/preload-helper-CO68xz6u.js +1 -0
  1074. ksadk/studio/static/assets/presentation-yYw7xK60-BmcZriri.js +1 -0
  1075. ksadk/studio/static/assets/{quadrantDiagram-AXDQQJYC-NzUfCbMR.js → quadrantDiagram-AXDQQJYC-BA3hpUZM.js} +6 -6
  1076. ksadk/studio/static/assets/radar-RG4KPBEZ-B6h6pWOs.js +1 -0
  1077. ksadk/studio/static/assets/railroad-74A4TZTK-CGtTWdGc.js +1 -0
  1078. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-Cq7y22IA.js +1 -0
  1079. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-V0aQVv9m.js +1 -0
  1080. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-BQiIsX_p.js +1 -0
  1081. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-BxpAazym.js +1 -0
  1082. ksadk/studio/static/assets/{requirementDiagram-BXWQKSXE-BF3d103U.js → requirementDiagram-BXWQKSXE-E-Ge0FcV.js} +1 -1
  1083. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-CA6YKhQ3.js +40 -0
  1084. ksadk/studio/static/assets/{sequenceDiagram-WJ2MYXX4-Dh4wZtUm.js → sequenceDiagram-WJ2MYXX4-CcElXGg4.js} +9 -9
  1085. ksadk/studio/static/assets/src-B6xuSHsQ.js +1 -0
  1086. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DdXZOFqY.js +1 -0
  1087. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-CJbOM-QK.js +1 -0
  1088. ksadk/studio/static/assets/swimlanes-42K2YHIH-NtgEEHLY.js +1 -0
  1089. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-D-AVlW8B.js +8 -0
  1090. ksadk/studio/static/assets/{timeline-definition-24CTP7MA-DxmSSjRB.js → timeline-definition-24CTP7MA-CIuYhNy3.js} +7 -7
  1091. ksadk/studio/static/assets/treeView-Q6P3EWNA-BTTYcvrF.js +1 -0
  1092. ksadk/studio/static/assets/treemap-WGGIJYW6-Cg7tyfH8.js +1 -0
  1093. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-7HbApbrv.js +34 -0
  1094. ksadk/studio/static/assets/wardley-WFR3VGLG-C6N1rULY.js +1 -0
  1095. ksadk/studio/static/assets/{wardleyDiagram-VM6X3IG4-Ba1AOWoe.js → wardleyDiagram-VM6X3IG4-CMJiaedy.js} +1 -1
  1096. ksadk/studio/static/assets/{xychartDiagram-S5SC5T6Z-Cr5pt5Y-.js → xychartDiagram-S5SC5T6Z-BdgtMvW2.js} +6 -6
  1097. ksadk/studio/static/index.html +8 -2
  1098. ksadk/studio/teams_catalog.py +166 -0
  1099. ksadk/studio/teams_installation.py +217 -0
  1100. ksadk/studio/teams_node.py +549 -0
  1101. ksadk/studio/teams_node_factory.py +558 -0
  1102. ksadk/studio/teams_node_runner.py +72 -0
  1103. ksadk/studio/teams_node_v1.py +935 -0
  1104. ksadk/studio/teams_remote.py +496 -0
  1105. ksadk/studio/templates.py +41 -19
  1106. ksadk/studio/validator.py +13 -0
  1107. ksadk/studio/workspace.py +19 -4
  1108. ksadk/studio/workspace_plugins.py +138 -0
  1109. ksadk/studio/workspace_registry.py +286 -0
  1110. ksadk/tools/a2a_policy.py +5 -0
  1111. ksadk/tools/artifact_observation.py +53 -0
  1112. ksadk/tools/captured_source_artifact.py +68 -0
  1113. ksadk/tools/schema.py +34 -0
  1114. ksadk/toolsets/__init__.py +93 -88
  1115. ksadk/toolsets/a2a.py +89 -89
  1116. ksadk/toolsets/sandbox.py +377 -6
  1117. ksadk/toolsets/skill_management.py +315 -0
  1118. ksadk/toolsets/skills.py +446 -378
  1119. ksadk/toolsets/tool_selection.py +94 -0
  1120. ksadk/toolsets/workspace.py +344 -326
  1121. ksadk/toolsets/workspace_editing.py +291 -0
  1122. ksadk/toolsets/workspace_identity.py +15 -0
  1123. ksadk/toolsets/workspace_model_observation.py +104 -0
  1124. ksadk/toolsets/workspace_mutation.py +75 -0
  1125. ksadk/toolsets/workspace_read_budget.py +216 -0
  1126. ksadk/toolsets/workspace_search.py +192 -0
  1127. ksadk/toolsets/workspace_search_process.py +129 -0
  1128. ksadk/toolsets/workspace_state.py +6 -0
  1129. ksadk/version.py +1 -1
  1130. ksadk_runtime_common/http_headers.py +18 -0
  1131. ksadk_runtime_common/memory_backend/providers/lancedb.py +56 -2
  1132. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -148
  1133. ksadk_runtime_common/workspace_files/router.py +28 -14
  1134. agentengine_sdk_python-0.8.4.dist-info/RECORD +0 -1070
  1135. ksadk/server/static/assets/MathMessageMarkdown-DbdW5A4_.js +0 -8
  1136. ksadk/server/static/assets/architecture-7GRP2DOG-BW5UtSnx.js +0 -1
  1137. ksadk/server/static/assets/channel-CF5Up3hQ.js +0 -1
  1138. ksadk/server/static/assets/chunk-2Q5K7J3B-KkXX47WI.js +0 -1
  1139. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Cz81acRQ.js +0 -1
  1140. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Cz81acRQ.js +0 -1
  1141. ksadk/server/static/assets/cynefin-OW5HDTMX-DVWs8a2t.js +0 -1
  1142. ksadk/server/static/assets/dist-B2_CVgKv.js +0 -1
  1143. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CQqR2hg3.js +0 -1
  1144. ksadk/server/static/assets/flowDiagram-A5DVABFB-DDRRbGPm.js +0 -1
  1145. ksadk/server/static/assets/gitGraph-4MIJSDKK-fgWEf7UD.js +0 -1
  1146. ksadk/server/static/assets/index-DcTML1Up.css +0 -2
  1147. ksadk/server/static/assets/index-Dh2XHqPK.js +0 -244
  1148. ksadk/server/static/assets/info-A6RAGUB7-BUecLTdt.js +0 -1
  1149. ksadk/server/static/assets/packet-AYTQ26CC-BeW-btFv.js +0 -1
  1150. ksadk/server/static/assets/pie-WAS4IAKB-X0xh4SaT.js +0 -1
  1151. ksadk/server/static/assets/radar-RG4KPBEZ-DzRMSqjd.js +0 -1
  1152. ksadk/server/static/assets/railroad-74A4TZTK-Cc44icX-.js +0 -1
  1153. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-D6S4BdV-.js +0 -1
  1154. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-vD3aVE2o.js +0 -1
  1155. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CYbW_b4T.js +0 -1
  1156. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BIcjKFhF.js +0 -1
  1157. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-tq3K3Ybl.js +0 -8
  1158. ksadk/server/static/assets/treeView-Q6P3EWNA-DBXt3GdU.js +0 -1
  1159. ksadk/server/static/assets/treemap-WGGIJYW6-DrCy4E_l.js +0 -1
  1160. ksadk/server/static/assets/wardley-WFR3VGLG-CefhOliM.js +0 -1
  1161. ksadk/studio/static/assets/CodeBlock-DCUUY0PL-BLjA7kbS.js +0 -41
  1162. ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--CUYIXwgI.js +0 -8
  1163. ksadk/studio/static/assets/MermaidBlock-DBFTztfQ-BTYKWEbD.js +0 -44
  1164. ksadk/studio/static/assets/PrismRenderer-wiXRHURw.js +0 -3
  1165. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-CLETGjKq.js +0 -1
  1166. ksadk/studio/static/assets/architecture-7GRP2DOG-hXMiO_AU.js +0 -1
  1167. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-B5EQysk6.js +0 -36
  1168. ksadk/studio/static/assets/channel-BqO-gtEw.js +0 -1
  1169. ksadk/studio/static/assets/chunk-75Z2AOVW-C8lLv_qc.js +0 -2
  1170. ksadk/studio/static/assets/chunk-F27PBJKO-Cpw14SNG.js +0 -1
  1171. ksadk/studio/static/assets/chunk-GVQU2GXP-DUdNBUCi.js +0 -1
  1172. ksadk/studio/static/assets/chunk-L3NEJ4N5-Db8Ab22W.js +0 -1
  1173. ksadk/studio/static/assets/chunk-POPQ4Y6H-DOpufJ3t.js +0 -1
  1174. ksadk/studio/static/assets/chunk-PWAF6VOD-CfLb1gSc.js +0 -1
  1175. ksadk/studio/static/assets/chunk-XXDRQBXY-7PcdR2B1.js +0 -1
  1176. ksadk/studio/static/assets/classDiagram-ZZMXUADV-D_bW8JjA.js +0 -1
  1177. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-D_bW8JjA.js +0 -1
  1178. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-snL88wkX.js +0 -1
  1179. ksadk/studio/static/assets/cynefin-OW5HDTMX-Bd1YhRo1.js +0 -1
  1180. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-BBrIG_mI.js +0 -62
  1181. ksadk/studio/static/assets/dagre-GXQ25YYZ-DtF1nGdY.js +0 -4
  1182. ksadk/studio/static/assets/diagram-UQ7AKVKN-6mLKEo6L.js +0 -41
  1183. ksadk/studio/static/assets/diagram-VSXAHHWV-CJBIaiZ2.js +0 -3
  1184. ksadk/studio/static/assets/diagram-VX7I27RA-BohLEE1C.js +0 -24
  1185. ksadk/studio/static/assets/diagram-Z3DM3KII-D8KIGonG.js +0 -24
  1186. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-C99HU61t.js +0 -1
  1187. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-B1_5Ac8j.js +0 -1
  1188. ksadk/studio/static/assets/flowDiagram-HODETNUW-DD5hmicn.js +0 -1
  1189. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BPJrVLSG.js +0 -292
  1190. ksadk/studio/static/assets/gitGraph-4MIJSDKK-Cy_ZQBGi.js +0 -1
  1191. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-CZCUz4MT.js +0 -106
  1192. ksadk/studio/static/assets/index-CeHL9ARV.css +0 -2
  1193. ksadk/studio/static/assets/index-D9QEcVpL.js +0 -320
  1194. ksadk/studio/static/assets/info-A6RAGUB7-DBzDQB_I.js +0 -1
  1195. ksadk/studio/static/assets/infoDiagram-27XIBGKW-B-sq07Hi.js +0 -2
  1196. ksadk/studio/static/assets/linear-BCxN9JLv.js +0 -1
  1197. ksadk/studio/static/assets/mermaid-parser.core-BdCz8fkS.js +0 -7
  1198. ksadk/studio/static/assets/packet-AYTQ26CC-gPln-_kG.js +0 -1
  1199. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-Dy3fB-gW.js +0 -1
  1200. ksadk/studio/static/assets/pie-WAS4IAKB-qZdHMr7B.js +0 -1
  1201. ksadk/studio/static/assets/radar-RG4KPBEZ-BZlnaea9.js +0 -1
  1202. ksadk/studio/static/assets/railroad-74A4TZTK-Ce3__H9c.js +0 -1
  1203. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-DqQn7EzD.js +0 -1
  1204. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-B55kCA8F.js +0 -1
  1205. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-DfQnvkHd.js +0 -1
  1206. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-DnhMjZCk.js +0 -1
  1207. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-Bo-JTwt0.js +0 -40
  1208. ksadk/studio/static/assets/src-SFn9St9H.js +0 -1
  1209. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DH774G6d.js +0 -1
  1210. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-DZvVWPBo.js +0 -1
  1211. ksadk/studio/static/assets/swimlanes-42K2YHIH-Bl13OvTX.js +0 -1
  1212. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-BnFOTALJ.js +0 -8
  1213. ksadk/studio/static/assets/treeView-Q6P3EWNA-D5Nn9Swz.js +0 -1
  1214. ksadk/studio/static/assets/treemap-WGGIJYW6-CgHgnQhE.js +0 -1
  1215. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-B9QEXcJq.js +0 -34
  1216. ksadk/studio/static/assets/wardley-WFR3VGLG-DXrK2RRY.js +0 -1
  1217. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/WHEEL +0 -0
  1218. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/entry_points.txt +0 -0
  1219. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/licenses/LICENSE +0 -0
  1220. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/top_level.txt +0 -0
  1221. /ksadk/studio/static/assets/{MathMessageMarkdown-CBcDrAw--BEOyPC3w.css → MathMessageMarkdown-BesSeCYl-BEOyPC3w.css} +0 -0
ksadk/studio/api.py CHANGED
@@ -4,18 +4,25 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import base64
7
+ import hashlib
7
8
  import hmac
8
9
  import json
10
+ import logging
9
11
  import os
10
12
  import secrets
13
+ import shutil
14
+ import subprocess
15
+ import sys
11
16
  from collections.abc import AsyncIterator
12
17
  from contextlib import asynccontextmanager
13
18
  from pathlib import Path
14
19
  from typing import Any, Literal
20
+ from urllib.parse import quote
15
21
 
22
+ import httpx
16
23
  from fastapi import FastAPI, File, Header, Query, Request, Response, UploadFile
17
24
  from fastapi.exceptions import RequestValidationError
18
- from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
25
+ from fastapi.responses import FileResponse, JSONResponse, RedirectResponse, StreamingResponse
19
26
  from fastapi.staticfiles import StaticFiles
20
27
  from starlette.background import BackgroundTask
21
28
 
@@ -26,13 +33,17 @@ from ksadk.conversations.contracts import (
26
33
  validate_conversation_input,
27
34
  )
28
35
  from ksadk.conversations.projector import project_conversation_item
36
+ from ksadk.conversations.runtime_payloads import extract_responses_resume_input
29
37
  from ksadk.events.canonical import parse_runtime_event_lenient
30
38
  from ksadk.scheduler.contracts import ScheduledTask
39
+ from ksadk.studio.api_a2a_routes import register_a2a_routes
31
40
  from ksadk.studio.api_catalog_routes import register_catalog_routes
32
41
  from ksadk.studio.api_contracts import (
33
42
  AgentScheduleRequest,
34
43
  AuthoringCommitRequest,
35
44
  BuildRequest,
45
+ CancelChildRequest,
46
+ ChildInputRequest,
36
47
  CloudAgentVersionRollbackRequest,
37
48
  CloudChatInteractionSubmitRequest,
38
49
  CloudChatMessageRequest,
@@ -42,12 +53,15 @@ from ksadk.studio.api_contracts import (
42
53
  CreateAgentRequest,
43
54
  ImportRootRequest,
44
55
  InteractionSubmitRequest,
56
+ LinkedDirectoryRequest,
45
57
  ProjectInspectRequest,
58
+ PromoteChildRequest,
46
59
  PromptCompileRequest,
47
60
  QuickAuthoringRequest,
48
61
  RollbackRequest,
49
62
  RunRequest,
50
63
  SessionExchangeRequest,
64
+ SteerRunRequest,
51
65
  StudioEvaluationCreate,
52
66
  ValidationRequest,
53
67
  WorkspaceOpenRequest,
@@ -79,6 +93,11 @@ from ksadk.studio.api_helpers import (
79
93
  from ksadk.studio.api_memory_routes import register_memory_routes
80
94
  from ksadk.studio.api_plugin_routes import register_plugin_routes
81
95
  from ksadk.studio.api_resource_connections import register_resource_connection_routes
96
+ from ksadk.studio.channel_connections import (
97
+ CHANNEL_ACTIONS,
98
+ ChannelAgentConnectionInput,
99
+ ChannelConnectionSettings,
100
+ )
82
101
  from ksadk.studio.cloud_shared_web import CloudSharedWebBridge, cloud_chat_target, is_cloud_agent_id
83
102
  from ksadk.studio.codex_manifest import CodexAgentManifest
84
103
  from ksadk.studio.contracts import (
@@ -90,8 +109,24 @@ from ksadk.studio.contracts import (
90
109
  OperationStatus,
91
110
  )
92
111
  from ksadk.studio.errors import StudioError
112
+ from ksadk.studio.native_documents import (
113
+ NativeDocumentActionRequest,
114
+ document_metadata,
115
+ is_local_desktop_request,
116
+ perform_document_action,
117
+ )
118
+ from ksadk.studio.run_activity import register_activity_routes
119
+ from ksadk.studio.run_documents import read_document
93
120
  from ksadk.studio.service import StudioService
94
121
  from ksadk.studio.shared_web import StudioSharedWebBridge
122
+ from ksadk.studio.workspace_registry import (
123
+ LinkedDirectoryPolicy,
124
+ WorkspaceRegistry,
125
+ WorkspaceRuntimeManager,
126
+ )
127
+ from ksadk.version import __version__ as _sdk_version
128
+
129
+ logger = logging.getLogger(__name__)
95
130
 
96
131
  _WRITE_METHODS = {"POST", "PUT", "PATCH", "DELETE"}
97
132
  _PUBLIC_API_PATHS = {
@@ -105,107 +140,38 @@ _LOCAL_HOSTS = {"127.0.0.1", "::1", "localhost", "testserver"}
105
140
  # convention. This is a narrow transport normalizer, not a provider payload
106
141
  # rewrite: only fields owned by the frozen RuntimeEvent envelope/content
107
142
  # contracts are translated before strict parsing.
108
- _RUNTIME_EVENT_WIRE_ALIASES = {
109
- "schemaVersion": "schema_version",
110
- "eventId": "event_id",
111
- "runId": "run_id",
112
- "runSeq": "run_seq",
113
- "scopeId": "scope_id",
114
- "parentScopeId": "parent_scope_id",
115
- "eventType": "event_type",
116
- "itemId": "item_id",
117
- "itemKind": "item_kind",
118
- "interactionId": "interaction_id",
119
- "interactionKind": "interaction_kind",
120
- "continuationId": "continuation_id",
121
- "resumeAttemptId": "resume_attempt_id",
122
- "outputRefs": "output_refs",
123
- "inputTokens": "input_tokens",
124
- "outputTokens": "output_tokens",
125
- "totalTokens": "total_tokens",
126
- "cachedTokens": "cached_tokens",
127
- "reasoningTokens": "reasoning_tokens",
128
- }
129
- _SOURCE_WIRE_ALIASES = {
130
- "nativeEventId": "native_event_id",
131
- "nativeCursor": "native_cursor",
132
- "nativeRunId": "native_run_id",
133
- "nativeItemId": "native_item_id",
134
- }
135
- _CONTENT_WIRE_ALIASES = {
136
- "contentType": "content_type",
137
- "partId": "part_id",
138
- "callId": "call_id",
139
- "artifactId": "artifact_id",
140
- "mimeType": "mime_type",
141
- "isError": "is_error",
142
- }
143
+ import re as _re
143
144
 
145
+ from ksadk.studio.api_cloud_chat_routes import _normalize_cloud_runtime_event_wire, _cloud_event_conversation_item, register_cloud_chat_routes
144
146
 
145
- def _normalize_cloud_runtime_event_wire(value: dict[str, Any]) -> dict[str, Any]:
146
- """Normalize only historic REST casing at the RuntimeEvent boundary."""
147
+ from ksadk.studio.api_cloud_chat_routes import _RUNTIME_EVENT_WIRE_ALIASES, _SOURCE_WIRE_ALIASES, _CONTENT_WIRE_ALIASES
147
148
 
148
- normalized = {_RUNTIME_EVENT_WIRE_ALIASES.get(key, key): item for key, item in value.items()}
149
- source = normalized.get("source")
150
- if isinstance(source, dict):
151
- normalized["source"] = {
152
- _SOURCE_WIRE_ALIASES.get(key, key): item for key, item in source.items()
153
- }
149
+ # 内容 hash 文件名(如 index-CQj_Jm9z.js)可安全 immutable 强缓存;
150
+ # index.html 与动态 HTML 仍需每次校验。
151
+ _HASHED_ASSET_RE = _re.compile(r"-[A-Za-z0-9_]{8,}\.(js|css|woff2?|ttf|png|svg|webp|mp4|wasm)$")
154
152
 
155
- def normalize_content(content: Any) -> Any:
156
- if not isinstance(content, dict):
157
- return content
158
- return {_CONTENT_WIRE_ALIASES.get(key, key): item for key, item in content.items()}
159
-
160
- normalized["update"] = normalize_content(normalized.get("update"))
161
- for key in ("initial", "snapshot"):
162
- snapshot = normalized.get(key)
163
- if not isinstance(snapshot, dict):
164
- continue
165
- parts = snapshot.get("parts")
166
- if isinstance(parts, list):
167
- normalized[key] = {
168
- **snapshot,
169
- "parts": [normalize_content(part) for part in parts],
170
- }
171
- return normalized
172
-
173
-
174
- def _cloud_event_conversation_item(
175
- event: dict[str, Any], *, session_id: str
176
- ) -> dict[str, Any] | None:
177
- """Project a complete cloud RuntimeEvent without inventing a browser item.
178
-
179
- Cloud SessionEvent history has a compatibility envelope around the runtime
180
- payload. Keep the source event untouched, but add the same typed
181
- ConversationItem that local Studio streams use whenever the nested event
182
- validates against RuntimeEvent/v2. A malformed or older envelope is still
183
- observable to diagnostics, never guessed into an actionable chat card.
184
- """
185
-
186
- payload = event.get("payload") if isinstance(event.get("payload"), dict) else event
187
- content = payload.get("content") if isinstance(payload.get("content"), dict) else {}
188
- candidates = (
189
- content.get("runtime_event"),
190
- content.get("runtimeEvent"),
191
- payload.get("runtime_event"),
192
- payload.get("runtimeEvent"),
193
- event.get("runtime_event"),
194
- event.get("runtimeEvent"),
195
- )
196
- raw_event = next((candidate for candidate in candidates if isinstance(candidate, dict)), None)
197
- if raw_event is None:
198
- return None
199
- try:
200
- runtime_event = parse_runtime_event_lenient(_normalize_cloud_runtime_event_wire(raw_event))
201
- item = project_conversation_item(
202
- runtime_event, # type: ignore[arg-type]
203
- session_id=session_id,
204
- run_id=runtime_event.run_id,
205
- )
206
- except (TypeError, ValueError):
207
- return None
208
- return item.model_dump(by_alias=True, exclude_none=True, mode="json")
153
+
154
+ def _cache_control_for(path: str, response: Any) -> str:
155
+ if path.startswith(("/api/", "/v1/")):
156
+ return "no-store"
157
+ if _HASHED_ASSET_RE.search(path) and 200 <= response.status_code < 300:
158
+ return "public, max-age=31536000, immutable"
159
+ return response.headers.get("Cache-Control", "no-cache")
160
+
161
+
162
+ _PYPI_LATEST_URL = "https://pypi.org/pypi/ksadk/json"
163
+
164
+
165
+ def _version_key(value: str) -> tuple[int, ...]:
166
+ parts = [int(piece) for piece in value.split(".") if piece.isdigit()]
167
+ return tuple(parts) or (0,)
168
+
169
+
170
+ async def _fetch_latest_ksadk_version() -> str:
171
+ async with httpx.AsyncClient(timeout=httpx.Timeout(6.0)) as client:
172
+ response = await client.get(_PYPI_LATEST_URL)
173
+ response.raise_for_status()
174
+ return str(response.json()["info"]["version"])
209
175
 
210
176
 
211
177
  def create_studio_app(
@@ -216,21 +182,114 @@ def create_studio_app(
216
182
  csrf_token: str | None = None,
217
183
  security_enabled: bool = True,
218
184
  ) -> FastAPI:
219
- studio = service or StudioService(root)
185
+ initial_service = service or StudioService(root)
186
+ studio = WorkspaceRuntimeManager(
187
+ initial_service, lambda workspace_root: StudioService(workspace_root)
188
+ )
220
189
  session_secret = session_token or secrets.token_urlsafe(32)
221
190
  csrf_secret = csrf_token or secrets.token_urlsafe(24)
191
+ session_cookie_name = "agentkit_studio_session_" + hashlib.sha256(
192
+ session_secret.encode("utf-8")
193
+ ).hexdigest()[:16]
194
+ legacy_session_cookie_name = "agentkit_studio_session"
222
195
 
223
196
  @asynccontextmanager
224
197
  async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
198
+ lazy_desktop_start = os.environ.get("KSADK_STUDIO_LAZY_START") == "1"
199
+ warmups: set[asyncio.Task[None]] = set()
200
+
201
+ def schedule_runtime_warmup(runtime: StudioService) -> None:
202
+ async def warm_runtime() -> None:
203
+ try:
204
+ await runtime.start()
205
+ except Exception:
206
+ # Runtime warmup is best effort; core Studio remains usable
207
+ # while optional DSH capability discovery is unavailable.
208
+ return
209
+ # The Channel UI is a wheel-owned client bundle. Bootstrap it
210
+ # after the listener is available and through the same Profile
211
+ # maintenance fence used by other DSH mutations.
212
+ if (
213
+ os.environ.get("KSADK_STUDIO_CHANNEL_DEFAULT", "1")
214
+ .strip()
215
+ .lower()
216
+ not in {"0", "false", "no", "off"}
217
+ and not os.environ.get("KSADK_DSH_HOME", "").strip()
218
+ and not os.environ.get("KSADK_DSH_PROFILE", "").strip()
219
+ ):
220
+ try:
221
+ from ksadk.plugins.dsh_channels import (
222
+ channel_default_bootstrap_needed,
223
+ configure_channel_profile,
224
+ )
225
+ from ksadk.studio.api_plugin_routes import _studio_dsh_options
226
+
227
+ home, profile, command, _ = _studio_dsh_options(runtime)
228
+ # 可选 bootstrap 必须先确认 DSH 命令真实可用:无工具链的
229
+ # 环境进入 Profile 维护栅栏后,恢复失败会按契约保持
230
+ # admission 关闭,导致整个会话面永久 503(回归过)。
231
+ if command and shutil.which(str(command[0])) is None:
232
+ logger.info(
233
+ "Channel 默认激活跳过:DSH 命令不可用 (%s)",
234
+ command[0],
235
+ )
236
+ elif profile == "web" and command and channel_default_bootstrap_needed(home):
237
+ async def configure_channel():
238
+ await asyncio.to_thread(
239
+ configure_channel_profile,
240
+ workspace=runtime.workspace.root,
241
+ dsh_home=home,
242
+ dsh_command=command,
243
+ )
244
+
245
+ await runtime.reconfigure_dsh_profile(configure_channel)
246
+ except Exception as error:
247
+ logger.info("Channel 默认激活未完成(可手动启用): %s", error)
248
+
249
+ if os.environ.get(
250
+ "KSADK_STUDIO_TEAMS_DEFAULT", "1"
251
+ ).strip().lower() not in {"0", "false", "no", "off"}:
252
+ installation = getattr(runtime, "teams_installation", None)
253
+ if installation is not None and not installation.status().get("enabled"):
254
+ try:
255
+ await installation.enable()
256
+ except Exception as error:
257
+ # 默认启用是预期行为,但 DSH 工具链/权威不可用时必须静默
258
+ # 降级,核心 Studio 与其他插件不受影响;页面仍保留手动入口。
259
+ logger.info(
260
+ "Teams 默认激活未完成(可手动启用): %s", error
261
+ )
262
+
263
+ task = asyncio.create_task(warm_runtime())
264
+ warmups.add(task)
265
+ task.add_done_callback(warmups.discard)
266
+
225
267
  try:
226
- await studio.start()
227
- await studio.run_service.recover_interrupted()
268
+ app.state.runtime_warmups = schedule_runtime_warmup
269
+ await studio.start(wait_for_dsh=not lazy_desktop_start)
270
+ # Optional plugin activation must not hold the HTTP listener closed
271
+ # while DSH starts subprocesses or acquires an authority lease.
272
+ schedule_runtime_warmup(studio.active)
273
+ # Pre-resolve the entry redirect choice once off the request path;
274
+ # failures are swallowed and ``index()`` has its own bounded wait.
275
+ probe_warmup = getattr(
276
+ studio.active.dsh_capabilities, "schedule_plugin_probe_warmup", None
277
+ )
278
+ if callable(probe_warmup):
279
+ probe_warmup()
280
+ await studio.run_service.recover_interrupted(studio.resolve_run_spec)
228
281
  await studio.scheduler.start_if_available()
229
282
  yield
230
283
  finally:
231
- await studio.scheduler.stop()
232
- await studio.aclose()
233
- studio.credentials.clear_session()
284
+ app.state.runtime_warmups = None
285
+ for task in tuple(warmups):
286
+ task.cancel()
287
+ if warmups:
288
+ await asyncio.gather(*warmups, return_exceptions=True)
289
+ for runtime in studio.services():
290
+ await runtime.scheduler.stop()
291
+ await runtime.aclose()
292
+ runtime.credentials.clear_session()
234
293
 
235
294
  app = FastAPI(
236
295
  title="AgentKit Local Studio",
@@ -261,14 +320,18 @@ def create_studio_app(
261
320
  collaboration_mode: str | None = None,
262
321
  goal_objective: str | None = None,
263
322
  runtime_input: Any = None,
323
+ presentation_profile: Literal["flat-v1", "agent-block-v1"] = "flat-v1",
264
324
  idempotency_key: str,
265
325
  ) -> StreamingResponse:
266
326
  """Create an observer-only SSE response for one durable Studio run."""
267
327
 
268
328
  queue: asyncio.Queue = asyncio.Queue()
329
+ from ksadk.studio.presentation import StudioConversationProjection
330
+
331
+ presentation = StudioConversationProjection(session_id, presentation_profile)
269
332
 
270
333
  def observe(event):
271
- queue.put_nowait(event)
334
+ queue.put_nowait(presentation.apply(event))
272
335
 
273
336
  # The Operation owns the runtime task. The SSE response is only one
274
337
  # observer, so refreshing or switching chats cannot cancel the Run.
@@ -285,6 +348,10 @@ def create_studio_app(
285
348
  runtime_input=runtime_input,
286
349
  idempotency_key=idempotency_key,
287
350
  on_event=observe,
351
+ **(
352
+ {"presentation_profile": presentation_profile}
353
+ if presentation_profile != "flat-v1" else {}
354
+ ),
288
355
  )
289
356
 
290
357
  async def render():
@@ -324,7 +391,8 @@ def create_studio_app(
324
391
 
325
392
  static_root = Path(__file__).with_name("static")
326
393
  shared_web = StudioSharedWebBridge(studio)
327
- cloud_web = CloudSharedWebBridge(studio.cloud)
394
+ register_activity_routes(app, studio, resolve_run_id=shared_web.resolve_run_reference)
395
+ cloud_web = CloudSharedWebBridge(studio)
328
396
  app.state.shared_web_bridge = shared_web
329
397
  app.mount("/static", StaticFiles(directory=static_root), name="studio-static")
330
398
 
@@ -379,8 +447,10 @@ def create_studio_app(
379
447
  or shared_web_api
380
448
  or responses_api
381
449
  ):
382
- supplied = request.cookies.get("agentkit_studio_session") or request.headers.get(
383
- "X-AgentKit-Session"
450
+ supplied = (
451
+ request.cookies.get(session_cookie_name)
452
+ or request.cookies.get(legacy_session_cookie_name)
453
+ or request.headers.get("X-AgentKit-Session")
384
454
  )
385
455
  if not supplied or not hmac.compare_digest(supplied, session_secret):
386
456
  return _error_response(
@@ -391,7 +461,8 @@ def create_studio_app(
391
461
  ),
392
462
  request,
393
463
  )
394
- if (studio_api or responses_api) and request.method in _WRITE_METHODS:
464
+ channel_api = shared_web_api and request.url.path.rsplit("/", 1)[-1] in CHANNEL_ACTIONS
465
+ if (studio_api or responses_api or channel_api) and request.method in _WRITE_METHODS:
395
466
  csrf = request.headers.get("X-CSRF-Token")
396
467
  if not csrf or not hmac.compare_digest(csrf, csrf_secret):
397
468
  return _error_response(
@@ -404,11 +475,7 @@ def create_studio_app(
404
475
  )
405
476
  response = await call_next(request)
406
477
  response.headers["X-Request-Id"] = request.state.request_id
407
- response.headers["Cache-Control"] = (
408
- "no-store"
409
- if request.url.path.startswith(("/api/", "/v1/"))
410
- else response.headers.get("Cache-Control", "no-cache")
411
- )
478
+ response.headers["Cache-Control"] = _cache_control_for(request.url.path, response)
412
479
  response.headers["X-Content-Type-Options"] = "nosniff"
413
480
  response.headers["X-Frame-Options"] = "DENY"
414
481
  response.headers["Referrer-Policy"] = "no-referrer"
@@ -466,18 +533,23 @@ def create_studio_app(
466
533
  )
467
534
 
468
535
  @app.get("/")
469
- async def index():
470
- path = static_root / "index.html"
471
- html = path.read_text(encoding="utf-8")
472
- # Vite filenames are content hashed and index.html is no-store. Keep
473
- # entry module URLs byte-for-byte identical to their internal imports:
474
- # adding a query only to the HTML entry makes browsers evaluate that
475
- # module again when a lazy chunk imports the unversioned URL.
476
- response = Response(content=html, media_type="text/html")
477
- response.headers["Cache-Control"] = "no-store"
536
+ @app.get("/studio-recovery/")
537
+ @app.get("/studio-shell/")
538
+ async def index(request: Request):
539
+ from ksadk.studio.entry import studio_entry_response
540
+
541
+ response = await studio_entry_response(studio, request, static_root)
478
542
  if security_enabled:
479
543
  response.set_cookie(
480
- "agentkit_studio_session",
544
+ session_cookie_name,
545
+ session_secret,
546
+ httponly=True,
547
+ samesite="strict",
548
+ secure=False,
549
+ path="/",
550
+ )
551
+ response.set_cookie(
552
+ legacy_session_cookie_name,
481
553
  session_secret,
482
554
  httponly=True,
483
555
  samesite="strict",
@@ -486,6 +558,42 @@ def create_studio_app(
486
558
  )
487
559
  return response
488
560
 
561
+ @app.get("/api/v1/plugin-ecosystems/dsh/recovery")
562
+ async def dsh_recovery_status():
563
+ # This endpoint must remain a read-only snapshot: no Core startup, Profile
564
+ # projection, credential resolution, or filesystem repair is attempted.
565
+ return studio.dsh_capabilities.startup_status
566
+
567
+ @app.get("/api/v1/plugins/workspace-contributions")
568
+ async def workspace_contributions():
569
+ """Expose enabled UI contributions without booting the DSH Core."""
570
+ from ksadk.plugins.dsh_channels import channel_workspace_contributions
571
+ from ksadk.plugins.dsh_home import studio_dsh_home
572
+
573
+ runtime = studio.active
574
+ contributions = await asyncio.to_thread(
575
+ channel_workspace_contributions,
576
+ studio_dsh_home(runtime.workspace.root),
577
+ os.environ.get("KSADK_DSH_PROFILE", "").strip() or "web",
578
+ )
579
+ # Teams remains served by its existing lifecycle endpoint; this endpoint
580
+ # only adds client-only contributions that have no domain lifecycle.
581
+ return {"items": contributions}
582
+
583
+ @app.get("/api/v1/channels/connection")
584
+ async def channel_connection_status():
585
+ return studio.channel_connections.status()
586
+
587
+ @app.put("/api/v1/channels/connection")
588
+ async def configure_channel_connection(payload: ChannelConnectionSettings):
589
+ return await studio.channel_connections.configure(payload)
590
+
591
+ @app.put("/api/v1/channels/agents/{agent_id}/connection")
592
+ async def configure_channel_agent_connection(
593
+ agent_id: str, payload: ChannelAgentConnectionInput
594
+ ):
595
+ return await studio.channel_connections.configure_agent(agent_id, payload)
596
+
489
597
  @app.get("/favicon.ico")
490
598
  async def favicon():
491
599
  return Response(status_code=204)
@@ -591,6 +699,31 @@ def create_studio_app(
591
699
  or metadata.get("invocationId")
592
700
  or f"resp_{secrets.token_hex(12)}"
593
701
  )
702
+ resume_input = extract_responses_resume_input(payload.get("input"))
703
+ if resume_input is not None:
704
+ previous_response_id = str(payload.get("previous_response_id") or "").strip()
705
+ if not previous_response_id:
706
+ raise StudioError(
707
+ "PREVIOUS_RESPONSE_REQUIRED",
708
+ "恢复审批时必须提供 previous_response_id",
709
+ status_code=422,
710
+ field="previous_response_id",
711
+ )
712
+ if bool(payload.get("stream")):
713
+ return StreamingResponse(
714
+ shared_web.stream_response_resume(
715
+ previous_response_id=previous_response_id,
716
+ response_id=response_id,
717
+ resume_input=resume_input,
718
+ ),
719
+ media_type="text/event-stream",
720
+ headers={"Cache-Control": "no-store", "X-Accel-Buffering": "no"},
721
+ )
722
+ return await shared_web.invoke_response_resume(
723
+ previous_response_id=previous_response_id,
724
+ response_id=response_id,
725
+ resume_input=resume_input,
726
+ )
594
727
  bridge_payload: dict[str, Any] = {
595
728
  "AgentId": shared_web.resolve_agent_id(agent_id),
596
729
  "SessionId": session_id or f"ses_{secrets.token_hex(12)}",
@@ -603,10 +736,9 @@ def create_studio_app(
603
736
  "ReasoningEffort": reasoning_effort,
604
737
  "ModelExplicit": bool(str(payload.get("model") or "").strip()),
605
738
  }
606
- bridge_payload["Model"] = shared_web.select_model(
607
- bridge_payload["AgentId"],
608
- bridge_payload["Model"],
609
- )
739
+ # The shared bridge validates the model after ensuring the current
740
+ # immutable Build. Do not validate here: provider-backed catalogs are
741
+ # discovered during a cold Build and may legitimately be empty now.
610
742
  if bool(payload.get("stream")):
611
743
  return StreamingResponse(
612
744
  shared_web.stream_run(bridge_payload),
@@ -617,7 +749,7 @@ def create_studio_app(
617
749
 
618
750
  @app.post("/v1/responses/{response_id}/cancel")
619
751
  async def cancel_openai_response(response_id: str):
620
- result = shared_web.cancel_run(response_id)
752
+ result = await shared_web.cancel_run(response_id)
621
753
  return {
622
754
  "id": response_id,
623
755
  "object": "response",
@@ -688,6 +820,10 @@ def create_studio_app(
688
820
  data = await cloud_web.submit_interaction(
689
821
  cloud_target, str(payload.get("SessionId") or ""), payload
690
822
  )
823
+ elif action == "CancelRun" or (
824
+ action == "RunAgent" and payload.get("Background") is True
825
+ ):
826
+ data = await cloud_web.cloud.shared_web_action(cloud_target, action, payload)
691
827
  elif action == "RunAgent":
692
828
  # Open the upstream connection before StreamingResponse
693
829
  # commits status 200, so admission failures remain a
@@ -721,7 +857,15 @@ def create_studio_app(
721
857
  )
722
858
  return {"Code": 0, "Message": "OK", "Data": data}
723
859
  if action == "GetAgentUiBootstrap":
724
- data = shared_web.bootstrap(shared_web.resolve_agent_id(requested_agent_id or None))
860
+ bootstrap_agent_id = shared_web.resolve_agent_id(
861
+ requested_agent_id or None
862
+ )
863
+ # 冷启动时 provider 模型描述符尚未发现;绑定 model:provider:*
864
+ # 的 Agent(尤其 Harness)若直接解析会 RESOURCE_NOT_FOUND,
865
+ # 前端只能无限转圈。访问资源库不应该是打开对话的前置条件。
866
+ if not bootstrap_agent_id.startswith(("ar-", "account:")):
867
+ await runtime_model_catalog()
868
+ data = shared_web.bootstrap(bootstrap_agent_id)
725
869
  elif action == "ListAgentModels":
726
870
  model_agent_id = shared_web.resolve_agent_id(requested_agent_id or None)
727
871
  # A cold Studio process has no discovered provider descriptors.
@@ -741,6 +885,12 @@ def create_studio_app(
741
885
  )
742
886
  elif action == "GetSession":
743
887
  data = await shared_web.get_session(str(payload.get("SessionId") or ""))
888
+ elif action == "GetRunReceipt":
889
+ data = shared_web.run_receipt(
890
+ shared_web.resolve_agent_id(requested_agent_id or None),
891
+ str(payload.get("SessionId") or ""),
892
+ str(payload.get("InvocationId") or ""),
893
+ )
744
894
  elif action == "CompactSession":
745
895
  data = await shared_web.compact_session(
746
896
  shared_web.resolve_agent_id(requested_agent_id or None),
@@ -771,9 +921,25 @@ def create_studio_app(
771
921
  },
772
922
  )
773
923
  elif action == "CancelRun":
774
- data = shared_web.cancel_run(str(payload.get("InvocationId") or ""))
924
+ data = await shared_web.cancel_run(str(payload.get("InvocationId") or ""))
925
+ elif action == "SteerRun":
926
+ instruction = payload.get("Text")
927
+ if (
928
+ not isinstance(instruction, str)
929
+ or not instruction.strip()
930
+ or len(instruction) > 32768
931
+ ):
932
+ raise StudioError(
933
+ "RUN_STEER_INVALID", "插话内容必须是非空文本", status_code=422
934
+ )
935
+ data = await shared_web.steer_run(
936
+ str(payload.get("InvocationId") or ""),
937
+ instruction,
938
+ delivery=payload.get("Delivery", "replace"),
939
+ )
775
940
  elif action == "SubmitInteraction":
776
941
  run_id = str(payload.get("RunId") or "")
942
+ studio._require_direct_run(run_id)
777
943
  interaction_id = str(payload.get("InteractionId") or "")
778
944
  resolved = await studio.run_service.submit_interaction(
779
945
  run_id,
@@ -810,6 +976,10 @@ def create_studio_app(
810
976
  elif action == "ListToolReceipts":
811
977
  data = {"ToolReceipts": []}
812
978
  else:
979
+ # Channel-related actions: proxy to channel backend
980
+ if action in CHANNEL_ACTIONS:
981
+ status, body = await studio.channel_connections.proxy(action, payload)
982
+ return JSONResponse(status_code=status, content=body)
813
983
  return JSONResponse(
814
984
  status_code=404,
815
985
  content={
@@ -829,6 +999,34 @@ def create_studio_app(
829
999
  },
830
1000
  )
831
1001
 
1002
+ @app.get("/agentengine/api/v1/SubscribeSessionEvents")
1003
+ async def shared_chat_subscribe_session_events(
1004
+ request: Request,
1005
+ session_id: str = Query(alias="SessionId"),
1006
+ after_seq: int = Query(default=0, ge=0),
1007
+ agent_id: str | None = Query(default=None, alias="AgentId"),
1008
+ ):
1009
+ requested_agent_id = str(
1010
+ agent_id or request.cookies.get("agentkit_studio_chat_agent") or ""
1011
+ )
1012
+ if not is_cloud_agent_id(requested_agent_id):
1013
+ raise StudioError("CLOUD_AGENT_REQUIRED", "需要云端 Agent", status_code=400)
1014
+ stream = await cloud_web.cloud.subscribe_cloud_session_events(
1015
+ cloud_chat_target(requested_agent_id), session_id=session_id, after_seq=after_seq,
1016
+ )
1017
+ async def forward():
1018
+ try:
1019
+ async for chunk in stream:
1020
+ yield chunk
1021
+ finally:
1022
+ close = getattr(stream, "aclose", None)
1023
+ if close is not None:
1024
+ await close()
1025
+ return StreamingResponse(
1026
+ forward(), media_type="text/event-stream",
1027
+ headers={"Cache-Control": "no-store", "X-Accel-Buffering": "no"},
1028
+ )
1029
+
832
1030
  @app.get("/agentengine/api/v1/SubscribeRunEvents")
833
1031
  async def shared_chat_subscribe_run_events(
834
1032
  request: Request,
@@ -882,7 +1080,15 @@ def create_studio_app(
882
1080
  status_code=401,
883
1081
  )
884
1082
  response.set_cookie(
885
- "agentkit_studio_session",
1083
+ session_cookie_name,
1084
+ session_secret,
1085
+ httponly=True,
1086
+ samesite="strict",
1087
+ secure=False,
1088
+ path="/",
1089
+ )
1090
+ response.set_cookie(
1091
+ legacy_session_cookie_name,
886
1092
  session_secret,
887
1093
  httponly=True,
888
1094
  samesite="strict",
@@ -896,18 +1102,21 @@ def create_studio_app(
896
1102
  return {
897
1103
  "serverVersion": "1.0.0",
898
1104
  "apiVersion": "v1",
1105
+ "sdkVersion": _sdk_version,
899
1106
  "sessionTokenRequired": security_enabled,
900
1107
  "csrfToken": csrf_secret,
901
1108
  "workspace": {
902
1109
  "name": studio.workspace.root.name,
903
1110
  "path": str(studio.workspace.root),
1111
+ "workspaceId": studio.workspace_record.workspace_id,
904
1112
  },
905
1113
  "operationScope": studio.deployment_operation_scope(),
1114
+ "frontend": studio.frontend_assets(),
906
1115
  "features": {
907
1116
  "build": True,
908
1117
  "run": True,
909
1118
  "runtimeRegistry": True,
910
- "runtimeTypes": ["codex", "adk", "langgraph"],
1119
+ "runtimeTypes": ["harness", "codex", "adk", "langgraph"],
911
1120
  "evaluation": True,
912
1121
  "deployment": True,
913
1122
  "cloudRebuild": False,
@@ -924,7 +1133,24 @@ def create_studio_app(
924
1133
 
925
1134
  @app.put("/api/v1/system/settings")
926
1135
  async def update_settings(payload: dict[str, Any]):
927
- return studio.update_settings(payload)
1136
+ return await studio.apply_settings(payload)
1137
+
1138
+ @app.get("/api/v1/system/update-check")
1139
+ async def update_check():
1140
+ try:
1141
+ latest = await _fetch_latest_ksadk_version()
1142
+ except Exception as exc: # noqa: BLE001 - 检查更新失败只降级展示,不进错误链路
1143
+ return {
1144
+ "currentVersion": _sdk_version,
1145
+ "latestVersion": None,
1146
+ "hasUpdate": False,
1147
+ "error": type(exc).__name__,
1148
+ }
1149
+ return {
1150
+ "currentVersion": _sdk_version,
1151
+ "latestVersion": latest,
1152
+ "hasUpdate": _version_key(latest) > _version_key(_sdk_version),
1153
+ }
928
1154
 
929
1155
  @app.get("/api/v1/schedules")
930
1156
  async def list_schedules():
@@ -1036,23 +1262,222 @@ def create_studio_app(
1036
1262
  studio.get_agent_schedule(agent_id, task_id)
1037
1263
  return {"items": studio.scheduler.list_occurrences(task_id, limit=limit)}
1038
1264
 
1265
+ def _decode_text_file(path: Path) -> str:
1266
+ """Decode with an encoding fallback chain so legacy GBK/GB18030 files
1267
+ written by agents preview correctly instead of turning into mojibake."""
1268
+ raw = path.read_bytes()
1269
+ for encoding in ("utf-8-sig", "utf-8", "gb18030"):
1270
+ try:
1271
+ return raw.decode(encoding)
1272
+ except UnicodeDecodeError:
1273
+ continue
1274
+ return raw.decode("utf-8", errors="replace")
1275
+
1276
+ @app.get("/api/v1/workspace/file")
1277
+ async def read_workspace_file(path: str = Query(...), download: bool = Query(default=False)):
1278
+ """Read one file inside the workspace (or a linked directory) for preview.
1279
+
1280
+ Absolute paths outside the workspace and its linked directories are
1281
+ rejected, as are oversized files; preview clients render the payload
1282
+ according to the returned contentType.
1283
+ """
1284
+ import mimetypes
1285
+ from urllib.parse import quote
1286
+
1287
+ raw = Path(path).expanduser()
1288
+ candidate = raw if raw.is_absolute() else studio.workspace.root / raw
1289
+ try:
1290
+ resolved = candidate.resolve()
1291
+ except OSError as error:
1292
+ raise StudioError("WORKSPACE_FILE_INVALID", "文件路径无效", status_code=422) from error
1293
+
1294
+ allowed_roots = [studio.workspace.root.resolve()]
1295
+ for item in LinkedDirectoryPolicy(studio.workspace.root).list():
1296
+ linked = Path(item.path).expanduser().resolve()
1297
+ if linked.is_dir():
1298
+ allowed_roots.append(linked)
1299
+ if not any(
1300
+ resolved == root or resolved.is_relative_to(root) for root in allowed_roots
1301
+ ):
1302
+ raise StudioError(
1303
+ "WORKSPACE_FILE_FORBIDDEN", "路径不在工作区(或链接目录)内", status_code=403
1304
+ )
1305
+ if not resolved.is_file():
1306
+ raise StudioError("WORKSPACE_FILE_NOT_FOUND", "文件不存在", status_code=404)
1307
+ size = resolved.stat().st_size
1308
+ if size > 2 * 1024 * 1024:
1309
+ raise StudioError(
1310
+ "WORKSPACE_FILE_TOO_LARGE", "文件超过 2MB 预览上限", status_code=413
1311
+ )
1312
+ suffix = resolved.suffix.lower()
1313
+ if suffix in {
1314
+ ".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp", ".ico",
1315
+ }:
1316
+ content_type = mimetypes.guess_type(resolved.name)[0] or "application/octet-stream"
1317
+ media_category = "image"
1318
+ payload: bytes | str = resolved.read_bytes()
1319
+ elif suffix in {".md", ".markdown"}:
1320
+ content_type, media_category = "text/markdown", "markdown"
1321
+ payload = _decode_text_file(resolved)
1322
+ else:
1323
+ text_types = {
1324
+ ".txt", ".json", ".csv", ".tsv", ".log", ".py", ".js", ".ts", ".tsx",
1325
+ ".jsx", ".html", ".css", ".yaml", ".yml", ".toml", ".xml", ".sh",
1326
+ ".sql", ".rs", ".go", ".java", ".c", ".cpp", ".h", ".diff", ".ini",
1327
+ }
1328
+ if suffix not in text_types:
1329
+ raise StudioError(
1330
+ "WORKSPACE_FILE_UNSUPPORTED", "该文件类型暂不支持预览", status_code=415
1331
+ )
1332
+ content_type, media_category = "text/plain", "text"
1333
+ payload = _decode_text_file(resolved)
1334
+ response = {
1335
+ "path": str(resolved),
1336
+ "name": resolved.name,
1337
+ "sizeBytes": size,
1338
+ "contentType": content_type,
1339
+ "mediaCategory": media_category,
1340
+ }
1341
+ if download:
1342
+ quoted = quote(resolved.name)
1343
+ return Response(
1344
+ content=payload if isinstance(payload, bytes) else payload.encode("utf-8"),
1345
+ media_type=content_type,
1346
+ headers={"Content-Disposition": f"attachment; filename*=UTF-8''{quoted}"},
1347
+ )
1348
+ if media_category == "image":
1349
+ import base64
1350
+
1351
+ response["dataBase64"] = base64.b64encode(payload).decode("ascii")
1352
+ else:
1353
+ response["content"] = payload
1354
+ return response
1355
+
1039
1356
  @app.post("/api/v1/workspaces:open")
1040
1357
  async def open_workspace(payload: WorkspaceOpenRequest):
1041
- # This endpoint only reconnects to the daemon's already-bound root. Do
1042
- # not resolve or otherwise touch a caller-provided filesystem path.
1043
- requested = os.path.normcase(os.path.abspath(os.path.expanduser(payload.path)))
1044
- bound_root = os.path.normcase(str(studio.workspace.root))
1045
- if requested != bound_root:
1358
+ try:
1359
+ # A user-selected directory is itself the workspace. The registry
1360
+ # entry is created as part of opening it; callers do not need to
1361
+ # pre-register paths in a separate settings screen.
1362
+ record = studio.switch(payload.path, create=True)
1363
+ # Start local state immediately, but keep optional DSH/Profile
1364
+ # discovery off the workspace-switch response path.
1365
+ runtime = studio.active
1366
+ await runtime.start(wait_for_dsh=False)
1367
+ schedule_runtime_warmup = getattr(app.state, "runtime_warmups", None)
1368
+ if schedule_runtime_warmup is not None:
1369
+ schedule_runtime_warmup(runtime)
1370
+ except FileNotFoundError as error:
1371
+ raise StudioError("WORKSPACE_NOT_FOUND", "工作区目录不存在", status_code=404) from error
1372
+ response = {
1373
+ "name": record.name,
1374
+ "path": record.path,
1375
+ "workspaceId": record.workspace_id,
1376
+ }
1377
+ # Preserve the legacy reconnect response shape for the daemon root;
1378
+ # switched workspaces include the stable identity for scoped clients.
1379
+ if os.path.normcase(record.path) == os.path.normcase(str(initial_service.workspace.root)):
1380
+ response.pop("workspaceId", None)
1381
+ return response
1382
+
1383
+ @app.post("/api/v1/workspaces:choose")
1384
+ async def choose_workspace_directory():
1385
+ """Open the host folder chooser for a local Web Studio session."""
1386
+ if sys.platform != "darwin":
1387
+ raise StudioError(
1388
+ "WORKSPACE_PICKER_UNAVAILABLE",
1389
+ "当前系统没有可用的原生目录选择器,请输入目录路径",
1390
+ status_code=501,
1391
+ )
1392
+ script = (
1393
+ 'tell application "System Events" to set selectedFolder to choose folder '
1394
+ 'with prompt "选择 AgentKit Studio 工作区"\n'
1395
+ 'POSIX path of selectedFolder'
1396
+ )
1397
+ result = await asyncio.to_thread(
1398
+ subprocess.run,
1399
+ ["osascript", "-e", script],
1400
+ capture_output=True,
1401
+ text=True,
1402
+ check=False,
1403
+ )
1404
+ if result.returncode != 0:
1405
+ return {"path": None, "cancelled": True}
1406
+ path = result.stdout.strip()
1407
+ return {"path": path or None, "cancelled": not bool(path)}
1408
+
1409
+ @app.get("/api/v1/workspaces")
1410
+ async def list_workspaces():
1411
+ active_path = os.path.normcase(str(studio.workspace.root))
1412
+ items = []
1413
+ for record in WorkspaceRegistry().list():
1414
+ item = record.__dict__.copy()
1415
+ item["active"] = os.path.normcase(record.path) == active_path
1416
+ items.append(item)
1417
+ return {"items": items}
1418
+
1419
+ @app.post("/api/v1/workspaces/{workspace_id}/linked-directories")
1420
+ async def add_linked_directory(workspace_id: str, payload: LinkedDirectoryRequest):
1421
+ record = next(
1422
+ (r for r in WorkspaceRegistry().list() if r.workspace_id == workspace_id), None
1423
+ )
1424
+ if record is None or os.path.normcase(record.path) != os.path.normcase(
1425
+ str(studio.workspace.root)
1426
+ ):
1046
1427
  raise StudioError(
1047
- "WORKSPACE_PATH_FORBIDDEN",
1048
- "当前 Daemon 不允许切换到启动 root 之外的工作区",
1049
- status_code=403,
1428
+ "WORKSPACE_NOT_FOUND", "工作区不存在或不属于当前 Studio", status_code=404
1429
+ )
1430
+ item = LinkedDirectoryPolicy(studio.workspace.root).set(
1431
+ payload.path, payload.mode, payload.label
1432
+ )
1433
+ return item.__dict__
1434
+
1435
+ @app.get("/api/v1/workspaces/{workspace_id}/linked-directories")
1436
+ async def list_linked_directories(workspace_id: str):
1437
+ record = next(
1438
+ (r for r in WorkspaceRegistry().list() if r.workspace_id == workspace_id), None
1439
+ )
1440
+ if record is None or os.path.normcase(record.path) != os.path.normcase(
1441
+ str(studio.workspace.root)
1442
+ ):
1443
+ raise StudioError(
1444
+ "WORKSPACE_NOT_FOUND", "工作区不存在或不属于当前 Studio", status_code=404
1050
1445
  )
1051
1446
  return {
1052
- "name": studio.workspace.root.name,
1053
- "path": str(studio.workspace.root),
1447
+ "items": [item.__dict__ for item in LinkedDirectoryPolicy(studio.workspace.root).list()]
1054
1448
  }
1055
1449
 
1450
+ @app.delete("/api/v1/workspaces/{workspace_id}/linked-directories")
1451
+ async def remove_linked_directory(workspace_id: str, path: str):
1452
+ record = next(
1453
+ (r for r in WorkspaceRegistry().list() if r.workspace_id == workspace_id), None
1454
+ )
1455
+ if record is None or os.path.normcase(record.path) != os.path.normcase(
1456
+ str(studio.workspace.root)
1457
+ ):
1458
+ raise StudioError(
1459
+ "WORKSPACE_NOT_FOUND", "工作区不存在或不属于当前 Studio", status_code=404
1460
+ )
1461
+ return {"removed": LinkedDirectoryPolicy(studio.workspace.root).remove(path)}
1462
+
1463
+ @app.get("/api/v1/workspaces/{workspace_id}/linked-directories/authorize")
1464
+ async def authorize_linked_directory(
1465
+ workspace_id: str,
1466
+ path: str,
1467
+ operation: Literal["read", "write"] = "read",
1468
+ ):
1469
+ record = next(
1470
+ (r for r in WorkspaceRegistry().list() if r.workspace_id == workspace_id), None
1471
+ )
1472
+ if record is None or os.path.normcase(record.path) != os.path.normcase(
1473
+ str(studio.workspace.root)
1474
+ ):
1475
+ raise StudioError(
1476
+ "WORKSPACE_NOT_FOUND", "工作区不存在或不属于当前 Studio", status_code=404
1477
+ )
1478
+ allowed = LinkedDirectoryPolicy(studio.workspace.root).authorize(path, operation)
1479
+ return {"path": path, "operation": operation, "allowed": allowed}
1480
+
1056
1481
  @app.get("/api/v1/codex/manifest")
1057
1482
  async def get_codex_manifest():
1058
1483
  return studio.codex_manifest_state()
@@ -1212,6 +1637,19 @@ def create_studio_app(
1212
1637
  display_input = "\n".join(text_parts).strip()
1213
1638
  if not display_input:
1214
1639
  display_input = "请处理本轮附件:" + "、".join(attachment_names)
1640
+ from ksadk.a2a.presentation import negotiate_presentation_profile
1641
+
1642
+ requested_profile = conversation_input.extensions.get("ksadk.presentation", {}).get(
1643
+ "profile"
1644
+ )
1645
+ presentation_profile = negotiate_presentation_profile(
1646
+ producer_declares_capability=any(
1647
+ capability.name == "agent.block" and capability.mode in {"native", "translated"}
1648
+ for capability in surface.outputs
1649
+ ),
1650
+ requested_profile=requested_profile,
1651
+ renderer_supports_agent_block=requested_profile == "agent-block-v1",
1652
+ )
1215
1653
  return _stream_studio_run(
1216
1654
  build_id,
1217
1655
  user_input=display_input,
@@ -1222,6 +1660,7 @@ def create_studio_app(
1222
1660
  approval_mode=conversation_input.approval_mode,
1223
1661
  collaboration_mode=conversation_input.collaboration_mode,
1224
1662
  goal_objective=conversation_input.goal_objective,
1663
+ presentation_profile=presentation_profile,
1225
1664
  runtime_input=runtime_parts if attachment_names else None,
1226
1665
  idempotency_key=key,
1227
1666
  )
@@ -1377,6 +1816,30 @@ def create_studio_app(
1377
1816
  async def get_agent(agent_id: str):
1378
1817
  return studio.agent_detail(agent_id)
1379
1818
 
1819
+ @app.post("/api/v1/agents/{agent_id}/runtime:prewarm", status_code=202)
1820
+ async def prewarm_agent_runtime(agent_id: str, payload: dict[str, Any]):
1821
+ """后台准备不可变 Build 的 Host,不提前绑定下一轮 Session 配置。"""
1822
+ session_id = str(payload.get("sessionId") or "")
1823
+ if not session_id:
1824
+ raise StudioError(
1825
+ "SESSION_ID_REQUIRED", "缺少 sessionId", status_code=422
1826
+ )
1827
+ try:
1828
+ build = await studio.ensure_current_build(agent_id)
1829
+ except StudioError as exc:
1830
+ raise StudioError(
1831
+ "BUILD_NOT_FOUND", f"Agent 尚无可运行的 Build:{exc.message}",
1832
+ status_code=404,
1833
+ ) from exc
1834
+
1835
+ from ksadk.studio.runtime_prewarm import prewarm_runtime_build
1836
+
1837
+ task = asyncio.create_task(prewarm_runtime_build(studio, build.id))
1838
+ app.state.runtime_prewarms = getattr(app.state, "runtime_prewarms", set())
1839
+ app.state.runtime_prewarms.add(task)
1840
+ task.add_done_callback(app.state.runtime_prewarms.discard)
1841
+ return {"status": "prewarming", "buildId": build.id}
1842
+
1380
1843
  @app.get("/api/v1/agents/{agent_id}/models")
1381
1844
  async def get_agent_models(agent_id: str):
1382
1845
  model_agent_id = shared_web.resolve_agent_id(agent_id)
@@ -1535,19 +1998,94 @@ def create_studio_app(
1535
1998
 
1536
1999
  @app.get("/api/v1/runs/{run_id}")
1537
2000
  async def get_run(run_id: str):
1538
- return studio.event_store.get(run_id)
2001
+ runtime = studio.runtime_for_run(run_id)
2002
+ if runtime is None:
2003
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2004
+ return runtime.event_store.get(run_id)
1539
2005
 
1540
2006
  @app.post("/api/v1/runs/{run_id}:cancel", status_code=202)
1541
2007
  async def cancel_run(run_id: str):
1542
- return await studio.run_service.cancel_run(run_id)
2008
+ runtime = studio.runtime_for_run(run_id)
2009
+ if runtime is None:
2010
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2011
+ runtime._require_direct_run(run_id)
2012
+ return await runtime.run_service.cancel_run(run_id)
1543
2013
 
1544
2014
  @app.post("/api/v1/runs/{run_id}:pause", status_code=202)
1545
2015
  async def pause_run(run_id: str):
1546
- return await studio.run_service.pause_run(run_id)
2016
+ runtime = studio.runtime_for_run(run_id)
2017
+ if runtime is None:
2018
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2019
+ runtime._require_direct_run(run_id)
2020
+ return await runtime.run_service.pause_run(run_id)
2021
+
2022
+ @app.post("/api/v1/runs/{run_id}:steer", status_code=202)
2023
+ async def steer_run(run_id: str, payload: SteerRunRequest):
2024
+ runtime = studio.runtime_for_run(run_id)
2025
+ if runtime is None:
2026
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2027
+ runtime._require_direct_run(run_id)
2028
+ return await runtime.run_service.steer_run(run_id, payload.text, delivery=payload.delivery)
1547
2029
 
1548
2030
  @app.post("/api/v1/runs/{run_id}:resume", status_code=202)
1549
2031
  async def resume_run(run_id: str):
1550
- return await studio.run_service.resume_run(run_id)
2032
+ runtime = studio.runtime_for_run(run_id)
2033
+ if runtime is None:
2034
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2035
+ runtime._require_direct_run(run_id)
2036
+ return await runtime.run_service.resume_run(run_id)
2037
+
2038
+ @app.get("/api/v1/runs/{run_id}/public-output/{artifact_id}")
2039
+ async def public_tool_output(run_id: str, artifact_id: str):
2040
+ from ksadk.studio.public_output_store import PublicOutputStore
2041
+
2042
+ runtime = studio.runtime_for_run(run_id)
2043
+ if runtime is None:
2044
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2045
+ runtime._require_direct_run(run_id)
2046
+ data = PublicOutputStore(runtime.workspace).read(run_id, artifact_id)
2047
+ return Response(content=data["text"], media_type="text/plain; charset=utf-8", headers={
2048
+ "Content-Disposition": 'attachment; filename="tool-output.txt"',
2049
+ "X-Content-Type-Options": "nosniff", "Cache-Control": "private, no-store",
2050
+ "X-Ksadk-Output-Truncated": str(data["truncated"]).lower(),
2051
+ })
2052
+
2053
+ @app.get("/api/v1/runs/{run_id}/children")
2054
+ async def child_tasks(run_id: str):
2055
+ runtime = studio.runtime_for_run(run_id)
2056
+ if runtime is None:
2057
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2058
+ runtime._require_direct_run(run_id)
2059
+ return await runtime.run_service.child_tasks(run_id)
2060
+
2061
+ @app.post("/api/v1/runs/{run_id}/children/{child_run_id}:cancel", status_code=202)
2062
+ async def cancel_child(run_id: str, child_run_id: str, payload: CancelChildRequest):
2063
+ runtime = studio.runtime_for_run(run_id)
2064
+ if runtime is None:
2065
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2066
+ runtime._require_direct_run(run_id)
2067
+ return await runtime.run_service.cancel_child(run_id, child_run_id,
2068
+ command_id=payload.command_id)
2069
+
2070
+ @app.post("/api/v1/runs/{run_id}/children/{child_run_id}:promote", status_code=202)
2071
+ async def promote_child(run_id: str, child_run_id: str, payload: PromoteChildRequest):
2072
+ runtime = studio.runtime_for_run(run_id)
2073
+ if runtime is None:
2074
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2075
+ runtime._require_direct_run(run_id)
2076
+ return await runtime.run_service.promote_child(run_id, child_run_id,
2077
+ command_id=payload.command_id)
2078
+
2079
+ @app.post("/api/v1/runs/{run_id}/children/{child_run_id}:send", status_code=202)
2080
+ async def send_child_input(run_id: str, child_run_id: str, payload: ChildInputRequest):
2081
+ runtime = studio.runtime_for_run(run_id)
2082
+ if runtime is None:
2083
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2084
+ runtime._require_direct_run(run_id)
2085
+ return await runtime.run_service.send_child_input(
2086
+ run_id, child_run_id, text=payload.text, command_id=payload.command_id,
2087
+ expected_goal_revision=payload.expected_goal_revision,
2088
+ )
1551
2089
 
1552
2090
  @app.post("/api/v1/runs/{run_id}/interactions/{interaction_id}:submit")
1553
2091
  async def submit_run_interaction(
@@ -1555,7 +2093,10 @@ def create_studio_app(
1555
2093
  interaction_id: str,
1556
2094
  payload: InteractionSubmitRequest,
1557
2095
  ):
1558
- return await studio.run_service.submit_interaction(
2096
+ runtime = studio.runtime_for_run(run_id)
2097
+ if runtime is None:
2098
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2099
+ return await runtime.run_service.submit_interaction(
1559
2100
  run_id,
1560
2101
  interaction_id,
1561
2102
  name=payload.name,
@@ -1567,7 +2108,10 @@ def create_studio_app(
1567
2108
  @app.get("/api/v1/runs/{run_id}/context")
1568
2109
  async def get_run_context(run_id: str):
1569
2110
  """Runtime Context Evidence:planned/projected/actual + 精度 + ownership。"""
1570
- record = studio.event_store.get(run_id)
2111
+ runtime = studio.runtime_for_run(run_id)
2112
+ if runtime is None:
2113
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2114
+ record = runtime.event_store.get(run_id)
1571
2115
  plan = record.context_plan or {}
1572
2116
  evidence = record.prompt_evidence or {}
1573
2117
  return {
@@ -1621,7 +2165,10 @@ def create_studio_app(
1621
2165
 
1622
2166
  @app.delete("/api/v1/sessions/{session_id}", status_code=204)
1623
2167
  async def delete_studio_session(session_id: str):
1624
- await studio.delete_session(session_id)
2168
+ runtime = await studio.runtime_for_session(session_id)
2169
+ if runtime is None:
2170
+ raise StudioError("SESSION_NOT_FOUND", "会话不存在", status_code=404)
2171
+ await runtime.delete_session(session_id)
1625
2172
  return Response(status_code=204)
1626
2173
 
1627
2174
  @app.get("/api/v1/sessions/{session_id}/events")
@@ -1631,7 +2178,10 @@ def create_studio_app(
1631
2178
  invocation_id: str | None = Query(default=None, alias="invocationId"),
1632
2179
  limit: int = Query(default=100, ge=1, le=500),
1633
2180
  ):
1634
- return await studio.trajectory_page(
2181
+ runtime = await studio.runtime_for_session(session_id)
2182
+ if runtime is None:
2183
+ raise StudioError("SESSION_NOT_FOUND", "会话不存在", status_code=404)
2184
+ return await runtime.trajectory_page(
1635
2185
  session_id,
1636
2186
  before_seq_id=before_seq_id,
1637
2187
  invocation_id=invocation_id,
@@ -1645,10 +2195,13 @@ def create_studio_app(
1645
2195
  after_seq_id: int = Query(default=0, ge=0, alias="afterSeqId"),
1646
2196
  invocation_id: str | None = Query(default=None, alias="invocationId"),
1647
2197
  ):
1648
- await studio._require_runtime_session(session_id)
2198
+ runtime = await studio.runtime_for_session(session_id)
2199
+ if runtime is None:
2200
+ raise StudioError("SESSION_NOT_FOUND", "会话不存在", status_code=404)
2201
+ await runtime._require_runtime_session(session_id)
1649
2202
  last = request.headers.get("Last-Event-ID")
1650
2203
  cursor = int(last) if last and last.isdigit() else after_seq_id
1651
- stream = studio.stream_trajectory(
2204
+ stream = runtime.stream_trajectory(
1652
2205
  session_id,
1653
2206
  cursor,
1654
2207
  invocation_id=invocation_id,
@@ -1719,15 +2272,61 @@ def create_studio_app(
1719
2272
  async def list_runs(session_id: str | None = Query(default=None, alias="sessionId")):
1720
2273
  return {"items": studio.event_store.list_runs(session_id=session_id)}
1721
2274
 
2275
+ @app.get("/api/v1/workspaces/runs")
2276
+ async def list_workspace_runs():
2277
+ """后台入口:聚合所有已打开 workspace 的运行,并保留归属。"""
2278
+ return {"items": studio.all_runs()}
2279
+
2280
+ @app.get("/api/v1/workspaces/operations")
2281
+ async def list_workspace_operations():
2282
+ return {"items": studio.all_operations()}
2283
+
2284
+ @app.get("/api/v1/runs/{run_id}/documents/metadata")
2285
+ def run_document_metadata(run_id: str, path: str, request: Request):
2286
+ return document_metadata(studio, run_id, path, local=is_local_desktop_request(request))
2287
+
2288
+ @app.post("/api/v1/runs/{run_id}/documents/actions")
2289
+ def run_document_action(run_id: str, payload: NativeDocumentActionRequest, request: Request):
2290
+ return perform_document_action(
2291
+ studio, run_id, payload, local=is_local_desktop_request(request)
2292
+ )
2293
+
2294
+ @app.get("/api/v1/runs/{run_id}/documents/content")
2295
+ def run_document(run_id: str, path: str, preview: bool = False):
2296
+ file_path, content = read_document(studio, run_id, path)
2297
+ if preview:
2298
+ return JSONResponse(
2299
+ {"name": file_path.name, "content": content},
2300
+ headers={"Cache-Control": "no-store"},
2301
+ )
2302
+ return Response(
2303
+ content,
2304
+ media_type="text/markdown",
2305
+ headers={
2306
+ "Content-Disposition": "attachment; filename*=UTF-8''"
2307
+ + quote(file_path.name),
2308
+ "X-Content-Type-Options": "nosniff",
2309
+ "Cache-Control": "no-store",
2310
+ },
2311
+ )
2312
+
1722
2313
  @app.get("/api/v1/runs/{run_id}/events")
1723
2314
  async def run_events(
1724
2315
  run_id: str,
1725
2316
  request: Request,
1726
2317
  after: int = Query(default=0, ge=0),
2318
+ presentation_profile: Literal["flat-v1", "agent-block-v1"] | None = Query(
2319
+ default=None, alias="presentationProfile"
2320
+ ),
1727
2321
  ):
1728
2322
  last = request.headers.get("Last-Event-ID")
1729
2323
  cursor = int(last) if last and last.isdigit() else after
1730
- events = await studio.run_service.events(run_id, after=cursor)
2324
+ runtime = studio.runtime_for_run(run_id)
2325
+ if runtime is None:
2326
+ raise StudioError("RUN_NOT_FOUND", "运行不存在", status_code=404)
2327
+ events = await runtime.run_service.events(
2328
+ run_id, after=cursor, presentation_profile=presentation_profile
2329
+ )
1731
2330
  return _sse(events)
1732
2331
 
1733
2332
  @app.get("/api/v1/traces/overview")
@@ -1742,6 +2341,10 @@ def create_studio_app(
1742
2341
  status=status,
1743
2342
  )
1744
2343
 
2344
+ @app.get("/api/v1/workspaces/traces")
2345
+ async def list_workspace_traces():
2346
+ return {"items": studio.all_traces()}
2347
+
1745
2348
  @app.get("/api/v1/traces")
1746
2349
  async def list_traces(
1747
2350
  agent_id: str | None = Query(default=None, alias="agentId"),
@@ -1911,266 +2514,6 @@ def create_studio_app(
1911
2514
 
1912
2515
  return await studio.cloud.delete(deployment_id)
1913
2516
 
1914
- @app.get("/api/v1/deployments/{deployment_id}/cloud-chat/sessions")
1915
- async def list_cloud_chat_sessions(
1916
- deployment_id: str,
1917
- page: int = Query(default=1, ge=1),
1918
- size: int = Query(default=50, ge=1, le=100),
1919
- ):
1920
- """List Server-owned sessions for this local deployment receipt only."""
1921
-
1922
- return await studio.cloud.list_cloud_chat_sessions(deployment_id, page=page, size=size)
1923
-
1924
- @app.get("/api/v1/deployments/{deployment_id}/cloud-chat/models")
1925
- async def list_cloud_chat_models(deployment_id: str):
1926
- """List models through Studio's signed Server client."""
1927
-
1928
- return await studio.cloud.list_cloud_chat_models(deployment_id)
1929
-
1930
- @app.post(
1931
- "/api/v1/deployments/{deployment_id}/cloud-chat/sessions",
1932
- status_code=201,
1933
- )
1934
- async def create_cloud_chat_session(deployment_id: str):
1935
- """Create a cloud session via loopback-held AK/SK; no secret reaches JS."""
1936
-
1937
- return await studio.cloud.create_cloud_chat_session(deployment_id)
1938
-
1939
- @app.get("/api/v1/deployments/{deployment_id}/cloud-chat/sessions/{session_id}/messages")
1940
- async def list_cloud_chat_messages(
1941
- deployment_id: str,
1942
- session_id: str,
1943
- after_seq_id: int | None = Query(default=None, alias="afterSeqId", ge=0),
1944
- limit: int = Query(default=100, ge=1, le=200),
1945
- ):
1946
- return await studio.cloud.list_cloud_chat_messages(
1947
- deployment_id,
1948
- session_id=session_id,
1949
- after_seq_id=after_seq_id,
1950
- limit=limit,
1951
- )
1952
-
1953
- @app.get("/api/v1/deployments/{deployment_id}/cloud-chat/sessions/{session_id}/events")
1954
- async def list_cloud_chat_events(
1955
- deployment_id: str,
1956
- session_id: str,
1957
- after_seq_id: int | None = Query(default=None, alias="afterSeqId", ge=0),
1958
- offset: int | None = Query(default=None, ge=0),
1959
- limit: int = Query(default=200, ge=1, le=1000),
1960
- ):
1961
- return await studio.cloud.list_cloud_chat_events(
1962
- deployment_id,
1963
- session_id=session_id,
1964
- after_seq_id=after_seq_id,
1965
- offset=offset,
1966
- limit=limit,
1967
- )
1968
-
1969
- @app.get("/api/v1/deployments/{deployment_id}/cloud-chat/sessions/{session_id}/events/stream")
1970
- async def stream_cloud_chat_events(
1971
- request: Request,
1972
- deployment_id: str,
1973
- session_id: str,
1974
- after_seq_id: int = Query(default=0, alias="afterSeqId", ge=0),
1975
- ):
1976
- """Stream canonical cloud events to the loopback browser.
1977
-
1978
- The public cloud control plane currently exposes cursor reads for this
1979
- surface. Keep that cursor in the Studio backend and present one SSE
1980
- response to the browser, so assistant deltas arrive before the durable
1981
- terminal message projection without exposing cloud credentials to JS.
1982
- """
1983
-
1984
- async def event_stream() -> AsyncIterator[str]:
1985
- cursor = after_seq_id
1986
- idle_polls = 0
1987
- while not await request.is_disconnected():
1988
- payload = await studio.cloud.list_cloud_chat_events(
1989
- deployment_id,
1990
- session_id=session_id,
1991
- after_seq_id=cursor,
1992
- limit=200,
1993
- )
1994
- events = payload.get("events") or []
1995
- if not isinstance(events, list):
1996
- events = []
1997
- terminal = False
1998
- emitted = False
1999
- for event in events:
2000
- if not isinstance(event, dict):
2001
- continue
2002
- event_payload = (
2003
- event.get("payload") if isinstance(event.get("payload"), dict) else event
2004
- )
2005
- seq = int(
2006
- event_payload.get("seq")
2007
- or event_payload.get("seq_id")
2008
- or event_payload.get("source_session_seq")
2009
- or event.get("seq")
2010
- or event.get("seq_id")
2011
- or 0
2012
- )
2013
- if seq and seq <= cursor:
2014
- continue
2015
- if seq:
2016
- cursor = max(cursor, seq)
2017
- event_type = str(
2018
- event.get("event_type")
2019
- or event.get("eventType")
2020
- or event_payload.get("event_type")
2021
- or event_payload.get("eventType")
2022
- or ""
2023
- ).lower()
2024
- content = (
2025
- event_payload.get("content")
2026
- if isinstance(event_payload.get("content"), dict)
2027
- else {}
2028
- )
2029
- status = str(event_payload.get("status") or content.get("status") or "").lower()
2030
- event_is_terminal = event_type in {
2031
- "run.completed",
2032
- "run.complete",
2033
- "run.succeeded",
2034
- "run.failed",
2035
- "run.cancelled",
2036
- "run.expired",
2037
- "run.error",
2038
- } or (
2039
- event_type in {"run_status", "run.status"}
2040
- and status
2041
- in {
2042
- "completed",
2043
- "complete",
2044
- "succeeded",
2045
- "success",
2046
- "failed",
2047
- "cancelled",
2048
- "canceled",
2049
- "expired",
2050
- "error",
2051
- "aborted",
2052
- }
2053
- )
2054
- terminal = terminal or event_is_terminal
2055
- emitted = True
2056
- projected_event = dict(event)
2057
- conversation_item = _cloud_event_conversation_item(
2058
- event,
2059
- session_id=session_id,
2060
- )
2061
- if conversation_item is not None:
2062
- projected_event["conversationItem"] = conversation_item
2063
- yield (
2064
- (f"id: {seq}\n" if seq else "")
2065
- + "event: session.event\n"
2066
- + f"data: {json.dumps(projected_event, ensure_ascii=False)}\n\n"
2067
- )
2068
- if terminal or payload.get("session_deleted"):
2069
- break
2070
- idle_polls = 0 if emitted else idle_polls + 1
2071
- if idle_polls and idle_polls % 20 == 0:
2072
- yield ": keepalive\n\n"
2073
- await asyncio.sleep(0.25)
2074
-
2075
- return StreamingResponse(
2076
- event_stream(),
2077
- media_type="text/event-stream",
2078
- headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"},
2079
- )
2080
-
2081
- @app.delete(
2082
- "/api/v1/deployments/{deployment_id}/cloud-chat/sessions/{session_id}",
2083
- status_code=204,
2084
- )
2085
- async def delete_cloud_chat_session(deployment_id: str, session_id: str):
2086
- await studio.cloud.delete_cloud_chat_session(deployment_id, session_id=session_id)
2087
- return Response(status_code=204)
2088
-
2089
- @app.post(
2090
- "/api/v1/deployments/{deployment_id}/cloud-chat/sessions/{session_id}/messages",
2091
- status_code=202,
2092
- )
2093
- async def send_cloud_chat_message(
2094
- deployment_id: str,
2095
- session_id: str,
2096
- payload: CloudChatMessageRequest,
2097
- ):
2098
- """Admit one cloud message through Server; response is a durable receipt."""
2099
-
2100
- return await studio.cloud.send_cloud_chat_message(
2101
- deployment_id,
2102
- session_id=session_id,
2103
- content=payload.content,
2104
- model=payload.model,
2105
- model_options=payload.model_options,
2106
- tool_approval_mode=payload.tool_approval_mode,
2107
- collaboration_mode=payload.collaboration_mode,
2108
- goal_objective=payload.goal_objective,
2109
- )
2110
-
2111
- @app.post(
2112
- "/api/v1/deployments/{deployment_id}/cloud-chat/sessions/{session_id}/messages/stream"
2113
- )
2114
- async def stream_cloud_chat_message(
2115
- request: Request,
2116
- deployment_id: str,
2117
- session_id: str,
2118
- payload: CloudChatMessageRequest,
2119
- ):
2120
- """Proxy one signed foreground RunAgent SSE response to loopback UI."""
2121
-
2122
- upstream = await studio.cloud.stream_cloud_chat_message(
2123
- deployment_id,
2124
- session_id=session_id,
2125
- content=payload.content,
2126
- model=payload.model,
2127
- model_options=payload.model_options,
2128
- tool_approval_mode=payload.tool_approval_mode,
2129
- collaboration_mode=payload.collaboration_mode,
2130
- goal_objective=payload.goal_objective,
2131
- )
2132
-
2133
- async def proxy_stream() -> AsyncIterator[bytes]:
2134
- try:
2135
- while not await request.is_disconnected():
2136
- try:
2137
- chunk = await anext(upstream)
2138
- except StopAsyncIteration:
2139
- break
2140
- if await request.is_disconnected():
2141
- break
2142
- yield chunk
2143
- finally:
2144
- close = getattr(upstream, "aclose", None)
2145
- if close is not None:
2146
- await close()
2147
-
2148
- return StreamingResponse(
2149
- proxy_stream(),
2150
- media_type="text/event-stream",
2151
- headers={"Cache-Control": "no-store", "X-Accel-Buffering": "no"},
2152
- )
2153
-
2154
- @app.post(
2155
- "/api/v1/deployments/{deployment_id}/cloud-chat/sessions/{session_id}/interactions",
2156
- status_code=202,
2157
- )
2158
- async def submit_cloud_chat_interaction(
2159
- deployment_id: str,
2160
- session_id: str,
2161
- payload: CloudChatInteractionSubmitRequest,
2162
- ):
2163
- return await studio.cloud.submit_cloud_chat_interaction(
2164
- deployment_id,
2165
- session_id=session_id,
2166
- run_id=payload.run_id,
2167
- interaction_id=payload.interaction_id,
2168
- expected_revision=payload.expected_revision,
2169
- action=payload.action,
2170
- response=payload.response,
2171
- idempotency_key=payload.idempotency_key,
2172
- )
2173
-
2174
2517
  @app.post("/api/v1/deployments/{deployment_id}:rollback", status_code=202)
2175
2518
  async def rollback_deployment(
2176
2519
  deployment_id: str,
@@ -2185,11 +2528,17 @@ def create_studio_app(
2185
2528
 
2186
2529
  @app.get("/api/v1/operations/{operation_id}")
2187
2530
  async def get_operation(operation_id: str):
2188
- return studio.operations.get(operation_id)
2531
+ runtime = studio.runtime_for_operation(operation_id)
2532
+ if runtime is None:
2533
+ raise StudioError("OPERATION_NOT_FOUND", "操作不存在", status_code=404)
2534
+ return runtime.operations.get(operation_id)
2189
2535
 
2190
2536
  @app.post("/api/v1/operations/{operation_id}:cancel")
2191
2537
  async def cancel_operation(operation_id: str):
2192
- return studio.operations.cancel(operation_id)
2538
+ runtime = studio.runtime_for_operation(operation_id)
2539
+ if runtime is None:
2540
+ raise StudioError("OPERATION_NOT_FOUND", "操作不存在", status_code=404)
2541
+ return runtime.operations.cancel(operation_id)
2193
2542
 
2194
2543
  @app.get("/api/v1/operations/{operation_id}/events")
2195
2544
  async def operation_events(
@@ -2199,7 +2548,10 @@ def create_studio_app(
2199
2548
  ):
2200
2549
  last = request.headers.get("Last-Event-ID")
2201
2550
  cursor = int(last) if last and last.isdigit() else after
2202
- events = studio.operations.events(operation_id, after=cursor)
2551
+ runtime = studio.runtime_for_operation(operation_id)
2552
+ if runtime is None:
2553
+ raise StudioError("OPERATION_NOT_FOUND", "操作不存在", status_code=404)
2554
+ events = runtime.operations.events(operation_id, after=cursor)
2203
2555
  if "application/json" in request.headers.get("Accept", ""):
2204
2556
  return {"items": events}
2205
2557
  return _sse(events)
@@ -2209,14 +2561,27 @@ def create_studio_app(
2209
2561
  studio,
2210
2562
  runtime_model_catalog=runtime_model_catalog,
2211
2563
  )
2564
+ register_cloud_chat_routes(app, studio)
2565
+ register_a2a_routes(app, studio)
2212
2566
  register_memory_routes(app, studio)
2213
2567
  register_resource_connection_routes(app, studio)
2214
2568
  register_plugin_routes(app, studio)
2569
+ async def workspace_plugin_api(scope, receive, send):
2570
+ # The plugin registry belongs to the active workspace. Mounting the
2571
+ # initial service registry directly would keep lifecycle/routes pinned
2572
+ # to the first folder after a workspace switch.
2573
+ await studio.active.workspace_plugins.api(scope, receive, send)
2574
+
2575
+ app.mount("/api/v1", workspace_plugin_api, name="workspace-plugin-api")
2215
2576
 
2216
2577
  from ksadk.studio.dsh_application import register_dsh_application
2217
2578
 
2218
2579
  register_dsh_application(
2219
- app, studio, session_secret=session_secret, security_enabled=security_enabled
2580
+ app,
2581
+ studio,
2582
+ session_secret=session_secret,
2583
+ security_enabled=security_enabled,
2584
+ fallback_url="/studio-shell/",
2220
2585
  )
2221
2586
 
2222
2587
  return app