agentengine-sdk-python 0.8.5__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 (851) hide show
  1. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/METADATA +12 -8
  2. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/RECORD +823 -388
  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/a2a/__init__.py +157 -167
  12. ksadk/a2a/_invocation_state.py +86 -0
  13. ksadk/a2a/_space_client_events.py +33 -22
  14. ksadk/a2a/adk.py +194 -0
  15. ksadk/a2a/adk_invocation_context.py +242 -0
  16. ksadk/a2a/adk_runtime.py +126 -0
  17. ksadk/a2a/adk_tools.py +319 -0
  18. ksadk/a2a/bootstrap.py +149 -23
  19. ksadk/a2a/build_validation.py +147 -0
  20. ksadk/a2a/card.py +23 -15
  21. ksadk/a2a/codex.py +160 -0
  22. ksadk/a2a/codex_checkpoint.py +111 -0
  23. ksadk/a2a/codex_recovery.py +96 -0
  24. ksadk/a2a/codex_recovery_events.py +123 -0
  25. ksadk/a2a/codex_runtime.py +198 -0
  26. ksadk/a2a/codex_session_checkpoint.py +162 -0
  27. ksadk/a2a/composition.py +88 -0
  28. ksadk/a2a/context_store.py +118 -19
  29. ksadk/a2a/control_plane.py +108 -106
  30. ksadk/a2a/event_adapter.py +92 -193
  31. ksadk/a2a/executor.py +257 -85
  32. ksadk/a2a/exposure.py +106 -0
  33. ksadk/a2a/external_transport.py +3 -4
  34. ksadk/a2a/identity.py +106 -12
  35. ksadk/a2a/ids.py +14 -3
  36. ksadk/a2a/inbound_kernel.py +133 -0
  37. ksadk/a2a/interaction_wire.py +76 -0
  38. ksadk/a2a/invocation_checkpoint.py +274 -0
  39. ksadk/a2a/invocation_policy.py +87 -0
  40. ksadk/a2a/invocation_publication.py +210 -0
  41. ksadk/a2a/invocation_service.py +972 -0
  42. ksadk/a2a/invocation_types.py +459 -0
  43. ksadk/a2a/kernel_task_adapter.py +259 -0
  44. ksadk/a2a/langgraph.py +20 -7
  45. ksadk/a2a/langgraph_invocation_context.py +136 -0
  46. ksadk/a2a/langgraph_managed.py +150 -0
  47. ksadk/a2a/langgraph_recovery.py +32 -0
  48. ksadk/a2a/langgraph_runtime.py +89 -0
  49. ksadk/a2a/langgraph_tool_runtime.py +132 -0
  50. ksadk/a2a/langgraph_tools.py +63 -0
  51. ksadk/a2a/message_digest.py +40 -0
  52. ksadk/a2a/platform.py +389 -0
  53. ksadk/a2a/policy_refs.py +13 -0
  54. ksadk/a2a/presentation.py +402 -0
  55. ksadk/a2a/product_kernel_facts.py +177 -0
  56. ksadk/a2a/product_key.py +99 -0
  57. ksadk/a2a/protocol_errors.py +116 -0
  58. ksadk/a2a/result_text.py +49 -0
  59. ksadk/a2a/resume_store.py +93 -3
  60. ksadk/a2a/routes.py +6 -1
  61. ksadk/a2a/runtime_approval.py +198 -0
  62. ksadk/a2a/runtime_input.py +151 -0
  63. ksadk/a2a/server.py +16 -7
  64. ksadk/a2a/space_client.py +101 -16
  65. ksadk/a2a/task_adapter.py +19 -5
  66. ksadk/a2a/task_event_dispatcher.py +39 -2
  67. ksadk/a2a/task_event_outbox.py +215 -0
  68. ksadk/a2a/task_event_outbox_owned.py +130 -0
  69. ksadk/a2a/task_store.py +37 -0
  70. ksadk/a2a/tool_activity.py +176 -0
  71. ksadk/a2a/workload_tokens.py +134 -0
  72. ksadk/api/client.py +32 -79
  73. ksadk/api/sse_stream.py +96 -0
  74. ksadk/builders/code_builder.py +83 -106
  75. ksadk/builders/container_builder.py +11 -29
  76. ksadk/builders/framework_requirements.py +2 -0
  77. ksadk/builders/managed_runtime_builder.py +12 -0
  78. ksadk/builders/source_provenance.py +87 -0
  79. ksadk/cli/cmd_a2a.py +43 -0
  80. ksadk/cli/cmd_build.py +9 -0
  81. ksadk/cli/cmd_deploy.py +27 -2
  82. ksadk/cli/cmd_invoke.py +45 -92
  83. ksadk/cli/cmd_studio.py +5 -1
  84. ksadk/cli/cmd_web.py +2 -0
  85. ksadk/cli/hosted_invoke.py +206 -0
  86. ksadk/cli/invoke_content.py +60 -0
  87. ksadk/cli/runtime_bootstrap.py +27 -5
  88. ksadk/codex/_expert_request_reader.py +48 -0
  89. ksadk/codex/a2a_tools.py +140 -0
  90. ksadk/codex/async_approval.py +169 -0
  91. ksadk/codex/async_client.py +938 -0
  92. ksadk/codex/async_proxy.py +216 -0
  93. ksadk/codex/base_runtime.py +25 -0
  94. ksadk/codex/client.py +3 -1048
  95. ksadk/codex/client_payloads.py +85 -0
  96. ksadk/codex/rollout_checkpoint.py +264 -0
  97. ksadk/codex/runtime.py +290 -54
  98. ksadk/common/auth.py +2 -2
  99. ksadk/common/cloud_headers.py +36 -0
  100. ksadk/common/diagnostics.py +34 -0
  101. ksadk/common/kop_client.py +2 -1
  102. ksadk/configs/env_registry.py +106 -127
  103. ksadk/configs/env_registry_a2a.py +173 -0
  104. ksadk/configs/env_registry_studio.py +53 -5
  105. ksadk/configs/global_config.py +1 -0
  106. ksadk/configs/settings.py +6 -0
  107. ksadk/context_engine/assembler.py +9 -0
  108. ksadk/context_engine/contributors.py +80 -17
  109. ksadk/context_engine/instruction_authority.py +18 -0
  110. ksadk/conversations/attachments.py +53 -15
  111. ksadk/conversations/contracts.py +28 -9
  112. ksadk/conversations/message_projection.py +30 -125
  113. ksadk/conversations/message_projection_blocks.py +137 -0
  114. ksadk/conversations/model_context.py +11 -3
  115. ksadk/conversations/projector.py +63 -0
  116. ksadk/conversations/runtime_compaction.py +7 -2
  117. ksadk/conversations/runtime_input.py +16 -4
  118. ksadk/conversations/runtime_payloads.py +4 -0
  119. ksadk/conversations/runtime_persistence.py +192 -24
  120. ksadk/conversations/runtime_preparation.py +85 -6
  121. ksadk/conversations/runtime_projection.py +217 -0
  122. ksadk/conversations/runtime_resume.py +141 -70
  123. ksadk/conversations/tool_receipt_resume.py +387 -0
  124. ksadk/conversations/tool_receipts.py +32 -0
  125. ksadk/deployment/env_forward.py +5 -0
  126. ksadk/deployment/manager.py +15 -6
  127. ksadk/deployment/providers/serverless.py +76 -136
  128. ksadk/deployment/providers/serverless_payloads.py +122 -0
  129. ksadk/evaluation/agent_eval_client.py +2 -1
  130. ksadk/evaluation/contracts.py +78 -3
  131. ksadk/evaluation/evaluators.py +166 -1
  132. ksadk/evaluation/evidence.py +271 -4
  133. ksadk/evaluation/local_adapter.py +76 -12
  134. ksadk/evaluation/studio_build_adapter.py +73 -9
  135. ksadk/events/adapters/_a2a_checkpoint.py +151 -0
  136. ksadk/events/adapters/_a2a_snapshot.py +18 -14
  137. ksadk/events/adapters/_a2a_support.py +15 -3
  138. ksadk/events/adapters/_a2a_tool_activity.py +123 -0
  139. ksadk/events/adapters/_codex_errors.py +49 -0
  140. ksadk/events/adapters/_langgraph_support.py +12 -1
  141. ksadk/events/adapters/a2a.py +54 -26
  142. ksadk/events/adapters/adk.py +188 -30
  143. ksadk/events/adapters/codex.py +33 -7
  144. ksadk/events/adapters/langgraph.py +16 -6
  145. ksadk/events/canonical.py +5 -0
  146. ksadk/events/canonical_store.py +200 -4
  147. ksadk/events/reducer.py +82 -0
  148. ksadk/events/run_authority.py +176 -0
  149. ksadk/harness/__init__.py +4 -0
  150. ksadk/harness/artifact_adapters/__init__.py +1 -0
  151. ksadk/harness/artifact_adapters/native_page_budget.py +172 -0
  152. ksadk/harness/artifact_adapters/native_search.py +249 -0
  153. ksadk/harness/artifact_adapters/native_search_budget.py +134 -0
  154. ksadk/harness/artifact_adapters/native_store.py +115 -0
  155. ksadk/harness/artifact_adapters/native_tool.py +222 -0
  156. ksadk/harness/artifact_store.py +26 -9
  157. ksadk/harness/browser_adapters/__init__.py +6 -0
  158. ksadk/harness/browser_adapters/native_browser_tool.py +92 -0
  159. ksadk/harness/browser_adapters/native_dom_snapshot.py +187 -0
  160. ksadk/harness/browser_adapters/native_playwright.py +953 -0
  161. ksadk/harness/browser_adapters/native_vision.py +295 -0
  162. ksadk/harness/capability_adapters/__init__.py +1 -0
  163. ksadk/harness/capability_adapters/native_dsh.py +289 -0
  164. ksadk/harness/capability_runtime.py +104 -9
  165. ksadk/harness/compaction_record.py +31 -0
  166. ksadk/harness/compiler.py +3 -3
  167. ksadk/harness/config.py +28 -5
  168. ksadk/harness/conformance/contract.py +9 -11
  169. ksadk/harness/context_engine.py +18 -33
  170. ksadk/harness/context_sections.py +397 -0
  171. ksadk/harness/diagnostic_adapters/__init__.py +1 -0
  172. ksadk/harness/diagnostic_adapters/contracts.py +70 -0
  173. ksadk/harness/diagnostic_adapters/lsp_rpc.py +210 -0
  174. ksadk/harness/diagnostic_adapters/native_lsp.py +286 -0
  175. ksadk/harness/engine/completion_guard.py +16 -1
  176. ksadk/harness/engine/context_pipeline.py +864 -92
  177. ksadk/harness/engine/graph_builder.py +123 -630
  178. ksadk/harness/engine/hooked_reasoner.py +380 -0
  179. ksadk/harness/engine/langgraph.py +126 -8
  180. ksadk/harness/engine/mcp_disclosure.py +65 -114
  181. ksadk/harness/engine/phases/__init__.py +6 -0
  182. ksadk/harness/engine/phases/context.py +48 -0
  183. ksadk/harness/engine/phases/interaction.py +31 -0
  184. ksadk/harness/engine/phases/reason.py +552 -0
  185. ksadk/harness/engine/phases/tools.py +638 -0
  186. ksadk/harness/engine/policy_runtime.py +21 -10
  187. ksadk/harness/engine/postgres_checkpointer.py +325 -2
  188. ksadk/harness/engine/run_control_bridge.py +21 -1
  189. ksadk/harness/engine/run_types.py +10 -0
  190. ksadk/harness/engine/skill_disclosure.py +98 -12
  191. ksadk/harness/engine/steering.py +177 -0
  192. ksadk/harness/engine/subagents.py +18 -1
  193. ksadk/harness/engine/tool_dispatch.py +112 -7
  194. ksadk/harness/events.py +39 -2
  195. ksadk/harness/execution_policy.py +10 -0
  196. ksadk/harness/hooks.py +259 -0
  197. ksadk/harness/loop/reason.py +281 -36
  198. ksadk/harness/loop/tools.py +157 -12
  199. ksadk/harness/managed_runtime.py +254 -94
  200. ksadk/harness/mcp_disclosure_contract.py +85 -0
  201. ksadk/harness/mcp_result_policy.py +44 -0
  202. ksadk/harness/mcp_runtime.py +33 -0
  203. ksadk/harness/micro_compact.py +69 -0
  204. ksadk/harness/model_adapters/__init__.py +1 -0
  205. ksadk/harness/model_adapters/native_mcp_media.py +100 -0
  206. ksadk/harness/model_adapters/native_mcp_result.py +36 -0
  207. ksadk/harness/model_adapters/native_openai.py +703 -0
  208. ksadk/harness/model_capability.py +223 -8
  209. ksadk/harness/model_provider.py +214 -4
  210. ksadk/harness/multimodal.py +57 -0
  211. ksadk/harness/native/__init__.py +1 -0
  212. ksadk/harness/native/activation_contract.py +25 -0
  213. ksadk/harness/native/activation_recovery.py +29 -0
  214. ksadk/harness/native/adapters.py +291 -0
  215. ksadk/harness/native/artifact_contract.py +14 -0
  216. ksadk/harness/native/artifact_partial_read_capacity.py +171 -0
  217. ksadk/harness/native/artifact_read_capacity.py +182 -0
  218. ksadk/harness/native/artifact_read_contract.py +27 -0
  219. ksadk/harness/native/artifact_runtime.py +408 -0
  220. ksadk/harness/native/artifact_search_capacity.py +206 -0
  221. ksadk/harness/native/artifact_search_contract.py +40 -0
  222. ksadk/harness/native/artifact_single_read_capacity.py +170 -0
  223. ksadk/harness/native/browser_contract.py +229 -0
  224. ksadk/harness/native/browser_recovery.py +183 -0
  225. ksadk/harness/native/capabilities.py +204 -0
  226. ksadk/harness/native/child_approval.py +60 -0
  227. ksadk/harness/native/child_budget.py +136 -0
  228. ksadk/harness/native/child_cancellation.py +80 -0
  229. ksadk/harness/native/child_input.py +98 -0
  230. ksadk/harness/native/child_input_runtime.py +59 -0
  231. ksadk/harness/native/child_interruption.py +81 -0
  232. ksadk/harness/native/child_lifecycle.py +246 -0
  233. ksadk/harness/native/child_lifecycle_contract.py +91 -0
  234. ksadk/harness/native/child_notifications.py +75 -0
  235. ksadk/harness/native/child_promotion.py +66 -0
  236. ksadk/harness/native/command_runtime.py +99 -0
  237. ksadk/harness/native/completion.py +302 -0
  238. ksadk/harness/native/completion_text.py +116 -0
  239. ksadk/harness/native/context.py +358 -0
  240. ksadk/harness/native/context_artifact_page.py +75 -0
  241. ksadk/harness/native/context_compaction_projection.py +131 -0
  242. ksadk/harness/native/context_contributions.py +320 -0
  243. ksadk/harness/native/context_contributor_contract.py +133 -0
  244. ksadk/harness/native/context_driver.py +820 -0
  245. ksadk/harness/native/context_fresh_tools.py +49 -0
  246. ksadk/harness/native/context_history.py +272 -0
  247. ksadk/harness/native/context_microcompact.py +61 -0
  248. ksadk/harness/native/context_partial_summary.py +58 -0
  249. ksadk/harness/native/context_partition.py +492 -0
  250. ksadk/harness/native/context_pruning.py +275 -0
  251. ksadk/harness/native/context_reduction.py +60 -0
  252. ksadk/harness/native/context_replay.py +148 -0
  253. ksadk/harness/native/context_request_projection.py +526 -0
  254. ksadk/harness/native/context_runtime.py +976 -0
  255. ksadk/harness/native/context_runtime_contracts.py +409 -0
  256. ksadk/harness/native/context_search.py +112 -0
  257. ksadk/harness/native/context_source_fragments.py +188 -0
  258. ksadk/harness/native/context_source_progress.py +119 -0
  259. ksadk/harness/native/context_summary_planning.py +788 -0
  260. ksadk/harness/native/context_summary_recovery.py +105 -0
  261. ksadk/harness/native/delivery_review.py +331 -0
  262. ksadk/harness/native/delivery_review_contract.py +54 -0
  263. ksadk/harness/native/effect_admission.py +82 -0
  264. ksadk/harness/native/effect_control.py +318 -0
  265. ksadk/harness/native/effect_receipts.py +729 -0
  266. ksadk/harness/native/effect_runtime.py +303 -0
  267. ksadk/harness/native/effective_configuration.py +28 -0
  268. ksadk/harness/native/engine.py +945 -0
  269. ksadk/harness/native/final_output.py +34 -0
  270. ksadk/harness/native/final_submission.py +58 -0
  271. ksadk/harness/native/finalization_workspace.py +96 -0
  272. ksadk/harness/native/fork.py +151 -0
  273. ksadk/harness/native/guidance.py +91 -0
  274. ksadk/harness/native/history.py +381 -0
  275. ksadk/harness/native/hook_executor.py +205 -0
  276. ksadk/harness/native/hook_runtime_contract.py +282 -0
  277. ksadk/harness/native/interaction_observation.py +117 -0
  278. ksadk/harness/native/lease.py +103 -0
  279. ksadk/harness/native/machine.py +974 -0
  280. ksadk/harness/native/mcp_result_governance.py +156 -0
  281. ksadk/harness/native/model.py +570 -0
  282. ksadk/harness/native/model_feedback.py +63 -0
  283. ksadk/harness/native/model_input.py +30 -0
  284. ksadk/harness/native/model_recovery_contract.py +35 -0
  285. ksadk/harness/native/model_replay.py +128 -0
  286. ksadk/harness/native/model_request.py +133 -0
  287. ksadk/harness/native/model_runtime.py +196 -0
  288. ksadk/harness/native/model_takeover.py +419 -0
  289. ksadk/harness/native/model_tool_batch.py +40 -0
  290. ksadk/harness/native/observed_progress.py +46 -0
  291. ksadk/harness/native/operator_guidance.py +201 -0
  292. ksadk/harness/native/output_contract.py +80 -0
  293. ksadk/harness/native/output_recovery.py +24 -0
  294. ksadk/harness/native/ports.py +749 -0
  295. ksadk/harness/native/precompact_hook_runtime.py +171 -0
  296. ksadk/harness/native/replay_context.py +149 -0
  297. ksadk/harness/native/request_media.py +112 -0
  298. ksadk/harness/native/restore_contract.py +16 -0
  299. ksadk/harness/native/run_clock.py +120 -0
  300. ksadk/harness/native/state.py +436 -0
  301. ksadk/harness/native/steering.py +170 -0
  302. ksadk/harness/native/stop_hook_runtime.py +151 -0
  303. ksadk/harness/native/studio_admission.py +29 -0
  304. ksadk/harness/native/subagents.py +86 -0
  305. ksadk/harness/native/task_policy.py +99 -0
  306. ksadk/harness/native/task_progress.py +86 -0
  307. ksadk/harness/native/terminal_verification.py +43 -0
  308. ksadk/harness/native/tool_argument_feedback.py +178 -0
  309. ksadk/harness/native/tool_budget.py +253 -0
  310. ksadk/harness/native/tool_error_streak.py +89 -0
  311. ksadk/harness/native/tool_hook_runtime.py +343 -0
  312. ksadk/harness/native/tool_input_validation.py +58 -0
  313. ksadk/harness/native/tool_interruption.py +96 -0
  314. ksadk/harness/native/tool_observation.py +259 -0
  315. ksadk/harness/native/tool_progress.py +223 -0
  316. ksadk/harness/native/tool_recovery.py +25 -0
  317. ksadk/harness/native/tool_scheduling.py +33 -0
  318. ksadk/harness/native/tool_schema.py +126 -0
  319. ksadk/harness/native/transitions.py +151 -0
  320. ksadk/harness/native/turn_control.py +98 -0
  321. ksadk/harness/native/user_document.py +98 -0
  322. ksadk/harness/native/user_document_capture.py +49 -0
  323. ksadk/harness/native/user_input.py +87 -0
  324. ksadk/harness/native/verification.py +432 -0
  325. ksadk/harness/native/verification_binding.py +40 -0
  326. ksadk/harness/native/verification_runtime.py +233 -0
  327. ksadk/harness/native/verification_workspace.py +67 -0
  328. ksadk/harness/native_driver_failure.py +123 -0
  329. ksadk/harness/native_facade.py +977 -0
  330. ksadk/harness/native_factory.py +244 -0
  331. ksadk/harness/native_projection.py +503 -0
  332. ksadk/harness/native_runtime.py +621 -0
  333. ksadk/harness/native_shadow.py +250 -0
  334. ksadk/harness/native_shadow_inputs.py +146 -0
  335. ksadk/harness/progress_adapters/__init__.py +5 -0
  336. ksadk/harness/progress_adapters/native_todo.py +75 -0
  337. ksadk/harness/prompt_cache.py +65 -3
  338. ksadk/harness/public_activity.py +59 -0
  339. ksadk/harness/public_output.py +30 -0
  340. ksadk/harness/public_summary.py +36 -0
  341. ksadk/harness/reasoner.py +331 -22
  342. ksadk/harness/rpc.py +200 -0
  343. ksadk/harness/run_control.py +107 -2
  344. ksadk/harness/runtime.py +11 -2
  345. ksadk/harness/runtime_capabilities.py +71 -1
  346. ksadk/harness/sandbox_backend.py +203 -0
  347. ksadk/harness/sdk.py +153 -0
  348. ksadk/harness/session_store.py +370 -24
  349. ksadk/harness/skill_adapters/__init__.py +1 -0
  350. ksadk/harness/skill_adapters/native_bundle.py +148 -0
  351. ksadk/harness/skill_adapters/native_disclosure.py +306 -0
  352. ksadk/harness/skill_intent.py +47 -0
  353. ksadk/harness/skill_runtime.py +74 -16
  354. ksadk/harness/spec.py +20 -10
  355. ksadk/harness/state.py +2 -0
  356. ksadk/harness/stores/__init__.py +14 -0
  357. ksadk/harness/stores/native_command_settlement.py +65 -0
  358. ksadk/harness/stores/native_contract.py +311 -0
  359. ksadk/harness/stores/native_memory.py +326 -0
  360. ksadk/harness/stores/native_memory_archive.py +70 -0
  361. ksadk/harness/stores/native_migration_cli.py +91 -0
  362. ksadk/harness/stores/native_outbox.py +56 -0
  363. ksadk/harness/stores/native_sqlite.py +782 -0
  364. ksadk/harness/stores/native_sqlite_audit.py +29 -0
  365. ksadk/harness/stores/native_sqlite_migration.py +252 -0
  366. ksadk/harness/subagent.py +12 -2
  367. ksadk/harness/subagent_adapters/checkpoint_recovery.py +120 -0
  368. ksadk/harness/subagent_adapters/native_background_child.py +803 -0
  369. ksadk/harness/subagent_adapters/native_child.py +819 -0
  370. ksadk/harness/subagent_adapters/native_child_approval.py +128 -0
  371. ksadk/harness/subagent_adapters/native_child_continuation.py +51 -0
  372. ksadk/harness/subagent_adapters/native_child_result.py +392 -0
  373. ksadk/harness/subagent_adapters/prepared_recovery.py +120 -0
  374. ksadk/harness/tool_display.py +75 -0
  375. ksadk/harness/tool_display_contract.py +134 -0
  376. ksadk/harness/tool_output.py +141 -0
  377. ksadk/harness/tool_policy.py +3 -0
  378. ksadk/harness/tool_result_policy.py +216 -0
  379. ksadk/harness/tools.py +52 -0
  380. ksadk/harness/workspace_adapters/__init__.py +6 -0
  381. ksadk/harness/workspace_adapters/native_directory.py +180 -0
  382. ksadk/harness/workspace_adapters/native_git.py +208 -0
  383. ksadk/harness/workspace_adapters/native_isolation.py +350 -0
  384. ksadk/interaction/providers/langgraph.py +8 -1
  385. ksadk/kernel/bootstrap.py +144 -160
  386. ksadk/kernel/contract_fingerprints.py +45 -1
  387. ksadk/kernel/contracts.py +25 -0
  388. ksadk/kernel/control.py +153 -33
  389. ksadk/kernel/execution_grants.py +209 -2
  390. ksadk/kernel/execution_grants_memory.py +127 -8
  391. ksadk/kernel/execution_grants_postgres.py +188 -10
  392. ksadk/kernel/execution_grants_sqlite.py +235 -9
  393. ksadk/kernel/execution_host_ingress.py +1071 -0
  394. ksadk/kernel/history_projection.py +120 -0
  395. ksadk/kernel/ingress.py +117 -204
  396. ksadk/kernel/ingress_bootstrap.py +268 -0
  397. ksadk/kernel/legacy_history.py +179 -0
  398. ksadk/kernel/memory_store.py +38 -48
  399. ksadk/kernel/memory_store_projection.py +63 -0
  400. ksadk/kernel/postgres_event_log.py +181 -0
  401. ksadk/kernel/postgres_store.py +167 -198
  402. ksadk/kernel/readiness.py +125 -0
  403. ksadk/kernel/recovery.py +89 -3
  404. ksadk/kernel/recovery_projection.py +124 -0
  405. ksadk/kernel/runtime_checkpoint.py +34 -0
  406. ksadk/kernel/sql/001_agent_kernel.sql +5 -0
  407. ksadk/kernel/sqlite_schema.py +100 -0
  408. ksadk/kernel/sqlite_store.py +147 -216
  409. ksadk/kernel/store.py +47 -15
  410. ksadk/kernel/teams_artifact_tools.py +392 -0
  411. ksadk/kernel/teams_effects.py +851 -0
  412. ksadk/kernel/teams_execution_context.py +408 -0
  413. ksadk/kernel/teams_host_http.py +237 -0
  414. ksadk/kernel/teams_material_transport.py +245 -0
  415. ksadk/kernel/teams_materials.py +318 -0
  416. ksadk/kernel/teams_runtime_bootstrap.py +604 -0
  417. ksadk/kernel/teams_tool_runtime.py +273 -0
  418. ksadk/kernel/teams_workspace.py +259 -0
  419. ksadk/kernel/worker.py +323 -332
  420. ksadk/kernel/worker_controls.py +454 -0
  421. ksadk/kernel/worker_identity.py +27 -0
  422. ksadk/kernel/worker_interactions.py +197 -0
  423. ksadk/knowledge_base/client.py +15 -1
  424. ksadk/managed_runtime.py +29 -2
  425. ksadk/memory/adk/backends/http_ltm_backend.py +2 -1
  426. ksadk/memory/adk/backends/sdk_ltm_backend.py +15 -1
  427. ksadk/memory/adk/bounded_database_session_service.py +232 -0
  428. ksadk/memory/adk/resilient_session_service.py +115 -15
  429. ksadk/memory/adk/short_term_memory.py +8 -9
  430. ksadk/memory/extraction.py +120 -7
  431. ksadk/memory/providers/local_candidates.py +183 -0
  432. ksadk/memory/providers/local_sqlite.py +252 -78
  433. ksadk/memory/resolved_policy.py +12 -7
  434. ksadk/model_gateway/__init__.py +29 -0
  435. ksadk/model_gateway/client.py +253 -0
  436. ksadk/model_gateway/events.py +113 -0
  437. ksadk/model_gateway/matrix.py +297 -0
  438. ksadk/model_proxy/compat.py +670 -0
  439. ksadk/model_proxy/server.py +10 -7
  440. ksadk/model_proxy/transform.py +37 -9
  441. ksadk/plugins/bridges/dsh.py +18 -20
  442. ksadk/plugins/bridges/dsh_profile_manifest.py +36 -0
  443. ksadk/plugins/builtin_resources.py +199 -0
  444. ksadk/plugins/builtins.py +380 -186
  445. ksadk/plugins/context_contributor.py +15 -4
  446. ksadk/plugins/dsh_dependency_policy.py +41 -0
  447. ksadk/plugins/dsh_toolchain.py +24 -35
  448. ksadk/plugins/execution_host.py +8 -0
  449. ksadk/plugins/host.py +73 -5
  450. ksadk/plugins/kernel_adapter.py +44 -1
  451. ksadk/plugins/memory_provider.py +180 -0
  452. ksadk/plugins/providers/_process_group.py +50 -0
  453. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +24 -2
  454. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +1 -1
  455. ksadk/plugins/providers/bundles/dsh-memory/package.json +1 -1
  456. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +1 -1
  457. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +1 -1
  458. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +1 -1
  459. ksadk/plugins/providers/codex.py +42 -38
  460. ksadk/plugins/providers/codex_native.py +20 -0
  461. ksadk/plugins/providers/codex_skills.py +46 -0
  462. ksadk/plugins/providers/dsh_capabilities.py +16 -171
  463. ksadk/plugins/providers/dsh_connector_lease.py +225 -0
  464. ksadk/plugins/providers/dsh_mcp.py +163 -1
  465. ksadk/plugins/providers/harness.py +247 -34
  466. ksadk/plugins/providers/harness_context.py +61 -0
  467. ksadk/plugins/providers/harness_contributions.py +241 -0
  468. ksadk/plugins/providers/harness_delegation.py +91 -14
  469. ksadk/plugins/providers/harness_hooks.py +121 -0
  470. ksadk/plugins/providers/harness_managed.py +269 -175
  471. ksadk/plugins/providers/harness_tools.py +165 -36
  472. ksadk/plugins/providers/legacy_catalog.py +1 -1
  473. ksadk/plugins/providers/mcp_projection.py +100 -3
  474. ksadk/plugins/providers/platform_resources.py +16 -6
  475. ksadk/plugins/teams/application.py +3 -143
  476. ksadk/plugins/teams/build_artifacts.py +460 -0
  477. ksadk/plugins/teams/cloud_contract_fingerprints.py +22 -0
  478. ksadk/plugins/teams/cloud_contracts.py +928 -0
  479. ksadk/plugins/teams/cloud_permits.py +250 -0
  480. ksadk/plugins/teams/domain.py +201 -148
  481. ksadk/plugins/teams/effect_contracts.py +255 -0
  482. ksadk/plugins/teams/execution_projection.py +255 -0
  483. ksadk/plugins/teams/leader_decisions.py +106 -0
  484. ksadk/plugins/teams/postgres_store.py +299 -85
  485. ksadk/plugins/teams/release_contracts.py +60 -0
  486. ksadk/plugins/teams/runtime.py +116 -40
  487. ksadk/plugins/teams/store.py +214 -6
  488. ksadk/plugins/teams/task_decisions.py +21 -8
  489. ksadk/plugins/teams/tool_service.py +152 -0
  490. ksadk/plugins/teams/transport.py +8 -3
  491. ksadk/resource_runtime/skill_runtime.py +3 -0
  492. ksadk/resource_runtime/socket_server.py +11 -0
  493. ksadk/resource_runtime/worker.py +28 -4
  494. ksadk/runners/_adk_a2a_stream.py +122 -0
  495. ksadk/runners/_adk_canonical_stream.py +474 -0
  496. ksadk/runners/_langgraph_canonical_streams.py +527 -0
  497. ksadk/runners/_langgraph_runner_streams.py +6 -400
  498. ksadk/runners/_langgraph_tool_projection.py +86 -0
  499. ksadk/runners/_langgraph_tools_transformer.py +27 -0
  500. ksadk/runners/adk_runner.py +195 -290
  501. ksadk/runners/base_runner.py +6 -5
  502. ksadk/runners/langgraph_runner.py +82 -86
  503. ksadk/runners/utils/loader.py +28 -14
  504. ksadk/runtime/_runner_adapter/a2ui_surface.py +145 -0
  505. ksadk/runtime/_runner_adapter/gateway_approvals.py +93 -0
  506. ksadk/runtime/_runner_adapter/stream_mapping.py +83 -128
  507. ksadk/runtime/adapter.py +40 -3
  508. ksadk/runtime/conversation_execution.py +4 -2
  509. ksadk/runtime/executor.py +97 -7
  510. ksadk/runtime/factory.py +13 -6
  511. ksadk/runtime/framework_adapters.py +184 -10
  512. ksadk/runtime/hosted_finalizer.py +4 -6
  513. ksadk/runtime/launch.py +2 -0
  514. ksadk/runtime/runner_adapter.py +123 -13
  515. ksadk/runtime_context.py +2 -0
  516. ksadk/sandbox/backends/e2b.py +30 -4
  517. ksadk/sandbox/backends/local_process.py +10 -0
  518. ksadk/sandbox/e2b_connection.py +9 -1
  519. ksadk/sandbox/local_controls.py +32 -2
  520. ksadk/sandbox/local_launcher.py +34 -0
  521. ksadk/server/factory.py +178 -25
  522. ksadk/server/history_deadline.py +158 -0
  523. ksadk/server/history_page_cache.py +129 -0
  524. ksadk/server/routes/checkpoint_audit.py +88 -0
  525. ksadk/server/routes/checkpoint_listing.py +294 -0
  526. ksadk/server/routes/checkpoint_resolution.py +73 -20
  527. ksadk/server/routes/control.py +51 -3
  528. ksadk/server/routes/display_projection.py +154 -0
  529. ksadk/server/routes/kernel_ingress.py +17 -2
  530. ksadk/server/routes/misc.py +102 -12
  531. ksadk/server/routes/models.py +25 -1
  532. ksadk/server/routes/openai_compat.py +6 -0
  533. ksadk/server/routes/projection.py +159 -216
  534. ksadk/server/routes/run.py +6 -2
  535. ksadk/server/routes/sessions.py +301 -342
  536. ksadk/server/routes/streaming.py +68 -15
  537. ksadk/server/routes/tool_receipt_claim_routes.py +107 -0
  538. ksadk/server/routes/workspace.py +5 -2
  539. ksadk/server/static/assets/{ArtifactsPanel-C1YoaKhx.js → ArtifactsPanel-CILaW-fC.js} +1 -1
  540. ksadk/server/static/assets/{CodeBlock-DHuAWfr5.js → CodeBlock-BVrNVtJC.js} +1 -1
  541. ksadk/server/static/assets/{MathMessageMarkdown-cvdrBwYr.js → MathMessageMarkdown-Dp7c4wWD.js} +1 -1
  542. ksadk/server/static/assets/{MermaidBlock-DeBkbJvI.js → MermaidBlock-Dxop8Rd7.js} +6 -6
  543. ksadk/server/static/assets/{NativeTerminalPanel-oJj44_sV.js → NativeTerminalPanel-Cjjz8B30.js} +1 -1
  544. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-Dhfv25o2.js → abnfDiagram-VCTEODGH-ckWDmOzw.js} +1 -1
  545. ksadk/server/static/assets/{arc-C35w-pn1.js → arc-DqxJede-.js} +1 -1
  546. ksadk/server/static/assets/architecture-7GRP2DOG-pn_DuLy6.js +1 -0
  547. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-FoMY_u6D.js → architectureDiagram-5GKGNRK7-SEQA4bVi.js} +1 -1
  548. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-zD4Rt7oE.js → blockDiagram-NRAW4CY4-pM0B-6NJ.js} +1 -1
  549. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BCtGGkhN.js → c4Diagram-UCG6FXSJ-m2tuCNVq.js} +1 -1
  550. ksadk/server/static/assets/channel-fySsnkft.js +1 -0
  551. ksadk/server/static/assets/chunk-2Q5K7J3B-BheGxKRQ.js +1 -0
  552. ksadk/server/static/assets/{chunk-5VM5RSS4-C2Ms13_k.js → chunk-5VM5RSS4-GJHDr9Ww.js} +1 -1
  553. ksadk/server/static/assets/{chunk-F27PBJKO-BoTj-qgx.js → chunk-F27PBJKO-CbAN45AV.js} +1 -1
  554. ksadk/server/static/assets/{chunk-G27WJ6UU-DOMyyjHH.js → chunk-G27WJ6UU-D5ngbbzF.js} +1 -1
  555. ksadk/server/static/assets/{chunk-JWPE2WC7-DbJJqDli.js → chunk-JWPE2WC7-Cc5IwuYC.js} +1 -1
  556. ksadk/server/static/assets/{chunk-LCL6LL3I-CLuRCt_W.js → chunk-LCL6LL3I-CprgDDdJ.js} +1 -1
  557. ksadk/server/static/assets/{chunk-POPQ4Y6H-D0Dz847e.js → chunk-POPQ4Y6H-CDZhSy82.js} +1 -1
  558. ksadk/server/static/assets/{chunk-RHFEMEQ7-BWSRzEcd.js → chunk-RHFEMEQ7-CZchUNro.js} +1 -1
  559. ksadk/server/static/assets/{chunk-SVP7TREG-CPoHqkCY.js → chunk-SVP7TREG-BVruqk6T.js} +1 -1
  560. ksadk/server/static/assets/{chunk-XXDRQBXY-Bx1jS-X-.js → chunk-XXDRQBXY-4ld9SxPN.js} +1 -1
  561. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DSfLtNYm.js +1 -0
  562. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DSfLtNYm.js +1 -0
  563. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-LzyWm4m0.js → cose-bilkent-JH36ORCC-Dmyyk_Vp.js} +1 -1
  564. ksadk/server/static/assets/cynefin-OW5HDTMX-PFWIGtvA.js +1 -0
  565. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-BlW_bHED.js → cynefinDiagram-5FMLGOSQ-BIyq3EJb.js} +1 -1
  566. ksadk/server/static/assets/{dagre-3AP2YEHR-Bu_S86_i.js → dagre-3AP2YEHR-eBw08Qdk.js} +1 -1
  567. ksadk/server/static/assets/{dagre-B7nCawed.js → dagre-DfvnEf45.js} +1 -1
  568. ksadk/server/static/assets/{diagram-S7CK7UJ4-W_Zow2Km.js → diagram-S7CK7UJ4-CUSrE3Mg.js} +1 -1
  569. ksadk/server/static/assets/{diagram-UQ7AKVKN-CLIKAHON.js → diagram-UQ7AKVKN-Dq5Zw2gy.js} +1 -1
  570. ksadk/server/static/assets/{diagram-VSXAHHWV-Dv6_QAlN.js → diagram-VSXAHHWV-DyUHfNwT.js} +1 -1
  571. ksadk/server/static/assets/{diagram-VX7I27RA-BWAWRDtZ.js → diagram-VX7I27RA-CREmM89O.js} +1 -1
  572. ksadk/server/static/assets/{diagram-Z3DM3KII-XA_rWMss.js → diagram-Z3DM3KII-Dw9zhHUK.js} +1 -1
  573. ksadk/server/static/assets/{dist-CGt_UGeO.js → dist-0uJ4tdx6.js} +1 -1
  574. ksadk/server/static/assets/{dist-C0J5_3qM.js → dist-AEv-vXf-.js} +1 -1
  575. ksadk/server/static/assets/{dist-CIpWk_5f.js → dist-B49GzZDb.js} +1 -1
  576. ksadk/server/static/assets/{dist-B3bA05-e.js → dist-B8Myiet9.js} +1 -1
  577. ksadk/server/static/assets/{dist-DWfdmz9s.js → dist-BBsYarrI.js} +1 -1
  578. ksadk/server/static/assets/{dist-BLpRy_Yx.js → dist-BQMrUwdI.js} +1 -1
  579. ksadk/server/static/assets/{dist-CIRMvUM4.js → dist-BX_-FENW.js} +1 -1
  580. ksadk/server/static/assets/{dist-BdNFAney.js → dist-CD4L6ymH.js} +1 -1
  581. ksadk/server/static/assets/{dist-n3n6t_FO.js → dist-CHpW1BHj.js} +1 -1
  582. ksadk/server/static/assets/{dist-DppE_r-D.js → dist-CVPau3tn.js} +1 -1
  583. ksadk/server/static/assets/{dist-qe8xjesy.js → dist-C_qdxcSH.js} +1 -1
  584. ksadk/server/static/assets/{dist-2vL2sAdF.js → dist-Co68Apq4.js} +1 -1
  585. ksadk/server/static/assets/{dist-1nXCdsej.js → dist-Cp2PaOMY.js} +1 -1
  586. ksadk/server/static/assets/{dist-DNKuMzWc.js → dist-CuR5Bgme.js} +1 -1
  587. ksadk/server/static/assets/{dist-t6MzE0jU.js → dist-DDSyLEOX.js} +1 -1
  588. ksadk/server/static/assets/{dist-CPyieXEf.js → dist-DUxO0R99.js} +1 -1
  589. ksadk/server/static/assets/{dist-DyG6Ya-z.js → dist-QzbGrED_.js} +1 -1
  590. ksadk/server/static/assets/{dist-0X_j2Rcc.js → dist-bupkyEBZ.js} +1 -1
  591. ksadk/server/static/assets/{dist-mqD5TZup.js → dist-cxTGfdqx.js} +1 -1
  592. ksadk/server/static/assets/{dist-M-SrdhhZ.js → dist-hL5p1til.js} +1 -1
  593. ksadk/server/static/assets/{dist-D-92S-Fd.js → dist-lOy23y43.js} +1 -1
  594. ksadk/server/static/assets/{dist-BO_UwatH.js → dist-pq-nD33R.js} +1 -1
  595. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-BfCzF1Xi.js → ebnfDiagram-PWID7BFC-BS5LdNoR.js} +1 -1
  596. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-Dpz9_0zn.js → erDiagram-SSCWMZ5O-Bv1QtiY-.js} +1 -1
  597. ksadk/server/static/assets/eventmodeling-NTZA5JFV-DsM4upQX.js +1 -0
  598. ksadk/server/static/assets/flowDiagram-A5DVABFB-D5NA16k9.js +1 -0
  599. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DDaG1f4_.js → ganttDiagram-EL5Y4UJY-musi-e0G.js} +1 -1
  600. ksadk/server/static/assets/gitGraph-4MIJSDKK-DUCVz-ih.js +1 -0
  601. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DcxzRwYC.js → gitGraphDiagram-WWUBYQGX-DH37EGkG.js} +1 -1
  602. ksadk/server/static/assets/index-CZdkAvsv.js +244 -0
  603. ksadk/server/static/assets/index-CvXdHgF3.css +2 -0
  604. ksadk/server/static/assets/info-A6RAGUB7-rw0ZNHZp.js +1 -0
  605. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CYMdn6lQ.js → infoDiagram-RXCK75RN-C1kEtv2y.js} +1 -1
  606. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CLHFAD6c.js → ishikawaDiagram-5VMMS53U-BCNPyMka.js} +1 -1
  607. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-BHSKQGAl.js → journeyDiagram-EYS64GPL--cDbKnjP.js} +1 -1
  608. ksadk/server/static/assets/{kanban-definition-3QL26DDD-D5W3tjTT.js → kanban-definition-3QL26DDD-R1rAVw2f.js} +1 -1
  609. ksadk/server/static/assets/{katex-mtjOi4KM.js → katex-BT-X-V7U.js} +1 -1
  610. ksadk/server/static/assets/{linear-BETqsxE_.js → linear-DTR631iG.js} +1 -1
  611. ksadk/server/static/assets/{mermaid-parser.core-DPWrvs90.js → mermaid-parser.core-DfFzJhX8.js} +2 -2
  612. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-CJG2mfBP.js → mindmap-definition-FBJOCRG2-D4by_rmk.js} +1 -1
  613. ksadk/server/static/assets/packet-AYTQ26CC-Ca4Hvki9.js +1 -0
  614. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-GjAPNaqn.js → pegDiagram-XKGWAZYB-xWXPEh0c.js} +1 -1
  615. ksadk/server/static/assets/pie-WAS4IAKB-hwiz6fbw.js +1 -0
  616. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-ToIewrqr.js → pieDiagram-E7YTZNPT-BudBDlCI.js} +1 -1
  617. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-4d78KiEY.js → quadrantDiagram-AXDQQJYC-DXZ0PCJF.js} +1 -1
  618. ksadk/server/static/assets/radar-RG4KPBEZ-BR1oZXLM.js +1 -0
  619. ksadk/server/static/assets/railroad-74A4TZTK-DfgEISfX.js +1 -0
  620. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-CWOC3rdk.js +1 -0
  621. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CiRvHCLY.js +1 -0
  622. ksadk/server/static/assets/railroad-peg-WCYAUIDC-DSDDyJ2f.js +1 -0
  623. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-DKzx4xfv.js → railroadDiagram-O6MQD6OU-BdAYRYB8.js} +1 -1
  624. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-CJYljxQS.js → requirementDiagram-EFPCY7ZU-CBBmaL70.js} +1 -1
  625. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-DLU2fV1w.js → sankeyDiagram-P5KCCOFB-Doc3rdwp.js} +1 -1
  626. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CVqysrA9.js → sequenceDiagram-WJ2MYXX4-0J8R8hWW.js} +1 -1
  627. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-BUxfmTHc.js → sizeCapture-X5ZJPWSS-CfFLlWsK.js} +1 -1
  628. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-CNFgYI9E.js → stateDiagram-HBIQ2CUA-jBwkjtTy.js} +1 -1
  629. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-Cw1fPb5w.js +1 -0
  630. ksadk/server/static/assets/{swimlanes-XN3QIQJK-B6qCMe8N.js → swimlanes-XN3QIQJK-B0WxTQf8.js} +1 -1
  631. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-Cc3JMBAF.js +8 -0
  632. ksadk/server/static/assets/{timeline-definition-24CTP7MA-CMD3x_U_.js → timeline-definition-24CTP7MA-BfCT_75A.js} +1 -1
  633. ksadk/server/static/assets/treeView-Q6P3EWNA-C05SJHxo.js +1 -0
  634. ksadk/server/static/assets/treemap-WGGIJYW6-BqNLAhc3.js +1 -0
  635. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-BqtUqvXM.js → vennDiagram-4TSXK5OY-9gX1VMDC.js} +1 -1
  636. ksadk/server/static/assets/wardley-WFR3VGLG-DokNktqB.js +1 -0
  637. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-B5KfDjI-.js → wardleyDiagram-VM6X3IG4-sEs_BP6O.js} +1 -1
  638. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BaUlSZrn.js → xychartDiagram-S5SC5T6Z-Ll4jvUN9.js} +1 -1
  639. ksadk/server/static/index.html +2 -2
  640. ksadk/sessions/__init__.py +8 -1
  641. ksadk/sessions/_checkpoint_resume_audit.py +44 -0
  642. ksadk/sessions/_in_memory_query.py +112 -0
  643. ksadk/sessions/_local_service_sync.py +157 -156
  644. ksadk/sessions/_local_state_sync.py +152 -0
  645. ksadk/sessions/_local_tables.py +2 -0
  646. ksadk/sessions/_postgres_checkpoint_read.py +323 -0
  647. ksadk/sessions/_postgres_checkpoint_stats.py +330 -0
  648. ksadk/sessions/_postgres_history_read.py +678 -0
  649. ksadk/sessions/_postgres_schema.py +44 -2
  650. ksadk/sessions/_postgres_tables.py +2 -0
  651. ksadk/sessions/_postgres_tool_receipts.py +169 -0
  652. ksadk/sessions/_resilient_read.py +630 -0
  653. ksadk/sessions/_tool_receipt_sync.py +119 -0
  654. ksadk/sessions/agent_identity.py +16 -0
  655. ksadk/sessions/base.py +278 -0
  656. ksadk/sessions/db_budget.py +332 -0
  657. ksadk/sessions/errors.py +12 -0
  658. ksadk/sessions/history_budget.py +36 -0
  659. ksadk/sessions/history_identity.py +27 -0
  660. ksadk/sessions/in_memory.py +376 -113
  661. ksadk/sessions/local_service.py +345 -0
  662. ksadk/sessions/postgres_service.py +515 -549
  663. ksadk/sessions/resilience.py +21 -14
  664. ksadk/sessions/resilient.py +611 -504
  665. ksadk/skills/loader.py +44 -2
  666. ksadk/skills/runtime/backends/e2b.py +17 -14
  667. ksadk/skills/service_client.py +6 -1
  668. ksadk/studio/a2a_bindings.py +407 -0
  669. ksadk/studio/a2a_orchestration.py +178 -0
  670. ksadk/studio/active_run_output.py +92 -0
  671. ksadk/studio/activity_records.py +542 -0
  672. ksadk/studio/agent_configuration.py +173 -0
  673. ksadk/studio/api.py +219 -389
  674. ksadk/studio/api_a2a_routes.py +93 -0
  675. ksadk/studio/api_catalog_routes.py +13 -0
  676. ksadk/studio/api_cloud_chat_routes.py +382 -0
  677. ksadk/studio/api_contracts.py +23 -0
  678. ksadk/studio/attachment_store.py +14 -2
  679. ksadk/studio/build_resolution.py +117 -0
  680. ksadk/studio/build_singleflight.py +37 -0
  681. ksadk/studio/builder.py +20 -2
  682. ksadk/studio/capabilities.py +8 -3
  683. ksadk/studio/cloud.py +83 -377
  684. ksadk/studio/cloud_gateways.py +424 -0
  685. ksadk/studio/cloud_shared_web.py +7 -0
  686. ksadk/studio/codex_agent_service.py +17 -0
  687. ksadk/studio/codex_manifest.py +5 -1
  688. ksadk/studio/codex_provider_build.py +65 -0
  689. ksadk/studio/compiler.py +102 -6
  690. ksadk/studio/contract_base.py +19 -0
  691. ksadk/studio/contracts.py +231 -201
  692. ksadk/studio/dsh_application.py +58 -12
  693. ksadk/studio/dsh_capability_service.py +17 -171
  694. ksadk/studio/dsh_mcp_transport.py +191 -0
  695. ksadk/studio/event_store.py +17 -0
  696. ksadk/studio/execution_host.py +84 -11
  697. ksadk/studio/framework_run.py +18 -0
  698. ksadk/studio/interaction_submission.py +265 -0
  699. ksadk/studio/kernel_registry.py +12 -1
  700. ksadk/studio/lifecycle_status.py +43 -0
  701. ksadk/studio/model_buffered_wire.py +227 -0
  702. ksadk/studio/model_chat_tools.py +143 -0
  703. ksadk/studio/model_client.py +1241 -761
  704. ksadk/studio/model_content_stream.py +129 -0
  705. ksadk/studio/model_credentials.py +196 -0
  706. ksadk/studio/model_profile_service.py +65 -31
  707. ksadk/studio/model_request_projection.py +284 -0
  708. ksadk/studio/model_responses_content.py +296 -0
  709. ksadk/studio/model_usage.py +109 -0
  710. ksadk/studio/model_wire_failure.py +110 -0
  711. ksadk/studio/model_wire_identity.py +138 -0
  712. ksadk/studio/model_wire_snapshot.py +45 -0
  713. ksadk/studio/model_wire_tools.py +283 -0
  714. ksadk/studio/native_acceptance.py +68 -0
  715. ksadk/studio/native_approval.py +111 -0
  716. ksadk/studio/native_browser_port.py +861 -0
  717. ksadk/studio/native_child_mcp.py +87 -0
  718. ksadk/studio/native_child_publication.py +68 -0
  719. ksadk/studio/native_child_skills.py +72 -0
  720. ksadk/studio/native_child_workspace.py +176 -0
  721. ksadk/studio/native_command_policy.py +53 -0
  722. ksadk/studio/native_context_port.py +326 -0
  723. ksadk/studio/native_context_registration.py +54 -0
  724. ksadk/studio/native_document_input.py +88 -0
  725. ksadk/studio/native_final_shape.py +852 -0
  726. ksadk/studio/native_gateway_stream.py +69 -0
  727. ksadk/studio/native_hook_port.py +145 -0
  728. ksadk/studio/native_hook_registration.py +70 -0
  729. ksadk/studio/native_inventory_disclosure.py +223 -0
  730. ksadk/studio/native_kernel_admission.py +84 -0
  731. ksadk/studio/native_language_diagnostics.py +320 -0
  732. ksadk/studio/native_mcp_disclosure.py +198 -0
  733. ksadk/studio/native_mcp_tool_port.py +219 -0
  734. ksadk/studio/native_memory_acceptance.py +362 -0
  735. ksadk/studio/native_memory_context.py +266 -0
  736. ksadk/studio/native_memory_flush.py +174 -0
  737. ksadk/studio/native_memory_sources.py +80 -0
  738. ksadk/studio/native_memory_tool_port.py +360 -0
  739. ksadk/studio/native_memory_turn.py +183 -0
  740. ksadk/studio/native_model_port.py +765 -0
  741. ksadk/studio/native_model_recovery.py +126 -0
  742. ksadk/studio/native_options.py +75 -0
  743. ksadk/studio/native_output_fields.py +58 -0
  744. ksadk/studio/native_planning.py +156 -0
  745. ksadk/studio/native_product.py +988 -0
  746. ksadk/studio/native_read_budget.py +426 -0
  747. ksadk/studio/native_recovery.py +171 -0
  748. ksadk/studio/native_scope.py +35 -0
  749. ksadk/studio/native_session_context_port.py +141 -0
  750. ksadk/studio/native_session_engine.py +14 -0
  751. ksadk/studio/native_skill_source.py +74 -0
  752. ksadk/studio/native_subagent_port.py +700 -0
  753. ksadk/studio/native_terminal_recovery.py +95 -0
  754. ksadk/studio/native_test_action.py +610 -0
  755. ksadk/studio/native_tool_port.py +477 -0
  756. ksadk/studio/native_user_input.py +60 -0
  757. ksadk/studio/native_verification_presentation.py +65 -0
  758. ksadk/studio/native_workspace_diagnostics.py +183 -0
  759. ksadk/studio/native_workspace_port.py +43 -0
  760. ksadk/studio/operations.py +34 -9
  761. ksadk/studio/plugin_composition.py +26 -10
  762. ksadk/studio/plugin_kernel_adapter.py +75 -1
  763. ksadk/studio/plugin_native_activation.py +163 -0
  764. ksadk/studio/plugin_runtime.py +639 -119
  765. ksadk/studio/plugin_runtime_admission.py +57 -0
  766. ksadk/studio/presentation.py +92 -0
  767. ksadk/studio/public_output_store.py +69 -0
  768. ksadk/studio/resource_authority.py +11 -3
  769. ksadk/studio/resource_catalog.py +8 -12
  770. ksadk/studio/run_activity.py +338 -385
  771. ksadk/studio/run_controls.py +185 -0
  772. ksadk/studio/run_service.py +908 -319
  773. ksadk/studio/run_submission_receipts.py +68 -0
  774. ksadk/studio/runtime_catalog.py +23 -4
  775. ksadk/studio/runtime_prewarm.py +22 -0
  776. ksadk/studio/scheduler_assistant.py +4 -1
  777. ksadk/studio/service.py +356 -282
  778. ksadk/studio/service_settings.py +229 -0
  779. ksadk/studio/shared_web.py +393 -169
  780. ksadk/studio/shared_web_response_events.py +180 -0
  781. ksadk/studio/shared_web_run_state.py +133 -0
  782. ksadk/studio/skill_discovery.py +305 -3
  783. ksadk/studio/static/assets/ChannelsPage-xX5HlMId.js +8 -0
  784. ksadk/studio/static/assets/{CodeBlock-DMIf4h33-UIqo-BPW.js → CodeBlock-DMIf4h33-CkufcPYo.js} +3 -3
  785. ksadk/studio/static/assets/{MathMessageMarkdown-BesSeCYl-OhNwH4K9.js → MathMessageMarkdown-BesSeCYl-DYG1Wzbx.js} +1 -1
  786. ksadk/studio/static/assets/{MessageMarkdown-CwMTvgFj-g0I-I4dD.js → MessageMarkdown-CwMTvgFj-BeyLyQHu.js} +2 -2
  787. ksadk/studio/static/assets/TeamsPage-CCaaGaVp.js +3 -0
  788. ksadk/studio/static/assets/index-C7DNDik2.css +2 -0
  789. ksadk/studio/static/assets/index-Cy68gTlH.js +265 -0
  790. ksadk/studio/static/index.html +3 -3
  791. ksadk/studio/teams_catalog.py +33 -0
  792. ksadk/studio/teams_installation.py +4 -1
  793. ksadk/studio/teams_node.py +4 -0
  794. ksadk/studio/teams_node_factory.py +558 -0
  795. ksadk/studio/teams_node_runner.py +3 -0
  796. ksadk/studio/teams_node_v1.py +935 -0
  797. ksadk/studio/teams_remote.py +259 -37
  798. ksadk/studio/templates.py +1 -0
  799. ksadk/studio/workspace_plugins.py +3 -1
  800. ksadk/tools/a2a_policy.py +5 -0
  801. ksadk/tools/artifact_observation.py +53 -0
  802. ksadk/tools/captured_source_artifact.py +68 -0
  803. ksadk/tools/schema.py +34 -0
  804. ksadk/toolsets/__init__.py +82 -88
  805. ksadk/toolsets/a2a.py +89 -89
  806. ksadk/toolsets/sandbox.py +377 -6
  807. ksadk/toolsets/skill_management.py +315 -0
  808. ksadk/toolsets/tool_selection.py +94 -0
  809. ksadk/toolsets/workspace.py +342 -324
  810. ksadk/toolsets/workspace_editing.py +291 -0
  811. ksadk/toolsets/workspace_model_observation.py +104 -0
  812. ksadk/toolsets/workspace_mutation.py +75 -0
  813. ksadk/toolsets/workspace_read_budget.py +216 -0
  814. ksadk/toolsets/workspace_search.py +192 -0
  815. ksadk/toolsets/workspace_search_process.py +129 -0
  816. ksadk/toolsets/workspace_state.py +6 -0
  817. ksadk/version.py +1 -1
  818. ksadk_runtime_common/http_headers.py +18 -0
  819. ksadk_runtime_common/workspace_files/router.py +2 -1
  820. ksadk/server/static/assets/architecture-7GRP2DOG-BCsa26zi.js +0 -1
  821. ksadk/server/static/assets/channel-_KDifNys.js +0 -1
  822. ksadk/server/static/assets/chunk-2Q5K7J3B-HdVkJ9F0.js +0 -1
  823. ksadk/server/static/assets/classDiagram-DTDB5LWJ-BVCW3ZqZ.js +0 -1
  824. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-BVCW3ZqZ.js +0 -1
  825. ksadk/server/static/assets/cynefin-OW5HDTMX-CNXjFctL.js +0 -1
  826. ksadk/server/static/assets/eventmodeling-NTZA5JFV-B5-8RH9c.js +0 -1
  827. ksadk/server/static/assets/flowDiagram-A5DVABFB-BppFxEKw.js +0 -1
  828. ksadk/server/static/assets/gitGraph-4MIJSDKK-B-AhYj4C.js +0 -1
  829. ksadk/server/static/assets/index-BMd2mucF.css +0 -2
  830. ksadk/server/static/assets/index-D5qyyhTH.js +0 -244
  831. ksadk/server/static/assets/info-A6RAGUB7-0uiKrC35.js +0 -1
  832. ksadk/server/static/assets/packet-AYTQ26CC-BVTmZ_cw.js +0 -1
  833. ksadk/server/static/assets/pie-WAS4IAKB-DyfxBU7V.js +0 -1
  834. ksadk/server/static/assets/radar-RG4KPBEZ-FFontjL2.js +0 -1
  835. ksadk/server/static/assets/railroad-74A4TZTK-D0Uidzen.js +0 -1
  836. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BOo_9T2h.js +0 -1
  837. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-D6-BjW7Z.js +0 -1
  838. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CXx__yMm.js +0 -1
  839. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BXAFScz8.js +0 -1
  840. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uIQ2lJKH.js +0 -8
  841. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5GgucZ.js +0 -1
  842. ksadk/server/static/assets/treemap-WGGIJYW6-Bq1u1SpG.js +0 -1
  843. ksadk/server/static/assets/wardley-WFR3VGLG-QAt06uEz.js +0 -1
  844. ksadk/studio/static/assets/ChannelsPage-D_PGmKVq.js +0 -8
  845. ksadk/studio/static/assets/TeamsPage-DqX4HWKQ.js +0 -3
  846. ksadk/studio/static/assets/index-CfEnms6Y.css +0 -2
  847. ksadk/studio/static/assets/index-Dp61rOWZ.js +0 -0
  848. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/WHEEL +0 -0
  849. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/entry_points.txt +0 -0
  850. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/licenses/LICENSE +0 -0
  851. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,803 @@
