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
@@ -4,7 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import json
7
- from collections.abc import Mapping, Sequence
7
+ import os
8
+ from collections.abc import Callable, Mapping, Sequence
8
9
  from dataclasses import dataclass
9
10
  from pathlib import Path
10
11
  from typing import Any, cast
@@ -29,6 +30,8 @@ from ksadk.plugins.providers.dsh_mcp import (
29
30
  dsh_profile_mcp_manifest,
30
31
  )
31
32
  from ksadk.plugins.providers.harness import (
33
+ HarnessEngineSelector,
34
+ HarnessNativeAdapterBuilder,
32
35
  HarnessTurnResult,
33
36
  KsADKHarnessProviderFactory,
34
37
  )
@@ -60,13 +63,67 @@ from ksadk.studio.contracts import (
60
63
  )
61
64
  from ksadk.studio.errors import StudioError
62
65
  from ksadk.studio.model_client import OpenAICompatibleModelClient
66
+ from ksadk.studio.native_context_registration import StudioNativeContextRegistration
67
+ from ksadk.studio.native_hook_registration import StudioNativeHookRegistration
63
68
  from ksadk.studio.plugin_kernel_adapter import StudioPluginKernelAdapter
69
+ from ksadk.studio.plugin_native_activation import StudioNativeActivationMixin, _NativeActivation
70
+ from ksadk.studio.plugin_runtime_admission import RuntimeAdmissionGate
64
71
  from ksadk.studio.repository import BuildRepository
65
72
  from ksadk.studio.run_service import StudioRunSpec
66
73
  from ksadk.studio.workspace import Workspace
67
74
  from ksadk.tools.gateway import normalize_tool_approval_mode
68
75
 
69
76
  _COMPOSED_RUNTIME_TYPES = frozenset({"harness", "plugin"})
