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,976 @@
1
+ """Host-owned request planning and compaction sealing; stable public entry points.
2
+
3
+ Projection, partition construction and immutable contracts live in focused
4
+ modules. The caller still owns model I/O, durable intents and Run budgets."""
5
+
6
+ from __future__ import annotations
7
+
8
+ import hashlib as hashlib
9
+ import json as json
10
+ from typing import Callable as Callable
11
+ from typing import Literal as Literal
12
+
13
+ from pydantic import AliasChoices as AliasChoices
14
+ from pydantic import BaseModel as BaseModel
15
+ from pydantic import ConfigDict as ConfigDict
16
+ from pydantic import Field as Field
17
+ from pydantic import JsonValue as JsonValue
18
+ from pydantic import model_serializer as model_serializer
19
+ from pydantic import model_validator as model_validator
20
+
21
+ from .completion import TaskContract as TaskContract
22
+ from .context import CompactionEnvelope as CompactionEnvelope
23
+ from .context import CompactionProjection as CompactionProjection
24
+ from .context import CompactionRejected as CompactionRejected
25
+ from .context import ContextBudget as ContextBudget
26
+ from .context import ContextMessage as ContextMessage
27
+ from .context import ExecutionContinuityState as ExecutionContinuityState
28
+ from .context import _tool_groups as _tool_groups
29
+ from .context import continuity_digest as continuity_digest
30
+ from .context import validate_compaction as validate_compaction
31
+ from .context_artifact_page import artifact_page_observation as artifact_page_observation
32
+ from .context_artifact_page import complete_artifact_call_ids as complete_artifact_call_ids
33
+ from .context_compaction_projection import seal_compaction_projection
34
+ from .context_fresh_tools import fresh_tool_group_refs
35
+ from .context_history import ContextRuntimeError as ContextRuntimeError
36
+ from .context_history import _content_blocks as _content_blocks
37
+ from .context_history import _goal_message_index
38
+ from .context_history import _historical_message as _historical_message
39
+ from .context_history import _json as _json
40
+ from .context_history import _unambiguous_json_object as _unambiguous_json_object
41
+ from .context_history import compact_historical_protocol as compact_historical_protocol
42
+ from .context_history import summary_media_blocks as summary_media_blocks
43
+ from .context_history import text_only_tool_message as text_only_tool_message
44
+ from .context_partition import BatchPartition as BatchPartition
45
+ from .context_partition import SummaryPartitionState as SummaryPartitionState
46
+ from .context_partition import acknowledge as acknowledge
47
+ from .context_partition import bind_pending as bind_pending
48
+ from .context_partition import expected_remaining_refs as expected_remaining_refs
49
+ from .context_partition import fragment_view as fragment_view
50
+ from .context_partition import new_coverage as new_coverage
51
+ from .context_partition import raw_batch_entries as raw_batch_entries
52
+ from .context_partition import require_complete as require_complete
53
+ from .context_partition import source_manifest as source_manifest
54
+ from .context_partition import validate_coverage as validate_coverage
55
+ from .context_pruning import project_fresh_workspace_reads as project_fresh_workspace_reads
56
+ from .context_pruning import project_historical_tool_result as project_historical_tool_result
57
+ from .context_pruning import project_workspace_read_result as project_workspace_read_result
58
+ from .context_request_projection import ContextRequestProjection
59
+ from .context_runtime_contracts import (
60
+ READER_SUMMARY_POLICY_VERSION as READER_SUMMARY_POLICY_VERSION,
61
+ )
62
+ from .context_runtime_contracts import (
63
+ CompactionHistory as CompactionHistory,
64
+ )
65
+ from .context_runtime_contracts import (
66
+ CompactionPolicy as CompactionPolicy,
67
+ )
68
+ from .context_runtime_contracts import (
69
+ CompactionProjectionOverflow as CompactionProjectionOverflow,
70
+ )
71
+ from .context_runtime_contracts import (
72
+ CompactionRequest as CompactionRequest,
73
+ )
74
+ from .context_runtime_contracts import (
75
+ CompactionResult as CompactionResult,
76
+ )
77
+ from .context_runtime_contracts import (
78
+ ContextPlan as ContextPlan,
79
+ )
80
+ from .context_runtime_contracts import (
81
+ Messages as Messages,
82
+ )
83
+ from .context_runtime_contracts import (
84
+ PreparedContext as PreparedContext,
85
+ )
86
+ from .context_runtime_contracts import (
87
+ _compacted_messages as _compacted_messages,
88
+ )
89
+ from .context_runtime_contracts import (
90
+ _complete_source_entry as _complete_source_entry,
91
+ )
92
+ from .context_runtime_contracts import (
93
+ _Contract as _Contract,
94
+ )
95
+ from .context_runtime_contracts import (
96
+ _full_reader_quote as _full_reader_quote,
97
+ )
98
+ from .context_runtime_contracts import (
99
+ _model_continuity as _model_continuity,
100
+ )
101
+ from .context_runtime_contracts import (
102
+ _refs as _refs,
103
+ )
104
+ from .context_runtime_contracts import (
105
+ _resume as _resume,
106
+ )
107
+ from .context_runtime_contracts import (
108
+ _summary as _summary,
109
+ )
110
+ from .context_runtime_contracts import (
111
+ _summary_continuation as _summary_continuation,
112
+ )
113
+ from .context_runtime_contracts import (
114
+ _summary_units as _summary_units,
115
+ )
116
+ from .context_runtime_contracts import (
117
+ source_context_digest as source_context_digest,
118
+ )
119
+ from .context_search import complete_search_call_ids as complete_search_call_ids
120
+ from .context_search import complete_search_observation as complete_search_observation
121
+ from .context_source_fragments import SourceTextPart as SourceTextPart
122
+ from .context_source_fragments import source_part_view as source_part_view
123
+ from .context_source_fragments import source_text_carrier as source_text_carrier
124
+ from .context_summary_planning import ContextSummaryPlanning
125
+ from .model import ModelProfile as ModelProfile
126
+ from .model import ModelReplayMetadata as ModelReplayMetadata
127
+ from .model_replay import replay_binding_failure as replay_binding_failure
128
+ from .model_replay import replay_fields as replay_fields
129
+ from .ports import ToolDefinition as ToolDefinition
130
+ from .ports import digest as digest
131
+ from .tool_observation import history_observation_message as history_observation_message
132
+ from .tool_observation import model_observation_message as model_observation_message
133
+ from .tool_observation import model_observation_messages as model_observation_messages
134
+ from .turn_control import ModelTurnControl as ModelTurnControl
135
+ from .user_document import user_document_indexes
136
+
137
+ _MAX_SUMMARY_CHUNKS = 8
138
+
139
+
140
+ class ContextPlanner(ContextRequestProjection, ContextSummaryPlanning):
141
+ def __init__(
142
+ self,
143
+ *,
144
+ count_tokens: Callable[[str], int],
145
+ tokenizer_id: str,
146
+ policy: CompactionPolicy | None = None,
147
+ count_message_tokens: Callable[[dict[str, JsonValue]], int] | None = None,
148
+ tool_media_projection_version: Literal["source-profile-tool-media/v1"] | None = None,
149
+ summary_budget_unit: Literal["tokens", "estimated tokens", "UTF-8 bytes"] = "tokens",
150
+ summary_budget_mode: Literal["strict", "context_bounded_estimate"] = "strict",
151
+ summary_completion_policy: Literal["bounded-committed-summary/v1"] | None = None,
152
+ subagent_continuity_policy: Literal["accounted_child_runs/v1"] | None = None,
153
+ source_progress_policy: Literal["receipt-source-progress/v2"] | None = None,
154
+ ) -> None:
155
+ if (
156
+ not callable(count_tokens)
157
+ or not isinstance(tokenizer_id, str)
158
+ or not tokenizer_id.strip()
159
+ ):
160
+ raise ValueError("a host token counter and tokenizer_id are required")
161
+ if count_message_tokens is not None and not callable(count_message_tokens):
162
+ raise ValueError("message token counter must be callable")
163
+ if summary_budget_unit not in {"tokens", "estimated tokens", "UTF-8 bytes"}:
164
+ raise ValueError("unsupported summary budget unit")
165
+ if summary_budget_mode not in {"strict", "context_bounded_estimate"} or (
166
+ summary_budget_mode == "context_bounded_estimate"
167
+ and summary_budget_unit != "estimated tokens"
168
+ ):
169
+ raise ValueError("context-bounded summary admission requires an estimated counter")
170
+ if tool_media_projection_version not in {None, "source-profile-tool-media/v1"}:
171
+ raise ValueError("unsupported tool media projection version")
172
+ self.tool_media_projection_version = tool_media_projection_version
173
+ self.count_tokens = count_tokens
174
+ # Effective source projection versions the counter input, not only
175
+ # its arithmetic. Existing history and ContextDriver binding inherit it.
176
+ self.tokenizer_id = (
177
+ f"{tokenizer_id}|{tool_media_projection_version}"
178
+ if tool_media_projection_version
179
+ else tokenizer_id
180
+ )
181
+ # tokenizer_id versions BOTH counters, including image cost/framing for
182
+ # the pinned provider projection. The host owns that model-specific math.
183
+ self.count_message_tokens = count_message_tokens
184
+ self.summary_budget_unit = summary_budget_unit
185
+ self.summary_budget_mode = summary_budget_mode
186
+ if summary_completion_policy not in {None, "bounded-committed-summary/v1"}:
187
+ raise ValueError("unsupported summary completion policy")
188
+ self.summary_completion_policy = summary_completion_policy
189
+ if subagent_continuity_policy not in {None, "accounted_child_runs/v1"}:
190
+ raise ValueError("unsupported subagent continuity policy")
191
+ self.subagent_continuity_policy = subagent_continuity_policy
192
+ if source_progress_policy not in {None, "receipt-source-progress/v2"}:
193
+ raise ValueError("unsupported source progress policy")
194
+ self.source_progress_policy = source_progress_policy
195
+ self.policy = policy or CompactionPolicy()
196
+
197
+ def plan(
198
+ self,
199
+ *,
200
+ source_revision: int,
201
+ model_turn: int,
202
+ profile: ModelProfile,
203
+ instructions: str,
204
+ tools: tuple[ToolDefinition, ...],
205
+ context_tools: tuple[ToolDefinition, ...] | None = None,
206
+ messages: Messages,
207
+ continuity: ExecutionContinuityState,
208
+ contract: TaskContract,
209
+ history: CompactionHistory | None = None,
210
+ force_compaction: bool = False,
211
+ turn_control: ModelTurnControl | None = None,
212
+ allow_compaction: bool = True,
213
+ ) -> ContextPlan:
214
+ try:
215
+ return self._plan(
216
+ source_revision=source_revision,
217
+ model_turn=model_turn,
218
+ profile=profile,
219
+ instructions=instructions,
220
+ tools=tools,
221
+ context_tools=tools if context_tools is None else context_tools,
222
+ messages=messages,
223
+ continuity=continuity,
224
+ contract=contract,
225
+ history=history or CompactionHistory(),
226
+ force_compaction=force_compaction,
227
+ turn_control=turn_control,
228
+ allow_compaction=allow_compaction,
229
+ )
230
+ except ContextRuntimeError as exc:
231
+ return ContextPlan(action="blocked", reason=str(exc))
232
+ except (CompactionRejected, ValueError, KeyError, TypeError):
233
+ return ContextPlan(action="blocked", reason="context_protocol_invalid")
234
+
235
+ def _active(
236
+ self,
237
+ messages: Messages,
238
+ continuity: ExecutionContinuityState,
239
+ history: CompactionHistory,
240
+ ) -> tuple[tuple[str, ...], Messages, str]:
241
+ refs = _refs(messages)
242
+ if history.count:
243
+ if history.summary_completion_policy != self.summary_completion_policy:
244
+ raise ContextRuntimeError("context_summary_completion_policy_changed")
245
+ if history.tokenizer_id != self.tokenizer_id:
246
+ raise ContextRuntimeError("context_tokenizer_changed")
247
+ prefix = messages[: history.prefix_message_count]
248
+ if (
249
+ len(prefix) != history.prefix_message_count
250
+ or source_context_digest(prefix) != history.prefix_digest
251
+ or history.contract_digest != continuity.contract_digest
252
+ ):
253
+ raise ContextRuntimeError("context_history_changed")
254
+ if (
255
+ not history.summary_text.strip()
256
+ or not set(history.retained_message_refs).issubset(
257
+ refs[: history.prefix_message_count]
258
+ )
259
+ or len(set(history.retained_message_refs)) != len(history.retained_message_refs)
260
+ ):
261
+ raise ContextRuntimeError("context_history_invalid")
262
+ indexes = [
263
+ i
264
+ for i, ref in enumerate(refs)
265
+ if i >= history.prefix_message_count or ref in history.retained_message_refs
266
+ ]
267
+ else:
268
+ indexes = list(range(len(messages)))
269
+ # A correction creates a new source receipt. Keep the old transcript
270
+ # and compaction prefix immutable, but do not present superseded data
271
+ # as the current goal's Context. Other history remains ordinary input.
272
+ indexes = [
273
+ i for i in indexes
274
+ if messages[i].get("kind") != "context_contribution"
275
+ or messages[i].get("goal_revision") == continuity.goal_revision
276
+ ]
277
+ indexes = [
278
+ i for i in indexes
279
+ if messages[i].get("kind") != "context_contribution"
280
+ or messages[i].get("context_operation_key") is None
281
+ or messages[i].get("context_operation_key") == continuity.context_source_operation_key
282
+ ]
283
+ active_refs = tuple(refs[i] for i in indexes)
284
+ active = tuple(messages[i] for i in indexes)
285
+ return active_refs, active, active_refs[_goal_message_index(active, continuity.goal)]
286
+
287
+ def _plan(
288
+ self,
289
+ *,
290
+ source_revision,
291
+ model_turn,
292
+ profile,
293
+ instructions,
294
+ tools,
295
+ context_tools,
296
+ messages,
297
+ continuity,
298
+ contract,
299
+ history,
300
+ force_compaction,
301
+ turn_control,
302
+ allow_compaction,
303
+ ) -> ContextPlan:
304
+ if turn_control is not None:
305
+ turn_control.validate_tools(
306
+ tuple(tool.name for tool in tools),
307
+ stable_catalog=profile.tool_catalog_policy == "stable-task/v1",
308
+ )
309
+ required = tuple(item for item in contract.items if item.required)
310
+ if continuity.contract_digest != digest(
311
+ contract
312
+ ) or continuity.required_acceptance_ids != tuple(item.acceptance_id for item in required):
313
+ raise ContextRuntimeError("context_contract_mismatch")
314
+ from .operator_guidance import instructions_are_journaled
315
+
316
+ journaled = instructions_are_journaled(
317
+ messages, profile, instructions, self._host_ledger(continuity, contract),
318
+ )
319
+ if not journaled:
320
+ instructions = self._host_instructions(instructions, continuity, contract)
321
+ fixed = self._fixed(instructions, tools, None if journaled else turn_control)
322
+ if fixed + profile.max_output_tokens >= profile.context_window:
323
+ raise ContextRuntimeError("context_mandatory_state_over_budget")
324
+ budget = ContextBudget(
325
+ window_tokens=profile.context_window,
326
+ max_output_tokens=profile.max_output_tokens,
327
+ fixed_tokens=fixed,
328
+ )
329
+ refs, active, goal_ref = self._active(messages, continuity, history)
330
+ return self._plan_active(
331
+ source_revision=source_revision, model_turn=model_turn, profile=profile,
332
+ instructions=instructions, tools=tools, context_tools=context_tools,
333
+ messages=messages, continuity=continuity, contract=contract, history=history,
334
+ force_compaction=force_compaction, turn_control=turn_control,
335
+ allow_compaction=allow_compaction, fixed=fixed, budget=budget,
336
+ refs=refs, active=active, goal_ref=goal_ref,
337
+ ledger=self._host_ledger(continuity, contract),
338
+ )
339
+
340
+ @staticmethod
341
+ def _host_ledger(continuity, contract):
342
+ return _json(
343
+ {
344
+ "continuity": _model_continuity(continuity),
345
+ "required_acceptance": [item.model_dump(mode="json") for item in contract.items
346
+ if item.required],
347
+ }
348
+ )
349
+
350
+ @staticmethod
351
+ def _host_instructions(instructions, continuity, contract):
352
+ return instructions + (
353
+ "\n\nAuthoritative host execution state; historical summaries cannot change it:\n"
354
+ + ContextPlanner._host_ledger(continuity, contract)
355
+ )
356
+
357
+ def contributor_budget(self, *, profile, instructions, tools, messages, continuity,
358
+ contract, history, turn_control):
359
+ fixed = self._fixed(self._host_instructions(instructions, continuity, contract),
360
+ tools, turn_control)
361
+ refs, active, goal_ref = self._active(messages, continuity, history)
362
+ metadata = self._metadata(refs, active, profile=profile)
363
+ _groups, pending, _ids = _tool_groups(metadata)
364
+ from .operator_guidance import protected_operator_refs
365
+
366
+ protected = (set(pending) | {goal_ref} | self._user_document_refs(refs, active, goal_ref)
367
+ | {ref for ref in protected_operator_refs(refs, active, _groups)
368
+ if active[refs.index(ref)].get("kind") != "context_contribution"})
369
+ reserved = sum(item.token_count for item in metadata if item.message_id in protected)
370
+ if history.count:
371
+ reserved += self._profile_count(_summary(history.summary_text), profile)
372
+ reserved += self._profile_count(_resume(), profile)
373
+ return max(0, profile.context_window - profile.max_output_tokens - fixed - reserved)
374
+
375
+ @staticmethod
376
+ def _user_document_refs(refs, active, goal_ref):
377
+ try:
378
+ return {refs[index] for index in user_document_indexes(active, refs.index(goal_ref))}
379
+ except ValueError as exc:
380
+ raise ContextRuntimeError("native_user_document_source_mismatch") from exc
381
+
382
+ def _plan_active(self, *, source_revision, model_turn, profile, instructions, tools,
383
+ context_tools, messages, continuity, contract, history, force_compaction,
384
+ turn_control, allow_compaction, fixed, budget, refs, active, goal_ref, ledger):
385
+ from .context_replay import compaction_replay_view
386
+ from .replay_context import request_header_digest
387
+
388
+ header = request_header_digest(instructions, tools, profile)
389
+
390
+ if history.count and (
391
+ history.provider_replay_projection_policy != profile.provider_replay_projection_policy
392
+ ):
393
+ raise ContextRuntimeError("context_provider_replay_policy_changed")
394
+ replay_view = compaction_replay_view(
395
+ active, refs, covered_refs=history.retained_message_refs, profile=profile,
396
+ root_prefix_digest=history.prefix_digest,
397
+ )
398
+ reader_names = frozenset(
399
+ tool.name
400
+ for tool in context_tools
401
+ if tool.read_only and tool.context_role == "workspace_read"
402
+ )
403
+ search_names = frozenset(
404
+ tool.name
405
+ for tool in context_tools
406
+ if tool.read_only and tool.context_role == "workspace_search"
407
+ )
408
+ artifact_reader_names = frozenset(
409
+ tool.name for tool in context_tools
410
+ if tool.read_only and tool.context_role == "artifact_read"
411
+ )
412
+ capture_reader_names = frozenset(
413
+ tool.name for tool in context_tools
414
+ if tool.name in reader_names and tool.result_archive_policy == "archived-model-view/v3"
415
+ ) | artifact_reader_names
416
+ metadata = self._metadata(refs, active, counted_messages=replay_view, profile=profile)
417
+ groups, pending_refs, pending_ids = _tool_groups(metadata)
418
+ fresh_group = fresh_tool_group_refs(messages)
419
+ if not fresh_group.issubset(refs):
420
+ # A prior summary may already cover the original trailing group.
421
+ fresh_group = frozenset()
422
+ if pending_ids != frozenset(continuity.pending_tool_call_ids):
423
+ raise ContextRuntimeError("context_pending_tool_mismatch")
424
+ summary_limit = min(self.policy.summary_max_tokens, profile.max_output_tokens)
425
+ reserved_summary = self.summary_reservation(profile)
426
+ from .operator_guidance import protected_operator_refs
427
+
428
+ mandatory = (
429
+ set(pending_refs) | {goal_ref} | protected_operator_refs(refs, active, groups)
430
+ | self._user_document_refs(refs, active, goal_ref)
431
+ | {ref for ref, raw in zip(refs, active)
432
+ if raw.get("kind") == "context_contribution"
433
+ and raw.get("goal_revision") == continuity.goal_revision}
434
+ | {ref for ref, raw in zip(refs, active)
435
+ if raw.get("kind") == "background_child_observation"
436
+ and raw.get("child_run_id") in continuity.pending_subagent_refs}
437
+ )
438
+ hook_refs = {raw.get("hook_operation_key"): ref for ref, raw in zip(refs, active)
439
+ if raw.get("kind") == "hook_context"
440
+ and raw.get("hook_goal_revision") == continuity.goal_revision}
441
+ guidance_refs = {raw.get("input_id"): ref for ref, raw in zip(refs, active)
442
+ if raw.get("role") == "user" and raw.get("kind") == "user_guidance"
443
+ and raw.get("input_goal_revision") == continuity.goal_revision}
444
+ if not set(continuity.pending_guidance_ids).issubset(guidance_refs):
445
+ raise ContextRuntimeError("context_pending_guidance_missing")
446
+ mandatory |= {guidance_refs[key] for key in continuity.pending_guidance_ids}
447
+ if not set(continuity.pending_hook_operation_keys).issubset(hook_refs):
448
+ raise ContextRuntimeError("context_pending_hook_missing")
449
+ mandatory |= {hook_refs[key] for key in continuity.pending_hook_operation_keys}
450
+ protected_readers = frozenset()
451
+ if groups and self.policy.read_working_set_count and not force_compaction:
452
+ latest = groups[-1]
453
+ definitions = {tool.name: tool for tool in context_tools}
454
+ calls = [
455
+ call
456
+ for ref, raw in zip(refs, active)
457
+ if ref in latest
458
+ for call in raw.get("tool_calls", ())
459
+ ]
460
+ group_cost = sum(m.token_count for m in metadata if m.message_id in latest)
461
+ if (
462
+ group_cost <= self.policy.read_working_set_max_tokens
463
+ and group_cost <= self.policy.read_working_set_total_max_tokens
464
+ and sum(m.token_count for m in metadata if m.message_id in latest | mandatory)
465
+ + reserved_summary
466
+ <= budget.input_capacity
467
+ and all(
468
+ (definition := definitions.get(call["function"]["name"])) is not None
469
+ and (definition.read_only or definition.context_role == "task_planning")
470
+ for call in calls
471
+ )
472
+ ):
473
+ # Compaction should reduce earlier history before clipping a
474
+ # latest, bounded complete source batch that already fits.
475
+ # A provider-reported overflow deliberately disables this.
476
+ protected_readers = frozenset(
477
+ call["id"] for call in calls if call["function"]["name"] in reader_names
478
+ )
479
+ read_view = self._read_view(replay_view, reader_names, protected_readers)
480
+ if read_view != active:
481
+ metadata = self._metadata(refs, active, counted_messages=read_view, profile=profile)
482
+ visible = (
483
+ _compacted_messages(history.summary_text, replay_view, continuity.goal)
484
+ if history.count
485
+ else replay_view
486
+ )
487
+ prepared = self._prepared(instructions, visible, fixed, turn_control,
488
+ profile=profile, goal=continuity.goal,
489
+ abandoned=history.abandoned_replay_digests,
490
+ replay_header_digest=header)
491
+ if (self.policy.enabled and self.policy.prune_tool_results and not force_compaction
492
+ and prepared.counted_input_tokens - budget.fixed_tokens
493
+ >= budget.input_capacity * self.policy.trigger_ratio):
494
+ pruned = self._prune_old_results(
495
+ prepared, refs=refs, active=replay_view, groups=groups, mandatory=mandatory,
496
+ metadata=metadata, continuity=continuity, history=history, tools=context_tools,
497
+ profile=profile, fixed=fixed, turn_control=turn_control,
498
+ )
499
+ if (pruned is not None and pruned.counted_input_tokens - budget.fixed_tokens
500
+ < budget.input_capacity * self.policy.trigger_ratio):
501
+ return ContextPlan(action="ready", reason="historical_tool_results_within_budget",
502
+ prepared=pruned)
503
+ if not self.policy.enabled:
504
+ if (force_compaction or prepared.counted_input_tokens + profile.max_output_tokens
505
+ > profile.context_window):
506
+ raise ContextRuntimeError("context_compaction_disabled")
507
+ return ContextPlan(
508
+ action="ready", reason="context_compaction_disabled", prepared=prepared
509
+ )
510
+ if not allow_compaction:
511
+ # A soft context target cannot spend a model call reserved for
512
+ # delivery. Keep the complete currently authorized projection;
513
+ # never seal a partial summary or drop evidence to make it fit.
514
+ if (force_compaction or prepared.counted_input_tokens + profile.max_output_tokens
515
+ > profile.context_window):
516
+ raise ContextRuntimeError("context_finalization_budget_unavailable")
517
+ return ContextPlan(
518
+ action="ready", reason="context_finalization_reserved", prepared=prepared
519
+ )
520
+ fresh_search_ids = (
521
+ complete_search_call_ids(
522
+ [raw for ref, raw in zip(refs, active) if ref in groups[-1]],
523
+ tool_names=search_names,
524
+ )
525
+ if groups
526
+ else frozenset()
527
+ )
528
+ fresh_artifact_ids = (
529
+ complete_artifact_call_ids(
530
+ [raw for ref, raw in zip(refs, active) if ref in groups[-1]],
531
+ tool_names=artifact_reader_names,
532
+ ) if groups else frozenset()
533
+ )
534
+ if (
535
+ not force_compaction
536
+ and groups
537
+ and (fresh_group or refs[-1] in groups[-1])
538
+ and (
539
+ fresh_group
540
+ or fresh_search_ids
541
+ or fresh_artifact_ids
542
+ or any(
543
+ call["function"]["name"] in reader_names
544
+ for ref, raw in zip(refs, active)
545
+ if ref in groups[-1]
546
+ for call in raw.get("tool_calls", ())
547
+ )
548
+ )
549
+ and prepared.counted_input_tokens + profile.max_output_tokens <= profile.context_window
550
+ ):
551
+ # The soft compaction target must not hide a just-returned source
552
+ # batch that fits the locked complete request. Provider overflow
553
+ # still takes the existing reduction path.
554
+ return ContextPlan(
555
+ action="ready",
556
+ reason=(
557
+ "fresh_search_complete_request_fits"
558
+ if fresh_search_ids
559
+ else "fresh_artifact_complete_request_fits"
560
+ if fresh_artifact_ids
561
+ else "fresh_reader_complete_request_fits"
562
+ if any(
563
+ call["function"]["name"] in reader_names
564
+ for ref, raw in zip(refs, active) if ref in groups[-1]
565
+ for call in raw.get("tool_calls", ())
566
+ )
567
+ else "fresh_tool_complete_request_fits"
568
+ ),
569
+ prepared=prepared,
570
+ )
571
+ if (
572
+ not force_compaction
573
+ and prepared.counted_input_tokens - budget.fixed_tokens
574
+ < budget.input_capacity * self.policy.trigger_ratio
575
+ ):
576
+ return ContextPlan(action="ready", reason="context_within_budget", prepared=prepared)
577
+ if not force_compaction and self.policy.fresh_read_max_chars is not None:
578
+ observed = self._read_view(visible, reader_names, protected_readers)
579
+ if observed != visible:
580
+ view = self._prepared(instructions, observed, fixed, turn_control,
581
+ profile=profile, goal=continuity.goal,
582
+ abandoned=history.abandoned_replay_digests,
583
+ replay_header_digest=header)
584
+ if view.counted_input_tokens + profile.max_output_tokens <= profile.context_window:
585
+ return ContextPlan(
586
+ action="ready",
587
+ reason="fresh_reader_observations_within_budget",
588
+ prepared=view,
589
+ )
590
+ # Growing history must not progressively starve the newest
591
+ # source observation. Reduce old history through compaction
592
+ # rather than shrinking all fresh windows down to 128 chars.
593
+ # The host's summary ceiling and the provider's output-token cap are
594
+ # different units. Reasoning tokens can consume the provider cap before
595
+ # any visible summary appears; enforce the host ceiling only when the
596
+ # visible summary is sealed. Only the actual hard request window may
597
+ # reduce a complete Reader quote's provider output cap.
598
+ mandatory_cost = sum(m.token_count for m in metadata if m.message_id in mandatory)
599
+ if mandatory_cost + reserved_summary > budget.input_capacity:
600
+ raise ContextRuntimeError("context_mandatory_state_over_budget")
601
+ retained = self._retain(
602
+ metadata,
603
+ groups,
604
+ pending_refs,
605
+ mandatory,
606
+ budget,
607
+ reserved_summary,
608
+ active=active,
609
+ continuity=continuity,
610
+ history=history,
611
+ tools=context_tools,
612
+ force_compaction=force_compaction,
613
+ fresh_group=fresh_group,
614
+ )
615
+ dropped = tuple(raw for ref, raw in zip(refs, active) if ref not in retained)
616
+ if not dropped:
617
+ if force_compaction:
618
+ raise ContextRuntimeError("context_overflow_no_reducible_history")
619
+ if prepared.counted_input_tokens + profile.max_output_tokens > profile.context_window:
620
+ raise ContextRuntimeError("context_mandatory_state_over_budget")
621
+ return ContextPlan(
622
+ action="ready", reason="context_no_reducible_history", prepared=prepared
623
+ )
624
+ if (
625
+ self.policy.max_compactions is not None
626
+ and history.total_compactions >= self.policy.max_compactions
627
+ ):
628
+ raise ContextRuntimeError("context_compaction_limit")
629
+ observed_progress = history.count > 0 and (
630
+ continuity.observed_progress_revision > history.last_observed_progress_revision
631
+ or (
632
+ continuity.workspace_revision is not None
633
+ and continuity.workspace_revision != history.last_workspace_revision
634
+ )
635
+ )
636
+ if (
637
+ history.count
638
+ and not observed_progress
639
+ and history.stagnant_count >= self.policy.max_compactions_without_progress
640
+ ):
641
+ raise ContextRuntimeError("context_compaction_no_observed_progress")
642
+ if (
643
+ history.total_compactions
644
+ and model_turn - history.last_model_turn < self.policy.min_model_turns_between
645
+ ):
646
+ raise ContextRuntimeError("context_rapid_refill")
647
+ return self._request(
648
+ source_revision,
649
+ model_turn,
650
+ profile,
651
+ instructions,
652
+ messages,
653
+ continuity,
654
+ history,
655
+ metadata,
656
+ refs,
657
+ active,
658
+ retained,
659
+ dropped,
660
+ budget,
661
+ summary_limit,
662
+ ledger,
663
+ turn_control,
664
+ reader_names,
665
+ protected_readers,
666
+ search_names=search_names,
667
+ capture_reader_names=capture_reader_names,
668
+ artifact_reader_names=artifact_reader_names,
669
+ replay_header_digest=header,
670
+ fresh_group=fresh_group,
671
+ )
672
+
673
+
674
+ class CompactionController:
675
+ def __init__(self, planner: ContextPlanner) -> None:
676
+ self.planner = planner
677
+
678
+ def continue_summary(
679
+ self,
680
+ request: CompactionRequest,
681
+ fragment: str,
682
+ *,
683
+ current_revision: int,
684
+ current_continuity: ExecutionContinuityState,
685
+ current_messages: Messages,
686
+ provider_replay: ModelReplayMetadata | None = None,
687
+ ) -> CompactionRequest:
688
+ self._validate_source(request, current_revision, current_continuity, current_messages)
689
+ if failure := replay_binding_failure(request.profile, provider_replay, required=True):
690
+ raise ContextRuntimeError(failure)
691
+ if request.summary_continuations >= request.profile.max_continuations:
692
+ raise ContextRuntimeError("compaction_summary_continuation_exhausted")
693
+ fragments = (*request.summary_fragments, fragment)
694
+ self._validate_summary(request, "".join(fragments))
695
+ messages = (
696
+ *request.summary_messages,
697
+ {"role": "assistant", "content": fragment, **replay_fields(provider_replay)},
698
+ _summary_continuation(),
699
+ )
700
+ counted = self.planner._fixed(request.summary_instructions, ()) + sum(
701
+ self.planner._count_message(message) for message in
702
+ self.planner._media_view(messages, request.profile, purpose="compaction")
703
+ )
704
+ output_limit = (
705
+ min(request.summary_output_tokens, request.profile.context_window - counted)
706
+ if request.full_reader_quote
707
+ else request.summary_output_tokens
708
+ )
709
+ if output_limit <= 0 or counted + output_limit > request.profile.context_window:
710
+ raise ContextRuntimeError("context_summary_continuation_over_budget")
711
+ return CompactionRequest.model_validate(
712
+ {
713
+ **request.model_dump(mode="json"),
714
+ "summary_messages": messages,
715
+ "summary_counted_input_tokens": counted,
716
+ "summary_output_tokens": output_limit,
717
+ "summary_fragments": fragments,
718
+ "summary_continuations": request.summary_continuations + 1,
719
+ }
720
+ )
721
+
722
+ def advance(
723
+ self,
724
+ request: CompactionRequest,
725
+ summary_text: str,
726
+ *,
727
+ current_revision: int,
728
+ current_continuity: ExecutionContinuityState,
729
+ current_messages: Messages,
730
+ ) -> CompactionRequest | CompactionResult:
731
+ self._validate_source(request, current_revision, current_continuity, current_messages)
732
+ summary_text = "".join((*request.summary_fragments, summary_text))
733
+ self._validate_summary(request, summary_text)
734
+ request = self._acknowledge_partition(request, current_messages)
735
+ if not request.remaining_history_entries:
736
+ return self.seal(
737
+ request,
738
+ summary_text,
739
+ current_revision=current_revision,
740
+ current_continuity=current_continuity,
741
+ current_messages=current_messages,
742
+ )
743
+ chunk_limit = _MAX_SUMMARY_CHUNKS
744
+ if request.summary_partition and request.summary_partition.partitions:
745
+ manifest, raw = source_manifest(
746
+ current_messages, request.old_messages, request.retained_message_refs,
747
+ capture_reader_names=request.source_capture_reader_names,
748
+ fresh_tool_observation_policy=request.fresh_tool_observation_policy,
749
+ fresh_tool_message_refs=request.fresh_tool_message_refs,
750
+ fresh_text_fragment_policy=request.fresh_text_fragment_policy,
751
+ fresh_text_excluded_tool_names=request.source_reader_names,
752
+ )
753
+ if any(
754
+ call["function"]["name"] in request.source_reader_names
755
+ for partition in request.summary_partition.partitions
756
+ for call in raw[partition.assistant_ref].get("tool_calls", ())
757
+ ) or (
758
+ request.fresh_text_fragment_policy is not None
759
+ and any(
760
+ ref in manifest.get("source_captures", {})
761
+ for partition in request.summary_partition.partitions
762
+ for ref in manifest["batches"][partition.assistant_ref]["receipt_refs"]
763
+ )
764
+ ):
765
+ # A validated quote consumes an original ref or advances a
766
+ # captured text cursor. Both are finite; every request still
767
+ # consumes the unchanged Run model budget.
768
+ chunk_limit = max(chunk_limit, len(manifest["dropped"]) + sum(
769
+ capture["total_chars"]
770
+ for capture in manifest.get("source_captures", {}).values()
771
+ ))
772
+ if request.chunk_index < 1 or request.chunk_index >= chunk_limit:
773
+ raise ContextRuntimeError("compaction_chunk_limit")
774
+ partition_state = request.summary_partition
775
+ if partition_state is None:
776
+ projected, counted, remaining = self.planner._next_chunk(
777
+ request.remaining_history_entries,
778
+ summary_text,
779
+ request.summary_instructions,
780
+ request.profile,
781
+ dict(zip(_refs(current_messages), current_messages)),
782
+ )
783
+ else:
784
+ manifest, source_messages = source_manifest(
785
+ current_messages, request.old_messages, request.retained_message_refs,
786
+ capture_reader_names=request.source_capture_reader_names,
787
+ fresh_tool_observation_policy=request.fresh_tool_observation_policy,
788
+ fresh_tool_message_refs=request.fresh_tool_message_refs,
789
+ fresh_text_fragment_policy=request.fresh_text_fragment_policy,
790
+ fresh_text_excluded_tool_names=request.source_reader_names,
791
+ )
792
+ projected, counted, remaining, partition_state = self.planner._next_covered_chunk(
793
+ request.remaining_history_entries,
794
+ summary_text,
795
+ request.summary_instructions,
796
+ request.profile,
797
+ source_messages,
798
+ partition_state,
799
+ manifest,
800
+ request.chunk_index + 1,
801
+ )
802
+ full_reader_quote = _full_reader_quote(projected, request.remaining_history_entries)
803
+ output_cap = self.planner._summary_output_cap(
804
+ counted, request.profile, full_reader_quote=full_reader_quote
805
+ )
806
+ next_request = CompactionRequest.model_validate(
807
+ {
808
+ **request.model_dump(mode="json"),
809
+ "summary_messages": projected,
810
+ "summary_counted_input_tokens": counted,
811
+ "remaining_history_entries": remaining,
812
+ "chunk_index": request.chunk_index + 1,
813
+ "summary_partition": partition_state,
814
+ "full_reader_quote": full_reader_quote,
815
+ "summary_output_tokens": output_cap,
816
+ "summary_fragments": (),
817
+ "summary_continuations": 0,
818
+ }
819
+ )
820
+ if next_request.fresh_tool_observation_policy is not None:
821
+ # Verify queued source before its next dispatch, not only after
822
+ # the provider responds. Rehashed, shortened remaining entries
823
+ # must never become an authorized fresh observation request.
824
+ self._validate_source(
825
+ next_request, current_revision, current_continuity, current_messages
826
+ )
827
+ return next_request
828
+
829
+ def _is_partition_quote(self, message):
830
+ if message.get("kind") == "summary_batch_fragment":
831
+ return True
832
+ content = message.get("content")
833
+ text = content[0].get("text") if isinstance(content, list) and content else content
834
+ try:
835
+ body = json.loads(text)
836
+ except (ValueError, TypeError):
837
+ return False
838
+ # Only the host's outer quote envelope; never scan nested tool text.
839
+ return isinstance(body, dict) and body.get("fragment") is not None
840
+
841
+ def _base_summary_messages(self, request):
842
+ return (
843
+ request.summary_messages[: -2 * request.summary_continuations]
844
+ if request.summary_continuations
845
+ else request.summary_messages
846
+ )
847
+
848
+ def _acknowledge_partition(self, request, messages):
849
+ state = request.summary_partition
850
+ if state is None or state.pending is None:
851
+ return request
852
+ manifest, raw = source_manifest(
853
+ messages, request.old_messages, request.retained_message_refs,
854
+ capture_reader_names=request.source_capture_reader_names,
855
+ fresh_tool_observation_policy=request.fresh_tool_observation_policy,
856
+ fresh_tool_message_refs=request.fresh_tool_message_refs,
857
+ fresh_text_fragment_policy=request.fresh_text_fragment_policy,
858
+ fresh_text_excluded_tool_names=request.source_reader_names,
859
+ )
860
+ state = acknowledge(
861
+ state,
862
+ manifest,
863
+ raw,
864
+ self._base_summary_messages(request),
865
+ request.chunk_index,
866
+ profile=request.profile if self.planner.tool_media_projection_version else None,
867
+ )
868
+ return request.model_copy(update={"summary_partition": state})
869
+
870
+ def _validate_source(
871
+ self,
872
+ request: CompactionRequest,
873
+ current_revision: int,
874
+ current_continuity: ExecutionContinuityState,
875
+ current_messages: Messages,
876
+ ) -> None:
877
+ if current_continuity != request.continuity:
878
+ raise ContextRuntimeError("context_continuity_changed")
879
+ if (
880
+ type(current_revision) is not int
881
+ or current_revision < request.source_revision
882
+ or source_context_digest(current_messages) != request.source_context_digest
883
+ ):
884
+ raise ContextRuntimeError("context_source_changed")
885
+ if request.tool_media_projection_version != self.planner.tool_media_projection_version:
886
+ raise ContextRuntimeError("context_media_projection_changed")
887
+ if request.tokenizer_id != self.planner.tokenizer_id:
888
+ raise ContextRuntimeError("context_tokenizer_changed")
889
+ if (request.summary_budget_mode or "strict") != self.planner.summary_budget_mode:
890
+ raise ContextRuntimeError("context_summary_policy_changed")
891
+ if request.summary_completion_policy != self.planner.summary_completion_policy:
892
+ raise ContextRuntimeError("context_summary_completion_policy_changed")
893
+ if request.fresh_tool_observation_policy is not None and (
894
+ request.summary_partition is None
895
+ or request.summary_partition_version != "quoted-history-coverage/v1"
896
+ ):
897
+ raise ContextRuntimeError("compaction_partition_state_missing")
898
+ if (
899
+ request.source_reader_names
900
+ or request.full_reader_quote
901
+ or any(_complete_source_entry(e) for e in request.remaining_history_entries)
902
+ ) and request.reader_summary_policy_version != READER_SUMMARY_POLICY_VERSION:
903
+ raise ContextRuntimeError("context_reader_policy_changed")
904
+ if request.summary_partition is None:
905
+ if any(
906
+ self._is_partition_quote(message)
907
+ for message in self._base_summary_messages(request)
908
+ ):
909
+ raise ContextRuntimeError("compaction_partition_state_missing")
910
+ else:
911
+ manifest, raw = source_manifest(
912
+ current_messages, request.old_messages, request.retained_message_refs,
913
+ capture_reader_names=request.source_capture_reader_names,
914
+ fresh_tool_observation_policy=request.fresh_tool_observation_policy,
915
+ fresh_tool_message_refs=request.fresh_tool_message_refs,
916
+ fresh_text_fragment_policy=request.fresh_text_fragment_policy,
917
+ fresh_text_excluded_tool_names=request.source_reader_names,
918
+ )
919
+ state = request.summary_partition
920
+ validate_coverage(
921
+ state,
922
+ manifest,
923
+ messages=self._base_summary_messages(request) if state.pending else None,
924
+ chunk_index=request.chunk_index,
925
+ raw=raw,
926
+ profile=request.profile if self.planner.tool_media_projection_version else None,
927
+ )
928
+ if state.pending is None:
929
+ require_complete(state, manifest)
930
+
931
+ def _validate_summary(self, request: CompactionRequest, summary_text: str) -> None:
932
+ if not isinstance(summary_text, str) or not summary_text.strip():
933
+ raise ContextRuntimeError("context_summary_empty")
934
+ # Exact counters retain their strict summary-size contract. A declared
935
+ # host estimate is a reduction target, not provider output usage: the
936
+ # same provider-limited response can exceed that estimate slightly.
937
+ # Transient text is bounded here; continuation and sealing separately
938
+ # admit the complete projected request against the original window.
939
+ limit = (
940
+ request.budget.input_capacity
941
+ if request.summary_budget_mode == "context_bounded_estimate"
942
+ else request.summary_max_tokens
943
+ )
944
+ if self.planner._count(summary_text) > limit:
945
+ raise ContextRuntimeError("context_summary_budget_exceeded")
946
+
947
+ def seal(
948
+ self,
949
+ request: CompactionRequest,
950
+ summary_text: str,
951
+ *,
952
+ current_revision: int,
953
+ current_continuity: ExecutionContinuityState,
954
+ current_messages: Messages,
955
+ ) -> CompactionResult:
956
+ self._validate_source(request, current_revision, current_continuity, current_messages)
957
+ self._validate_summary(request, summary_text)
958
+ if request.remaining_history_entries:
959
+ raise ContextRuntimeError("compaction_chunks_incomplete")
960
+ request = self._acknowledge_partition(request, current_messages)
961
+ if request.summary_partition is not None:
962
+ manifest, _ = source_manifest(
963
+ current_messages, request.old_messages, request.retained_message_refs,
964
+ capture_reader_names=request.source_capture_reader_names,
965
+ fresh_tool_observation_policy=request.fresh_tool_observation_policy,
966
+ fresh_tool_message_refs=request.fresh_tool_message_refs,
967
+ fresh_text_fragment_policy=request.fresh_text_fragment_policy,
968
+ fresh_text_excluded_tool_names=request.source_reader_names,
969
+ )
970
+ require_complete(request.summary_partition, manifest)
971
+ return self._seal_projection(request, summary_text, current_continuity, current_messages)
972
+
973
+ def _seal_projection(self, request, summary_text, current_continuity, current_messages):
974
+ return seal_compaction_projection(
975
+ self.planner, request, summary_text, current_continuity, current_messages
976
+ )