1
+ """Single-process child owner, sharing the existing Native child execution path.
2
+
3
+ Handles own asyncio resources only. Run state, initial identity, reservations and
4
+ results remain in the original scoped Store and parent effect receipts. Missing
5
+ owners are never reconstructed by blindly launching the child again.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ from dataclasses import dataclass, field
12
+ from typing import Literal
13
+
14
+ from pydantic import Field, model_validator
15
+
16
+ from ksadk.harness.native.child_lifecycle import ChildLifecycleRequest, ChildLifecycleResult
17
+ from ksadk.harness.native.child_lifecycle_contract import (
18
+ ChildInterruptedReceipt,
19
+ ChildInterruptedReceiptRequest,
20
+ ChildReadyRequest,
21
+ ChildReadyResult,
22
+ ChildResourceReleaseRequest,
23
+ )
24
+ from ksadk.harness.native.effect_admission import owned_child_admission
25
+ from ksadk.harness.native.engine import NativeKernel
26
+ from ksadk.harness.native.model import ModelToolCall
27
+ from ksadk.harness.native.ports import (
28
+ ChildBudgetSettlement,
29
+ RunConfiguration,
30
+ ToolDefinition,
31
+ ToolRequest,
32
+ ToolResult,
33
+ digest,
34
+ )
35
+ from ksadk.harness.native.state import (
36
+ ChildApproval,
37
+ ChildBudgetReservation,
38
+ Contract,
39
+ RunScope,
40
+ RunSnapshot,
41
+ )
42
+ from ksadk.harness.native.subagents import ChildRole, ChildRunRequest
43
+ from ksadk.harness.stores.native_contract import RunStore, ScopeMismatch, StoreConflict
44
+
45
+ from .native_child import ChildFactory, NativeChildToolPort, _settle
46
+ from .native_child_approval import (
47
+ answer_original_pause,
48
+ await_decision,
49
+ current_approval,
50
+ observe_until_ready,
51
+ )
52
+ from .native_child_continuation import bind_child_continuation
53
+ from .native_child_result import NativeChildResultPort
54
+
55
+
56
+ async def _join(tasks):
57
+ return await asyncio.gather(*tasks, return_exceptions=True)
58
+
59
+
60
+ def _finish_startup(task: asyncio.Task, ready: asyncio.Future) -> None:
61
+ # A Task cancelled before its first step never enters _drive's finally.
62
+ # The owner still owes every launch waiter a settled readiness signal.
63
+ if not ready.done():
64
+ ready.set_result(False)
65
+ if not task.cancelled():
66
+ task.exception()
67
+
68
+
69
+ class _Launch(Contract):
70
+ role: str = Field(min_length=1)
71
+ task: str = Field(min_length=1, max_length=32000, pattern=r"\S")
72
+ model_call_limit: int = Field(default=4, strict=True, ge=1)
73
+ tool_call_limit: int = Field(default=8, strict=True, ge=0)
74
+ output_format: Literal["text", "json_object"] | None = None
75
+ output_contract: Literal["parent"] | None = None
76
+ continuation_of: str | None = Field(default=None, min_length=1, max_length=256, pattern=r"\S")
77
+ background: bool = Field(default=True, strict=True)
78
+
79
+
80
+ class _Control(Contract):
81
+ child_run_id: str = Field(min_length=1, max_length=256)
82
+ action: Literal["wait", "send", "stop"]
83
+ message: str | None = Field(default=None, min_length=1, max_length=32000, pattern=r"\S")
84
+ wait_seconds: float = Field(default=15, ge=0, le=30, allow_inf_nan=False)
85
+
86
+ @model_validator(mode="after")
87
+ def message_only_for_send(self):
88
+ if (self.action == "send") != (self.message is not None):
89
+ raise ValueError("send requires a message; other actions cannot send one")
90
+ return self
91
+
92
+
93
+ @dataclass
94
+ class _Handle:
95
+ request: ChildRunRequest
96
+ ready: asyncio.Future
97
+ task: asyncio.Task | None = None
98
+ kernel: NativeKernel | None = None
99
+ reservation: ChildBudgetReservation | None = None
100
+ background: bool = True
101
+ promotion: asyncio.Event | None = None
102
+ # Resource ownership is common; the original foreground receipt protocol
103
+ # and its declared profile stay sealed until an explicit migration.
104
+ sealed_runner: NativeChildToolPort | None = None
105
+ approval: ChildApproval | None = None
106
+ approval_ready: asyncio.Event = field(default_factory=asyncio.Event)
107
+ approval_decision: asyncio.Future | None = None
108
+
109
+
110
+ class _GuidedChildToolPort(NativeChildToolPort):
111
+ @staticmethod
112
+ def _configuration(child, bindings):
113
+ # Background send is supplemental guidance, not a replacement task.
114
+ # Pin that supported control policy before the child Run is published;
115
+ # synchronous delegates keep their original host configuration.
116
+ config = NativeChildToolPort._configuration(child, bindings).model_dump(mode="json")
117
+ config["guidance_policy"] = "boundary-guide/v1"
118
+ return RunConfiguration.model_validate(config)
119
+
120
+
121
+ class NativeBackgroundChildToolPort:
122
+ def __init__(
123
+ self,
124
+ *,
125
+ scope: RunScope,
126
+ roles: tuple[ChildRole, ...],
127
+ factory: ChildFactory,
128
+ store: RunStore,
129
+ approval_bridge: bool = False,
130
+ ):
131
+ self._delegate = _GuidedChildToolPort(scope=scope, roles=roles, factory=factory)
132
+ self.scope, self.store = self._delegate.scope, store
133
+ self._reader = NativeChildResultPort(scope=scope, roles=roles, store=store)
134
+ self._handles: dict[str, _Handle] = {}
135
+ self._locks: dict[str, asyncio.Lock] = {}
136
+ self._closed = False
137
+ self.approval_bridge = approval_bridge
138
+
139
+ def definitions(self) -> tuple[ToolDefinition, ...]:
140
+ properties = dict(self._delegate.definition().parameters["properties"])
141
+ properties.update(
142
+ background={"type": "boolean", "default": True, "description": (
143
+ "False waits in the foreground. The host may move this same child to "
144
+ "the background while it runs; true starts in the background immediately."
145
+ )},
146
+ model_call_limit={"type": "integer", "minimum": 1, "default": 4},
147
+ tool_call_limit={"type": "integer", "minimum": 0, "default": 8},
148
+ continuation_of={
149
+ "type": "string", "minLength": 1, "maxLength": 256,
150
+ "description": (
151
+ "Continue an already collected terminal child in its original session. "
152
+ "Use the same role and a new task; the returned Run ID is new. "
153
+ "First wait/collect the source result. Omit for an independent child."
154
+ ),
155
+ },
156
+ )
157
+ return (
158
+ ToolDefinition(
159
+ name="native_start_child",
160
+ description=(
161
+ "Start a bounded approved child (background by default), then continue "
162
+ "independent "
163
+ "parent work. The startup result reserves shared budget; it is not findings. "
164
+ "Use native_child_control to send input, stop, wait and consume its result "
165
+ "before final delivery. No parent acceptance is inherited. For a follow-up, "
166
+ "provide continuation_of after collecting the previous result; its history "
167
+ "is retained but its immutable Run and usage are not reopened."
168
+ ),
169
+ parameters={
170
+ "type": "object",
171
+ "additionalProperties": False,
172
+ "required": ["role", "task"],
173
+ "properties": properties,
174
+ },
175
+ child_budget_policy="start/v1",
176
+ ),
177
+ ToolDefinition(
178
+ name="native_child_control",
179
+ description=(
180
+ "Control a child started by this parent: send additional input, stop it, "
181
+ "or wait up to 30 seconds and consume its terminal findings. A running "
182
+ "response is not completion; terminal results settle actual usage once. "
183
+ "A terminal child is immutable; use native_start_child with continuation_of "
184
+ "for a follow-up after collecting its result."
185
+ ),
186
+ parameters={
187
+ "type": "object",
188
+ "additionalProperties": False,
189
+ "required": ["child_run_id", "action"],
190
+ "properties": {
191
+ "child_run_id": {"type": "string", "minLength": 1, "maxLength": 256},
192
+ "action": {"type": "string", "enum": ["wait", "send", "stop"]},
193
+ "message": {"type": "string", "minLength": 1, "maxLength": 32000},
194
+ "wait_seconds": {"type": "number", "minimum": 0, "maximum": 30},
195
+ },
196
+ },
197
+ child_budget_policy="settle/v1",
198
+ child_approval_policy="owned-child-approval/v1" if self.approval_bridge else None,
199
+ ),
200
+ )
201
+
202
+ def _child_request(self, request: ToolRequest) -> ChildRunRequest:
203
+ launch = _Launch.model_validate(request.call.arguments)
204
+ allowance = request.budget
205
+ model_slots = allowance.max_model_calls_remaining - (
206
+ 0 if allowance.parent_finalization_reserved else 1
207
+ )
208
+ # Preserve a parent collection/control call rather than allocate every
209
+ # remaining tool slot to the child. The outer final model reserve stays.
210
+ tool_slots = allowance.max_tool_calls_remaining - 1
211
+ if model_slots < 1 or tool_slots < 0:
212
+ raise ValueError("child_budget_exhausted")
213
+ args = {"role": launch.role, "task": launch.task}
214
+ if launch.output_format is not None:
215
+ args["output_format"] = launch.output_format
216
+ if launch.output_contract is not None:
217
+ args["output_contract"] = launch.output_contract
218
+ adapted = request.model_copy(
219
+ update={
220
+ "call": ModelToolCall(
221
+ call_id=request.call.call_id, name="native_delegate", arguments=args
222
+ ),
223
+ "definition": self._delegate.definition(),
224
+ "budget": allowance.model_copy(
225
+ update={
226
+ "max_model_calls_remaining": min(model_slots, launch.model_call_limit),
227
+ "max_tool_calls_remaining": min(tool_slots, launch.tool_call_limit),
228
+ "parent_finalization_reserved": True,
229
+ }
230
+ ),
231
+ }
232
+ )
233
+ child = self._delegate._request(adapted)
234
+ if launch.continuation_of is None:
235
+ return child
236
+ child = bind_child_continuation(
237
+ child, launch.continuation_of, store=self.store,
238
+ roles=tuple(self._delegate.roles.values()),
239
+ )
240
+ self._check_continuation_resource(child)
241
+ return child
242
+
243
+ def _check_continuation_resource(self, child: ChildRunRequest) -> None:
244
+ handle = self._handles.get(child.continuation_of)
245
+ if handle is None:
246
+ return
247
+ if handle.request.role != child.role:
248
+ raise ValueError("child_followup_role_mismatch")
249
+ if handle.task is None or not handle.task.done():
250
+ raise ValueError("child_followup_requires_result_collection")
251
+
252
+ async def _drive(self, handle: _Handle) -> ToolResult:
253
+ child = handle.request
254
+ runner = handle.sealed_runner or self._delegate
255
+
256
+ def ready(kernel: NativeKernel, config: RunConfiguration, snapshot: RunSnapshot):
257
+ handle.kernel = kernel
258
+ handle.reservation = ChildBudgetReservation(
259
+ child_run_id=child.child_run_id,
260
+ child_scope=child.scope,
261
+ parent_operation_key=child.parent_operation_key,
262
+ parent_tool_call_id=child.parent_tool_call_id,
263
+ child_request_digest=digest(child),
264
+ configuration_digest=config.digest,
265
+ max_model_calls=config.limits.max_model_calls,
266
+ max_tool_calls=config.limits.max_tool_calls,
267
+ )
268
+ handle.ready.set_result(True)
269
+
270
+ try:
271
+ async def interaction(kernel, snapshot):
272
+ await await_decision(handle, kernel, snapshot)
273
+
274
+ result = await runner._run(
275
+ child, digest(child), on_ready=ready,
276
+ on_interaction=interaction if self.approval_bridge else None,
277
+ )
278
+ runner._results[child.child_run_id] = (digest(child), result)
279
+ return result
280
+ finally:
281
+ if not handle.ready.done():
282
+ handle.ready.set_result(False)
283
+
284
+ async def execute_foreground(
285
+ self, request: ToolRequest, *, delegate: NativeChildToolPort
286
+ ) -> ToolResult:
287
+ """Own the declared delegate, preserving legacy sealed SDK delivery."""
288
+ try:
289
+ request = ToolRequest.model_validate_json(request.model_dump_json())
290
+ if delegate.scope != self.scope or delegate.roles != self._delegate.roles:
291
+ raise ValueError("child_scope_or_definition_mismatch")
292
+ child = delegate._request(request)
293
+ self._check_continuation_resource(child)
294
+ except (ValueError, TypeError) as error:
295
+ codes = {"child_scope_or_definition_mismatch", "child_arguments_invalid",
296
+ "child_budget_exhausted", "child_followup_not_available",
297
+ "child_followup_role_mismatch", "child_followup_requires_result_collection"}
298
+ return delegate._error(str(error) if str(error) in codes else "child_request_rejected")
299
+ async with self._locks.setdefault(child.child_run_id, asyncio.Lock()):
300
+ if self._closed:
301
+ return delegate._error("child_owner_closed")
302
+ handle = self._handles.get(child.child_run_id)
303
+ if handle is not None and (
304
+ handle.request != child or handle.sealed_runner is not delegate
305
+ ):
306
+ return delegate._error("child_operation_conflict")
307
+ # The original runner seals a cancellation receipt before its
308
+ # Task raises. Repeated callers consume that receipt, not the
309
+ # cancelled Task, and must never relaunch its effects.
310
+ cached = delegate._results.get(child.child_run_id)
311
+ if cached is not None:
312
+ if cached[0] != digest(child):
313
+ return delegate._error("child_operation_conflict")
314
+ if (child.delivery_mode is None or child.delivery_mode == "foreground"
315
+ and not handle.promotion.is_set()):
316
+ return ToolResult.model_validate_json(cached[1].model_dump_json())
317
+ return self._startup_result(handle)
318
+ if handle is None:
319
+ with owned_child_admission():
320
+ handle = _Handle(child, asyncio.get_running_loop().create_future(),
321
+ background=child.delivery_mode == "background",
322
+ promotion=asyncio.Event() if child.delivery_mode else None,
323
+ sealed_runner=delegate)
324
+ self._handles[child.child_run_id] = handle
325
+ handle.task = asyncio.create_task(self._drive(handle))
326
+ handle.task.add_done_callback(
327
+ lambda completed: _finish_startup(completed, handle.ready)
328
+ )
329
+ if child.delivery_mode is not None:
330
+ return await self._deliver_owned(handle, sealed_foreground=True)
331
+ try:
332
+ result = await asyncio.shield(handle.task)
333
+ except asyncio.CancelledError:
334
+ handle.task.cancel()
335
+ await _settle(_join((handle.task,)), propagate_cancel=False)
336
+ raise
337
+ return ToolResult.model_validate_json(result.model_dump_json())
338
+
339
+ @staticmethod
340
+ def _startup_result(handle: _Handle) -> ToolResult:
341
+ return ToolResult(
342
+ status="ok",
343
+ content={
344
+ "child_run_id": handle.request.child_run_id,
345
+ "started": True,
346
+ "parent_acceptance": "not_evaluated",
347
+ "result_consumed": False,
348
+ "control_tool": "native_child_control",
349
+ "background": handle.background or handle.promotion.is_set(),
350
+ },
351
+ child_budget_reservation=handle.reservation,
352
+ )
353
+
354
+ async def _deliver_owned(self, handle: _Handle, *, sealed_foreground: bool) -> ToolResult:
355
+ try:
356
+ ready = await asyncio.shield(handle.ready)
357
+ if not ready:
358
+ return await handle.task
359
+ if not handle.background:
360
+ promotion = asyncio.create_task(handle.promotion.wait())
361
+ approval = asyncio.create_task(handle.approval_ready.wait())
362
+ try:
363
+ await asyncio.wait((handle.task, promotion, approval),
364
+ return_when=asyncio.FIRST_COMPLETED)
365
+ finally:
366
+ promotion.cancel()
367
+ approval.cancel()
368
+ await _settle(_join((promotion, approval)), propagate_cancel=False)
369
+ if handle.task.done() and (
370
+ not sealed_foreground or not handle.promotion.is_set()
371
+ ):
372
+ result = await handle.task
373
+ if sealed_foreground:
374
+ return ToolResult.model_validate_json(result.model_dump_json())
375
+ return self._startup_result(handle)
376
+ except asyncio.CancelledError:
377
+ handle.task.cancel()
378
+ await _settle(_join((handle.task,)), propagate_cancel=False)
379
+ raise
380
+
381
+ async def _start(self, request: ToolRequest) -> ToolResult:
382
+ launch = _Launch.model_validate(request.call.arguments)
383
+ try:
384
+ child = self._child_request(request)
385
+ except ValueError as error:
386
+ if str(error) not in {
387
+ "child_followup_not_available", "child_followup_role_mismatch",
388
+ "child_followup_requires_result_collection", "child_budget_exhausted",
389
+ }:
390
+ raise
391
+ return self._delegate._error(str(error))
392
+ async with self._locks.setdefault(child.child_run_id, asyncio.Lock()):
393
+ if self._closed:
394
+ return self._delegate._error("child_owner_closed")
395
+ handle = self._handles.get(child.child_run_id)
396
+ if handle is not None and (
397
+ handle.request != child or handle.background != launch.background
398
+ ):
399
+ return self._delegate._error("child_operation_conflict")
400
+ if handle is None:
401
+ with owned_child_admission():
402
+ handle = _Handle(child, asyncio.get_running_loop().create_future())
403
+ handle.background = launch.background
404
+ handle.promotion = asyncio.Event()
405
+ self._handles[child.child_run_id] = handle
406
+ handle.task = asyncio.create_task(self._drive(handle))
407
+ handle.task.add_done_callback(
408
+ lambda completed: _finish_startup(completed, handle.ready)
409
+ )
410
+ return await self._deliver_owned(handle, sealed_foreground=False)
411
+
412
+ def _waiting_handle(self, parent: RunSnapshot, child_run_id: str, *, read_closed=False):
413
+ handle = self._handles.get(child_run_id)
414
+ if (self._closed and not read_closed or parent.scope != self.scope or parent.phase.terminal
415
+ or handle is None or handle.kernel is None or handle.reservation is None
416
+ or handle.request.parent_scope != parent.scope
417
+ or handle.request.parent_run_id != parent.run_id or parent.pending_intent is None):
418
+ return None
419
+ intent = self.store.get_intent(self.scope, parent.run_id, parent.pending_intent)
420
+ call = None
421
+ if intent is not None and handle.request.parent_operation_key == intent.operation_key:
422
+ call = intent.payload.get("call")
423
+ elif intent is not None and intent.payload.get("parallel_delegation") is True:
424
+ for index, member in enumerate(intent.payload.get("calls", ()), 1):
425
+ if handle.request.parent_operation_key == f"{intent.operation_key}:call:{index}":
426
+ call = member
427
+ break
428
+ name = "native_delegate" if handle.sealed_runner is not None else "native_start_child"
429
+ if (intent is None or intent.kind != "tool" or intent.status != "running"
430
+ or not isinstance(call, dict) or call.get("name") != name
431
+ or call.get("call_id") != handle.request.parent_tool_call_id):
432
+ return None
433
+ args = call.get("arguments")
434
+ child = self.store.load(handle.request.scope, child_run_id)
435
+ if (not isinstance(args, dict) or args.get("role") != handle.request.role.role_id
436
+ or args.get("task") != handle.request.task
437
+ or child.origin is None or child.origin.get("parent_run_id") != parent.run_id
438
+ or child.origin.get("parent_scope") != parent.scope.model_dump(mode="json")
439
+ or child.origin.get("parent_operation_key") != handle.request.parent_operation_key
440
+ or child.origin.get("parent_tool_call_id") != handle.request.parent_tool_call_id
441
+ or child.configuration_digest != handle.reservation.configuration_digest):
442
+ return None
443
+ return handle
444
+
445
+ def _foreground_handle(self, parent: RunSnapshot, child_run_id: str):
446
+ handle = self._waiting_handle(parent, child_run_id)
447
+ if (handle is None or (handle.sealed_runner is not None
448
+ and handle.request.delivery_mode is None) or handle.background
449
+ or handle.task.done()
450
+ or self.store.load(handle.request.scope, child_run_id).phase.terminal):
451
+ return None
452
+ return handle
453
+
454
+ def can_promote(self, parent: RunSnapshot, child_run_id: str) -> bool:
455
+ handle = self._foreground_handle(parent, child_run_id)
456
+ return handle is not None and not handle.promotion.is_set()
457
+
458
+ def release_foreground(self, parent: RunSnapshot, child_run_id: str) -> None:
459
+ # The Kernel commits child.promoted before releasing this local wait.
460
+ # Both operations are synchronous under its original driver ownership.
461
+ handle = self._foreground_handle(parent, child_run_id)
462
+ if handle is not None:
463
+ handle.promotion.set()
464
+
465
+ def child_tasks(self, parent: RunSnapshot) -> tuple[dict, ...]:
466
+ if parent.scope != self.scope:
467
+ raise ValueError("child_task_scope_mismatch")
468
+ rows = []
469
+ promoted_ids = {e.payload.get("child_run_id")
470
+ for e in self.store.events(self.scope, parent.run_id)
471
+ if e.kind == "child.promoted"}
472
+ for child_id in dict.fromkeys((*parent.child_run_ids, *self._handles)):
473
+ handle = self._waiting_handle(parent, child_id)
474
+ child = (self.store.load(handle.request.scope, child_id) if handle is not None
475
+ else self._reader._load_direct_child(parent, child_id))
476
+ if child is None:
477
+ continue
478
+ original = self.store.get_intent(
479
+ self.scope, parent.run_id, child.origin["parent_operation_key"]
480
+ )
481
+ original_call = original.payload.get("call", {}) if original is not None else {}
482
+ if handle is not None:
483
+ foreground = not handle.background and child_id not in promoted_ids
484
+ else:
485
+ foreground = (
486
+ original_call.get("name") == "native_delegate"
487
+ and original_call.get("arguments", {}).get("background", False) is False
488
+ or original_call.get("name") == "native_start_child"
489
+ and original_call.get("arguments", {}).get("background") is False
490
+ ) and child_id not in promoted_ids
491
+ rows.append({"child_run_id": child_id, "session_id": child.session_id,
492
+ "role": child.origin.get("role"), "phase": child.phase.value,
493
+ "delivery": "foreground" if foreground else "background",
494
+ "can_promote": self.can_promote(parent, child_id),
495
+ "can_cancel": self.can_cancel(parent, child_id),
496
+ "goal_revision": child.goal_revision,
497
+ "can_send_input": self.child_input_target(parent, child_id) is not None})
498
+ return tuple(rows)
499
+
500
+ def can_cancel(self, parent: RunSnapshot, child_run_id: str) -> bool:
501
+ handle = self._waiting_handle(parent, child_run_id)
502
+ child = (self.store.load(handle.request.scope, child_run_id) if handle is not None
503
+ else self._reader._load_direct_child(parent, child_run_id))
504
+ handle = handle or self._handles.get(child_run_id)
505
+ return bool(not self._closed and parent.scope == self.scope and not parent.phase.terminal
506
+ and child is not None and not child.phase.terminal and handle is not None
507
+ and handle.kernel is not None and not handle.task.done()
508
+ and handle.request.parent_run_id == parent.run_id
509
+ and handle.request.parent_scope == parent.scope
510
+ and handle.request.scope == child.scope)
511
+
512
+ async def cancel_child(self, parent: RunSnapshot, child_run_id: str) -> None:
513
+ if not self.can_cancel(parent, child_run_id):
514
+ return # The child may have naturally finished after admission.
515
+ task = self._handles[child_run_id].task
516
+ if not task.cancelling():
517
+ task.cancel()
518
+ # Join the existing runner's bounded cleanup; it remains the authority
519
+ # for child terminal facts and usage. A slow cleanup is still not success.
520
+ await asyncio.wait((task,), timeout=1.0)
521
+
522
+ def child_execution_view(self, parent: RunSnapshot, child_run_id: str) -> dict:
523
+ """Read only an admitted direct child through its original scope/receipt."""
524
+ from ksadk.harness.native_projection import NativeEventProjection
525
+
526
+ if parent.scope != self.scope:
527
+ raise ValueError("child_task_scope_mismatch")
528
+ handle = self._waiting_handle(parent, child_run_id)
529
+ child = (self.store.load(handle.request.scope, child_run_id) if handle is not None
530
+ else self._reader._load_direct_child(parent, child_run_id))
531
+ if child is None:
532
+ raise ValueError("child_not_owned")
533
+ projection = NativeEventProjection(child.scope, child.run_id)
534
+ events = [event.model_dump(mode="json")
535
+ for native in self.store.events(child.scope, child.run_id)
536
+ for event in projection.consume(native)]
537
+ return {"child_run_id": child.run_id, "session_id": child.session_id,
538
+ "call_id": child.origin.get("parent_tool_call_id"),
539
+ "role": child.origin.get("role"), "phase": child.phase.value,
540
+ "events": events}
541
+
542
+ def child_input_target(self, parent: RunSnapshot, child_run_id: str):
543
+ from ksadk.harness.native.child_input import ChildInputTarget
544
+
545
+ handle = self._waiting_handle(parent, child_run_id)
546
+ child = (self.store.load(handle.request.scope, child_run_id) if handle is not None
547
+ else self._reader._load_direct_child(parent, child_run_id))
548
+ handle = handle or self._handles.get(child_run_id)
549
+ if (self._closed or parent.scope != self.scope or parent.phase.terminal
550
+ or child is None or child.phase.terminal or handle is None
551
+ or handle.kernel is None or handle.task.done()
552
+ or handle.kernel.configuration.guidance_policy is None
553
+ or handle.request.parent_run_id != parent.run_id
554
+ or handle.request.parent_scope != parent.scope
555
+ or handle.request.scope != child.scope):
556
+ return None
557
+ return ChildInputTarget(scope=child.scope, run_id=child.run_id,
558
+ configuration_digest=child.configuration_digest,
559
+ parent_operation_key=handle.request.parent_operation_key,
560
+ parent_tool_call_id=handle.request.parent_tool_call_id)
561
+
562
+ def wake_child_input(self, parent: RunSnapshot, child_run_id: str) -> None:
563
+ target = self.child_input_target(parent, child_run_id)
564
+ if target is not None:
565
+ self._handles[child_run_id].kernel.notify_pending_commands(child_run_id)
566
+
567
+ def interrupted_receipts(
568
+ self, request: ChildInterruptedReceiptRequest
569
+ ) -> tuple[ChildInterruptedReceipt, ...]:
570
+ request = ChildInterruptedReceiptRequest.model_validate_json(request.model_dump_json())
571
+ if request.scope != self.scope:
572
+ raise ValueError("child_interrupted_receipt_scope_mismatch")
573
+ parent = self.store.load(self.scope, request.run_id)
574
+ if parent.pending_intent != request.parent_operation_key or parent.phase.terminal:
575
+ raise ValueError("child_interrupted_receipt_parent_changed")
576
+ results = []
577
+ for child_id in self._handles:
578
+ handle = self._waiting_handle(parent, child_id, read_closed=True)
579
+ if handle is None or (handle.sealed_runner is not None
580
+ and handle.request.delivery_mode is None):
581
+ continue
582
+ # Reading a known receipt never runs a factory or model, and does
583
+ # not require a cancelled Task to return successfully. In-progress
584
+ # owned resources enter the parent's existing cancellation ledger.
585
+ runner = handle.sealed_runner or self._delegate
586
+ cached = runner._results.get(child_id)
587
+ child = self.store.load(handle.request.scope, child_id)
588
+ if (handle.request.delivery_mode == "foreground"
589
+ and handle.task.done() and child.phase.terminal and cached is not None
590
+ and cached[0] == digest(handle.request)
591
+ and not handle.background and not handle.promotion.is_set()):
592
+ result = ToolResult.model_validate_json(cached[1].model_dump_json())
593
+ else:
594
+ result = self._startup_result(handle)
595
+ results.append(ChildInterruptedReceipt(
596
+ parent_operation_key=handle.request.parent_operation_key,
597
+ parent_tool_call_id=handle.request.parent_tool_call_id,
598
+ result=result,
599
+ ))
600
+ return tuple(results)
601
+
602
+ async def _control(self, request: ToolRequest) -> ToolResult:
603
+ control = _Control.model_validate(request.call.arguments)
604
+ parent = self.store.load(self.scope, request.run_id)
605
+ child = self._reader._load_direct_child(parent, control.child_run_id)
606
+ handle = self._handles.get(control.child_run_id)
607
+ if child is None or handle is None or handle.kernel is None:
608
+ return self._delegate._error("child_owner_unavailable_or_not_authorized")
609
+ if not any(item.child_run_id == child.run_id for item in parent.child_budget_reservations):
610
+ # Its original receipt already charged usage. Returning an
611
+ # allocation settlement would charge it again or break the parent
612
+ # reducer. Keep reads on the existing scoped result query seam.
613
+ return ToolResult(status="error", content={
614
+ "error_code": "child_already_accounted_use_result_tool",
615
+ "result_tool": "native_child_result",
616
+ })
617
+ if request.child_approval is not None:
618
+ if request.child_approval.child_run_id != child.run_id or control.action != "wait":
619
+ raise ValueError("child_approval_control_changed")
620
+ answer_original_pause(self, parent, request)
621
+ if not child.phase.terminal and control.action == "send":
622
+ accepted = handle.kernel.guide(
623
+ child.run_id,
624
+ text=control.message,
625
+ command_id=request.operation_key,
626
+ expected_goal_revision=handle.kernel.reserved_goal_revision(child.run_id),
627
+ )
628
+ return ToolResult(
629
+ status="ok",
630
+ content={
631
+ "child_run_id": child.run_id,
632
+ "input_status": accepted.status,
633
+ "input_reason": accepted.reason,
634
+ "result_consumed": False,
635
+ },
636
+ )
637
+ if control.action == "send":
638
+ return self._delegate._error("child_terminal_requires_new_run")
639
+ if control.action == "stop" and not handle.task.done():
640
+ handle.task.cancel()
641
+ await _settle(_join((handle.task,)))
642
+ elif not handle.task.done() and control.wait_seconds:
643
+ # Timeout ends this observation only; shield the independently
644
+ # owned child so a bounded poll cannot cancel its work.
645
+ try:
646
+ await asyncio.wait_for(observe_until_ready((handle,)), control.wait_seconds)
647
+ except TimeoutError:
648
+ pass
649
+ if not handle.task.done():
650
+ if (approval := current_approval(handle)) is not None:
651
+ from ksadk.harness.native.child_approval import host_id
652
+
653
+ return ToolResult(status="approval_required", interaction_id=host_id(approval),
654
+ child_approval=approval,
655
+ content={"child_run_id": child.run_id})
656
+ current = self.store.load(child.scope, child.run_id)
657
+ return ToolResult(
658
+ status="ok",
659
+ content={
660
+ "child_run_id": child.run_id,
661
+ "phase": current.phase.value,
662
+ "result_consumed": False,
663
+ "parent_acceptance": "not_evaluated",
664
+ },
665
+ )
666
+ return self._terminal_result(handle)
667
+
668
+ def _terminal_result(self, handle: _Handle) -> ToolResult:
669
+ child = handle.request
670
+ runner = handle.sealed_runner or self._delegate
671
+ cached = runner._results.get(child.child_run_id)
672
+ if cached is None:
673
+ return self._delegate._error("child_terminal_receipt_unavailable")
674
+ current = self.store.load(child.scope, child.child_run_id)
675
+ if not current.phase.terminal:
676
+ return ToolResult(status="uncertain", content={"error_code": "child_owner_lost"})
677
+ return cached[1].model_copy(
678
+ deep=True,
679
+ update={
680
+ "child_budget_settlement": ChildBudgetSettlement(
681
+ child_run_id=child.child_run_id,
682
+ parent_operation_key=handle.request.parent_operation_key,
683
+ child_request_digest=digest(handle.request),
684
+ terminal_snapshot_digest=digest(current),
685
+ ),
686
+ },
687
+ )
688
+
689
+ async def collect(self, request: ChildLifecycleRequest) -> ChildLifecycleResult:
690
+ request = ChildLifecycleRequest.model_validate_json(request.model_dump_json())
691
+ if request.scope != self.scope:
692
+ raise ValueError("child_lifecycle_scope_mismatch")
693
+ parent = self.store.load(self.scope, request.run_id)
694
+ expected = tuple(item for item in parent.child_budget_reservations
695
+ if item.settled_usage_digest is None)
696
+ if (parent.phase.terminal or parent.pending_intent != request.operation_key
697
+ or expected != request.reservations):
698
+ raise ValueError("child_lifecycle_parent_changed")
699
+ if request.child_approval is not None:
700
+ answer_original_pause(self, parent, request)
701
+ handles, pending, error = [], [], None
702
+ for allocation in request.reservations:
703
+ child = self._reader._load_direct_child(parent, allocation.child_run_id)
704
+ handle = self._handles.get(allocation.child_run_id)
705
+ if (child is None or handle is None or handle.kernel is None
706
+ or handle.reservation != allocation):
707
+ pending.append(allocation.child_run_id)
708
+ error = "child_owner_unavailable"
709
+ else:
710
+ handles.append(handle)
711
+ if request.action == "cancel":
712
+ for handle in handles:
713
+ if not handle.task.done():
714
+ handle.task.cancel()
715
+ await _settle(_join(tuple(handle.task for handle in handles)))
716
+ elif request.action == "wait":
717
+ # The enclosing parent effect owns a deadline and cancellation.
718
+ # Ending observation cannot itself cancel an independent child.
719
+ if self.approval_bridge:
720
+ await observe_until_ready(handles)
721
+ else:
722
+ await asyncio.gather(*(asyncio.shield(handle.task) for handle in handles),
723
+ return_exceptions=True)
724
+ results, approvals = [], []
725
+ for handle in handles:
726
+ if not handle.task.done():
727
+ pending.append(handle.request.child_run_id)
728
+ if self.approval_bridge and (approval := current_approval(handle)) is not None:
729
+ approvals.append(approval)
730
+ continue
731
+ result = self._terminal_result(handle)
732
+ if result.child_budget_settlement is None:
733
+ pending.append(handle.request.child_run_id)
734
+ error = "child_receipt_unavailable"
735
+ else:
736
+ results.append(result)
737
+ return ChildLifecycleResult(
738
+ operation_key=request.operation_key, results=tuple(results),
739
+ pending_child_run_ids=tuple(pending), error_code=error,
740
+ approvals=tuple(approvals),
741
+ )
742
+
743
+ def ready_children(self, request: ChildReadyRequest) -> ChildReadyResult:
744
+ """Hint from original owned terminal receipts; never mutate parent facts."""
745
+ request = ChildReadyRequest.model_validate_json(request.model_dump_json())
746
+ if request.scope != self.scope:
747
+ raise ValueError("child_lifecycle_scope_mismatch")
748
+ parent = self.store.load(self.scope, request.run_id)
749
+ expected = tuple(item for item in parent.child_budget_reservations
750
+ if item.settled_usage_digest is None)
751
+ if parent.phase.terminal or expected != request.reservations:
752
+ raise ValueError("child_lifecycle_parent_changed")
753
+ ready = []
754
+ for allocation in request.reservations:
755
+ child = self._reader._load_direct_child(parent, allocation.child_run_id)
756
+ handle = self._handles.get(allocation.child_run_id)
757
+ if (child is not None and handle is not None and handle.reservation == allocation
758
+ and handle.task is not None and (
759
+ handle.task.done()
760
+ and self._terminal_result(handle).child_budget_settlement is not None
761
+ or request.include_approvals and self.approval_bridge
762
+ and current_approval(handle) is not None
763
+ )):
764
+ ready.append(allocation.child_run_id)
765
+ return ChildReadyResult(child_run_ids=tuple(ready))
766
+
767
+ async def execute(self, request: ToolRequest) -> ToolResult:
768
+ request = ToolRequest.model_validate_json(request.model_dump_json())
769
+ definitions = {item.name: item for item in self.definitions()}
770
+ if self._closed:
771
+ return self._delegate._error("child_owner_closed")
772
+ if request.scope != self.scope or request.definition != definitions.get(request.call.name):
773
+ return self._delegate._error("child_scope_or_definition_mismatch")
774
+ try:
775
+ if request.call.name == "native_start_child":
776
+ return await self._start(request)
777
+ return await self._control(request)
778
+ except (ValueError, KeyError, ScopeMismatch, StoreConflict):
779
+ return self._delegate._error("child_lifecycle_request_rejected")
780
+
781
+ async def close(self):
782
+ self._closed = True
783
+ tasks = [handle.task for handle in self._handles.values() if handle.task is not None]
784
+ for task in tasks:
785
+ if not task.done():
786
+ task.cancel()
787
+ if tasks:
788
+ await _settle(_join(tasks))
789
+
790
+ async def release_run(self, request: ChildResourceReleaseRequest) -> None:
791
+ request = ChildResourceReleaseRequest.model_validate_json(request.model_dump_json())
792
+ if request.scope != self.scope:
793
+ raise ValueError("child_release_scope_mismatch")
794
+ tasks = [handle.task for handle in self._handles.values()
795
+ if handle.request.parent_run_id == request.run_id
796
+ and handle.request.parent_scope == request.scope and handle.task is not None]
797
+ for task in tasks:
798
+ if not task.done():
799
+ task.cancel()
800
+ if tasks:
801
+ await _settle(_join(tasks))
802
+ # The activation is reusable by later parent turns. Do not close the
803
+ # owner, mutate parent facts, or stop another parent's resources.