77
+ _DEFAULT_REASONING_ONLY_ACTION_BUDGET_CHARS = 8_192
78
+
79
+
80
+ def _model_request_timeout_seconds(execution: Mapping[str, Any]) -> int:
81
+ """Cap a stalled provider request independently from the complete run budget."""
82
+
83
+ run_timeout = int(
84
+ execution.get("timeoutSeconds") or execution.get("timeout_seconds") or 300
85
+ )
86
+ raw_idle_timeout = os.getenv("KSADK_MODEL_REQUEST_IDLE_TIMEOUT_SECONDS")
87
+ default_idle_timeout = min(180, max(60, run_timeout // 10))
88
+ try:
89
+ idle_timeout = (
90
+ int(raw_idle_timeout)
91
+ if raw_idle_timeout is not None
92
+ else default_idle_timeout
93
+ )
94
+ except (TypeError, ValueError):
95
+ idle_timeout = default_idle_timeout
96
+ return max(1, min(run_timeout, max(1, idle_timeout)))
97
+
98
+
99
+ def _model_total_timeout_seconds(execution: Mapping[str, Any]) -> int:
100
+ """整个 run 的模型预算,用作增量传输的硬上限。
101
+
102
+ ``_model_request_timeout_seconds`` 是"无进度"超时(可能只有 60s);增量流在
103
+ 持续吐字时不受它约束,所以还需要一个上限,防止一条只发 keepalive 的流把
104
+ 整个 run 拖死。
105
+ """
106
+
107
+ return max(1, int(execution.get("timeoutSeconds") or execution.get("timeout_seconds") or 300))
108
+
109
+
110
+ def _reasoning_only_action_budget_chars() -> int:
111
+ """Bound a tool-capable turn that produces reasoning but no action.
112
+
113
+ The threshold is deliberately semantic rather than a socket timeout: a
114
+ provider can keep the TCP stream healthy for minutes while emitting only
115
+ reasoning. The 8 KiB default is roughly 2K tokens and is comfortably
116
+ above the 143 reasoning tokens observed before a successful Pi tool call,
117
+ while stopping the 20K-chunk GLM failure long before the one-hour run
118
+ deadline.
119
+ """
120
+
121
+ raw = os.getenv("KSADK_REASONING_ONLY_ACTION_BUDGET_CHARS")
122
+ try:
123
+ value = int(raw) if raw is not None else _DEFAULT_REASONING_ONLY_ACTION_BUDGET_CHARS
124
+ except (TypeError, ValueError):
125
+ value = _DEFAULT_REASONING_ONLY_ACTION_BUDGET_CHARS
126
+ return max(1_024, min(value, 65_536))
70
127
 
71
128
 
72
129
  @dataclass(frozen=True)
@@ -87,6 +144,22 @@ class _HostEntry:
87
144
  host: PluginHost
88
145
 
89
146
 
147
+
148
+
149
+ def _parse_tool_arguments(raw: str | None) -> dict[str, Any] | None:
150
+ """解析模型给出的工具参数;非 JSON 对象一律返回 None(不抛错)。
151
+
152
+ 返回 None 表示"参数形状不可用":调用方要么修复一次,要么把它作为
153
+ invalid_arguments 回灌给模型,绝不允许升级成整轮致命错误。
154
+ """
155
+
156
+ try:
157
+ arguments = json.loads(raw or "{}")
158
+ except json.JSONDecodeError:
159
+ return None
160
+ return arguments if isinstance(arguments, dict) else None
161
+
162
+
90
163
  class _StudioHarnessReasoner:
91
164
  """Bind the Harness loop to the immutable Studio model/network policy."""
92
165
 
@@ -95,17 +168,62 @@ class _StudioHarnessReasoner:
95
168
  client: OpenAICompatibleModelClient,
96
169
  *,
97
170
  model: ResolvedModel,
171
+ fallback_models: Sequence[ResolvedModel] = (),
98
172
  network_policy: NetworkPolicy,
99
173
  timeout_seconds: int,
100
174
  max_attempts: int,
101
175
  backoff_seconds: float,
176
+ total_timeout_seconds: int | None = None,
102
177
  ) -> None:
103
178
  self._client = client
104
179
  self._model = model
180
+ self._models = {
181
+ item.model: item for item in (model, *tuple(fallback_models))
182
+ }
105
183
  self._network_policy = network_policy
106
184
  self._timeout_seconds = timeout_seconds
107
185
  self._max_attempts = max_attempts
108
186
  self._backoff_seconds = backoff_seconds
187
+ # 整个 run 的预算:增量传输的硬上限(防止"一直吐 keepalive"的流永不结束)。
188
+ self._total_timeout_seconds = max(
189
+ timeout_seconds, int(total_timeout_seconds or timeout_seconds)
190
+ )
191
+ # 传输模式来自"端点声明"(见 ksadk/model_proxy/compat.py),不是代码里的
192
+ # 模型名分支:默认流式;只有真正不支持增量的端点才声明
193
+ # prefer_buffered_transport。曾经的 kspmas 档整条走缓冲,代价是一次
194
+ # 模型调用从发出到返回之间前端没有任何可显示内容("像卡住")。
195
+ from ksadk.model_proxy import compat as provider_compat
196
+
197
+ self._streaming = not provider_compat.prefer_buffered_transport(
198
+ base_url=self._model.endpoint_url,
199
+ model=self._model.model,
200
+ )
201
+ if hasattr(self._client, "supports_streaming"):
202
+ self._streaming = self._client.supports_streaming(
203
+ self._model, requested=self._streaming
204
+ )
205
+ # "空闲进度"超时:连续这么久没有**内容** chunk 才算卡住(keepalive 不算),
206
+ # 所以慢但持续吐字的回合不会被误杀。
207
+ self._stream_idle_timeout_seconds = max(
208
+ 0.001,
209
+ float(
210
+ provider_compat.stream_idle_timeout(
211
+ base_url=self._model.endpoint_url,
212
+ model=self._model.model,
213
+ fallback=timeout_seconds,
214
+ )
215
+ or timeout_seconds
216
+ ),
217
+ )
218
+
219
+ def _require_model(self, model: str) -> ResolvedModel:
220
+ try:
221
+ return self._models[model]
222
+ except KeyError as error:
223
+ raise PluginHostError(
224
+ "harness_model_not_bound",
225
+ f"Harness requested unbound model {model!r}",
226
+ ) from error
109
227
 
110
228
  async def complete(
111
229
  self,
@@ -114,15 +232,13 @@ class _StudioHarnessReasoner:
114
232
  prompt: str,
115
233
  messages: Sequence[dict[str, Any]],
116
234
  tools: Sequence[Any],
235
+ max_output_tokens: int | None = None,
236
+ reasoning_effort: str | None = None,
117
237
  ) -> HarnessReasoningTurn:
118
238
  del prompt
119
- if model != self._model.model:
120
- raise PluginHostError(
121
- "harness_model_not_bound",
122
- f"Harness requested unbound model {model!r}",
123
- )
239
+ selected_model = self._require_model(model)
124
240
  response = await self._client.complete(
125
- self._model,
241
+ selected_model,
126
242
  messages=[dict(message) for message in messages],
127
243
  network_policy=self._network_policy,
128
244
  timeout_seconds=self._timeout_seconds,
@@ -130,35 +246,552 @@ class _StudioHarnessReasoner:
130
246
  backoff_seconds=self._backoff_seconds,
131
247
  tools=[dict(tool.openai_schema) for tool in tools],
132
248
  allow_empty=bool(tools),
249
+ max_output_tokens=max_output_tokens,
250
+ reasoning_effort=reasoning_effort,
251
+ # 触顶一次性升级(对齐 Claude Code 的 max_output_tokens_escalate):
252
+ # 平时给 slot 友好的小预算,真被截断才扩容重试一次。
253
+ retry_on_length=True,
133
254
  )
134
255
  calls: list[HarnessToolCall] = []
135
- for call in response.tool_calls:
136
- try:
137
- arguments = json.loads(call.arguments or "{}")
138
- except json.JSONDecodeError as error:
139
- raise PluginHostError(
140
- "harness_tool_arguments_invalid",
141
- f"model emitted invalid arguments for tool {call.name!r}",
142
- ) from error
143
- if not isinstance(arguments, dict):
144
- raise PluginHostError(
145
- "harness_tool_arguments_invalid",
146
- f"model emitted non-object arguments for tool {call.name!r}",
147
- )
148
- calls.append(
149
- HarnessToolCall(
150
- call_id=call.id,
151
- name=call.name,
152
- arguments=arguments,
256
+ invalid_names: list[str] = []
257
+
258
+ def _collect(source_calls: Sequence[Any]) -> list[HarnessToolCall]:
259
+ collected: list[HarnessToolCall] = []
260
+ for call in source_calls:
261
+ arguments = _parse_tool_arguments(call.arguments)
262
+ if arguments is None:
263
+ invalid_names.append(call.name)
264
+ collected.append(
265
+ HarnessToolCall(
266
+ call_id=call.id,
267
+ name=call.name,
268
+ arguments={},
269
+ invalid_reason="model emitted non-JSON-object tool arguments",
270
+ )
271
+ )
272
+ continue
273
+ collected.append(
274
+ HarnessToolCall(call_id=call.id, name=call.name, arguments=arguments)
153
275
  )
276
+ return collected
277
+
278
+ calls = _collect(response.tool_calls)
279
+ if any(call.invalid_reason for call in calls):
280
+ # 与流式路径同策略:先给一次修复(更大预算 + 明确要求合法 JSON),
281
+ # 修复仍不可用则保留 invalid_reason,由循环层以 invalid_arguments 的
282
+ # tool result 回灌给模型重试——参数形状问题不中断整轮。
283
+ repair = await self._client.complete(
284
+ selected_model,
285
+ messages=[
286
+ *[dict(message) for message in messages],
287
+ {
288
+ "role": "system",
289
+ "content": (
290
+ "The previous tool call could not be parsed. "
291
+ f"Retry the intended {invalid_names[0]} call once with valid "
292
+ "JSON arguments. Keep the arguments concise enough to fit in "
293
+ "one tool call and do not repeat the analysis."
294
+ ),
295
+ },
296
+ ],
297
+ network_policy=self._network_policy,
298
+ timeout_seconds=self._timeout_seconds,
299
+ max_attempts=self._max_attempts,
300
+ backoff_seconds=self._backoff_seconds,
301
+ tools=[dict(tool.openai_schema) for tool in tools],
302
+ allow_empty=bool(tools),
303
+ retry_on_length=True,
304
+ max_output_tokens=max(
305
+ 16_384,
306
+ int(max_output_tokens or selected_model.parameters.max_tokens or 0),
307
+ ),
308
+ reasoning_effort=reasoning_effort,
154
309
  )
310
+ repaired = _collect(repair.tool_calls)
311
+ if any(not call.invalid_reason for call in repaired):
312
+ calls = repaired
313
+ reported_usage = response.usage if response.usage.reported else None
155
314
  return HarnessReasoningTurn(
156
315
  final_text=response.content or None,
157
316
  tool_calls=tuple(calls),
317
+ reasoning=response.reasoning or None,
318
+ degraded=(
319
+ "reasoning_only_turn"
320
+ if getattr(response, "empty_reasoning_only", False)
321
+ else None
322
+ ),
323
+ usage=None
324
+ if reported_usage is None
325
+ else {
326
+ "input_tokens": max(0, int(reported_usage.input_tokens)),
327
+ "output_tokens": max(0, int(reported_usage.output_tokens)),
328
+ "cached_tokens": max(0, int(reported_usage.cached_input_tokens)),
329
+ "reasoning_tokens": max(0, int(reported_usage.reasoning_output_tokens)),
330
+ },
331
+ )
332
+
333
+ async def stream_complete(
334
+ self,
335
+ *,
336
+ model: str,
337
+ prompt: str,
338
+ messages: Sequence[dict[str, Any]],
339
+ tools: Sequence[Any],
340
+ max_output_tokens: int | None = None,
341
+ reasoning_effort: str | None = None,
342
+ ):
343
+ """Pass model deltas through the Harness loop as soon as they arrive.
344
+
345
+ 传输纪律(本轮修复的"像卡住"根因):
346
+
347
+ - 正文、思考、工具调用或完成信号都是真实传输进展,会顺延空闲
348
+ 计时。不能把思考型模型持续返回的 ``reasoning_content`` 当成
349
+ “无进展”;这会在模型正常思考时误杀连接。
350
+ - usage/keepalive 不续命。一条始终只产生思考的流仍受
351
+ ``total_timeout_seconds`` 硬上限约束,不会无限运行。
352
+ - 连续 ``stream_idle_timeout_seconds`` 没有任何内容(只有 keepalive 或
353
+ 干脆静默)即判定为卡住:关闭当前流并抛出可重试的超时。外层统一
354
+ provider policy 会立即记录 ``model.call.failed``,再按策略重试或切换
355
+ provider。这里不能偷偷再发一次完整缓冲请求,否则一次 60 秒的流超时
356
+ 后还会叠加完整请求超时,Studio 会无进展地假死数分钟。
357
+ - 卡住前已经流出的半截内容会由循环层在失败时清理,不会污染答案或模型
358
+ 上下文。
359
+ """
360
+ selected_model = self._require_model(model)
361
+ from ksadk.model_proxy import compat as provider_compat
362
+
363
+ stream_idle_timeout_seconds = max(
364
+ 0.001,
365
+ float(
366
+ provider_compat.stream_idle_timeout(
367
+ base_url=selected_model.endpoint_url,
368
+ model=selected_model.model,
369
+ fallback=self._timeout_seconds,
370
+ )
371
+ or self._timeout_seconds
372
+ ),
158
373
  )
374
+ text_parts: list[str] = []
375
+ reasoning_parts: list[str] = []
376
+ reasoning_only_action_chars = 0
377
+ tool_calls: list[HarnessToolCall] = []
378
+ invalid_tool_name: str | None = None
379
+ usage = None
380
+ stream_kwargs = {
381
+ "messages": [dict(message) for message in messages],
382
+ "network_policy": self._network_policy,
383
+ "timeout_seconds": self._timeout_seconds,
384
+ "tools": [dict(tool.openai_schema) for tool in tools],
385
+ "max_output_tokens": max_output_tokens,
386
+ "reasoning_effort": reasoning_effort,
387
+ }
388
+ if hasattr(self._client, "stream_events"):
389
+ # Studio and direct SDK execution both consume the canonical model
390
+ # event vocabulary. This small compatibility projection preserves
391
+ # the established HarnessReasoner protocol while keeping provider
392
+ # wire chunks out of the loop and UI layers.
393
+ from ksadk.model_gateway.events import ModelStreamEventType
394
+ from ksadk.studio.contracts import Usage
395
+ from ksadk.studio.model_client import ModelStreamChunk, ToolCall
159
396
 
397
+ async def _canonical_chunks():
398
+ async for event in self._client.stream_events(
399
+ selected_model, **stream_kwargs
400
+ ):
401
+ if event.type is ModelStreamEventType.TEXT_DELTA:
402
+ yield ModelStreamChunk(
403
+ text=event.text,
404
+ provider_request_id=event.provider_request_id,
405
+ )
406
+ elif event.type is ModelStreamEventType.REASONING_DELTA:
407
+ yield ModelStreamChunk(
408
+ reasoning=event.text,
409
+ provider_request_id=event.provider_request_id,
410
+ )
411
+ elif event.type is ModelStreamEventType.TOOL_CALL_COMPLETED:
412
+ yield ModelStreamChunk(
413
+ tool_calls=(
414
+ ToolCall(
415
+ id=event.call_id,
416
+ name=event.tool_name,
417
+ arguments=event.arguments,
418
+ ),
419
+ ),
420
+ provider_request_id=event.provider_request_id,
421
+ )
422
+ elif event.type is ModelStreamEventType.USAGE_UPDATED:
423
+ values = event.usage or {}
424
+ yield ModelStreamChunk(
425
+ usage=Usage(
426
+ input_tokens=int(values.get("input_tokens") or 0),
427
+ output_tokens=int(values.get("output_tokens") or 0),
428
+ total_tokens=int(values.get("input_tokens") or 0)
429
+ + int(values.get("output_tokens") or 0),
430
+ cached_input_tokens=int(values.get("cached_tokens") or 0),
431
+ reasoning_output_tokens=int(
432
+ values.get("reasoning_tokens") or 0
433
+ ),
434
+ reported=True,
435
+ source="model-gateway",
436
+ ),
437
+ provider_request_id=event.provider_request_id,
438
+ )
439
+ elif event.type is ModelStreamEventType.TURN_COMPLETED:
440
+ yield ModelStreamChunk(
441
+ done=True,
442
+ finish_reason=str(
443
+ event.metadata.get("finish_reason") or ""
444
+ ),
445
+ provider_request_id=event.provider_request_id,
446
+ )
447
+
448
+ stream = _canonical_chunks()
449
+ else:
450
+ stream = self._client.stream(selected_model, **stream_kwargs)
451
+ iterator = stream.__aiter__()
452
+ loop = asyncio.get_running_loop()
453
+ total_deadline = loop.time() + self._total_timeout_seconds
454
+ idle_deadline = loop.time() + stream_idle_timeout_seconds
160
455
 
161
- class StudioPluginRuntime:
456
+ async def _raise_idle_timeout(*, close_stream: bool) -> None:
457
+ """终止无进展流,把重试决策交给统一 provider policy。"""
458
+
459
+ # ``asyncio.wait_for(iterator.__anext__())`` 超时会先取消并等待当前
460
+ # ``__anext__``,取消会沿着 httpx 流自动释放连接。此时再次并发
461
+ # ``aclose`` 会让 Python 的异步生成器终结器报
462
+ # ``aclose(): asynchronous generator is already running``。只有尚未
463
+ # 启动 ``__anext__`` 就发现预算耗尽时,才需要在这里主动关闭。
464
+ if close_stream:
465
+ try:
466
+ await stream.aclose()
467
+ except Exception: # noqa: BLE001 - 关闭失败不能遮蔽真正的空闲超时
468
+ pass
469
+ raise TimeoutError(
470
+ "model stream made no progress for "
471
+ f"{stream_idle_timeout_seconds:g} seconds"
472
+ )
473
+
474
+ while True:
475
+ now = loop.time()
476
+ if now >= total_deadline:
477
+ # 整轮预算耗尽:不再发起新请求,保持原有硬失败语义(由循环层
478
+ # 决定重试或切换候选模型),不做缓冲回退。
479
+ raise TimeoutError("model stream exceeded the run budget")
480
+ budget = min(idle_deadline, total_deadline) - now
481
+ if budget <= 0:
482
+ # 走到这里只可能是空闲进度超时(总预算已在上面拦下)。
483
+ await _raise_idle_timeout(close_stream=True)
484
+ try:
485
+ chunk = await asyncio.wait_for(iterator.__anext__(), timeout=budget)
486
+ except StopAsyncIteration:
487
+ break
488
+ except (asyncio.TimeoutError, TimeoutError):
489
+ if loop.time() >= total_deadline:
490
+ raise TimeoutError(
491
+ "model stream exceeded the run budget"
492
+ ) from None
493
+ await _raise_idle_timeout(close_stream=False)
494
+ if (chunk.text or chunk.reasoning or chunk.public_summary
495
+ or chunk.tool_calls or chunk.done):
496
+ # 真实内容增量证明运输活着:正文、思考、工具调用和完成
497
+ # 信号都顺延空闲计时。无限 reasoning-only 回合由 total_deadline
498
+ # 截止;usage/keepalive 仍不续命。
499
+ idle_deadline = loop.time() + stream_idle_timeout_seconds
500
+ if chunk.text:
501
+ text_parts.append(chunk.text)
502
+ yield {"text_delta": chunk.text}
503
+ if chunk.public_summary:
504
+ yield {"summary_delta": chunk.public_summary}
505
+ if chunk.reasoning:
506
+ reasoning_parts.append(chunk.reasoning)
507
+ reasoning_only_action_chars += len(chunk.reasoning)
508
+ yield {"reasoning_delta": chunk.reasoning}
509
+ if (
510
+ tools
511
+ and not text_parts
512
+ and not tool_calls
513
+ and reasoning_only_action_chars
514
+ >= _reasoning_only_action_budget_chars()
515
+ ):
516
+ # The transport is healthy, but the Agent has made no
517
+ # observable progress. Live GLM 5.3 Flash comparison
518
+ # produced 20,366 reasoning chunks and zero tool calls in
519
+ # Studio; native DeepAgents and bare Pi showed the same
520
+ # first-response failure. A measured provider probe
521
+ # recovered in 1.13s only when thinking was disabled and
522
+ # one tool call was required. Apply that narrow recovery
523
+ # once, then return to the ordinary auto policy on the
524
+ # following turn.
525
+ try:
526
+ await stream.aclose()
527
+ except Exception: # noqa: BLE001 - recovery owns the next request
528
+ pass
529
+ recovery = await self._client.complete(
530
+ selected_model,
531
+ messages=[
532
+ *[dict(message) for message in messages],
533
+ {
534
+ "role": "system",
535
+ "content": (
536
+ "This tool-capable turn spent its action budget on "
537
+ "reasoning without making progress. Call exactly one "
538
+ "small, relevant tool now to inspect or advance the "
539
+ "task. Do not draft the complete implementation or "
540
+ "return more reasoning in this recovery turn."
541
+ ),
542
+ },
543
+ ],
544
+ network_policy=self._network_policy,
545
+ timeout_seconds=self._timeout_seconds,
546
+ max_attempts=1,
547
+ backoff_seconds=0,
548
+ tools=[dict(tool.openai_schema) for tool in tools],
549
+ allow_empty=False,
550
+ retry_on_length=True,
551
+ max_output_tokens=min(2_048, int(max_output_tokens or 2_048)),
552
+ reasoning_effort=reasoning_effort,
553
+ tool_choice="required",
554
+ )
555
+ recovered_calls: list[HarnessToolCall] = []
556
+ for call in recovery.tool_calls:
557
+ arguments = _parse_tool_arguments(call.arguments)
558
+ recovered_calls.append(
559
+ HarnessToolCall(
560
+ call_id=call.id,
561
+ name=call.name,
562
+ arguments=arguments or {},
563
+ invalid_reason=(
564
+ None
565
+ if arguments is not None
566
+ else "model emitted non-JSON-object tool arguments"
567
+ ),
568
+ )
569
+ )
570
+ reported_usage = recovery.usage if recovery.usage.reported else None
571
+ yield {
572
+ "turn": HarnessReasoningTurn(
573
+ final_text=recovery.content or None,
574
+ tool_calls=tuple(recovered_calls),
575
+ reasoning=recovery.reasoning or None,
576
+ degraded="reasoning_only_action_recovered",
577
+ usage=None
578
+ if reported_usage is None
579
+ else {
580
+ "input_tokens": max(
581
+ 0, int(reported_usage.input_tokens)
582
+ ),
583
+ "output_tokens": max(
584
+ 0, int(reported_usage.output_tokens)
585
+ ),
586
+ "cached_tokens": max(
587
+ 0, int(reported_usage.cached_input_tokens)
588
+ ),
589
+ "reasoning_tokens": max(
590
+ 0, int(reported_usage.reasoning_output_tokens)
591
+ ),
592
+ },
593
+ )
594
+ }
595
+ return
596
+ if chunk.usage is not None:
597
+ usage = chunk.usage
598
+ if chunk.tool_calls:
599
+ tool_calls = []
600
+ for call in chunk.tool_calls:
601
+ try:
602
+ arguments = json.loads(call.arguments or "{}")
603
+ except json.JSONDecodeError:
604
+ invalid_tool_name = call.name
605
+ continue
606
+ if not isinstance(arguments, dict):
607
+ invalid_tool_name = call.name
608
+ continue
609
+ tool_calls.append(
610
+ HarnessToolCall(call_id=call.id, name=call.name, arguments=arguments)
611
+ )
612
+ if chunk.done:
613
+ if (
614
+ chunk.finish_reason
615
+ in {"length", "incomplete", "max_tokens", "max_output_tokens"}
616
+ and tools
617
+ and not tool_calls
618
+ ):
619
+ # Pi's native auto-continuation treats a length stop as an
620
+ # unfinished turn. Live KSPMAS evidence showed the same
621
+ # GLM request drafting prose until the 2K cap with
622
+ # ``tool_choice=auto``, while a required-action recovery
623
+ # returned a valid tool call in about one second. Do not
624
+ # publish the truncated plan as a final answer.
625
+ recovery = await self._client.complete(
626
+ selected_model,
627
+ messages=[
628
+ *[dict(message) for message in messages],
629
+ {
630
+ "role": "system",
631
+ "content": (
632
+ "The previous tool-capable response was truncated "
633
+ "before it took action. Call exactly one small, "
634
+ "relevant tool now to advance the task. Do not "
635
+ "repeat the plan or draft the complete implementation "
636
+ "in this recovery turn."
637
+ ),
638
+ },
639
+ ],
640
+ network_policy=self._network_policy,
641
+ timeout_seconds=self._timeout_seconds,
642
+ max_attempts=1,
643
+ backoff_seconds=0,
644
+ tools=[dict(tool.openai_schema) for tool in tools],
645
+ allow_empty=False,
646
+ retry_on_length=True,
647
+ # Unlike reasoning-only recovery, this branch often
648
+ # carries a whole file in structured arguments. The
649
+ # original 2K cap simply truncated the required tool
650
+ # call a second time. Match the existing malformed-
651
+ # argument repair budget so one large write can remain
652
+ # valid JSON.
653
+ max_output_tokens=max(
654
+ 16_384,
655
+ int(
656
+ max_output_tokens
657
+ or selected_model.parameters.max_tokens
658
+ or 0
659
+ ),
660
+ ),
661
+ reasoning_effort=reasoning_effort,
662
+ tool_choice="required",
663
+ )
664
+ recovered_calls: list[HarnessToolCall] = []
665
+ for call in recovery.tool_calls:
666
+ arguments = _parse_tool_arguments(call.arguments)
667
+ recovered_calls.append(
668
+ HarnessToolCall(
669
+ call_id=call.id,
670
+ name=call.name,
671
+ arguments=arguments or {},
672
+ invalid_reason=(
673
+ None
674
+ if arguments is not None
675
+ else "model emitted non-JSON-object tool arguments"
676
+ ),
677
+ )
678
+ )
679
+ reported_usage = recovery.usage if recovery.usage.reported else None
680
+ yield {
681
+ "turn": HarnessReasoningTurn(
682
+ tool_calls=tuple(recovered_calls),
683
+ reasoning=recovery.reasoning or None,
684
+ degraded="length_truncated_action_recovered",
685
+ usage=None
686
+ if reported_usage is None
687
+ else {
688
+ "input_tokens": max(
689
+ 0, int(reported_usage.input_tokens)
690
+ ),
691
+ "output_tokens": max(
692
+ 0, int(reported_usage.output_tokens)
693
+ ),
694
+ "cached_tokens": max(
695
+ 0, int(reported_usage.cached_input_tokens)
696
+ ),
697
+ "reasoning_tokens": max(
698
+ 0, int(reported_usage.reasoning_output_tokens)
699
+ ),
700
+ },
701
+ )
702
+ }
703
+ return
704
+ if invalid_tool_name:
705
+ # Some OpenAI-compatible GLM gateways truncate or slightly
706
+ # corrupt a large native function-call JSON object. The
707
+ # first attempt's public prose has already streamed, so ask
708
+ # once for the intended call again with a larger budget and
709
+ # consume only its structured call. Raw invalid arguments
710
+ # are never placed back into model context or Studio events.
711
+ repair = await self._client.complete(
712
+ selected_model,
713
+ messages=[
714
+ *[dict(message) for message in messages],
715
+ {
716
+ "role": "system",
717
+ "content": (
718
+ "The previous tool call could not be parsed. "
719
+ f"Retry the intended {invalid_tool_name} call once with "
720
+ "valid JSON arguments. Keep the file content concise enough "
721
+ "to fit in one tool call and do not repeat the analysis."
722
+ ),
723
+ },
724
+ ],
725
+ network_policy=self._network_policy,
726
+ timeout_seconds=self._timeout_seconds,
727
+ max_attempts=self._max_attempts,
728
+ backoff_seconds=self._backoff_seconds,
729
+ tools=[dict(tool.openai_schema) for tool in tools],
730
+ allow_empty=bool(tools),
731
+ retry_on_length=True,
732
+ max_output_tokens=max(
733
+ 16_384,
734
+ int(
735
+ max_output_tokens
736
+ or selected_model.parameters.max_tokens
737
+ or 0
738
+ ),
739
+ ),
740
+ reasoning_effort=reasoning_effort,
741
+ )
742
+ tool_calls = []
743
+ for call in repair.tool_calls:
744
+ arguments = _parse_tool_arguments(call.arguments)
745
+ if arguments is None:
746
+ # 修复轮仍给出坏参数:保留 invalid_reason,交给循环层
747
+ # 以 invalid_arguments 回灌,不中断整轮。
748
+ tool_calls.append(
749
+ HarnessToolCall(
750
+ call_id=call.id,
751
+ name=call.name,
752
+ arguments={},
753
+ invalid_reason=(
754
+ "model emitted non-JSON-object tool arguments"
755
+ ),
756
+ )
757
+ )
758
+ continue
759
+ tool_calls.append(
760
+ HarnessToolCall(
761
+ call_id=call.id,
762
+ name=call.name,
763
+ arguments=arguments,
764
+ )
765
+ )
766
+ # 修复轮完全没有给出调用:按"纯文本回合"收尾(不加人造调用,
767
+ # 否则会产生没有配对 tool_call 的 tool result)。
768
+ usage = repair.usage
769
+ yield {
770
+ "turn": HarnessReasoningTurn(
771
+ final_text=(
772
+ "".join(text_parts)
773
+ or (repair.content if invalid_tool_name else "")
774
+ or None
775
+ ),
776
+ tool_calls=tuple(tool_calls),
777
+ reasoning=(
778
+ "".join(reasoning_parts)
779
+ or (repair.reasoning if invalid_tool_name else "")
780
+ or None
781
+ ),
782
+ usage=None
783
+ if usage is None
784
+ else {
785
+ "input_tokens": max(0, int(usage.input_tokens)),
786
+ "output_tokens": max(0, int(usage.output_tokens)),
787
+ "cached_tokens": max(0, int(usage.cached_input_tokens)),
788
+ "reasoning_tokens": max(0, int(usage.reasoning_output_tokens)),
789
+ },
790
+ )
791
+ }
792
+
793
+
794
+ class StudioPluginRuntime(StudioNativeActivationMixin):
162
795
  """Resolve, activate, and retain composed providers for Studio sessions."""
163
796
 
164
797
  def __init__(
@@ -170,14 +803,21 @@ class StudioPluginRuntime:
170
803
  model_client: OpenAICompatibleModelClient,
171
804
  secret_resolver: Any,
172
805
  harness_reasoner: HarnessReasoner | None = None,
806
+ harness_engine_selector: HarnessEngineSelector | None = None,
807
+ harness_native_adapter_builder: HarnessNativeAdapterBuilder | None = None,
808
+ harness_native_session_enabled: Callable[[str, str], bool] | None = None,
173
809
  provider_manifests: Mapping[str, PluginManifest] | None = None,
174
810
  provider_factories: Mapping[str, Any] | None = None,
811
+ hook_registrations: tuple[StudioNativeHookRegistration, ...] = (),
812
+ context_registrations: tuple[StudioNativeContextRegistration, ...] = (),
175
813
  legacy_harness_sources: Sequence[LegacyHarnessSource] = (),
176
814
  dsh_capability_service: Any | None = None,
177
815
  resource_dsh_capability_service: Any | None = None,
178
816
  resource_authority: Any | None = None,
179
817
  resource_connections: Any | None = None,
180
818
  resource_actor_ref: str = "local-user",
819
+ native_tenant_id: str = "local-studio",
820
+ native_workspace_id: str | None = None,
181
821
  codex_local_launch_resolver: Any = None,
182
822
  runtime_executor: RuntimeExecutor | None = None,
183
823
  ) -> None:
@@ -187,8 +827,15 @@ class StudioPluginRuntime:
187
827
  self._model_client = model_client
188
828
  self._secret_resolver = secret_resolver
189
829
  self._harness_reasoner = harness_reasoner
830
+ if (harness_engine_selector is None) != (harness_native_adapter_builder is None):
831
+ raise ValueError("Native Harness requires both host selector and adapter builder")
832
+ self._harness_engine_selector = harness_engine_selector
833
+ self._harness_native_adapter_builder = harness_native_adapter_builder
834
+ self._harness_native_session_enabled = harness_native_session_enabled
190
835
  self._provider_manifests = dict(provider_manifests or {})
191
836
  self._provider_factories = dict(provider_factories or {})
837
+ self._hook_registrations = tuple(hook_registrations)
838
+ self._context_registrations = tuple(context_registrations)
192
839
  self._dsh_capability_service = dsh_capability_service
193
840
  self._resource_dsh_capability_service = (
194
841
  resource_dsh_capability_service or dsh_capability_service
@@ -196,14 +843,23 @@ class StudioPluginRuntime:
196
843
  self._resource_authority = resource_authority
197
844
  self._resource_connections = resource_connections
198
845
  self._resource_actor_ref = resource_actor_ref
846
+ self._native_tenant_id = native_tenant_id
847
+ self._native_workspace_id = native_workspace_id
199
848
  self._codex_local_launch_resolver = codex_local_launch_resolver
200
849
  self._runtime_executor = runtime_executor
201
850
  self._legacy_bundles = LegacyBundleAdapter(legacy_harness_sources)
202
851
  self._lock = asyncio.Lock()
203
852
  self._hosts: dict[str, _HostEntry] = {}
853
+ self._native_activations: dict[tuple[str, str], _NativeActivation] = {}
854
+ self._activation_locks: dict[str, asyncio.Lock] = {}
204
855
  self._resource_write_modes: dict[str, str] = {}
205
- self._admission_open = True
856
+ self._admission = RuntimeAdmissionGate()
206
857
  self._closed = False
858
+ self.execution_policy_resolver: Any | None = None
859
+
860
+ @property
861
+ def _admission_open(self) -> bool:
862
+ return self._admission.is_open
207
863
 
208
864
  def replace_provider_registrations(
209
865
  self,
@@ -251,8 +907,29 @@ class StudioPluginRuntime:
251
907
  dynamic_dsh_mcp = self._bundle_uses_dynamic_dsh(bundle)
252
908
  selected_model = self._select_model(build, model)
253
909
  resolved = bundle.resolved_agent_spec
910
+ primary_model = resolved.get("model")
911
+ candidate_models = [primary_model]
912
+ fallback_models = resolved.get("fallbackModels") or resolved.get("fallback_models")
913
+ if isinstance(fallback_models, list):
914
+ candidate_models.extend(fallback_models)
915
+ selected_model_spec = next(
916
+ (
917
+ item
918
+ for item in candidate_models
919
+ if isinstance(item, Mapping) and str(item.get("model") or "") == selected_model
920
+ ),
921
+ primary_model if isinstance(primary_model, Mapping) else {},
922
+ )
254
923
  instructions = resolved.get("instructions")
255
924
  instructions = instructions if isinstance(instructions, Mapping) else {}
925
+ context_spec = resolved.get("context")
926
+ context_spec = context_spec if isinstance(context_spec, Mapping) else {}
927
+ max_input_tokens = context_spec.get("maxInputTokens") or context_spec.get(
928
+ "max_input_tokens"
929
+ )
930
+ reserve_output_tokens = context_spec.get(
931
+ "reserveOutputTokens"
932
+ ) or context_spec.get("reserve_output_tokens")
256
933
  provider_id, _provider_version = _parse_plugin_ref(
257
934
  bundle.composition.profile.agent_provider.ref
258
935
  )
@@ -260,6 +937,9 @@ class StudioPluginRuntime:
260
937
  CODEX_AGENT_PROVIDER_PLUGIN_ID: "codex",
261
938
  KSADK_HARNESS_AGENT_PROVIDER_PLUGIN_ID: "harness",
262
939
  }.get(provider_id)
940
+ execution_spec = resolved.get("execution")
941
+ execution_spec = execution_spec if isinstance(execution_spec, Mapping) else {}
942
+ approval_timeout = execution_spec.get("approvalTimeoutSeconds")
263
943
  return StudioRunSpec(
264
944
  launch_context=RuntimeLaunchContext(
265
945
  runtime_type=runtime_type,
@@ -269,6 +949,7 @@ class StudioPluginRuntime:
269
949
  build_id=build.id,
270
950
  agent_id=build.agent_id,
271
951
  model=selected_model,
952
+ model_metadata=dict(selected_model_spec.get("metadata") or {}),
272
953
  request_config={
273
954
  "agent_system": str(instructions.get("system") or ""),
274
955
  "agent_task": str(instructions.get("task") or ""),
@@ -278,10 +959,27 @@ class StudioPluginRuntime:
278
959
  "provider_runtime_type": provider_runtime_type or "",
279
960
  "provider_ref": bundle.composition.profile.agent_provider.ref,
280
961
  **(
281
- {"tool_approval_mode": normalize_tool_approval_mode(approval_mode)}
282
- if approval_mode
962
+ {"approval_timeout_seconds": int(approval_timeout)}
963
+ if provider_runtime_type == "harness" and approval_timeout is not None
964
+ else {}
965
+ ),
966
+ # Provider-backed Harness runs use this resolver rather than
967
+ # FrameworkRunSpecResolver. Preserve the immutable AgentVersion
968
+ # budget here as well, otherwise ManagedHarnessRuntimeAdapter
969
+ # cannot derive the real model window and silently falls back
970
+ # to 32K for every Studio run.
971
+ **(
972
+ {"max_input_tokens": int(max_input_tokens)}
973
+ if max_input_tokens is not None
974
+ else {}
975
+ ),
976
+ **(
977
+ {"reserve_output_tokens": int(reserve_output_tokens)}
978
+ if reserve_output_tokens is not None
283
979
  else {}
284
980
  ),
981
+ **({"tool_approval_mode": normalize_tool_approval_mode(approval_mode)}
982
+ if provider_runtime_type == "harness" or approval_mode else {}),
285
983
  },
286
984
  manifest_sha256=build.resolved_digest,
287
985
  plugin_bundle_root=bundle_root,
@@ -298,7 +996,7 @@ class StudioPluginRuntime:
298
996
  raise PluginHostError(
299
997
  "plugin_bundle_unavailable", "Studio run has no PluginHost Bundle"
300
998
  )
301
- entry = await self._host_for(spec.plugin_bundle_root)
999
+ entry = await self._admission.resolve(lambda: self._host_for(spec.plugin_bundle_root))
302
1000
  if entry.agent_id != spec.agent_id:
303
1001
  raise PluginHostError(
304
1002
  "plugin_bundle_agent_mismatch",
@@ -311,6 +1009,7 @@ class StudioPluginRuntime:
311
1009
  activation = await entry.host.open_activation(
312
1010
  entry.bundle,
313
1011
  activation_key=session_id,
1012
+ activation_claims=await self._native_activation_claims(spec, session_id),
314
1013
  )
315
1014
  except BaseException:
316
1015
  self._resource_write_modes.pop(session_id, None)
@@ -339,64 +1038,34 @@ class StudioPluginRuntime:
339
1038
  )
340
1039
  return lambda: StudioPluginKernelAdapter(self, spec)
341
1040
 
342
- async def kernel_adapter(
343
- self,
344
- spec: StudioRunSpec,
345
- *,
346
- session_id: str,
347
- ) -> Any:
348
- """Bind a Scheduler run to the provider-owned activation adapter."""
349
1041
 
350
- if spec.plugin_bundle_root is None:
351
- raise StudioError(
352
- "PLUGIN_RUNTIME_UNAVAILABLE",
353
- "Studio Build 没有 PluginHost Bundle",
354
- status_code=409,
355
- )
356
- entry = await self._host_for(spec.plugin_bundle_root)
357
- if entry.agent_id != spec.agent_id:
358
- raise PluginHostError(
359
- "plugin_bundle_agent_mismatch",
360
- "Studio run Agent does not match its immutable PluginHost Bundle",
361
- )
362
- self._resource_write_modes[session_id] = str(
363
- spec.request_config.get("tool_approval_mode") or ""
364
- )
365
- try:
366
- activation = await entry.host.open_activation(
367
- entry.bundle,
368
- activation_key=session_id,
369
- )
370
- except BaseException:
371
- self._resource_write_modes.pop(session_id, None)
372
- raise
373
- try:
374
- return await activation.runtime_adapter()
375
- except BaseException:
376
- try:
377
- await activation.close()
378
- finally:
379
- self._resource_write_modes.pop(session_id, None)
380
- raise
381
1042
 
382
- async def close_session(self, session_id: str) -> None:
383
- async with self._lock:
384
- entries = tuple(self._hosts.values())
385
- try:
386
- for entry in entries:
387
- await entry.host.close_activation(session_id)
388
- finally:
389
- self._resource_write_modes.pop(session_id, None)
1043
+
1044
+
390
1045
 
391
1046
  async def close_session_if_dynamic(self, spec: StudioRunSpec, session_id: str) -> None:
392
- if bool(spec.request_config.get("dynamic_dsh_mcp")):
393
- await self.close_session(session_id)
1047
+ # 每轮运行后关闭 dynamic-DSH MCP 激活会让下一轮重新 spawn/health/list
1048
+ # 全部 MCP server(实测 ~12s),这是 harness 首 token 延迟的主因。
1049
+ # open_activation 以 session 为 key 复用同一激活(图与 Bundle digest
1050
+ # 不变),因此跨轮保留激活;激活只在会话删除(close_session)与
1051
+ # Studio 退出(aclose)时释放。
1052
+ return None
1053
+
1054
+ def check_configuration_mutable(self) -> None:
1055
+ if self._hosts:
1056
+ raise StudioError(
1057
+ "SETTINGS_RUNTIME_BUSY", "请通过设置接口刷新运行配置", status_code=409
1058
+ )
1059
+
1060
+ def replace_resource_authority(self, authority: Any) -> None:
1061
+ self.check_configuration_mutable()
1062
+ self._resource_authority = authority
394
1063
 
395
1064
  async def suspend_admission(self) -> None:
396
1065
  """Stop new activations and drain every currently owned host."""
397
1066
 
398
1067
  async with self._lock:
399
- self._admission_open = False
1068
+ self._admission.suspend()
400
1069
  entries = tuple(self._hosts.values())
401
1070
  self._hosts.clear()
402
1071
  cleanup = asyncio.create_task(self._dispose_entries(entries))
@@ -417,7 +1086,7 @@ class StudioPluginRuntime:
417
1086
  "plugin_runtime_closed",
418
1087
  "Studio plugin runtime is closed",
419
1088
  )
420
- self._admission_open = True
1089
+ self._admission.resume()
421
1090
 
422
1091
  @staticmethod
423
1092
  async def _dispose_entries(entries: Sequence[_HostEntry]) -> None:
@@ -435,7 +1104,7 @@ class StudioPluginRuntime:
435
1104
  if self._closed:
436
1105
  return
437
1106
  self._closed = True
438
- self._admission_open = False
1107
+ self._admission.close()
439
1108
  entries = tuple(self._hosts.values())
440
1109
  self._hosts.clear()
441
1110
  cleanup = asyncio.create_task(self._dispose_entries(entries))
@@ -453,14 +1122,24 @@ class StudioPluginRuntime:
453
1122
  # Re-resolve every turn. This deliberately rechecks enabled receipts and
454
1123
  # package digests rather than trusting a previously healthy child.
455
1124
  bundle = self._resolve_bundle(bundle_root)
1125
+ if any(
1126
+ item.ref == PLATFORM_RESOURCE_MCP_REF
1127
+ for item in bundle.composition.profile.capabilities
1128
+ ) and not callable(getattr(self._resource_authority, "admit_runtime", None)):
1129
+ raise StudioError(
1130
+ "PLATFORM_RESOURCE_CONFIGURATION_REQUIRED",
1131
+ "平台资源连接尚未配置,请在设置的云端连接中填写账号凭据和控制面地址",
1132
+ status_code=422,
1133
+ )
456
1134
  key = bundle.bundle_digest
1135
+ await self._admission.wait()
457
1136
  async with self._lock:
458
1137
  if self._closed:
459
1138
  raise PluginHostError(
460
1139
  "plugin_runtime_closed",
461
1140
  "Studio plugin runtime is closed",
462
1141
  )
463
- if not self._admission_open:
1142
+ if not self._admission.is_open:
464
1143
  raise PluginHostError(
465
1144
  "plugin_runtime_reconfiguring",
466
1145
  "Studio plugin runtime is reconfiguring",
@@ -481,8 +1160,15 @@ class StudioPluginRuntime:
481
1160
  # Providers resolve credential *references* at activation time.
482
1161
  # The DSH discovery host never receives this service.
483
1162
  "credential_resolver": self._secret_resolver,
1163
+ # Harness Provider 持久 Checkpoint/RunStore/Receipt 的状态根
1164
+ # (与 builtin capability factories 同一 Workspace 命名空间)。
1165
+ "harness_state_dir": str(self.workspace.resolve(".agentkit/plugin-runtime/state")),
1166
+ # 用户当前选择的 Studio 工作区:harness 的文件工具应写在这里,
1167
+ # 而不是 plugin-runtime state 的哈希目录里。
1168
+ "harness_workspace_root": str(self.workspace.root),
484
1169
  "codex_local_launch_resolver": self._codex_local_launch_resolver,
485
1170
  "runtime_executor": self._runtime_executor,
1171
+ "execution_policy_resolver": self.execution_policy_resolver,
486
1172
  "dsh_capability_service": self._resource_dsh_capability_service,
487
1173
  "resource_authority": self._resource_authority,
488
1174
  "resource_connections": self._resource_connections,
@@ -496,6 +1182,11 @@ class StudioPluginRuntime:
496
1182
  services["harness_reasoner"] = (
497
1183
  self._harness_reasoner or self._bound_harness_reasoner(verified)
498
1184
  )
1185
+ if self._harness_engine_selector is not None:
1186
+ services["harness_engine_selector"] = self._harness_engine_selector
1187
+ services["harness_native_adapter_builder"] = (
1188
+ self._harness_native_adapter_builder
1189
+ )
499
1190
  host = PluginHost(
500
1191
  registry,
501
1192
  factories,
@@ -512,15 +1203,10 @@ class StudioPluginRuntime:
512
1203
  bundle=verified,
513
1204
  host=host,
514
1205
  )
515
- stale = [
516
- (digest, entry)
517
- for digest, entry in self._hosts.items()
518
- if entry.agent_id == candidate.agent_id and digest != key
519
- ]
520
1206
  self._hosts[key] = candidate
521
- for digest, entry in stale:
522
- self._hosts.pop(digest, None)
523
- await entry.host.dispose()
1207
+ # Distinct immutable Builds of the same Agent may be active in
1208
+ # different authorized sessions. Their profile graphs are owned
1209
+ # until explicit maintenance/close, never evicted by another Build.
524
1210
  return candidate
525
1211
 
526
1212
  def _resource_write_authorizer(
@@ -539,8 +1225,7 @@ class StudioPluginRuntime:
539
1225
  )
540
1226
  dynamic_refs = {reference, PLATFORM_RESOURCE_MCP_REF}
541
1227
  return any(
542
- capability.ref in dynamic_refs
543
- for capability in bundle.composition.profile.capabilities
1228
+ capability.ref in dynamic_refs for capability in bundle.composition.profile.capabilities
544
1229
  )
545
1230
 
546
1231
  def _resolve_bundle(self, bundle_root: Path) -> ResolvedPluginBundle:
@@ -605,6 +1290,10 @@ class StudioPluginRuntime:
605
1290
  *builtin_capability_manifests(),
606
1291
  dsh_profile_mcp_manifest(),
607
1292
  platform_resource_mcp_manifest(),
1293
+ *(item.manifest for item in self._hook_registrations
1294
+ if manifest.agent_id in item.agent_ids),
1295
+ *(item.manifest for item in self._context_registrations
1296
+ if manifest.agent_id in item.agent_ids),
608
1297
  ]
609
1298
  external = self._external_manifest(profile)
610
1299
  if external is not None:
@@ -635,6 +1324,10 @@ class StudioPluginRuntime:
635
1324
  )
636
1325
  factories[DSH_PROFILE_MCP_PLUGIN_ID] = DshProfileMCPFactory(self._dsh_capability_service)
637
1326
  factories[PLATFORM_RESOURCE_MCP_PLUGIN_ID] = PlatformResourceMCPFactory()
1327
+ for item in (*self._hook_registrations, *self._context_registrations):
1328
+ if bundle.manifest.agent_id in item.agent_ids:
1329
+ manifests.append(item.manifest)
1330
+ factories[item.manifest.metadata.id] = item.factory
638
1331
  provider_id, provider_version = _parse_plugin_ref(
639
1332
  bundle.composition.profile.agent_provider.ref
640
1333
  )
@@ -697,6 +1390,13 @@ class StudioPluginRuntime:
697
1390
  try:
698
1391
  host.preflight(bundle.composition.profile)
699
1392
  except PluginHostError as error:
1393
+ if error.code == "plugin_permission_denied":
1394
+ raise StudioError(
1395
+ "PLUGIN_PERMISSION_DENIED",
1396
+ "Agent 插件组合未通过运行前检查",
1397
+ status_code=409,
1398
+ details=_permission_denial_details(error),
1399
+ ) from error
700
1400
  code = (
701
1401
  "PLUGIN_PERMISSION_DENIED"
702
1402
  if error.code == "plugin_permission_denied"
@@ -712,22 +1412,33 @@ class StudioPluginRuntime:
712
1412
  def _bound_harness_reasoner(self, bundle: ResolvedPluginBundle) -> HarnessReasoner:
713
1413
  spec = bundle.resolved_agent_spec
714
1414
  model = ResolvedModel.model_validate(spec.get("model"))
1415
+ raw_fallback_models = spec.get("fallbackModels") or spec.get("fallback_models") or []
1416
+ fallback_models = tuple(
1417
+ ResolvedModel.model_validate(item)
1418
+ for item in raw_fallback_models
1419
+ if isinstance(item, Mapping)
1420
+ )
715
1421
  security = spec.get("security")
716
1422
  security = security if isinstance(security, Mapping) else {}
717
1423
  network = NetworkPolicy.model_validate(security.get("network") or {})
718
1424
  execution = spec.get("execution")
719
1425
  execution = execution if isinstance(execution, Mapping) else {}
720
- retry = execution.get("retry")
721
- retry = retry if isinstance(retry, Mapping) else {}
1426
+ # Managed Harness owns provider retry/failover in ModelProviderPolicy.
1427
+ # Retrying again inside the HTTP client multiplies attempts (for
1428
+ # example 3 outer attempts x 2 hidden HTTP attempts), makes the public
1429
+ # attempt counter dishonest, and applies two independent backoffs.
1430
+ # Keep this transport call single-shot; the Harness loop performs the
1431
+ # visible ten-attempt policy and emits one durable event per retry.
722
1432
  return _StudioHarnessReasoner(
723
1433
  self._model_client,
724
1434
  model=model,
1435
+ fallback_models=fallback_models,
725
1436
  network_policy=network,
726
- timeout_seconds=int(
727
- execution.get("timeoutSeconds") or execution.get("timeout_seconds") or 120
728
- ),
729
- max_attempts=int(retry.get("maxAttempts") or retry.get("max_attempts") or 2),
730
- backoff_seconds=float(retry.get("backoffSeconds") or retry.get("backoff_seconds") or 1),
1437
+ timeout_seconds=_model_request_timeout_seconds(execution),
1438
+ # 增量传输的硬上限用整个 run 的预算;上面的 timeout 只用于"无进度"。
1439
+ total_timeout_seconds=_model_total_timeout_seconds(execution),
1440
+ max_attempts=1,
1441
+ backoff_seconds=0,
731
1442
  )
732
1443
 
733
1444
  def _external_manifest(self, profile: CompositionProfile) -> PluginManifest | None:
@@ -801,6 +1512,28 @@ def _parse_plugin_ref(value: str) -> tuple[str, str]:
801
1512
  return plugin_id, version
802
1513
 
803
1514
 
1515
+ _PERMISSION_DENIAL_MARKER = "requests unapproved permissions:"
1516
+
1517
+
1518
+ def _permission_denial_details(error: PluginHostError) -> dict[str, Any]:
1519
+ """把权限拒绝错误转成可自助修复的 details(缺失权限 + 修复指引)。"""
1520
+
1521
+ message = str(error)
1522
+ missing: list[str] = []
1523
+ if _PERMISSION_DENIAL_MARKER in message:
1524
+ tail = message.split(_PERMISSION_DENIAL_MARKER, 1)[1]
1525
+ missing = [item.strip() for item in tail.split(",") if item.strip()]
1526
+ return {
1527
+ "reason": error.code,
1528
+ "missingPermissions": missing,
1529
+ "hint": (
1530
+ "在 Agent 安全设置的允许权限中加入缺失权限后重新构建并运行"
1531
+ if missing
1532
+ else "在 Agent 安全设置中调整允许权限后重新构建并运行"
1533
+ ),
1534
+ }
1535
+
1536
+
804
1537
  def _normalize_result(raw: Any, *, session_id: str) -> StudioPluginTurnResult:
805
1538
  if isinstance(raw, (CodexTurnResult, HarnessTurnResult)):
806
1539
  return StudioPluginTurnResult(