agentengine-sdk-python 0.8.4__py3-none-any.whl → 0.8.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1221) hide show
  1. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/METADATA +17 -10
  2. agentengine_sdk_python-0.8.6.dist-info/RECORD +1731 -0
  3. ksadk/_async_iterators.py +79 -0
  4. ksadk/_build_provenance.json +1 -1
  5. ksadk/_model_anthropic.py +49 -0
  6. ksadk/_model_input.py +86 -0
  7. ksadk/_model_json.py +40 -0
  8. ksadk/_model_reasoning.py +17 -0
  9. ksadk/_model_refusal.py +20 -0
  10. ksadk/_model_sse.py +163 -0
  11. ksadk/_process.py +83 -0
  12. ksadk/_str_enum.py +17 -0
  13. ksadk/a2a/__init__.py +157 -167
  14. ksadk/a2a/_invocation_state.py +86 -0
  15. ksadk/a2a/_space_client_events.py +33 -22
  16. ksadk/a2a/adk.py +194 -0
  17. ksadk/a2a/adk_invocation_context.py +242 -0
  18. ksadk/a2a/adk_runtime.py +126 -0
  19. ksadk/a2a/adk_tools.py +319 -0
  20. ksadk/a2a/bootstrap.py +149 -23
  21. ksadk/a2a/build_validation.py +147 -0
  22. ksadk/a2a/card.py +23 -15
  23. ksadk/a2a/codex.py +160 -0
  24. ksadk/a2a/codex_checkpoint.py +111 -0
  25. ksadk/a2a/codex_recovery.py +96 -0
  26. ksadk/a2a/codex_recovery_events.py +123 -0
  27. ksadk/a2a/codex_runtime.py +198 -0
  28. ksadk/a2a/codex_session_checkpoint.py +162 -0
  29. ksadk/a2a/composition.py +88 -0
  30. ksadk/a2a/context_store.py +118 -19
  31. ksadk/a2a/control_plane.py +108 -106
  32. ksadk/a2a/event_adapter.py +92 -193
  33. ksadk/a2a/executor.py +257 -85
  34. ksadk/a2a/exposure.py +106 -0
  35. ksadk/a2a/external_transport.py +3 -4
  36. ksadk/a2a/identity.py +106 -12
  37. ksadk/a2a/ids.py +14 -3
  38. ksadk/a2a/inbound_kernel.py +133 -0
  39. ksadk/a2a/interaction_wire.py +76 -0
  40. ksadk/a2a/invocation_checkpoint.py +274 -0
  41. ksadk/a2a/invocation_policy.py +87 -0
  42. ksadk/a2a/invocation_publication.py +210 -0
  43. ksadk/a2a/invocation_service.py +972 -0
  44. ksadk/a2a/invocation_types.py +459 -0
  45. ksadk/a2a/kernel_task_adapter.py +259 -0
  46. ksadk/a2a/langgraph.py +20 -7
  47. ksadk/a2a/langgraph_invocation_context.py +136 -0
  48. ksadk/a2a/langgraph_managed.py +150 -0
  49. ksadk/a2a/langgraph_recovery.py +32 -0
  50. ksadk/a2a/langgraph_runtime.py +89 -0
  51. ksadk/a2a/langgraph_tool_runtime.py +132 -0
  52. ksadk/a2a/langgraph_tools.py +63 -0
  53. ksadk/a2a/message_digest.py +40 -0
  54. ksadk/a2a/platform.py +389 -0
  55. ksadk/a2a/policy_refs.py +13 -0
  56. ksadk/a2a/presentation.py +402 -0
  57. ksadk/a2a/product_kernel_facts.py +177 -0
  58. ksadk/a2a/product_key.py +99 -0
  59. ksadk/a2a/protocol_errors.py +116 -0
  60. ksadk/a2a/result_text.py +49 -0
  61. ksadk/a2a/resume_store.py +93 -3
  62. ksadk/a2a/routes.py +6 -1
  63. ksadk/a2a/runtime_approval.py +198 -0
  64. ksadk/a2a/runtime_input.py +151 -0
  65. ksadk/a2a/server.py +16 -7
  66. ksadk/a2a/space_client.py +101 -16
  67. ksadk/a2a/task_adapter.py +19 -5
  68. ksadk/a2a/task_event_dispatcher.py +39 -2
  69. ksadk/a2a/task_event_outbox.py +215 -0
  70. ksadk/a2a/task_event_outbox_owned.py +130 -0
  71. ksadk/a2a/task_store.py +37 -0
  72. ksadk/a2a/tool_activity.py +176 -0
  73. ksadk/a2a/workload_tokens.py +134 -0
  74. ksadk/a2ui/core.py +3 -3
  75. ksadk/api/client.py +38 -79
  76. ksadk/api/sse_stream.py +96 -0
  77. ksadk/builders/code_builder.py +121 -118
  78. ksadk/builders/container_builder.py +11 -29
  79. ksadk/builders/framework_requirements.py +22 -2
  80. ksadk/builders/managed_runtime_builder.py +12 -0
  81. ksadk/builders/source_provenance.py +87 -0
  82. ksadk/cli/__init__.py +36 -0
  83. ksadk/cli/cmd_a2a.py +43 -0
  84. ksadk/cli/cmd_build.py +9 -0
  85. ksadk/cli/cmd_config.py +4 -4
  86. ksadk/cli/cmd_create.py +12 -12
  87. ksadk/cli/cmd_deploy.py +27 -2
  88. ksadk/cli/cmd_hermes.py +24 -2
  89. ksadk/cli/cmd_invoke.py +64 -88
  90. ksadk/cli/cmd_openclaw.py +26 -1
  91. ksadk/cli/cmd_plugin.py +70 -12
  92. ksadk/cli/cmd_studio.py +69 -17
  93. ksadk/cli/cmd_web.py +2 -0
  94. ksadk/cli/hosted_invoke.py +206 -0
  95. ksadk/cli/invoke_content.py +60 -0
  96. ksadk/cli/openclaw_env.py +1 -1
  97. ksadk/cli/resource_common.py +26 -0
  98. ksadk/cli/runtime_bootstrap.py +27 -5
  99. ksadk/codex/_expert_request_reader.py +48 -0
  100. ksadk/codex/a2a_tools.py +140 -0
  101. ksadk/codex/async_approval.py +169 -0
  102. ksadk/codex/async_client.py +938 -0
  103. ksadk/codex/async_proxy.py +216 -0
  104. ksadk/codex/base_runtime.py +25 -0
  105. ksadk/codex/client.py +3 -1047
  106. ksadk/codex/client_payloads.py +85 -0
  107. ksadk/codex/rollout_checkpoint.py +264 -0
  108. ksadk/codex/runtime.py +290 -54
  109. ksadk/common/auth.py +2 -2
  110. ksadk/common/cloud_headers.py +36 -0
  111. ksadk/common/diagnostics.py +34 -0
  112. ksadk/common/kop_client.py +2 -1
  113. ksadk/configs/__init__.py +1 -1
  114. ksadk/configs/env_registry.py +216 -143
  115. ksadk/configs/env_registry_a2a.py +173 -0
  116. ksadk/configs/env_registry_studio.py +134 -0
  117. ksadk/configs/global_config.py +2 -1
  118. ksadk/configs/settings.py +9 -3
  119. ksadk/connector/__init__.py +17 -0
  120. ksadk/connector/channel.py +477 -0
  121. ksadk/context_engine/assembler.py +9 -0
  122. ksadk/context_engine/capabilities.py +52 -4
  123. ksadk/context_engine/contributors.py +80 -17
  124. ksadk/context_engine/instruction_authority.py +18 -0
  125. ksadk/conversations/attachment_storage.py +10 -3
  126. ksadk/conversations/attachments.py +69 -20
  127. ksadk/conversations/contracts.py +28 -9
  128. ksadk/conversations/message_projection.py +51 -155
  129. ksadk/conversations/message_projection_blocks.py +137 -0
  130. ksadk/conversations/model_context.py +11 -3
  131. ksadk/conversations/normalize.py +28 -10
  132. ksadk/conversations/projector.py +63 -0
  133. ksadk/conversations/runtime_baseline.py +37 -0
  134. ksadk/conversations/runtime_compaction.py +7 -2
  135. ksadk/conversations/runtime_input.py +16 -4
  136. ksadk/conversations/runtime_invocation.py +17 -4
  137. ksadk/conversations/runtime_observability.py +39 -10
  138. ksadk/conversations/runtime_payloads.py +12 -0
  139. ksadk/conversations/runtime_persistence.py +296 -32
  140. ksadk/conversations/runtime_preparation.py +98 -13
  141. ksadk/conversations/runtime_projection.py +217 -0
  142. ksadk/conversations/runtime_resume.py +141 -70
  143. ksadk/conversations/runtime_stream_events.py +29 -35
  144. ksadk/conversations/runtime_streaming.py +8 -0
  145. ksadk/conversations/tool_receipt_resume.py +387 -0
  146. ksadk/conversations/tool_receipts.py +32 -0
  147. ksadk/deployment/env_forward.py +5 -0
  148. ksadk/deployment/manager.py +15 -6
  149. ksadk/deployment/providers/serverless.py +76 -136
  150. ksadk/deployment/providers/serverless_payloads.py +122 -0
  151. ksadk/evaluation/agent_eval_client.py +2 -1
  152. ksadk/evaluation/contracts.py +78 -3
  153. ksadk/evaluation/evaluators.py +166 -1
  154. ksadk/evaluation/evidence.py +271 -4
  155. ksadk/evaluation/local_adapter.py +76 -12
  156. ksadk/evaluation/studio_build_adapter.py +73 -9
  157. ksadk/events/adapters/_a2a_checkpoint.py +151 -0
  158. ksadk/events/adapters/_a2a_snapshot.py +18 -14
  159. ksadk/events/adapters/_a2a_support.py +15 -3
  160. ksadk/events/adapters/_a2a_tool_activity.py +123 -0
  161. ksadk/events/adapters/_codex_errors.py +49 -0
  162. ksadk/events/adapters/_codex_items.py +16 -8
  163. ksadk/events/adapters/_langgraph_support.py +46 -1
  164. ksadk/events/adapters/a2a.py +54 -26
  165. ksadk/events/adapters/adk.py +188 -30
  166. ksadk/events/adapters/codex.py +33 -7
  167. ksadk/events/adapters/langgraph.py +16 -6
  168. ksadk/events/canonical.py +5 -0
  169. ksadk/events/canonical_store.py +200 -4
  170. ksadk/events/reducer.py +82 -0
  171. ksadk/events/run_authority.py +176 -0
  172. ksadk/events/session_event.py +2 -2
  173. ksadk/harness/__init__.py +18 -0
  174. ksadk/harness/app.py +11 -0
  175. ksadk/harness/artifact_adapters/__init__.py +1 -0
  176. ksadk/harness/artifact_adapters/native_page_budget.py +172 -0
  177. ksadk/harness/artifact_adapters/native_search.py +249 -0
  178. ksadk/harness/artifact_adapters/native_search_budget.py +134 -0
  179. ksadk/harness/artifact_adapters/native_store.py +115 -0
  180. ksadk/harness/artifact_adapters/native_tool.py +222 -0
  181. ksadk/harness/artifact_store.py +230 -0
  182. ksadk/harness/browser_adapters/__init__.py +6 -0
  183. ksadk/harness/browser_adapters/native_browser_tool.py +92 -0
  184. ksadk/harness/browser_adapters/native_dom_snapshot.py +187 -0
  185. ksadk/harness/browser_adapters/native_playwright.py +953 -0
  186. ksadk/harness/browser_adapters/native_vision.py +295 -0
  187. ksadk/harness/capabilities.py +115 -0
  188. ksadk/harness/capability_adapters/__init__.py +1 -0
  189. ksadk/harness/capability_adapters/native_dsh.py +289 -0
  190. ksadk/harness/capability_runtime.py +332 -0
  191. ksadk/harness/closure_contract.py +92 -0
  192. ksadk/harness/compaction_record.py +153 -0
  193. ksadk/harness/compiler.py +284 -0
  194. ksadk/harness/config.py +28 -5
  195. ksadk/harness/conformance/__init__.py +33 -0
  196. ksadk/harness/conformance/contract.py +504 -0
  197. ksadk/harness/conformance/fixtures.py +102 -0
  198. ksadk/harness/context_engine.py +388 -0
  199. ksadk/harness/context_maintenance.py +259 -0
  200. ksadk/harness/context_manifest.py +188 -0
  201. ksadk/harness/context_sections.py +397 -0
  202. ksadk/harness/context_tuning.py +168 -0
  203. ksadk/harness/diagnostic_adapters/__init__.py +1 -0
  204. ksadk/harness/diagnostic_adapters/contracts.py +70 -0
  205. ksadk/harness/diagnostic_adapters/lsp_rpc.py +210 -0
  206. ksadk/harness/diagnostic_adapters/native_lsp.py +286 -0
  207. ksadk/harness/draft_runtime.py +322 -0
  208. ksadk/harness/engine/__init__.py +40 -0
  209. ksadk/harness/engine/base.py +122 -0
  210. ksadk/harness/engine/budgets.py +108 -0
  211. ksadk/harness/engine/capability_declarations.py +59 -0
  212. ksadk/harness/engine/completion_guard.py +57 -0
  213. ksadk/harness/engine/context_pipeline.py +1351 -0
  214. ksadk/harness/engine/graph_builder.py +352 -0
  215. ksadk/harness/engine/hooked_reasoner.py +380 -0
  216. ksadk/harness/engine/langgraph.py +1049 -0
  217. ksadk/harness/engine/mcp_disclosure.py +701 -0
  218. ksadk/harness/engine/phases/__init__.py +6 -0
  219. ksadk/harness/engine/phases/context.py +48 -0
  220. ksadk/harness/engine/phases/interaction.py +31 -0
  221. ksadk/harness/engine/phases/reason.py +552 -0
  222. ksadk/harness/engine/phases/tools.py +638 -0
  223. ksadk/harness/engine/policy_runtime.py +81 -0
  224. ksadk/harness/engine/postgres_checkpointer.py +386 -0
  225. ksadk/harness/engine/run_control_bridge.py +100 -0
  226. ksadk/harness/engine/run_types.py +98 -0
  227. ksadk/harness/engine/skill_disclosure.py +275 -0
  228. ksadk/harness/engine/spans.py +41 -0
  229. ksadk/harness/engine/steering.py +177 -0
  230. ksadk/harness/engine/subagents.py +360 -0
  231. ksadk/harness/engine/thread_ids.py +112 -0
  232. ksadk/harness/engine/tool_dispatch.py +249 -0
  233. ksadk/harness/event_tree.py +212 -0
  234. ksadk/harness/events.py +498 -0
  235. ksadk/harness/execution_policy.py +104 -0
  236. ksadk/harness/hooks.py +259 -0
  237. ksadk/harness/insights.py +210 -0
  238. ksadk/harness/lifecycle.py +578 -0
  239. ksadk/harness/lifecycle_conformance.py +233 -0
  240. ksadk/harness/lifecycle_local_plane.py +104 -0
  241. ksadk/harness/loop/__init__.py +44 -0
  242. ksadk/harness/loop/reason.py +699 -0
  243. ksadk/harness/loop/tools.py +907 -0
  244. ksadk/harness/managed_runtime.py +1044 -0
  245. ksadk/harness/mcp_disclosure_contract.py +85 -0
  246. ksadk/harness/mcp_matrix.py +474 -0
  247. ksadk/harness/mcp_result_policy.py +44 -0
  248. ksadk/harness/mcp_runtime.py +504 -0
  249. ksadk/harness/memory_consolidation.py +157 -0
  250. ksadk/harness/memory_loop.py +156 -0
  251. ksadk/harness/memory_runtime.py +541 -0
  252. ksadk/harness/metrics.py +90 -0
  253. ksadk/harness/micro_compact.py +69 -0
  254. ksadk/harness/model_adapters/__init__.py +1 -0
  255. ksadk/harness/model_adapters/native_mcp_media.py +100 -0
  256. ksadk/harness/model_adapters/native_mcp_result.py +36 -0
  257. ksadk/harness/model_adapters/native_openai.py +703 -0
  258. ksadk/harness/model_capability.py +468 -0
  259. ksadk/harness/model_provider.py +430 -0
  260. ksadk/harness/multimodal.py +57 -0
  261. ksadk/harness/native/__init__.py +1 -0
  262. ksadk/harness/native/activation_contract.py +25 -0
  263. ksadk/harness/native/activation_recovery.py +29 -0
  264. ksadk/harness/native/adapters.py +291 -0
  265. ksadk/harness/native/artifact_contract.py +14 -0
  266. ksadk/harness/native/artifact_partial_read_capacity.py +171 -0
  267. ksadk/harness/native/artifact_read_capacity.py +182 -0
  268. ksadk/harness/native/artifact_read_contract.py +27 -0
  269. ksadk/harness/native/artifact_runtime.py +408 -0
  270. ksadk/harness/native/artifact_search_capacity.py +206 -0
  271. ksadk/harness/native/artifact_search_contract.py +40 -0
  272. ksadk/harness/native/artifact_single_read_capacity.py +170 -0
  273. ksadk/harness/native/browser_contract.py +229 -0
  274. ksadk/harness/native/browser_recovery.py +183 -0
  275. ksadk/harness/native/capabilities.py +204 -0
  276. ksadk/harness/native/child_approval.py +60 -0
  277. ksadk/harness/native/child_budget.py +136 -0
  278. ksadk/harness/native/child_cancellation.py +80 -0
  279. ksadk/harness/native/child_input.py +98 -0
  280. ksadk/harness/native/child_input_runtime.py +59 -0
  281. ksadk/harness/native/child_interruption.py +81 -0
  282. ksadk/harness/native/child_lifecycle.py +246 -0
  283. ksadk/harness/native/child_lifecycle_contract.py +91 -0
  284. ksadk/harness/native/child_notifications.py +75 -0
  285. ksadk/harness/native/child_promotion.py +66 -0
  286. ksadk/harness/native/command_runtime.py +99 -0
  287. ksadk/harness/native/completion.py +302 -0
  288. ksadk/harness/native/completion_text.py +116 -0
  289. ksadk/harness/native/context.py +358 -0
  290. ksadk/harness/native/context_artifact_page.py +75 -0
  291. ksadk/harness/native/context_compaction_projection.py +131 -0
  292. ksadk/harness/native/context_contributions.py +320 -0
  293. ksadk/harness/native/context_contributor_contract.py +133 -0
  294. ksadk/harness/native/context_driver.py +820 -0
  295. ksadk/harness/native/context_fresh_tools.py +49 -0
  296. ksadk/harness/native/context_history.py +272 -0
  297. ksadk/harness/native/context_microcompact.py +61 -0
  298. ksadk/harness/native/context_partial_summary.py +58 -0
  299. ksadk/harness/native/context_partition.py +492 -0
  300. ksadk/harness/native/context_pruning.py +275 -0
  301. ksadk/harness/native/context_reduction.py +60 -0
  302. ksadk/harness/native/context_replay.py +148 -0
  303. ksadk/harness/native/context_request_projection.py +526 -0
  304. ksadk/harness/native/context_runtime.py +976 -0
  305. ksadk/harness/native/context_runtime_contracts.py +409 -0
  306. ksadk/harness/native/context_search.py +112 -0
  307. ksadk/harness/native/context_source_fragments.py +188 -0
  308. ksadk/harness/native/context_source_progress.py +119 -0
  309. ksadk/harness/native/context_summary_planning.py +788 -0
  310. ksadk/harness/native/context_summary_recovery.py +105 -0
  311. ksadk/harness/native/delivery_review.py +331 -0
  312. ksadk/harness/native/delivery_review_contract.py +54 -0
  313. ksadk/harness/native/effect_admission.py +82 -0
  314. ksadk/harness/native/effect_control.py +318 -0
  315. ksadk/harness/native/effect_receipts.py +729 -0
  316. ksadk/harness/native/effect_runtime.py +303 -0
  317. ksadk/harness/native/effective_configuration.py +28 -0
  318. ksadk/harness/native/engine.py +945 -0
  319. ksadk/harness/native/final_output.py +34 -0
  320. ksadk/harness/native/final_submission.py +58 -0
  321. ksadk/harness/native/finalization_workspace.py +96 -0
  322. ksadk/harness/native/fork.py +151 -0
  323. ksadk/harness/native/guidance.py +91 -0
  324. ksadk/harness/native/history.py +381 -0
  325. ksadk/harness/native/hook_executor.py +205 -0
  326. ksadk/harness/native/hook_runtime_contract.py +282 -0
  327. ksadk/harness/native/interaction_observation.py +117 -0
  328. ksadk/harness/native/lease.py +103 -0
  329. ksadk/harness/native/machine.py +974 -0
  330. ksadk/harness/native/mcp_result_governance.py +156 -0
  331. ksadk/harness/native/model.py +570 -0
  332. ksadk/harness/native/model_feedback.py +63 -0
  333. ksadk/harness/native/model_input.py +30 -0
  334. ksadk/harness/native/model_recovery_contract.py +35 -0
  335. ksadk/harness/native/model_replay.py +128 -0
  336. ksadk/harness/native/model_request.py +133 -0
  337. ksadk/harness/native/model_runtime.py +196 -0
  338. ksadk/harness/native/model_takeover.py +419 -0
  339. ksadk/harness/native/model_tool_batch.py +40 -0
  340. ksadk/harness/native/observed_progress.py +46 -0
  341. ksadk/harness/native/operator_guidance.py +201 -0
  342. ksadk/harness/native/output_contract.py +80 -0
  343. ksadk/harness/native/output_recovery.py +24 -0
  344. ksadk/harness/native/ports.py +749 -0
  345. ksadk/harness/native/precompact_hook_runtime.py +171 -0
  346. ksadk/harness/native/replay_context.py +149 -0
  347. ksadk/harness/native/request_media.py +112 -0
  348. ksadk/harness/native/restore_contract.py +16 -0
  349. ksadk/harness/native/run_clock.py +120 -0
  350. ksadk/harness/native/state.py +436 -0
  351. ksadk/harness/native/steering.py +170 -0
  352. ksadk/harness/native/stop_hook_runtime.py +151 -0
  353. ksadk/harness/native/studio_admission.py +29 -0
  354. ksadk/harness/native/subagents.py +86 -0
  355. ksadk/harness/native/task_policy.py +99 -0
  356. ksadk/harness/native/task_progress.py +86 -0
  357. ksadk/harness/native/terminal_verification.py +43 -0
  358. ksadk/harness/native/tool_argument_feedback.py +178 -0
  359. ksadk/harness/native/tool_budget.py +253 -0
  360. ksadk/harness/native/tool_error_streak.py +89 -0
  361. ksadk/harness/native/tool_hook_runtime.py +343 -0
  362. ksadk/harness/native/tool_input_validation.py +58 -0
  363. ksadk/harness/native/tool_interruption.py +96 -0
  364. ksadk/harness/native/tool_observation.py +259 -0
  365. ksadk/harness/native/tool_progress.py +223 -0
  366. ksadk/harness/native/tool_recovery.py +25 -0
  367. ksadk/harness/native/tool_scheduling.py +33 -0
  368. ksadk/harness/native/tool_schema.py +126 -0
  369. ksadk/harness/native/transitions.py +151 -0
  370. ksadk/harness/native/turn_control.py +98 -0
  371. ksadk/harness/native/user_document.py +98 -0
  372. ksadk/harness/native/user_document_capture.py +49 -0
  373. ksadk/harness/native/user_input.py +87 -0
  374. ksadk/harness/native/verification.py +432 -0
  375. ksadk/harness/native/verification_binding.py +40 -0
  376. ksadk/harness/native/verification_runtime.py +233 -0
  377. ksadk/harness/native/verification_workspace.py +67 -0
  378. ksadk/harness/native_driver_failure.py +123 -0
  379. ksadk/harness/native_facade.py +977 -0
  380. ksadk/harness/native_factory.py +244 -0
  381. ksadk/harness/native_projection.py +503 -0
  382. ksadk/harness/native_runtime.py +621 -0
  383. ksadk/harness/native_shadow.py +250 -0
  384. ksadk/harness/native_shadow_inputs.py +146 -0
  385. ksadk/harness/observability/__init__.py +29 -0
  386. ksadk/harness/observability/inspection.py +528 -0
  387. ksadk/harness/observability/metrics.py +167 -0
  388. ksadk/harness/observability/otel_exporter.py +218 -0
  389. ksadk/harness/progress_adapters/__init__.py +5 -0
  390. ksadk/harness/progress_adapters/native_todo.py +75 -0
  391. ksadk/harness/prompt_cache.py +132 -0
  392. ksadk/harness/public_activity.py +213 -0
  393. ksadk/harness/public_output.py +30 -0
  394. ksadk/harness/public_summary.py +36 -0
  395. ksadk/harness/readiness.py +249 -0
  396. ksadk/harness/reasoner.py +779 -17
  397. ksadk/harness/release_readiness.py +140 -0
  398. ksadk/harness/resource_ref.py +69 -0
  399. ksadk/harness/rpc.py +200 -0
  400. ksadk/harness/run_control.py +773 -0
  401. ksadk/harness/runtime.py +157 -113
  402. ksadk/harness/runtime_capabilities.py +228 -0
  403. ksadk/harness/runtime_server.py +514 -0
  404. ksadk/harness/sandbox_adapters.py +739 -0
  405. ksadk/harness/sandbox_backend.py +733 -0
  406. ksadk/harness/sandbox_conformance.py +288 -0
  407. ksadk/harness/sandbox_lease.py +77 -0
  408. ksadk/harness/sandbox_lease_conformance.py +259 -0
  409. ksadk/harness/sandbox_matrix.py +170 -0
  410. ksadk/harness/sandbox_reconciliation.py +140 -0
  411. ksadk/harness/sandbox_recovery.py +586 -0
  412. ksadk/harness/sandbox_recovery_conformance.py +246 -0
  413. ksadk/harness/sdk.py +153 -0
  414. ksadk/harness/session_store.py +589 -0
  415. ksadk/harness/skill_adapters/__init__.py +1 -0
  416. ksadk/harness/skill_adapters/native_bundle.py +148 -0
  417. ksadk/harness/skill_adapters/native_disclosure.py +306 -0
  418. ksadk/harness/skill_composition.py +212 -0
  419. ksadk/harness/skill_feedback.py +123 -0
  420. ksadk/harness/skill_intent.py +47 -0
  421. ksadk/harness/skill_matrix.py +233 -0
  422. ksadk/harness/skill_runtime.py +317 -0
  423. ksadk/harness/spec.py +342 -0
  424. ksadk/harness/state.py +155 -0
  425. ksadk/harness/stores/__init__.py +14 -0
  426. ksadk/harness/stores/native_command_settlement.py +65 -0
  427. ksadk/harness/stores/native_contract.py +311 -0
  428. ksadk/harness/stores/native_memory.py +326 -0
  429. ksadk/harness/stores/native_memory_archive.py +70 -0
  430. ksadk/harness/stores/native_migration_cli.py +91 -0
  431. ksadk/harness/stores/native_outbox.py +56 -0
  432. ksadk/harness/stores/native_sqlite.py +782 -0
  433. ksadk/harness/stores/native_sqlite_audit.py +29 -0
  434. ksadk/harness/stores/native_sqlite_migration.py +252 -0
  435. ksadk/harness/strategies.py +149 -0
  436. ksadk/harness/subagent.py +263 -0
  437. ksadk/harness/subagent_adapters/checkpoint_recovery.py +120 -0
  438. ksadk/harness/subagent_adapters/native_background_child.py +803 -0
  439. ksadk/harness/subagent_adapters/native_child.py +819 -0
  440. ksadk/harness/subagent_adapters/native_child_approval.py +128 -0
  441. ksadk/harness/subagent_adapters/native_child_continuation.py +51 -0
  442. ksadk/harness/subagent_adapters/native_child_result.py +392 -0
  443. ksadk/harness/subagent_adapters/prepared_recovery.py +120 -0
  444. ksadk/harness/tool_display.py +75 -0
  445. ksadk/harness/tool_display_contract.py +134 -0
  446. ksadk/harness/tool_output.py +141 -0
  447. ksadk/harness/tool_policy.py +134 -0
  448. ksadk/harness/tool_receipts.py +96 -0
  449. ksadk/harness/tool_reliability.py +81 -0
  450. ksadk/harness/tool_result_policy.py +216 -0
  451. ksadk/harness/tools.py +52 -0
  452. ksadk/harness/user_errors.py +69 -0
  453. ksadk/harness/working_context.py +81 -0
  454. ksadk/harness/working_context_patch.py +99 -0
  455. ksadk/harness/workspace_adapters/__init__.py +6 -0
  456. ksadk/harness/workspace_adapters/native_directory.py +180 -0
  457. ksadk/harness/workspace_adapters/native_git.py +208 -0
  458. ksadk/harness/workspace_adapters/native_isolation.py +350 -0
  459. ksadk/identity/resolver.py +18 -0
  460. ksadk/interaction/__init__.py +1 -1
  461. ksadk/interaction/ledger.py +1 -1
  462. ksadk/interaction/provider.py +1 -1
  463. ksadk/interaction/providers/__init__.py +3 -1
  464. ksadk/interaction/providers/adk.py +1 -1
  465. ksadk/interaction/providers/codex.py +1 -1
  466. ksadk/interaction/providers/harness.py +50 -0
  467. ksadk/interaction/providers/langgraph.py +9 -2
  468. ksadk/kernel/__init__.py +10 -0
  469. ksadk/kernel/approval_presentation.py +91 -0
  470. ksadk/kernel/authorization.py +1 -1
  471. ksadk/kernel/bootstrap.py +220 -252
  472. ksadk/kernel/contract_fingerprints.py +45 -1
  473. ksadk/kernel/contracts.py +30 -0
  474. ksadk/kernel/control.py +180 -29
  475. ksadk/kernel/execution_grants.py +428 -0
  476. ksadk/kernel/execution_grants_memory.py +252 -0
  477. ksadk/kernel/execution_grants_postgres.py +395 -0
  478. ksadk/kernel/execution_grants_sqlite.py +435 -0
  479. ksadk/kernel/execution_host_ingress.py +1071 -0
  480. ksadk/kernel/history_projection.py +120 -0
  481. ksadk/kernel/ingress.py +139 -226
  482. ksadk/kernel/ingress_bootstrap.py +268 -0
  483. ksadk/kernel/legacy_history.py +179 -0
  484. ksadk/kernel/mapping.py +1 -1
  485. ksadk/kernel/memory_store.py +61 -58
  486. ksadk/kernel/memory_store_projection.py +63 -0
  487. ksadk/kernel/postgres_event_log.py +181 -0
  488. ksadk/kernel/postgres_store.py +230 -231
  489. ksadk/kernel/readiness.py +125 -0
  490. ksadk/kernel/recovery.py +166 -16
  491. ksadk/kernel/recovery_projection.py +124 -0
  492. ksadk/kernel/runtime_checkpoint.py +34 -0
  493. ksadk/kernel/sql/001_agent_kernel.sql +28 -0
  494. ksadk/kernel/sqlite_schema.py +100 -0
  495. ksadk/kernel/sqlite_store.py +410 -200
  496. ksadk/kernel/state.py +2 -3
  497. ksadk/kernel/store.py +104 -5
  498. ksadk/kernel/teams_artifact_tools.py +392 -0
  499. ksadk/kernel/teams_effects.py +851 -0
  500. ksadk/kernel/teams_execution_context.py +408 -0
  501. ksadk/kernel/teams_host_http.py +237 -0
  502. ksadk/kernel/teams_material_transport.py +245 -0
  503. ksadk/kernel/teams_materials.py +318 -0
  504. ksadk/kernel/teams_runtime_bootstrap.py +604 -0
  505. ksadk/kernel/teams_tool_runtime.py +273 -0
  506. ksadk/kernel/teams_workspace.py +259 -0
  507. ksadk/kernel/worker.py +369 -340
  508. ksadk/kernel/worker_controls.py +454 -0
  509. ksadk/kernel/worker_history.py +72 -0
  510. ksadk/kernel/worker_identity.py +74 -0
  511. ksadk/kernel/worker_interactions.py +197 -0
  512. ksadk/knowledge_base/client.py +15 -1
  513. ksadk/managed_runtime.py +29 -2
  514. ksadk/memory/adk/backends/http_ltm_backend.py +2 -1
  515. ksadk/memory/adk/backends/sdk_ltm_backend.py +15 -1
  516. ksadk/memory/adk/bounded_database_session_service.py +232 -0
  517. ksadk/memory/adk/resilient_session_service.py +115 -15
  518. ksadk/memory/adk/short_term_memory.py +8 -9
  519. ksadk/memory/coordinator.py +22 -6
  520. ksadk/memory/extraction.py +159 -7
  521. ksadk/memory/models.py +77 -1
  522. ksadk/memory/provider_resolver.py +5 -0
  523. ksadk/memory/providers/local_candidates.py +183 -0
  524. ksadk/memory/providers/local_postgres.py +200 -0
  525. ksadk/memory/providers/local_sqlite.py +280 -67
  526. ksadk/memory/resolved_policy.py +12 -7
  527. ksadk/memory/retrieval.py +189 -0
  528. ksadk/memory/store_adapter.py +150 -0
  529. ksadk/model_gateway/__init__.py +29 -0
  530. ksadk/model_gateway/client.py +253 -0
  531. ksadk/model_gateway/events.py +113 -0
  532. ksadk/model_gateway/matrix.py +297 -0
  533. ksadk/model_policy.py +2 -2
  534. ksadk/model_proxy/compat.py +670 -0
  535. ksadk/model_proxy/detect.py +254 -0
  536. ksadk/model_proxy/server.py +14 -9
  537. ksadk/model_proxy/transform.py +72 -6
  538. ksadk/plugins/__init__.py +1 -1
  539. ksadk/plugins/bridges/dsh.py +29 -20
  540. ksadk/plugins/bridges/dsh_profile_manifest.py +36 -0
  541. ksadk/plugins/builtin_resources.py +199 -0
  542. ksadk/plugins/builtins.py +417 -185
  543. ksadk/plugins/companion_artifacts.py +83 -0
  544. ksadk/plugins/companions.py +368 -0
  545. ksadk/plugins/context_contributor.py +15 -4
  546. ksadk/plugins/contracts.py +1 -1
  547. ksadk/plugins/dsh_channels.py +156 -0
  548. ksadk/plugins/dsh_dependency_policy.py +41 -0
  549. ksadk/plugins/dsh_home.py +140 -0
  550. ksadk/plugins/dsh_teams.py +105 -0
  551. ksadk/plugins/dsh_toolchain.py +92 -21
  552. ksadk/plugins/execution_host.py +107 -0
  553. ksadk/plugins/host.py +73 -5
  554. ksadk/plugins/kernel_adapter.py +44 -1
  555. ksadk/plugins/memory_provider.py +180 -0
  556. ksadk/plugins/providers/_process_group.py +50 -0
  557. ksadk/plugins/providers/bundles/dsh-channels-client/client.js +19 -0
  558. ksadk/plugins/providers/bundles/dsh-channels-client/cordis.patch.yml +3 -0
  559. ksadk/plugins/providers/bundles/dsh-channels-client/index.mjs +7 -0
  560. ksadk/plugins/providers/bundles/dsh-channels-client/package.json +12 -0
  561. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +24 -2
  562. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +1 -1
  563. ksadk/plugins/providers/bundles/dsh-memory/package.json +1 -1
  564. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +1 -1
  565. ksadk/plugins/providers/bundles/dsh-teams-client/client.js +29 -0
  566. ksadk/plugins/providers/bundles/dsh-teams-client/cordis.patch.yml +3 -0
  567. ksadk/plugins/providers/bundles/dsh-teams-client/index.mjs +11 -0
  568. ksadk/plugins/providers/bundles/dsh-teams-client/package.json +35 -0
  569. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/cordis.patch.yml +3 -0
  570. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/index.mjs +13 -0
  571. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/package.json +27 -0
  572. ksadk/plugins/providers/bundles/dsh-teams-profile/cordis.patch.yml +3 -0
  573. ksadk/plugins/providers/bundles/dsh-teams-profile/index.mjs +12 -0
  574. ksadk/plugins/providers/bundles/dsh-teams-profile/package.json +26 -0
  575. ksadk/plugins/providers/bundles/dsh-teams-router/cordis.patch.yml +3 -0
  576. ksadk/plugins/providers/bundles/dsh-teams-router/index.mjs +16 -0
  577. ksadk/plugins/providers/bundles/dsh-teams-router/package.json +27 -0
  578. ksadk/plugins/providers/bundles/dsh-teams-tasks/cordis.patch.yml +3 -0
  579. ksadk/plugins/providers/bundles/dsh-teams-tasks/index.mjs +16 -0
  580. ksadk/plugins/providers/bundles/dsh-teams-tasks/package.json +27 -0
  581. ksadk/plugins/providers/bundles/dsh-teams-tools/cordis.patch.yml +3 -0
  582. ksadk/plugins/providers/bundles/dsh-teams-tools/index.mjs +25 -0
  583. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +29 -0
  584. ksadk/plugins/providers/bundles/dsh-teams-tools/tools.json +235 -0
  585. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +1 -1
  586. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +51 -1
  587. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +2 -2
  588. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/client.mjs +133 -0
  589. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/index.mjs +14 -0
  590. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +27 -4
  591. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +9 -5
  592. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +1 -1
  593. ksadk/plugins/providers/codex.py +52 -40
  594. ksadk/plugins/providers/codex_native.py +20 -0
  595. ksadk/plugins/providers/codex_skills.py +46 -0
  596. ksadk/plugins/providers/dsh_capabilities.py +49 -143
  597. ksadk/plugins/providers/dsh_connector_lease.py +225 -0
  598. ksadk/plugins/providers/dsh_mcp.py +163 -1
  599. ksadk/plugins/providers/harness.py +413 -52
  600. ksadk/plugins/providers/harness_context.py +61 -0
  601. ksadk/plugins/providers/harness_contributions.py +241 -0
  602. ksadk/plugins/providers/harness_delegation.py +670 -0
  603. ksadk/plugins/providers/harness_hooks.py +121 -0
  604. ksadk/plugins/providers/harness_managed.py +550 -0
  605. ksadk/plugins/providers/harness_tools.py +455 -0
  606. ksadk/plugins/providers/legacy_catalog.py +1 -1
  607. ksadk/plugins/providers/mcp_projection.py +100 -3
  608. ksadk/plugins/providers/platform_resources.py +16 -6
  609. ksadk/plugins/providers/shipped_dsh.py +4 -1
  610. ksadk/plugins/subagent_providers/codex.py +28 -6
  611. ksadk/plugins/teams/__init__.py +5 -0
  612. ksadk/plugins/teams/api.py +405 -0
  613. ksadk/plugins/teams/application.py +540 -0
  614. ksadk/plugins/teams/artifacts.py +60 -0
  615. ksadk/plugins/teams/build_artifacts.py +460 -0
  616. ksadk/plugins/teams/cloud_contract_fingerprints.py +22 -0
  617. ksadk/plugins/teams/cloud_contracts.py +928 -0
  618. ksadk/plugins/teams/cloud_permits.py +250 -0
  619. ksadk/plugins/teams/context.py +96 -0
  620. ksadk/plugins/teams/contracts.py +136 -0
  621. ksadk/plugins/teams/domain.py +1480 -0
  622. ksadk/plugins/teams/domain_values.py +24 -0
  623. ksadk/plugins/teams/effect_contracts.py +255 -0
  624. ksadk/plugins/teams/errors.py +13 -0
  625. ksadk/plugins/teams/execution_projection.py +255 -0
  626. ksadk/plugins/teams/leader_decisions.py +106 -0
  627. ksadk/plugins/teams/migration.py +311 -0
  628. ksadk/plugins/teams/migration_cli.py +322 -0
  629. ksadk/plugins/teams/postgres_store.py +352 -0
  630. ksadk/plugins/teams/release_contracts.py +60 -0
  631. ksadk/plugins/teams/runtime.py +853 -0
  632. ksadk/plugins/teams/source_projection.py +84 -0
  633. ksadk/plugins/teams/store.py +519 -0
  634. ksadk/plugins/teams/task_decisions.py +436 -0
  635. ksadk/plugins/teams/tool_service.py +152 -0
  636. ksadk/plugins/teams/transport.py +96 -0
  637. ksadk/plugins/teams/workspaces.py +255 -0
  638. ksadk/resource_runtime/skill_runtime.py +3 -0
  639. ksadk/resource_runtime/socket_server.py +11 -0
  640. ksadk/resource_runtime/worker.py +28 -4
  641. ksadk/runners/_adk_a2a_stream.py +122 -0
  642. ksadk/runners/_adk_canonical_stream.py +474 -0
  643. ksadk/runners/_langgraph_canonical_streams.py +527 -0
  644. ksadk/runners/_langgraph_runner_streams.py +83 -401
  645. ksadk/runners/_langgraph_state_reader.py +106 -0
  646. ksadk/runners/_langgraph_tool_projection.py +86 -0
  647. ksadk/runners/_langgraph_tools_transformer.py +27 -0
  648. ksadk/runners/_session_identity.py +285 -0
  649. ksadk/runners/adk_runner.py +220 -350
  650. ksadk/runners/base_runner.py +6 -5
  651. ksadk/runners/langgraph_runner.py +208 -195
  652. ksadk/runners/patch_langchain.py +47 -0
  653. ksadk/runners/usage_accumulator.py +11 -3
  654. ksadk/runners/utils/loader.py +28 -14
  655. ksadk/runtime/_runner_adapter/a2ui_surface.py +145 -0
  656. ksadk/runtime/_runner_adapter/gateway_approvals.py +93 -0
  657. ksadk/runtime/_runner_adapter/stream_mapping.py +134 -129
  658. ksadk/runtime/adapter.py +40 -3
  659. ksadk/runtime/conversation_execution.py +29 -3
  660. ksadk/runtime/executor.py +105 -7
  661. ksadk/runtime/factory.py +45 -3
  662. ksadk/runtime/framework_adapters.py +184 -10
  663. ksadk/runtime/hosted_finalizer.py +4 -6
  664. ksadk/runtime/launch.py +2 -0
  665. ksadk/runtime/preprocessing.py +11 -3
  666. ksadk/runtime/runner_adapter.py +160 -21
  667. ksadk/runtime/skill_eval_result.py +36 -0
  668. ksadk/runtime/timing.py +46 -0
  669. ksadk/runtime/usage.py +49 -18
  670. ksadk/runtime_context.py +105 -1
  671. ksadk/sandbox/backends/e2b.py +272 -24
  672. ksadk/sandbox/backends/local_process.py +73 -39
  673. ksadk/sandbox/base.py +62 -1
  674. ksadk/sandbox/diagnostics.py +82 -0
  675. ksadk/sandbox/e2b_connection.py +9 -1
  676. ksadk/sandbox/local_controls.py +776 -0
  677. ksadk/sandbox/local_launcher.py +124 -0
  678. ksadk/scheduler/dispatcher.py +1 -1
  679. ksadk/server/factory.py +178 -25
  680. ksadk/server/history_deadline.py +158 -0
  681. ksadk/server/history_page_cache.py +129 -0
  682. ksadk/server/invocation_identity.py +118 -0
  683. ksadk/server/routes/checkpoint_audit.py +88 -0
  684. ksadk/server/routes/checkpoint_listing.py +294 -0
  685. ksadk/server/routes/checkpoint_resolution.py +73 -20
  686. ksadk/server/routes/common.py +32 -3
  687. ksadk/server/routes/control.py +112 -9
  688. ksadk/server/routes/dependencies.py +2 -1
  689. ksadk/server/routes/display_projection.py +154 -0
  690. ksadk/server/routes/kernel_ingress.py +26 -3
  691. ksadk/server/routes/misc.py +331 -33
  692. ksadk/server/routes/models.py +28 -4
  693. ksadk/server/routes/openai_compat.py +82 -13
  694. ksadk/server/routes/projection.py +159 -216
  695. ksadk/server/routes/run.py +112 -37
  696. ksadk/server/routes/sessions.py +493 -358
  697. ksadk/server/routes/streaming.py +68 -15
  698. ksadk/server/routes/tool_receipt_claim_routes.py +107 -0
  699. ksadk/server/routes/workspace.py +135 -23
  700. ksadk/server/static/assets/{ArtifactsPanel-CGbWlMNh.js → ArtifactsPanel-CILaW-fC.js} +1 -1
  701. ksadk/server/static/assets/{CodeBlock-b4C7upmO.js → CodeBlock-BVrNVtJC.js} +10 -7
  702. ksadk/server/static/assets/MathMessageMarkdown-Dp7c4wWD.js +8 -0
  703. ksadk/server/static/assets/{MermaidBlock-BEBN4Ksz.js → MermaidBlock-Dxop8Rd7.js} +9 -9
  704. ksadk/server/static/assets/{NativeTerminalPanel-zvL-WpAn.js → NativeTerminalPanel-Cjjz8B30.js} +1 -1
  705. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-BYafW7Za.js → abnfDiagram-VCTEODGH-ckWDmOzw.js} +1 -1
  706. ksadk/server/static/assets/{arc-bTohInsS.js → arc-DqxJede-.js} +1 -1
  707. ksadk/server/static/assets/architecture-7GRP2DOG-pn_DuLy6.js +1 -0
  708. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-Ch5Lbzsi.js → architectureDiagram-5GKGNRK7-SEQA4bVi.js} +1 -1
  709. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-kqF4MDOG.js → blockDiagram-NRAW4CY4-pM0B-6NJ.js} +1 -1
  710. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-8uSRIODv.js → c4Diagram-UCG6FXSJ-m2tuCNVq.js} +1 -1
  711. ksadk/server/static/assets/channel-fySsnkft.js +1 -0
  712. ksadk/server/static/assets/chunk-2Q5K7J3B-BheGxKRQ.js +1 -0
  713. ksadk/server/static/assets/{chunk-5VM5RSS4-DkhehZDr.js → chunk-5VM5RSS4-GJHDr9Ww.js} +1 -1
  714. ksadk/server/static/assets/{chunk-F27PBJKO-BdXhtPe9.js → chunk-F27PBJKO-CbAN45AV.js} +1 -1
  715. ksadk/server/static/assets/{chunk-G27WJ6UU-DPTpvpwi.js → chunk-G27WJ6UU-D5ngbbzF.js} +1 -1
  716. ksadk/server/static/assets/{chunk-JWPE2WC7-Pqoh38el.js → chunk-JWPE2WC7-Cc5IwuYC.js} +1 -1
  717. ksadk/server/static/assets/{chunk-LCL6LL3I-DeU00qC-.js → chunk-LCL6LL3I-CprgDDdJ.js} +1 -1
  718. ksadk/server/static/assets/{chunk-POPQ4Y6H-CzxScFkr.js → chunk-POPQ4Y6H-CDZhSy82.js} +1 -1
  719. ksadk/server/static/assets/{chunk-RHFEMEQ7-DpqMx-ux.js → chunk-RHFEMEQ7-CZchUNro.js} +1 -1
  720. ksadk/server/static/assets/{chunk-SVP7TREG-C6t0SypQ.js → chunk-SVP7TREG-BVruqk6T.js} +1 -1
  721. ksadk/server/static/assets/{chunk-XXDRQBXY-DVaeafZk.js → chunk-XXDRQBXY-4ld9SxPN.js} +1 -1
  722. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DSfLtNYm.js +1 -0
  723. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DSfLtNYm.js +1 -0
  724. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-Bf9D3tzJ.js → cose-bilkent-JH36ORCC-Dmyyk_Vp.js} +1 -1
  725. ksadk/server/static/assets/cynefin-OW5HDTMX-PFWIGtvA.js +1 -0
  726. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-B9cY3iTz.js → cynefinDiagram-5FMLGOSQ-BIyq3EJb.js} +1 -1
  727. ksadk/server/static/assets/{dagre-3AP2YEHR-CSwlx3CB.js → dagre-3AP2YEHR-eBw08Qdk.js} +1 -1
  728. ksadk/server/static/assets/{dagre-UBpgon5q.js → dagre-DfvnEf45.js} +1 -1
  729. ksadk/server/static/assets/{diagram-S7CK7UJ4-C9akhN9a.js → diagram-S7CK7UJ4-CUSrE3Mg.js} +1 -1
  730. ksadk/server/static/assets/{diagram-UQ7AKVKN-CgedhTPI.js → diagram-UQ7AKVKN-Dq5Zw2gy.js} +1 -1
  731. ksadk/server/static/assets/{diagram-VSXAHHWV-Cjucz5BY.js → diagram-VSXAHHWV-DyUHfNwT.js} +1 -1
  732. ksadk/server/static/assets/{diagram-VX7I27RA-Dd4Vleyn.js → diagram-VX7I27RA-CREmM89O.js} +1 -1
  733. ksadk/server/static/assets/{diagram-Z3DM3KII-CZ2jGtYW.js → diagram-Z3DM3KII-Dw9zhHUK.js} +1 -1
  734. ksadk/server/static/assets/{dist-Bj730Ib4.js → dist-0uJ4tdx6.js} +1 -1
  735. ksadk/server/static/assets/{dist-BnaTiyzN.js → dist-AEv-vXf-.js} +1 -1
  736. ksadk/server/static/assets/{dist-BgV_owcB.js → dist-B49GzZDb.js} +1 -1
  737. ksadk/server/static/assets/{dist-D_ctSS2i.js → dist-B8Myiet9.js} +1 -1
  738. ksadk/server/static/assets/{dist-ufY3F5p6.js → dist-BBsYarrI.js} +2 -2
  739. ksadk/server/static/assets/{dist-ClYUxfeK.js → dist-BQMrUwdI.js} +1 -1
  740. ksadk/server/static/assets/{dist-CFzsn6BG.js → dist-BX_-FENW.js} +1 -1
  741. ksadk/server/static/assets/{dist-B3FR1SKK.js → dist-CD4L6ymH.js} +1 -1
  742. ksadk/server/static/assets/{dist-Cf125P_m.js → dist-CHpW1BHj.js} +1 -1
  743. ksadk/server/static/assets/{dist-DVCOWtha.js → dist-CVPau3tn.js} +1 -1
  744. ksadk/server/static/assets/{dist-DFD6Qa6T.js → dist-C_qdxcSH.js} +1 -1
  745. ksadk/server/static/assets/{dist-BIr4DSRq.js → dist-Co68Apq4.js} +1 -1
  746. ksadk/server/static/assets/{dist-DiixqL0J.js → dist-Cp2PaOMY.js} +1 -1
  747. ksadk/server/static/assets/{dist-fBO2v5Kt.js → dist-CuR5Bgme.js} +1 -1
  748. ksadk/server/static/assets/{dist-DoVSwoDb.js → dist-DDSyLEOX.js} +1 -1
  749. ksadk/server/static/assets/{dist-C5_ZAZsG.js → dist-DUxO0R99.js} +1 -1
  750. ksadk/server/static/assets/{dist-C1NMAY5a.js → dist-QzbGrED_.js} +1 -1
  751. ksadk/server/static/assets/dist-bupkyEBZ.js +1 -0
  752. ksadk/server/static/assets/{dist-DvFK7p5S.js → dist-cxTGfdqx.js} +1 -1
  753. ksadk/server/static/assets/{dist-CB9iJrvg.js → dist-hL5p1til.js} +1 -1
  754. ksadk/server/static/assets/{dist-btbmmX5O.js → dist-lOy23y43.js} +1 -1
  755. ksadk/server/static/assets/{dist-QfkEHOlb.js → dist-pq-nD33R.js} +1 -1
  756. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Ci8NqqZu.js → ebnfDiagram-PWID7BFC-BS5LdNoR.js} +1 -1
  757. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CCIOhLZG.js → erDiagram-SSCWMZ5O-Bv1QtiY-.js} +1 -1
  758. ksadk/server/static/assets/eventmodeling-NTZA5JFV-DsM4upQX.js +1 -0
  759. ksadk/server/static/assets/flowDiagram-A5DVABFB-D5NA16k9.js +1 -0
  760. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-Cp_r9Hb6.js → ganttDiagram-EL5Y4UJY-musi-e0G.js} +1 -1
  761. ksadk/server/static/assets/gitGraph-4MIJSDKK-DUCVz-ih.js +1 -0
  762. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-Dlhc8Wr8.js → gitGraphDiagram-WWUBYQGX-DH37EGkG.js} +1 -1
  763. ksadk/server/static/assets/index-CZdkAvsv.js +244 -0
  764. ksadk/server/static/assets/index-CvXdHgF3.css +2 -0
  765. ksadk/server/static/assets/info-A6RAGUB7-rw0ZNHZp.js +1 -0
  766. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CO0rRTRA.js → infoDiagram-RXCK75RN-C1kEtv2y.js} +1 -1
  767. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CHiaedSS.js → ishikawaDiagram-5VMMS53U-BCNPyMka.js} +1 -1
  768. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-CHcCIB09.js → journeyDiagram-EYS64GPL--cDbKnjP.js} +1 -1
  769. ksadk/server/static/assets/{kanban-definition-3QL26DDD-CJ_ebBZf.js → kanban-definition-3QL26DDD-R1rAVw2f.js} +1 -1
  770. ksadk/server/static/assets/{katex-B4weu383.js → katex-BT-X-V7U.js} +1 -1
  771. ksadk/server/static/assets/{linear-V-MgYHW1.js → linear-DTR631iG.js} +1 -1
  772. ksadk/server/static/assets/{mermaid-parser.core-CBijEX_c.js → mermaid-parser.core-DfFzJhX8.js} +2 -2
  773. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-Bc-pQvpp.js → mindmap-definition-FBJOCRG2-D4by_rmk.js} +1 -1
  774. ksadk/server/static/assets/packet-AYTQ26CC-Ca4Hvki9.js +1 -0
  775. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-D7genGLl.js → pegDiagram-XKGWAZYB-xWXPEh0c.js} +1 -1
  776. ksadk/server/static/assets/pie-WAS4IAKB-hwiz6fbw.js +1 -0
  777. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-Bxj32zwD.js → pieDiagram-E7YTZNPT-BudBDlCI.js} +1 -1
  778. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BURv2mGh.js → quadrantDiagram-AXDQQJYC-DXZ0PCJF.js} +1 -1
  779. ksadk/server/static/assets/radar-RG4KPBEZ-BR1oZXLM.js +1 -0
  780. ksadk/server/static/assets/railroad-74A4TZTK-DfgEISfX.js +1 -0
  781. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-CWOC3rdk.js +1 -0
  782. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CiRvHCLY.js +1 -0
  783. ksadk/server/static/assets/railroad-peg-WCYAUIDC-DSDDyJ2f.js +1 -0
  784. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-CCsh3avW.js → railroadDiagram-O6MQD6OU-BdAYRYB8.js} +1 -1
  785. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-_FRRBKEd.js → requirementDiagram-EFPCY7ZU-CBBmaL70.js} +1 -1
  786. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-C-gr2o9M.js → sankeyDiagram-P5KCCOFB-Doc3rdwp.js} +1 -1
  787. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-D97NmfKg.js → sequenceDiagram-WJ2MYXX4-0J8R8hWW.js} +1 -1
  788. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DjrPC5FX.js → sizeCapture-X5ZJPWSS-CfFLlWsK.js} +1 -1
  789. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DzMNg1hh.js → stateDiagram-HBIQ2CUA-jBwkjtTy.js} +1 -1
  790. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-Cw1fPb5w.js +1 -0
  791. ksadk/server/static/assets/{swimlanes-XN3QIQJK-Cssf_CsU.js → swimlanes-XN3QIQJK-B0WxTQf8.js} +1 -1
  792. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-Cc3JMBAF.js +8 -0
  793. ksadk/server/static/assets/{timeline-definition-24CTP7MA-BWTHzyS1.js → timeline-definition-24CTP7MA-BfCT_75A.js} +1 -1
  794. ksadk/server/static/assets/treeView-Q6P3EWNA-C05SJHxo.js +1 -0
  795. ksadk/server/static/assets/treemap-WGGIJYW6-BqNLAhc3.js +1 -0
  796. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-BSKgJsmR.js → vennDiagram-4TSXK5OY-9gX1VMDC.js} +1 -1
  797. ksadk/server/static/assets/wardley-WFR3VGLG-DokNktqB.js +1 -0
  798. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-eflHNoaZ.js → wardleyDiagram-VM6X3IG4-sEs_BP6O.js} +1 -1
  799. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-eYqrQ-v4.js → xychartDiagram-S5SC5T6Z-Ll4jvUN9.js} +1 -1
  800. ksadk/server/static/index.html +2 -2
  801. ksadk/server/terminal_sessions.py +34 -2
  802. ksadk/sessions/__init__.py +8 -1
  803. ksadk/sessions/_checkpoint_resume_audit.py +44 -0
  804. ksadk/sessions/_in_memory_query.py +112 -0
  805. ksadk/sessions/_local_service_sync.py +157 -156
  806. ksadk/sessions/_local_state_sync.py +152 -0
  807. ksadk/sessions/_local_tables.py +2 -0
  808. ksadk/sessions/_postgres_checkpoint_read.py +323 -0
  809. ksadk/sessions/_postgres_checkpoint_stats.py +330 -0
  810. ksadk/sessions/_postgres_history_read.py +678 -0
  811. ksadk/sessions/_postgres_schema.py +44 -2
  812. ksadk/sessions/_postgres_tables.py +2 -0
  813. ksadk/sessions/_postgres_tool_receipts.py +169 -0
  814. ksadk/sessions/_resilient_read.py +630 -0
  815. ksadk/sessions/_tool_receipt_sync.py +119 -0
  816. ksadk/sessions/agent_identity.py +16 -0
  817. ksadk/sessions/base.py +278 -0
  818. ksadk/sessions/db_budget.py +332 -0
  819. ksadk/sessions/errors.py +12 -0
  820. ksadk/sessions/history_budget.py +36 -0
  821. ksadk/sessions/history_identity.py +27 -0
  822. ksadk/sessions/in_memory.py +376 -113
  823. ksadk/sessions/invocation_identity.py +235 -0
  824. ksadk/sessions/local_service.py +345 -0
  825. ksadk/sessions/postgres_service.py +515 -549
  826. ksadk/sessions/resilience.py +21 -14
  827. ksadk/sessions/resilient.py +611 -504
  828. ksadk/skills/__init__.py +26 -0
  829. ksadk/skills/events.py +464 -0
  830. ksadk/skills/loader.py +44 -2
  831. ksadk/skills/manifest_cache.py +263 -0
  832. ksadk/skills/mcp_server/__init__.py +0 -0
  833. ksadk/skills/mcp_server/_registry.py +33 -0
  834. ksadk/skills/mcp_server/_routing.py +26 -0
  835. ksadk/skills/mcp_server/_workspace_files.py +160 -0
  836. ksadk/skills/mcp_server/register.py +415 -0
  837. ksadk/skills/mcp_server/server.py +218 -0
  838. ksadk/skills/models.py +11 -0
  839. ksadk/skills/observability.py +132 -0
  840. ksadk/skills/package_store.py +75 -2
  841. ksadk/skills/runtime/agent.py +38 -5
  842. ksadk/skills/runtime/artifacts.py +87 -0
  843. ksadk/skills/runtime/backends/e2b.py +400 -56
  844. ksadk/skills/runtime/backends/local.py +621 -119
  845. ksadk/skills/runtime/base.py +78 -7
  846. ksadk/skills/runtime/executor.py +266 -1
  847. ksadk/skills/runtime/loader.py +108 -3
  848. ksadk/skills/runtime/request.py +18 -0
  849. ksadk/skills/service_client.py +6 -1
  850. ksadk/skills/tool_defs.py +108 -3
  851. ksadk/studio/a2a_bindings.py +407 -0
  852. ksadk/studio/a2a_orchestration.py +178 -0
  853. ksadk/studio/active_run_output.py +92 -0
  854. ksadk/studio/activity_records.py +542 -0
  855. ksadk/studio/agent_configuration.py +173 -0
  856. ksadk/studio/api.py +784 -419
  857. ksadk/studio/api_a2a_routes.py +93 -0
  858. ksadk/studio/api_catalog_routes.py +13 -0
  859. ksadk/studio/api_cloud_chat_routes.py +382 -0
  860. ksadk/studio/api_contracts.py +31 -2
  861. ksadk/studio/api_plugin_routes.py +39 -12
  862. ksadk/studio/api_resource_connections.py +79 -41
  863. ksadk/studio/attachment_store.py +14 -2
  864. ksadk/studio/authoring.py +12 -6
  865. ksadk/studio/authoring_coordinator.py +4 -2
  866. ksadk/studio/build_resolution.py +117 -0
  867. ksadk/studio/build_singleflight.py +37 -0
  868. ksadk/studio/builder.py +32 -2
  869. ksadk/studio/capabilities.py +31 -9
  870. ksadk/studio/channel_connections.py +333 -0
  871. ksadk/studio/cloud.py +113 -387
  872. ksadk/studio/cloud_gateways.py +424 -0
  873. ksadk/studio/cloud_shared_web.py +82 -2
  874. ksadk/studio/codex_agent_service.py +19 -2
  875. ksadk/studio/codex_builder.py +1 -1
  876. ksadk/studio/codex_manifest.py +5 -1
  877. ksadk/studio/codex_provider_build.py +65 -0
  878. ksadk/studio/codex_run.py +6 -1
  879. ksadk/studio/compiler.py +112 -6
  880. ksadk/studio/configuration.py +182 -0
  881. ksadk/studio/contract_base.py +19 -0
  882. ksadk/studio/contracts.py +260 -202
  883. ksadk/studio/dsh_application.py +183 -27
  884. ksadk/studio/dsh_capability_service.py +302 -189
  885. ksadk/studio/dsh_lifecycle.py +58 -0
  886. ksadk/studio/dsh_mcp_transport.py +191 -0
  887. ksadk/studio/dsh_provider_registration.py +55 -16
  888. ksadk/studio/entry.py +53 -0
  889. ksadk/studio/event_store.py +53 -5
  890. ksadk/studio/execution_host.py +598 -0
  891. ksadk/studio/framework_run.py +50 -10
  892. ksadk/studio/hosted_kernel.py +1 -1
  893. ksadk/studio/interaction_submission.py +265 -0
  894. ksadk/studio/kernel_registry.py +429 -0
  895. ksadk/studio/kernel_sqlite_migration.py +181 -0
  896. ksadk/studio/lifecycle_status.py +43 -0
  897. ksadk/studio/model_buffered_wire.py +227 -0
  898. ksadk/studio/model_chat_tools.py +143 -0
  899. ksadk/studio/model_client.py +1939 -345
  900. ksadk/studio/model_content_stream.py +129 -0
  901. ksadk/studio/model_credentials.py +196 -0
  902. ksadk/studio/model_profile_service.py +89 -40
  903. ksadk/studio/model_request_projection.py +284 -0
  904. ksadk/studio/model_responses_content.py +296 -0
  905. ksadk/studio/model_usage.py +109 -0
  906. ksadk/studio/model_wire_failure.py +110 -0
  907. ksadk/studio/model_wire_identity.py +138 -0
  908. ksadk/studio/model_wire_snapshot.py +45 -0
  909. ksadk/studio/model_wire_tools.py +283 -0
  910. ksadk/studio/native_acceptance.py +68 -0
  911. ksadk/studio/native_approval.py +111 -0
  912. ksadk/studio/native_browser_port.py +861 -0
  913. ksadk/studio/native_child_mcp.py +87 -0
  914. ksadk/studio/native_child_publication.py +68 -0
  915. ksadk/studio/native_child_skills.py +72 -0
  916. ksadk/studio/native_child_workspace.py +176 -0
  917. ksadk/studio/native_command_policy.py +53 -0
  918. ksadk/studio/native_context_port.py +326 -0
  919. ksadk/studio/native_context_registration.py +54 -0
  920. ksadk/studio/native_document_input.py +88 -0
  921. ksadk/studio/native_documents.py +172 -0
  922. ksadk/studio/native_final_shape.py +852 -0
  923. ksadk/studio/native_gateway_stream.py +69 -0
  924. ksadk/studio/native_hook_port.py +145 -0
  925. ksadk/studio/native_hook_registration.py +70 -0
  926. ksadk/studio/native_inventory_disclosure.py +223 -0
  927. ksadk/studio/native_kernel_admission.py +84 -0
  928. ksadk/studio/native_language_diagnostics.py +320 -0
  929. ksadk/studio/native_mcp_disclosure.py +198 -0
  930. ksadk/studio/native_mcp_tool_port.py +219 -0
  931. ksadk/studio/native_memory_acceptance.py +362 -0
  932. ksadk/studio/native_memory_context.py +266 -0
  933. ksadk/studio/native_memory_flush.py +174 -0
  934. ksadk/studio/native_memory_sources.py +80 -0
  935. ksadk/studio/native_memory_tool_port.py +360 -0
  936. ksadk/studio/native_memory_turn.py +183 -0
  937. ksadk/studio/native_model_port.py +765 -0
  938. ksadk/studio/native_model_recovery.py +126 -0
  939. ksadk/studio/native_options.py +75 -0
  940. ksadk/studio/native_output_fields.py +58 -0
  941. ksadk/studio/native_planning.py +156 -0
  942. ksadk/studio/native_product.py +988 -0
  943. ksadk/studio/native_read_budget.py +426 -0
  944. ksadk/studio/native_recovery.py +171 -0
  945. ksadk/studio/native_scope.py +35 -0
  946. ksadk/studio/native_session_context_port.py +141 -0
  947. ksadk/studio/native_session_engine.py +14 -0
  948. ksadk/studio/native_skill_source.py +74 -0
  949. ksadk/studio/native_subagent_port.py +700 -0
  950. ksadk/studio/native_terminal_recovery.py +95 -0
  951. ksadk/studio/native_test_action.py +610 -0
  952. ksadk/studio/native_tool_port.py +477 -0
  953. ksadk/studio/native_user_input.py +60 -0
  954. ksadk/studio/native_verification_presentation.py +65 -0
  955. ksadk/studio/native_workspace_diagnostics.py +183 -0
  956. ksadk/studio/native_workspace_port.py +43 -0
  957. ksadk/studio/operations.py +34 -9
  958. ksadk/studio/plugin_composition.py +39 -12
  959. ksadk/studio/plugin_kernel_adapter.py +89 -0
  960. ksadk/studio/plugin_lifecycle.py +80 -0
  961. ksadk/studio/plugin_native_activation.py +163 -0
  962. ksadk/studio/plugin_runtime.py +832 -99
  963. ksadk/studio/plugin_runtime_admission.py +57 -0
  964. ksadk/studio/presentation.py +92 -0
  965. ksadk/studio/provider_recovery.py +59 -0
  966. ksadk/studio/public_output_store.py +69 -0
  967. ksadk/studio/recovery_page.py +70 -0
  968. ksadk/studio/resource_authority.py +69 -34
  969. ksadk/studio/resource_catalog.py +14 -12
  970. ksadk/studio/run_activity.py +848 -0
  971. ksadk/studio/run_controls.py +185 -0
  972. ksadk/studio/run_documents.py +127 -0
  973. ksadk/studio/run_service.py +1220 -335
  974. ksadk/studio/run_submission_receipts.py +68 -0
  975. ksadk/studio/runtime_catalog.py +73 -11
  976. ksadk/studio/runtime_prewarm.py +22 -0
  977. ksadk/studio/runtime_source.py +1 -1
  978. ksadk/studio/scheduler_assistant.py +4 -1
  979. ksadk/studio/scheduler_runtime.py +32 -289
  980. ksadk/studio/service.py +615 -246
  981. ksadk/studio/service_settings.py +229 -0
  982. ksadk/studio/shared_web.py +518 -181
  983. ksadk/studio/shared_web_response_events.py +180 -0
  984. ksadk/studio/shared_web_run_state.py +133 -0
  985. ksadk/studio/skill_discovery.py +305 -3
  986. ksadk/studio/static/assets/ChannelsPage-xX5HlMId.js +8 -0
  987. ksadk/studio/static/assets/CodeBlock-DMIf4h33-CkufcPYo.js +44 -0
  988. ksadk/studio/static/assets/ExecutionTree-v3HexvPo-Bk8wzGSy.js +1 -0
  989. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-DYG1Wzbx.js +8 -0
  990. ksadk/studio/static/assets/MermaidBlock-H_0qzQDf-BdXtxug_.js +11 -0
  991. ksadk/studio/static/assets/MessageMarkdown-CwMTvgFj-BeyLyQHu.js +59 -0
  992. ksadk/studio/static/assets/PrismRenderer-5pK6tUdb.js +3 -0
  993. ksadk/studio/static/assets/TeamsPage-CCaaGaVp.js +3 -0
  994. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-Bnb1O3tA.js +1 -0
  995. ksadk/studio/static/assets/architecture-7GRP2DOG-BMOPAkUC.js +1 -0
  996. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-5Zn1gqJv.js +36 -0
  997. ksadk/studio/static/assets/{blockDiagram-I7D4REHJ-CFmPl1de.js → blockDiagram-I7D4REHJ-CLB4L11u.js} +6 -6
  998. ksadk/studio/static/assets/{c4Diagram-7LVT6UL2-BRrGu8qt.js → c4Diagram-7LVT6UL2-BOma_Z_F.js} +7 -7
  999. ksadk/studio/static/assets/channel-r8itPEik.js +1 -0
  1000. ksadk/studio/static/assets/chunk-2E4U76K2-BFf_huql.js +2 -0
  1001. ksadk/studio/static/assets/chunk-2ZTRR5NV-C2qZJila.js +2 -0
  1002. ksadk/studio/static/assets/chunk-3Z5EZCMW-DMniOlPd.js +1 -0
  1003. ksadk/studio/static/assets/{chunk-4HAMMTFA-D220vUtq.js → chunk-4HAMMTFA-DVtDP4rm.js} +7 -7
  1004. ksadk/studio/static/assets/chunk-5V3GS4D5-i-ZDOEnP.js +1 -0
  1005. ksadk/studio/static/assets/chunk-6AZGARVD-BB6FqMl-.js +1 -0
  1006. ksadk/studio/static/assets/chunk-6EIED4P4-DdUJkP0f.js +1 -0
  1007. ksadk/studio/static/assets/chunk-6K3QC6MW-CqVsVn-y.js +1 -0
  1008. ksadk/studio/static/assets/chunk-6TQVIW2G-DKlLbNIP.js +1 -0
  1009. ksadk/studio/static/assets/chunk-747NJXEK-BFkZPlab.js +2 -0
  1010. ksadk/studio/static/assets/chunk-75Z2AOVW-BZNhM4vB.js +2 -0
  1011. ksadk/studio/static/assets/chunk-CLGD4ZFX-D-GTtyKs.js +1 -0
  1012. ksadk/studio/static/assets/{chunk-DU6HZSFF-C4DtVpCu.js → chunk-DU6HZSFF-CpEZCUgg.js} +1 -1
  1013. ksadk/studio/static/assets/chunk-F27PBJKO-D7pvKf0C.js +1 -0
  1014. ksadk/studio/static/assets/{chunk-GMAD6QVW-DiQA-u2N.js → chunk-GMAD6QVW-DE_8H717.js} +6 -6
  1015. ksadk/studio/static/assets/chunk-GVQU2GXP-BfEB0lNv.js +1 -0
  1016. ksadk/studio/static/assets/chunk-I5DQTOEV-Hm2LfiYI.js +1 -0
  1017. ksadk/studio/static/assets/chunk-ICYGCRZG-749o-pGJ.js +1 -0
  1018. ksadk/studio/static/assets/chunk-IH6LHLGP-CC6I9F3i.js +1 -0
  1019. ksadk/studio/static/assets/{chunk-IMKFNOWR-BSlbjT_b.js → chunk-IMKFNOWR-D38axYOR.js} +5 -5
  1020. ksadk/studio/static/assets/chunk-KI3K4JFJ-Rma-0k_M.js +1 -0
  1021. ksadk/studio/static/assets/chunk-L3NEJ4N5-Dq5xn7aL.js +1 -0
  1022. ksadk/studio/static/assets/chunk-LNGE3PJU-DWpGwHrW.js +34 -0
  1023. ksadk/studio/static/assets/{chunk-OSK3NFVY-M2m6G3j4.js → chunk-OSK3NFVY-DiCQjx9b.js} +5 -5
  1024. ksadk/studio/static/assets/chunk-OUJLGHUK-D0j2JRSg.js +2 -0
  1025. ksadk/studio/static/assets/{chunk-P2QGCYS3-DezaQxiK.js → chunk-P2QGCYS3-VdhKmfYq.js} +1 -1
  1026. ksadk/studio/static/assets/chunk-POPQ4Y6H-C1_rzO5M.js +1 -0
  1027. ksadk/studio/static/assets/chunk-PWAF6VOD-B45HvflI.js +1 -0
  1028. ksadk/studio/static/assets/{chunk-SHT3W25Y-DAyIVp5H.js → chunk-SHT3W25Y-DsCFnRVE.js} +9 -9
  1029. ksadk/studio/static/assets/{chunk-SVP7TREG-DulomOrS.js → chunk-SVP7TREG-DljApgRX.js} +1 -1
  1030. ksadk/studio/static/assets/{chunk-TICWLB2K-bHJYoflj.js → chunk-TICWLB2K-DWqRtyqa.js} +6 -6
  1031. ksadk/studio/static/assets/chunk-TLUHSLCS-DUeGgnD5.js +2 -0
  1032. ksadk/studio/static/assets/chunk-UY3FDG6J-CnmaAkG5.js +1 -0
  1033. ksadk/studio/static/assets/chunk-XHIXRSVI-BFQ6B8BE.js +1 -0
  1034. ksadk/studio/static/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
  1035. ksadk/studio/static/assets/classDiagram-ZZMXUADV-DjeMNJmu.js +1 -0
  1036. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-DjeMNJmu.js +1 -0
  1037. ksadk/studio/static/assets/clsx-DB0hHKMi.js +1 -0
  1038. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-om8AY0Mc.js +1 -0
  1039. ksadk/studio/static/assets/createLucideIcon-DR0LGTP5.js +1 -0
  1040. ksadk/studio/static/assets/cynefin-OW5HDTMX-7tP7QfM3.js +1 -0
  1041. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-6BrmK52S.js +62 -0
  1042. ksadk/studio/static/assets/dagre-GXQ25YYZ-buZBRlwz.js +4 -0
  1043. ksadk/studio/static/assets/{diagram-S7CK7UJ4-0BZ98mya.js → diagram-S7CK7UJ4-C6aH78c4.js} +3 -3
  1044. ksadk/studio/static/assets/diagram-UQ7AKVKN-DY_tQ6C_.js +41 -0
  1045. ksadk/studio/static/assets/diagram-VSXAHHWV-DX9p5cQT.js +3 -0
  1046. ksadk/studio/static/assets/diagram-VX7I27RA-DB2WSH8X.js +24 -0
  1047. ksadk/studio/static/assets/diagram-Z3DM3KII-Ce1BJwHE.js +24 -0
  1048. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-Daukxwqf.js +1 -0
  1049. ksadk/studio/static/assets/{erDiagram-RLTQ6QDP-DLGry2Ap.js → erDiagram-RLTQ6QDP-CGthTMmJ.js} +6 -6
  1050. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-BR2FzK4R.js +1 -0
  1051. ksadk/studio/static/assets/flowDiagram-HODETNUW-CZ1tEenp.js +1 -0
  1052. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BfoAZW9X.js +292 -0
  1053. ksadk/studio/static/assets/gitGraph-4MIJSDKK-DYlXv_yJ.js +1 -0
  1054. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-S985OIJF.js +106 -0
  1055. ksadk/studio/static/assets/iconfont-4HN3C9Pg.woff2 +0 -0
  1056. ksadk/studio/static/assets/index-C7DNDik2.css +2 -0
  1057. ksadk/studio/static/assets/index-Cy68gTlH.js +265 -0
  1058. ksadk/studio/static/assets/index.dom-BQenBtFm.js +1 -0
  1059. ksadk/studio/static/assets/info-A6RAGUB7-BlU-8_xu.js +1 -0
  1060. ksadk/studio/static/assets/infoDiagram-27XIBGKW-CO3W8tFn.js +2 -0
  1061. ksadk/studio/static/assets/{ishikawaDiagram-5VMMS53U-CljI2wyf.js → ishikawaDiagram-5VMMS53U-BUGEl8cO.js} +2 -2
  1062. ksadk/studio/static/assets/{journeyDiagram-3NMN7TZE-D50Fo2sL.js → journeyDiagram-3NMN7TZE-Ch2ZYxvr.js} +6 -6
  1063. ksadk/studio/static/assets/{kanban-definition-UXKFOSKX-DimfOTam.js → kanban-definition-UXKFOSKX-Da-Fp4vC.js} +3 -3
  1064. ksadk/studio/static/assets/kingsoft-cloud-BOcLiQ3e.ico +0 -0
  1065. ksadk/studio/static/assets/{line-CX5BOOUP.js → line-BDaeq300.js} +1 -1
  1066. ksadk/studio/static/assets/linear-DmucvK78.js +1 -0
  1067. ksadk/studio/static/assets/mermaid-parser.core-Cj5mYdBi.js +4 -0
  1068. ksadk/studio/static/assets/{mindmap-definition-YA3MSWOX-Bizzqy5R.js → mindmap-definition-YA3MSWOX-CvlsVQ38.js} +1 -1
  1069. ksadk/studio/static/assets/packet-AYTQ26CC-BSJEH9Lb.js +1 -0
  1070. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-BuHuNgT5.js +1 -0
  1071. ksadk/studio/static/assets/pie-WAS4IAKB-qxv01Y8W.js +1 -0
  1072. ksadk/studio/static/assets/{pieDiagram-E7YTZNPT-B9mrFSDF.js → pieDiagram-E7YTZNPT-DlrWiSOv.js} +1 -1
  1073. ksadk/studio/static/assets/preload-helper-CO68xz6u.js +1 -0
  1074. ksadk/studio/static/assets/presentation-yYw7xK60-BmcZriri.js +1 -0
  1075. ksadk/studio/static/assets/{quadrantDiagram-AXDQQJYC-NzUfCbMR.js → quadrantDiagram-AXDQQJYC-BA3hpUZM.js} +6 -6
  1076. ksadk/studio/static/assets/radar-RG4KPBEZ-B6h6pWOs.js +1 -0
  1077. ksadk/studio/static/assets/railroad-74A4TZTK-CGtTWdGc.js +1 -0
  1078. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-Cq7y22IA.js +1 -0
  1079. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-V0aQVv9m.js +1 -0
  1080. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-BQiIsX_p.js +1 -0
  1081. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-BxpAazym.js +1 -0
  1082. ksadk/studio/static/assets/{requirementDiagram-BXWQKSXE-BF3d103U.js → requirementDiagram-BXWQKSXE-E-Ge0FcV.js} +1 -1
  1083. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-CA6YKhQ3.js +40 -0
  1084. ksadk/studio/static/assets/{sequenceDiagram-WJ2MYXX4-Dh4wZtUm.js → sequenceDiagram-WJ2MYXX4-CcElXGg4.js} +9 -9
  1085. ksadk/studio/static/assets/src-B6xuSHsQ.js +1 -0
  1086. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DdXZOFqY.js +1 -0
  1087. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-CJbOM-QK.js +1 -0
  1088. ksadk/studio/static/assets/swimlanes-42K2YHIH-NtgEEHLY.js +1 -0
  1089. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-D-AVlW8B.js +8 -0
  1090. ksadk/studio/static/assets/{timeline-definition-24CTP7MA-DxmSSjRB.js → timeline-definition-24CTP7MA-CIuYhNy3.js} +7 -7
  1091. ksadk/studio/static/assets/treeView-Q6P3EWNA-BTTYcvrF.js +1 -0
  1092. ksadk/studio/static/assets/treemap-WGGIJYW6-Cg7tyfH8.js +1 -0
  1093. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-7HbApbrv.js +34 -0
  1094. ksadk/studio/static/assets/wardley-WFR3VGLG-C6N1rULY.js +1 -0
  1095. ksadk/studio/static/assets/{wardleyDiagram-VM6X3IG4-Ba1AOWoe.js → wardleyDiagram-VM6X3IG4-CMJiaedy.js} +1 -1
  1096. ksadk/studio/static/assets/{xychartDiagram-S5SC5T6Z-Cr5pt5Y-.js → xychartDiagram-S5SC5T6Z-BdgtMvW2.js} +6 -6
  1097. ksadk/studio/static/index.html +8 -2
  1098. ksadk/studio/teams_catalog.py +166 -0
  1099. ksadk/studio/teams_installation.py +217 -0
  1100. ksadk/studio/teams_node.py +549 -0
  1101. ksadk/studio/teams_node_factory.py +558 -0
  1102. ksadk/studio/teams_node_runner.py +72 -0
  1103. ksadk/studio/teams_node_v1.py +935 -0
  1104. ksadk/studio/teams_remote.py +496 -0
  1105. ksadk/studio/templates.py +41 -19
  1106. ksadk/studio/validator.py +13 -0
  1107. ksadk/studio/workspace.py +19 -4
  1108. ksadk/studio/workspace_plugins.py +138 -0
  1109. ksadk/studio/workspace_registry.py +286 -0
  1110. ksadk/tools/a2a_policy.py +5 -0
  1111. ksadk/tools/artifact_observation.py +53 -0
  1112. ksadk/tools/captured_source_artifact.py +68 -0
  1113. ksadk/tools/schema.py +34 -0
  1114. ksadk/toolsets/__init__.py +93 -88
  1115. ksadk/toolsets/a2a.py +89 -89
  1116. ksadk/toolsets/sandbox.py +377 -6
  1117. ksadk/toolsets/skill_management.py +315 -0
  1118. ksadk/toolsets/skills.py +446 -378
  1119. ksadk/toolsets/tool_selection.py +94 -0
  1120. ksadk/toolsets/workspace.py +344 -326
  1121. ksadk/toolsets/workspace_editing.py +291 -0
  1122. ksadk/toolsets/workspace_identity.py +15 -0
  1123. ksadk/toolsets/workspace_model_observation.py +104 -0
  1124. ksadk/toolsets/workspace_mutation.py +75 -0
  1125. ksadk/toolsets/workspace_read_budget.py +216 -0
  1126. ksadk/toolsets/workspace_search.py +192 -0
  1127. ksadk/toolsets/workspace_search_process.py +129 -0
  1128. ksadk/toolsets/workspace_state.py +6 -0
  1129. ksadk/version.py +1 -1
  1130. ksadk_runtime_common/http_headers.py +18 -0
  1131. ksadk_runtime_common/memory_backend/providers/lancedb.py +56 -2
  1132. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -148
  1133. ksadk_runtime_common/workspace_files/router.py +28 -14
  1134. agentengine_sdk_python-0.8.4.dist-info/RECORD +0 -1070
  1135. ksadk/server/static/assets/MathMessageMarkdown-DbdW5A4_.js +0 -8
  1136. ksadk/server/static/assets/architecture-7GRP2DOG-BW5UtSnx.js +0 -1
  1137. ksadk/server/static/assets/channel-CF5Up3hQ.js +0 -1
  1138. ksadk/server/static/assets/chunk-2Q5K7J3B-KkXX47WI.js +0 -1
  1139. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Cz81acRQ.js +0 -1
  1140. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Cz81acRQ.js +0 -1
  1141. ksadk/server/static/assets/cynefin-OW5HDTMX-DVWs8a2t.js +0 -1
  1142. ksadk/server/static/assets/dist-B2_CVgKv.js +0 -1
  1143. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CQqR2hg3.js +0 -1
  1144. ksadk/server/static/assets/flowDiagram-A5DVABFB-DDRRbGPm.js +0 -1
  1145. ksadk/server/static/assets/gitGraph-4MIJSDKK-fgWEf7UD.js +0 -1
  1146. ksadk/server/static/assets/index-DcTML1Up.css +0 -2
  1147. ksadk/server/static/assets/index-Dh2XHqPK.js +0 -244
  1148. ksadk/server/static/assets/info-A6RAGUB7-BUecLTdt.js +0 -1
  1149. ksadk/server/static/assets/packet-AYTQ26CC-BeW-btFv.js +0 -1
  1150. ksadk/server/static/assets/pie-WAS4IAKB-X0xh4SaT.js +0 -1
  1151. ksadk/server/static/assets/radar-RG4KPBEZ-DzRMSqjd.js +0 -1
  1152. ksadk/server/static/assets/railroad-74A4TZTK-Cc44icX-.js +0 -1
  1153. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-D6S4BdV-.js +0 -1
  1154. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-vD3aVE2o.js +0 -1
  1155. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CYbW_b4T.js +0 -1
  1156. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BIcjKFhF.js +0 -1
  1157. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-tq3K3Ybl.js +0 -8
  1158. ksadk/server/static/assets/treeView-Q6P3EWNA-DBXt3GdU.js +0 -1
  1159. ksadk/server/static/assets/treemap-WGGIJYW6-DrCy4E_l.js +0 -1
  1160. ksadk/server/static/assets/wardley-WFR3VGLG-CefhOliM.js +0 -1
  1161. ksadk/studio/static/assets/CodeBlock-DCUUY0PL-BLjA7kbS.js +0 -41
  1162. ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--CUYIXwgI.js +0 -8
  1163. ksadk/studio/static/assets/MermaidBlock-DBFTztfQ-BTYKWEbD.js +0 -44
  1164. ksadk/studio/static/assets/PrismRenderer-wiXRHURw.js +0 -3
  1165. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-CLETGjKq.js +0 -1
  1166. ksadk/studio/static/assets/architecture-7GRP2DOG-hXMiO_AU.js +0 -1
  1167. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-B5EQysk6.js +0 -36
  1168. ksadk/studio/static/assets/channel-BqO-gtEw.js +0 -1
  1169. ksadk/studio/static/assets/chunk-75Z2AOVW-C8lLv_qc.js +0 -2
  1170. ksadk/studio/static/assets/chunk-F27PBJKO-Cpw14SNG.js +0 -1
  1171. ksadk/studio/static/assets/chunk-GVQU2GXP-DUdNBUCi.js +0 -1
  1172. ksadk/studio/static/assets/chunk-L3NEJ4N5-Db8Ab22W.js +0 -1
  1173. ksadk/studio/static/assets/chunk-POPQ4Y6H-DOpufJ3t.js +0 -1
  1174. ksadk/studio/static/assets/chunk-PWAF6VOD-CfLb1gSc.js +0 -1
  1175. ksadk/studio/static/assets/chunk-XXDRQBXY-7PcdR2B1.js +0 -1
  1176. ksadk/studio/static/assets/classDiagram-ZZMXUADV-D_bW8JjA.js +0 -1
  1177. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-D_bW8JjA.js +0 -1
  1178. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-snL88wkX.js +0 -1
  1179. ksadk/studio/static/assets/cynefin-OW5HDTMX-Bd1YhRo1.js +0 -1
  1180. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-BBrIG_mI.js +0 -62
  1181. ksadk/studio/static/assets/dagre-GXQ25YYZ-DtF1nGdY.js +0 -4
  1182. ksadk/studio/static/assets/diagram-UQ7AKVKN-6mLKEo6L.js +0 -41
  1183. ksadk/studio/static/assets/diagram-VSXAHHWV-CJBIaiZ2.js +0 -3
  1184. ksadk/studio/static/assets/diagram-VX7I27RA-BohLEE1C.js +0 -24
  1185. ksadk/studio/static/assets/diagram-Z3DM3KII-D8KIGonG.js +0 -24
  1186. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-C99HU61t.js +0 -1
  1187. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-B1_5Ac8j.js +0 -1
  1188. ksadk/studio/static/assets/flowDiagram-HODETNUW-DD5hmicn.js +0 -1
  1189. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BPJrVLSG.js +0 -292
  1190. ksadk/studio/static/assets/gitGraph-4MIJSDKK-Cy_ZQBGi.js +0 -1
  1191. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-CZCUz4MT.js +0 -106
  1192. ksadk/studio/static/assets/index-CeHL9ARV.css +0 -2
  1193. ksadk/studio/static/assets/index-D9QEcVpL.js +0 -320
  1194. ksadk/studio/static/assets/info-A6RAGUB7-DBzDQB_I.js +0 -1
  1195. ksadk/studio/static/assets/infoDiagram-27XIBGKW-B-sq07Hi.js +0 -2
  1196. ksadk/studio/static/assets/linear-BCxN9JLv.js +0 -1
  1197. ksadk/studio/static/assets/mermaid-parser.core-BdCz8fkS.js +0 -7
  1198. ksadk/studio/static/assets/packet-AYTQ26CC-gPln-_kG.js +0 -1
  1199. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-Dy3fB-gW.js +0 -1
  1200. ksadk/studio/static/assets/pie-WAS4IAKB-qZdHMr7B.js +0 -1
  1201. ksadk/studio/static/assets/radar-RG4KPBEZ-BZlnaea9.js +0 -1
  1202. ksadk/studio/static/assets/railroad-74A4TZTK-Ce3__H9c.js +0 -1
  1203. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-DqQn7EzD.js +0 -1
  1204. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-B55kCA8F.js +0 -1
  1205. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-DfQnvkHd.js +0 -1
  1206. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-DnhMjZCk.js +0 -1
  1207. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-Bo-JTwt0.js +0 -40
  1208. ksadk/studio/static/assets/src-SFn9St9H.js +0 -1
  1209. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DH774G6d.js +0 -1
  1210. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-DZvVWPBo.js +0 -1
  1211. ksadk/studio/static/assets/swimlanes-42K2YHIH-Bl13OvTX.js +0 -1
  1212. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-BnFOTALJ.js +0 -8
  1213. ksadk/studio/static/assets/treeView-Q6P3EWNA-D5Nn9Swz.js +0 -1
  1214. ksadk/studio/static/assets/treemap-WGGIJYW6-CgHgnQhE.js +0 -1
  1215. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-B9QEXcJq.js +0 -34
  1216. ksadk/studio/static/assets/wardley-WFR3VGLG-DXrK2RRY.js +0 -1
  1217. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/WHEEL +0 -0
  1218. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/entry_points.txt +0 -0
  1219. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/licenses/LICENSE +0 -0
  1220. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/top_level.txt +0 -0
  1221. /ksadk/studio/static/assets/{MathMessageMarkdown-CBcDrAw--BEOyPC3w.css → MathMessageMarkdown-BesSeCYl-BEOyPC3w.css} +0 -0
@@ -0,0 +1,1351 @@
1
+ """Managed Engine 的 Context 构建管线(长任务方案 §6 / §8)。
2
+
3
+ 从 ``engine/langgraph.py`` 抽出(模块体量守卫):规划 → 主动/紧急压缩 →
4
+ 组装 → ContextManifest/context.built 投影,以及压缩前受控 Memory Flush。
5
+ 事件落账统一走引擎注入的 ``event_fn``(保证 seq 单调与信封一致)。
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import hashlib
12
+ import json
13
+ import re
14
+ from typing import Any, Callable
15
+
16
+ from ksadk.harness.compaction_record import CompactionRecord, build_compaction_record
17
+ from ksadk.harness.context_sections import BUILTIN_CONTRIBUTORS, sections_to_context_items
18
+ from ksadk.harness.events import EventType, RuntimeEvent
19
+ from ksadk.harness.hooks import RunContext, run_hooks
20
+ from ksadk.harness.loop import ModelFailoverExhausted, ReasonInput, reason_turn_async
21
+ from ksadk.harness.multimodal import runtime_input_text
22
+ from ksadk.harness.state import Message, MessageRole
23
+
24
+ #: 事件构造函数签名(引擎的 _event)。
25
+ EventFn = Callable[..., RuntimeEvent]
26
+
27
+ #: G12 §15.2:摘要输出命中敏感策略时的占位文本。
28
+ _REDACTED_SUMMARY_PLACEHOLDER = "[摘要降级为占位:摘要输出命中敏感数据策略,原文不进入 Context]"
29
+
30
+
31
+ class EngineContextPipeline:
32
+ """ContextEngine 的运行时编排:规划、压缩、组装、Manifest 投影。"""
33
+
34
+ def __init__(
35
+ self,
36
+ *,
37
+ context_engine: Any,
38
+ reasoner: Any,
39
+ event_fn: EventFn,
40
+ memory_runtime: Any | None = None,
41
+ prompt_cache_tracker: Any | None = None,
42
+ context_contributors: tuple[Any, ...] = (),
43
+ sensitive_policy: Any | None = None,
44
+ hooks: tuple[Any, ...] = (),
45
+ ) -> None:
46
+ self._context_engine = context_engine
47
+ self._reasoner = reasoner
48
+ self._event = event_fn
49
+ self._memory_runtime = memory_runtime
50
+ self._prompt_cache_tracker = prompt_cache_tracker
51
+ # Compile 期固化(引擎构造时冻结,Runtime 期只读,与 hooks 纪律一致)。
52
+ self._context_contributors = tuple(context_contributors)
53
+ # G12:与 MCP Offload 同源的敏感数据策略(sensitive_match/sensitive_patterns)。
54
+ self._sensitive_policy = sensitive_policy
55
+ # G5:Provider 级扩展拦截面(on_context 等四钩子),构造期固化、只读。
56
+ self._hooks = tuple(hooks)
57
+
58
+ # ------------------------------------------------------------ 主入口
59
+
60
+ async def prepare_context(self, run: Any, instructions: str) -> list[dict[str, Any]] | None:
61
+ """ContextEngine 真正控制首次模型输入(收口 1)。
62
+
63
+ 规划 → 超过主动阈值(Spec context_policy)先主动压缩 → 仍超预算做一次
64
+ 紧急压缩(只允许一次,§8.4)→ 组装为 Chat 输入。未注入 ContextEngine 时
65
+ 返回 None(回退旧拼接路径)。
66
+ """
67
+ from ksadk.harness.context_engine import ContextEngineError
68
+
69
+ history = run.request.metadata.get("conversation_history") or []
70
+ messages = [
71
+ Message(
72
+ role=MessageRole(m.get("role", "user")),
73
+ content=str(m.get("content") or ""),
74
+ tool_call_id=str(m["tool_call_id"]) if m.get("tool_call_id") else None,
75
+ name=str(m["name"]) if m.get("name") else None,
76
+ )
77
+ for m in history
78
+ if isinstance(m, dict) and m.get("role") in {"user", "assistant", "system"}
79
+ ]
80
+ # 回放路径 tool 消息被整体过滤(上方角色白名单),原 assistant
81
+ # tool_calls 载体退化为空文本 assistant——纯噪音(G15.1 观察项),
82
+ # 且无正文可保留,直接剔除。
83
+ messages = [
84
+ m for m in messages if not (m.role is MessageRole.ASSISTANT and not m.content.strip())
85
+ ]
86
+ current_input = runtime_input_text(run.request.input)
87
+ # Studio/Draft 会把本轮输入同时放进 request.input 和历史末尾。历史副本
88
+ # 不能继续作为可丢弃 history_round 参与规划,否则超大本轮输入会在
89
+ # Planner 限额时被静默裁掉。只移除重复副本,本轮输入始终以 required
90
+ # current_input 单独进入 ContextPlan。
91
+ if (
92
+ current_input
93
+ and messages
94
+ and messages[-1].role is MessageRole.USER
95
+ and messages[-1].content == current_input
96
+ ):
97
+ messages = messages[:-1]
98
+ # 长任务方案 §9:recall_memory_and_knowledge——规划前检索长期 Memory,
99
+ # 命中以 system 段注入(planner 按 history_system 高优先级保留)。
100
+ messages = self._recall_memory(run, messages) + messages
101
+ window, source = self._resolve_window(run)
102
+ plan = self._plan_context(run, messages, current_input=current_input)
103
+ self._emit_planned(run, plan, window, source)
104
+ policy = run.compiled.spec.context_policy
105
+ max_input = plan.budget.max_input_tokens
106
+
107
+ if (
108
+ plan.planned_input_tokens > int(policy.proactive_compaction_threshold * max_input)
109
+ or (
110
+ # G18 ② 预测式触发:在 proactive_threshold 之前提前压缩。
111
+ # 复用 proactive 路径,不新增档位;
112
+ # trigger 仍记 "proactive" 保持事件契约稳定,以 trigger_reason 区分预测式与主动式)
113
+ plan.planned_input_tokens > int(policy.predictive_compaction_ratio * max_input)
114
+ )
115
+ or (
116
+ # Planner 丢弃了历史轮次(静默丢上下文)→ 主动压缩以摘要保住事实。
117
+ any(
118
+ d.action == "dropped" and d.item_id.startswith("history")
119
+ for d in plan.decisions
120
+ )
121
+ )
122
+ ):
123
+ trigger_reason = (
124
+ "predictive"
125
+ if plan.planned_input_tokens
126
+ <= int(policy.proactive_compaction_threshold * max_input)
127
+ else "proactive"
128
+ )
129
+ compacted = await self._compact_history(
130
+ run,
131
+ messages,
132
+ trigger="proactive",
133
+ keep_recent=6,
134
+ budget_tokens=max_input,
135
+ keep_recent_tokens=int(policy.keep_recent_token_ratio * max_input),
136
+ trigger_reason=trigger_reason,
137
+ )
138
+ if compacted is not None:
139
+ messages = compacted
140
+ plan = self._plan_context(run, messages, current_input=current_input)
141
+ self._emit_planned(run, plan, window, source)
142
+ max_input = plan.budget.max_input_tokens
143
+
144
+ if plan.planned_input_tokens > max_input:
145
+ # 紧急压缩(§8.4):更强压缩,只允许一次。
146
+ compacted = await self._compact_history(
147
+ run,
148
+ messages,
149
+ trigger="emergency",
150
+ keep_recent=2,
151
+ budget_tokens=max_input,
152
+ keep_recent_tokens=int(policy.keep_recent_token_ratio * max_input),
153
+ )
154
+ if compacted is not None:
155
+ messages = compacted
156
+ plan = self._plan_context(run, messages, current_input=current_input)
157
+ self._emit_planned(run, plan, window, source)
158
+ run.events.append(
159
+ self._event(
160
+ run,
161
+ EventType.CONTEXT_RECOVERED,
162
+ {"reason": "context_overflow", "trigger": "emergency"},
163
+ )
164
+ )
165
+ if plan.planned_input_tokens > plan.budget.max_input_tokens:
166
+ current_tokens = count_tokens(current_input)
167
+ raise ContextEngineError(
168
+ "紧急压缩后仍超出输入预算;本轮用户输入不会被静默丢弃: "
169
+ f"planned_input_tokens={plan.planned_input_tokens}, "
170
+ f"current_input_tokens={current_tokens}, "
171
+ f"max_input_tokens={plan.budget.max_input_tokens}"
172
+ )
173
+
174
+ assembled = self._context_engine.assemble_chat(plan)
175
+ if not assembled.messages or assembled.messages[0].get("role") != "system":
176
+ assembled.messages.insert(0, {"role": "system", "content": instructions})
177
+ # G5 §5.2:on_context 在组装后、Manifest 投影前拦截首次模型输入(语义见下)。
178
+ messages_out = list(assembled.messages)
179
+ projected = _projected_tokens(messages_out)
180
+ messages_out, projected = await self._apply_on_context_hooks(
181
+ run, plan, messages_out, projected, window
182
+ )
183
+ # 长任务方案 §6.2:Manifest 可观测快照 + context.built(Planned/Projected;
184
+ # Actual 由 usage 回填)。正文不入 Manifest,只记 Hash/引用/Token。
185
+ self._emit_context_built(run, plan, projected, window)
186
+ return messages_out
187
+
188
+ async def prepare_turn_context(
189
+ self,
190
+ run: Any,
191
+ messages: list[dict[str, Any]],
192
+ instructions: str,
193
+ tools: list[Any] | tuple[Any, ...],
194
+ ) -> list[dict[str, Any]]:
195
+ """在每个后续模型回合前重新核算并按需压缩真实输入。
196
+
197
+ 首轮 ``prepare_context`` 只负责把会话历史装配进图状态。长任务随后会不断
198
+ 追加 assistant/tool 消息;如果后续回合不再经过预算闸门,ContextEngine
199
+ 实际只在首轮生效。这里以 Provider 真正收到的 ``messages + tools`` 为口径
200
+ 做预测式压缩,并保留未被压缩尾部的原始 OpenAI 消息(尤其是完整
201
+ ``tool_calls`` / ``tool_call_id``),避免为了压缩破坏工具调用配对。
202
+ """
203
+
204
+ if not messages:
205
+ return messages
206
+ window, source = self._resolve_window(run)
207
+ build_budget = getattr(self._context_engine, "build_budget", None)
208
+ if not callable(build_budget):
209
+ # ContextEngine 的旧兼容实现只提供 plan/assemble_chat。逐轮预算核算是
210
+ # 增量能力,不能让这类实现(以及第三方 adapter)在第二个模型回合
211
+ # 直接崩溃;它们仍保留首轮 plan 的既有行为。
212
+ return messages
213
+ budget = build_budget(run.compiled.spec, context_window_tokens=window)
214
+ max_input = budget.max_input_tokens
215
+ tool_schema_tokens = _tool_schema_tokens(tools)
216
+ projected = _projected_tokens(messages) + tool_schema_tokens
217
+ policy = run.compiled.spec.context_policy
218
+ trigger_at = int(policy.predictive_compaction_ratio * max_input)
219
+ if projected <= trigger_at:
220
+ return messages
221
+
222
+ stable_prefix: list[dict[str, Any]] = []
223
+ dynamic_messages = list(messages)
224
+ if messages and str(messages[0].get("role") or "") == "system":
225
+ stable_prefix = [dict(messages[0])]
226
+ dynamic_messages = list(messages[1:])
227
+ converted = [_chat_message(message) for message in dynamic_messages]
228
+ # 少量消息无法形成有意义的 head/tail;工具 schema 本身过大也不能靠
229
+ # 摘要解决。此时保持原输入,避免每轮重复生成无效摘要。
230
+ if len(converted) <= 6:
231
+ return messages
232
+
233
+ available_for_messages = max(1024, max_input - tool_schema_tokens)
234
+ keep_recent_tokens = max(512, int(policy.keep_recent_token_ratio * available_for_messages))
235
+ compacted = await self._compact_history(
236
+ run,
237
+ converted,
238
+ trigger="proactive",
239
+ keep_recent=6,
240
+ budget_tokens=available_for_messages,
241
+ keep_recent_tokens=keep_recent_tokens,
242
+ trigger_reason="predictive_turn",
243
+ )
244
+ if compacted is None:
245
+ return messages
246
+
247
+ # _compact_history 的第一条是新摘要,后面是原 converted 尾部。模型输入
248
+ # 必须换回原始 dict 尾部,才能保住 assistant.tool_calls 等结构字段。
249
+ tail_count = max(0, len(compacted) - 1)
250
+ rebuilt = list(stable_prefix)
251
+ rebuilt.append({"role": "system", "content": compacted[0].content})
252
+ if tail_count:
253
+ tail = [dict(message) for message in dynamic_messages[-tail_count:]]
254
+ # Some OpenAI-compatible gateways reject a compacted transcript
255
+ # whose first non-system message is an assistant tool-call, even
256
+ # when its following tool results are perfectly paired. Replay the
257
+ # actual current request here: a generic "continue" user message
258
+ # made a short Skill question turn into an unrelated older task.
259
+ if str(tail[0].get("role") or "") == "assistant":
260
+ current_request = runtime_input_text(run.request.input).strip()
261
+ rebuilt.append(
262
+ {
263
+ "role": "user",
264
+ "content": current_request
265
+ or "【运行时衔接占位,非用户新指令】请只处理本轮已记录的请求。",
266
+ }
267
+ )
268
+ rebuilt.extend(tail)
269
+
270
+ projected_after = _projected_tokens(rebuilt) + tool_schema_tokens
271
+ plan = self._plan_context(
272
+ run,
273
+ [_chat_message(message) for message in rebuilt[len(stable_prefix) :]],
274
+ current_input="",
275
+ )
276
+ self._emit_planned(
277
+ run,
278
+ plan,
279
+ window,
280
+ source,
281
+ planned_input_tokens=projected_after,
282
+ tool_schema_tokens=tool_schema_tokens,
283
+ )
284
+ self._emit_context_built(
285
+ run,
286
+ plan,
287
+ projected_after,
288
+ window,
289
+ tool_schema_tokens=tool_schema_tokens,
290
+ )
291
+ return rebuilt
292
+
293
+ # ------------------------------------------------------------ Provider 钩子
294
+
295
+ def _hook_event(self, run: Any) -> Callable[..., None]:
296
+ """钩子的降级上报通道:复用引擎 ``_event`` 信封与 seq 单调。"""
297
+
298
+ def _emit(_hook_run: Any, event_type: str, payload: dict[str, Any]) -> None:
299
+ run.events.append(self._event(run, event_type, payload))
300
+
301
+ return _emit
302
+
303
+ async def _apply_on_context_hooks(
304
+ self, run: Any, plan: Any, messages: list[dict[str, Any]], projected: int, window: int
305
+ ) -> tuple[list[dict[str, Any]], int]:
306
+ """on_context 拦截待发 Provider 的模型输入(prepare_context / recover 共用)。
307
+
308
+ Option B:钩子改写时先按改写前输入落一代 context.built,再按改写后输入追投
309
+ 一代(supersedes 链指向初跑世代);仅 projected_tokens 反映改写后规模,
310
+ sections/content_hash/planned_tokens 保持改写前记账(投影语义,非事实源)。
311
+ 改写回合 PROMPT_CACHE_DIAGNOSTIC 双跑属预期(两代同属一次构建,与 G13
312
+ 断言语义一致)。返回非 list 属协议违约 → 可见降级、沿用原输入,不抛错。
313
+ """
314
+ if not self._hooks:
315
+ return messages, projected
316
+ hooked = await run_hooks(
317
+ self._hooks,
318
+ "on_context",
319
+ _run_context_of(run),
320
+ self._hook_event(run),
321
+ # 逐条 dict 拷贝:就地改写的钩子作用于副本,`!=` 才能检出。
322
+ payload={"messages": [dict(m) for m in messages]},
323
+ )
324
+ if not isinstance(hooked, list):
325
+ # run_hooks 链式守卫下不可达;纵深防御。(降级落账后沿用原输入)
326
+ self._hook_event(run)(
327
+ None,
328
+ EventType.POLICY_DECISION,
329
+ {
330
+ "action": "hook_failed",
331
+ "reason": "on_context returned non-list",
332
+ "outcome": "hook_failed",
333
+ "method": "on_context",
334
+ "error": f"on_context 返回 {type(hooked).__name__},期望 list[dict]",
335
+ },
336
+ )
337
+ return messages, projected
338
+ if hooked == messages:
339
+ return messages, projected
340
+ self._emit_context_built(run, plan, projected, window)
341
+ return hooked, _projected_tokens(hooked)
342
+
343
+ async def recover_model_overflow(
344
+ self,
345
+ run: Any,
346
+ messages: list[dict[str, Any]],
347
+ instructions: str,
348
+ ) -> list[dict[str, Any]]:
349
+ """模型明确拒绝上下文后执行一次更强压缩并重建输入。
350
+
351
+ 这是 provider 真实 overflow 的恢复路径,不是首次调用前的预算预测。
352
+ 重试预算保存在 HarnessState,避免模型/备用模型之间形成无限循环;
353
+ 最近 Tool Call/Result 作为完整尾部原样保留,不能被重建成残缺消息。
354
+ """
355
+ from ksadk.harness.context_engine import ContextEngineError
356
+
357
+ retries = run.state.retry_state.emergency_compaction_retries
358
+ limit = run.compiled.spec.context_policy.emergency_retry_limit
359
+ if retries >= limit:
360
+ raise ContextEngineError(f"模型上下文溢出已执行 {retries} 次紧急压缩,达到上限 {limit}")
361
+
362
+ # Stable Prompt 是高信任、不参与摘要的固定前缀;只压缩其后的动态消息。
363
+ stable_prefix: list[dict[str, Any]] = []
364
+ dynamic_messages = messages
365
+ if messages and str(messages[0].get("role") or "") == "system":
366
+ stable_prefix = [dict(messages[0])]
367
+ dynamic_messages = messages[1:]
368
+ converted = [_chat_message(message) for message in dynamic_messages]
369
+ # 三路压缩共用边界:至少保留最后两条,并把边界回退到 Tool Pair 之前。
370
+ kept = find_compaction_boundary(converted, keep_messages=2, keep_tokens=None)
371
+ cutoff = len(dynamic_messages) - kept
372
+ if cutoff <= 0:
373
+ raise ContextEngineError("上下文溢出但没有可继续压缩的历史消息")
374
+
375
+ run.state.retry_state = run.state.retry_state.model_copy(
376
+ update={
377
+ "emergency_compaction_retries": retries + 1,
378
+ "last_error_kind": "context_length",
379
+ }
380
+ )
381
+ compacted = await self._compact_history(
382
+ run,
383
+ converted,
384
+ trigger="emergency",
385
+ keep_recent=len(dynamic_messages) - cutoff,
386
+ budget_tokens=self._plan_context(run, converted).budget.max_input_tokens,
387
+ )
388
+ if compacted is None:
389
+ raise ContextEngineError("上下文溢出但紧急压缩没有产生新输入")
390
+
391
+ summary = compacted[0].content
392
+ recovered: list[dict[str, Any]] = list(stable_prefix)
393
+ recovered.append({"role": "system", "content": summary})
394
+ recovered.extend(dict(message) for message in dynamic_messages[cutoff:])
395
+ if not recovered or recovered[0].get("role") != "system":
396
+ recovered.insert(0, {"role": "system", "content": instructions})
397
+
398
+ # 为恢复后的真实模型输入生成新的 Manifest 世代;正文仍不落 Manifest。
399
+ recovered_state = [_chat_message(message) for message in recovered[len(stable_prefix) :]]
400
+ plan = self._plan_context(run, recovered_state)
401
+ window, _source = self._resolve_window(run)
402
+ projected = sum(count_tokens(str(m.get("content") or "")) for m in recovered)
403
+ # G5 §5.2:overflow 恢复后的真实输入与 prepare_context 同款 on_context 拦截。
404
+ recovered, projected = await self._apply_on_context_hooks(
405
+ run, plan, recovered, projected, window
406
+ )
407
+ self._emit_context_built(run, plan, projected, window)
408
+ run.events.append(
409
+ self._event(
410
+ run,
411
+ EventType.CONTEXT_RECOVERED,
412
+ {
413
+ "reason": "provider_context_overflow",
414
+ "trigger": "emergency",
415
+ "retry": retries + 1,
416
+ "retry_limit": limit,
417
+ "message_count_before": len(messages),
418
+ "message_count_after": len(recovered),
419
+ },
420
+ )
421
+ )
422
+ return recovered
423
+
424
+ # ------------------------------------------------------------ Memory 召回
425
+
426
+ def _recall_memory(self, run: Any, messages: list[Message]) -> list[Message]:
427
+ """检索长期 Memory 并以 system 段注入(长任务方案 §7.5 / §9)。
428
+
429
+ - 检索前先做 scope 允许列表过滤(policy 未启用 → 不检索);
430
+ - 每条命中在 ``memory.recalled`` 事件中给出 memory_id/score/injected
431
+ (injected = 最终被 planner 选入;由 context.built 的 sections
432
+ 佐证,这里记召回集合本身);
433
+ - Provider 故障返回空结果(HarnessMemoryRuntime 语义),不污染输入。
434
+ """
435
+ if self._memory_runtime is None or not run.compiled.spec.memory_policy.enabled:
436
+ return []
437
+ query = runtime_input_text(run.request.input).strip()
438
+ if not query:
439
+ return []
440
+
441
+ def _scope_id(scope: str) -> str:
442
+ if scope == "agent":
443
+ return f"agent:{run.state.agent_id}"
444
+ return f"user:{run.state.user_id or 'anonymous'}"
445
+
446
+ scopes = [
447
+ (scope, _scope_id(scope))
448
+ for scope in ("agent", "user")
449
+ if scope in set(run.compiled.spec.memory_policy.scopes)
450
+ ]
451
+ if not scopes:
452
+ return []
453
+ result = self._memory_runtime.recall(query=query, scopes=scopes)
454
+ if result.status != "ok" or not result.records:
455
+ return []
456
+ items = []
457
+ lines: list[str] = []
458
+ for record in result.records:
459
+ items.append(
460
+ {
461
+ "memory_id": record.memory_id,
462
+ "scope": record.scope,
463
+ "score": _keyword_score(query, record.content),
464
+ "injected": True,
465
+ }
466
+ )
467
+ lines.append(f"- (长期记忆 {record.memory_id}){record.summary or record.content}")
468
+ run.events.append(
469
+ self._event(
470
+ run,
471
+ EventType.MEMORY_RECALLED,
472
+ {
473
+ "scope": ",".join(s for s, _ in scopes),
474
+ "query": query[:256],
475
+ "items": items,
476
+ },
477
+ )
478
+ )
479
+ return [Message(role=MessageRole.SYSTEM, content="【相关长期记忆】\n" + "\n".join(lines))]
480
+
481
+ # ------------------------------------------------------------ 规划
482
+
483
+ def _resolve_window(self, run: Any) -> tuple[int, str]:
484
+ from ksadk.harness.context_engine import resolve_context_window
485
+
486
+ raw_window = run.request.metadata.get("context_window_tokens")
487
+ return resolve_context_window(
488
+ model_profile_window=int(raw_window) if isinstance(raw_window, (int, float)) else None
489
+ )
490
+
491
+ def _plan_context(
492
+ self,
493
+ run: Any,
494
+ messages: list[Message],
495
+ *,
496
+ current_input: str | None = None,
497
+ ) -> Any:
498
+ """对给定历史做一次上下文规划(ContextRequest 以快照构建)。"""
499
+ from ksadk.harness.context_engine import ContextRequest
500
+
501
+ window, _source = self._resolve_window(run)
502
+ snapshot = run.state.model_copy(update={"messages": messages})
503
+ effective_input = (
504
+ runtime_input_text(run.request.input) if current_input is None else current_input
505
+ )
506
+ return self._context_engine.plan(
507
+ ContextRequest(
508
+ spec=run.compiled.spec,
509
+ state=snapshot,
510
+ user_input=effective_input,
511
+ context_window_tokens=window,
512
+ section_items=tuple(
513
+ sections_to_context_items(self._collect_sections(run), count_text=count_tokens)
514
+ ),
515
+ )
516
+ )
517
+
518
+ def _collect_sections(self, run: Any) -> list[Any]:
519
+ """收集全部 ContextSection(G9 §12.3.1):内置贡献者 + 宿主贡献者。
520
+
521
+ 贡献者异常 → ``policy.decision(outcome="context_section_failed")`` 可见
522
+ 降级,该贡献者的段缺席(Manifest 如实记录缺席事实),不阻断 Run。
523
+ """
524
+ sections: list[Any] = []
525
+ for index, contributor in enumerate((*BUILTIN_CONTRIBUTORS, *self._context_contributors)):
526
+ try:
527
+ produced = contributor.sections(run)
528
+ except Exception as exc: # noqa: BLE001 - 可见降级,不静默吞
529
+ run.events.append(
530
+ self._event(
531
+ run,
532
+ EventType.POLICY_DECISION,
533
+ {
534
+ "action": "degrade",
535
+ "reason": "context_section_failed",
536
+ "outcome": "context_section_failed",
537
+ "contributor_index": index,
538
+ "contributor": type(contributor).__name__,
539
+ "error": str(exc)[:256],
540
+ },
541
+ )
542
+ )
543
+ continue
544
+ if produced:
545
+ sections.extend(produced)
546
+ return sections
547
+
548
+ def _emit_planned(
549
+ self,
550
+ run: Any,
551
+ plan: Any,
552
+ window: int,
553
+ source: str,
554
+ *,
555
+ planned_input_tokens: int | None = None,
556
+ tool_schema_tokens: int = 0,
557
+ ) -> None:
558
+ payload = {
559
+ "budget_tokens": plan.budget.max_input_tokens,
560
+ "sections": dict(plan.tokens_by_kind),
561
+ "window_source": source,
562
+ "context_window_tokens": window,
563
+ "planned_input_tokens": (
564
+ plan.planned_input_tokens if planned_input_tokens is None else planned_input_tokens
565
+ ),
566
+ }
567
+ if tool_schema_tokens:
568
+ payload["tool_schema_tokens"] = tool_schema_tokens
569
+ run.events.append(
570
+ self._event(
571
+ run,
572
+ EventType.CONTEXT_PLANNED,
573
+ payload,
574
+ )
575
+ )
576
+
577
+ def _emit_context_built(
578
+ self,
579
+ run: Any,
580
+ plan: Any,
581
+ projected: int,
582
+ window: int,
583
+ *,
584
+ tool_schema_tokens: int = 0,
585
+ ) -> None:
586
+ from ksadk.harness.context_manifest import build_manifest
587
+
588
+ previous = run.context_manifest
589
+ manifest = build_manifest(
590
+ plan=plan,
591
+ projected_tokens=projected,
592
+ run_id=run.handle.run_id,
593
+ scope_id=f"agent:{run.state.agent_id}",
594
+ model_profile_ref=run.compiled.spec.model.profile_ref,
595
+ supersedes=previous.manifest_id if previous is not None else None,
596
+ )
597
+ run.context_manifest = manifest
598
+ sections = {
599
+ section.item_id: section.estimated_tokens
600
+ for section in manifest.sections
601
+ if section.included
602
+ }
603
+ payload = {
604
+ "manifest_id": manifest.manifest_id,
605
+ "stable_prompt_hash": manifest.stable_prompt_hash,
606
+ "planned_tokens": manifest.planned_tokens,
607
+ "projected_tokens": manifest.projected_tokens,
608
+ "context_window_tokens": window,
609
+ "sections": sections,
610
+ "supersedes": manifest.supersedes or "",
611
+ }
612
+ if tool_schema_tokens:
613
+ payload["tool_schema_tokens"] = tool_schema_tokens
614
+ run.events.append(self._event(run, EventType.CONTEXT_BUILT, payload))
615
+ if self._prompt_cache_tracker is not None:
616
+ # G13 §16.2 一期:稳定前缀 Hash 覆盖 stable 段(project_docs/
617
+ # skill_catalog/mcp_catalog)——装配顺序保证它们物理前置,本
618
+ # Hash 即缓存边界断言的记账面。
619
+ stable_material = manifest.stable_prompt_hash
620
+ for item in plan.selected:
621
+ if getattr(item, "stable", False):
622
+ content = item.content if isinstance(item.content, str) else str(item.content)
623
+ stable_material += (
624
+ f"|{item.item_id}:{hashlib.sha256(content.encode('utf-8')).hexdigest()}"
625
+ )
626
+ stable_prefix_hash = (
627
+ "sha256:" + hashlib.sha256(stable_material.encode("utf-8")).hexdigest()
628
+ )
629
+ scope = (
630
+ f"{run.state.tenant_id}:{run.state.agent_id}:{run.compiled.spec.model.profile_ref}"
631
+ )
632
+ diagnostic = self._prompt_cache_tracker.observe(
633
+ scope=scope,
634
+ stable_prompt_hash=stable_prefix_hash,
635
+ )
636
+ run.events.append(
637
+ self._event(
638
+ run,
639
+ EventType.PROMPT_CACHE_DIAGNOSTIC,
640
+ {
641
+ **diagnostic.to_payload(),
642
+ "manifest_id": manifest.manifest_id,
643
+ },
644
+ )
645
+ )
646
+ # 边界断言(G13 §16.2):stable 前缀在 Revision 生命周期内变化
647
+ # 即发事件(可见,不阻塞)。cold_start 是首个观察,不算断裂。
648
+ if diagnostic.cache_break and diagnostic.reason not in ("cold_start",):
649
+ run.events.append(
650
+ self._event(
651
+ run,
652
+ EventType.CONTEXT_CACHE_BOUNDARY_BROKEN,
653
+ {
654
+ "scope": scope,
655
+ "stable_prefix_hash": stable_prefix_hash,
656
+ "previous_hash": diagnostic.previous_stable_prompt_hash,
657
+ },
658
+ )
659
+ )
660
+
661
+ # ------------------------------------------------------------ 压缩
662
+
663
+ async def _summarize(
664
+ self,
665
+ run: Any,
666
+ head: list[Message],
667
+ split_turn: bool = False,
668
+ previous_summary: str = "",
669
+ ) -> tuple[str, dict[str, Any]]:
670
+ """受控摘要调用:走统一 reason 通道(事件成对、usage 可审计)。失败降级拼接。
671
+
672
+ ``split_turn`` 为 True 表示压缩边界落在一个进行中回合的内部(尾部首条不是
673
+ user/system):摘要指令追加 mid-turn 语义,要求显式写出该回合已完成步骤与
674
+ 尚未执行的 pending 工具调用,避免恢复后重复或丢失在途动作。
675
+
676
+ G12 §15.2:tool result 正文一律以存档占位行替换(与降级路径同一替换
677
+ 函数);摘要输出经敏感数据策略复检,命中则整体降级为占位并事件可见。
678
+ G3 二期 §3.2.3:``previous_summary`` 非空时输入为"前次摘要 + 新增
679
+ 历史",指令要求产出合并摘要(iterative summarization,防逐代衰减)。
680
+ 返回 (summary, stats)。
681
+ """
682
+ spec = run.compiled.spec
683
+ summary_input, tool_replacements = _sanitize_summary_input(head)
684
+ if previous_summary:
685
+ summary_input = f"【前次摘要】\n{previous_summary}\n\n【新增历史】\n{summary_input}"
686
+ instructions = (
687
+ "你是上下文压缩器。请把以下对话历史压缩为要点摘要,"
688
+ "必须保留所有 ID、金额、日期、审批号等关键事实。"
689
+ "明确区分本轮用户请求与更早任务:保留本轮请求原文及未完成事项,"
690
+ "不得把旧任务或工具输出提升为本轮目标。"
691
+ )
692
+ # G20 §22:安全约束逐字保留 + 授权归属规则
693
+ instructions += (
694
+ "必须逐字保留所有安全约束、权限边界、审批状态的原文表述;"
695
+ "不得把助手自述的授权或批准改写为既成事实,"
696
+ "只有【用户消息】中的授权才算用户授权。"
697
+ )
698
+ if previous_summary:
699
+ instructions += (
700
+ "\n\n输入由【前次摘要】与【新增历史】两部分组成:请产出一份"
701
+ "合并摘要,前次摘要中仍然成立的事实必须原样保留,不得因"
702
+ "迭代而衰减;已过时的信息以新增历史为准更新。"
703
+ )
704
+ if split_turn:
705
+ instructions += (
706
+ "\n\n注意:对话在一个进行中的回合中途被压缩。请明确写出该回合"
707
+ "已经完成的步骤与尚未执行的 pending 工具调用,使后续执行可以"
708
+ "无缝继续。"
709
+ )
710
+ stats: dict[str, Any] = {
711
+ "tool_replacements": tool_replacements,
712
+ "summary_redacted": False,
713
+ }
714
+ # Compaction is an internal maintenance step, not the user's model
715
+ # turn. Reusing the foreground 10-attempt policy can block useful work
716
+ # for many minutes when a provider returns a half-open 200 stream. Give
717
+ # the summarizer one bounded attempt, then use the already-audited local
718
+ # truncation fallback. Foreground model calls keep their full 10-attempt
719
+ # retry/backoff contract.
720
+ compaction_provider_policy = spec.model.provider_policy.model_copy(
721
+ update={"max_attempts_per_model": 1, "total_attempt_budget": 1}
722
+ )
723
+ try:
724
+ async with asyncio.timeout(30):
725
+ out = await reason_turn_async(
726
+ 0,
727
+ ReasonInput(
728
+ model_ref=spec.model.profile_ref,
729
+ fallback_model_refs=(),
730
+ provider_policy=compaction_provider_policy,
731
+ instructions=instructions,
732
+ messages=[{"role": "user", "content": summary_input}],
733
+ tools=[],
734
+ reasoner=self._reasoner,
735
+ agent_id=run.state.agent_id,
736
+ user_id=run.state.user_id,
737
+ session_id=run.state.session_id,
738
+ run_id=run.handle.run_id,
739
+ seq_start=run.seq,
740
+ max_turns=1,
741
+ reasoning_effort=(
742
+ str((getattr(run.request, "config", {}) or {}).get("effort") or "")
743
+ .strip()
744
+ .lower()
745
+ or None
746
+ ),
747
+ ),
748
+ )
749
+ except Exception as exc: # noqa: BLE001 - 摘要失败降级/熔断/413 逃生
750
+ if isinstance(exc, ModelFailoverExhausted):
751
+ for event in exc.events:
752
+ run.events.append(event)
753
+ run.seq = max(run.seq, event.seq_id)
754
+ # G18 ③ 413 逃生:payload_too_large / context_length / HTTP 413
755
+ # → 减半摘要输入再试一次,仍失败则进熔断计数。
756
+ err_str = str(exc)
757
+ is_413 = (
758
+ "413" in err_str or "payload_too_large" in err_str or "context_length" in err_str
759
+ )
760
+ if is_413:
761
+ half = summary_input[: max(1, len(summary_input) // 2)]
762
+ try:
763
+ async with asyncio.timeout(30):
764
+ out = await reason_turn_async(
765
+ 0,
766
+ ReasonInput(
767
+ model_ref=spec.model.profile_ref,
768
+ fallback_model_refs=(),
769
+ provider_policy=compaction_provider_policy,
770
+ instructions=instructions,
771
+ messages=[{"role": "user", "content": half}],
772
+ tools=[],
773
+ reasoner=self._reasoner,
774
+ agent_id=run.state.agent_id,
775
+ user_id=run.state.user_id,
776
+ session_id=run.state.session_id,
777
+ run_id=run.handle.run_id,
778
+ seq_start=run.seq,
779
+ max_turns=1,
780
+ reasoning_effort=(
781
+ str(
782
+ (getattr(run.request, "config", {}) or {}).get("effort")
783
+ or ""
784
+ )
785
+ .strip()
786
+ .lower()
787
+ or None
788
+ ),
789
+ ),
790
+ )
791
+ # 413 逃生成功:走正常成功路径
792
+ for ev in out.events:
793
+ # The summarizer shares the foreground reason loop for
794
+ # provider policy and usage accounting, but its output
795
+ # is internal context state rather than an assistant
796
+ # reply. Mark every emitted event so adapters can keep
797
+ # summary text out of the conversation while retaining
798
+ # an auditable model-call trace.
799
+ ev.payload.setdefault("purpose", "compaction")
800
+ run.events.append(ev)
801
+ run.seq = max(run.seq, ev.seq_id)
802
+ summary = (
803
+ str(out.new_messages[0].get("content") or "") if out.new_messages else ""
804
+ )
805
+ run.events.append(
806
+ self._event(
807
+ run,
808
+ EventType.CONTEXT_RECOVERED,
809
+ {"reason": "compaction_summary_413_fallback"},
810
+ )
811
+ )
812
+ # 413 逃生成功重置失败计数
813
+ _rs = getattr(run.state, "retry_state", None)
814
+ if _rs is not None and hasattr(_rs, "model_copy"):
815
+ run.state.retry_state = _rs.model_copy(
816
+ update={"consecutive_compaction_failures": 0}
817
+ )
818
+ return summary, stats
819
+ except Exception: # noqa: BLE001 - 413 回退仍失败,进降级/熔断
820
+ pass
821
+ # G18 ① 连续失败熔断:连续 3 次 → 抛 ContextEngineError,停止空转
822
+ _rs = getattr(run.state, "retry_state", None)
823
+ if _rs is not None and hasattr(_rs, "model_copy"):
824
+ failures = _rs.consecutive_compaction_failures + 1
825
+ run.state.retry_state = _rs.model_copy(
826
+ update={"consecutive_compaction_failures": failures}
827
+ )
828
+ else:
829
+ failures = 0
830
+ if failures >= 3:
831
+ run.events.append(
832
+ self._event(
833
+ run,
834
+ EventType.CONTEXT_RECOVERED,
835
+ {
836
+ "reason": "compaction_circuit_breaker_open",
837
+ "error": f"3 consecutive summary failures; last: {err_str[:128]}",
838
+ },
839
+ )
840
+ )
841
+ from ksadk.harness.context_engine import ContextEngineError
842
+
843
+ raise ContextEngineError(
844
+ "compaction circuit breaker open (3 consecutive summary failures)"
845
+ )
846
+ text = summary_input
847
+ # 降级不静默(§6.4 "不静默丢弃"):真实模型评测曾把摘要失败
848
+ # 吞成 0-token Run;发 context.recovered 让降级可观测可告警。
849
+ # G12:降级拼接同样只使用脱敏输入(tool result 不回填)。
850
+ reason = (
851
+ "compaction_summary_413_fallback_failed"
852
+ if is_413
853
+ else "compaction_summary_failed:degraded_truncation"
854
+ )
855
+ run.events.append(
856
+ self._event(
857
+ run,
858
+ EventType.CONTEXT_RECOVERED,
859
+ {
860
+ "reason": reason,
861
+ "error": str(exc)[:256],
862
+ },
863
+ )
864
+ )
865
+ return text[:2000] + ("\n…[截断]" if len(text) > 2000 else ""), stats
866
+ for ev in out.events:
867
+ # 压缩摘要是管线内部模型调用,不对应任何 ContextManifest,也不是
868
+ # 面向用户的 assistant message。全部事件显式标记 purpose,既让
869
+ # usage 可归因,也让 adapter 能隔离摘要正文而保留审计生命周期。
870
+ ev.payload.setdefault("purpose", "compaction")
871
+ run.events.append(ev)
872
+ run.seq = max(run.seq, ev.seq_id)
873
+ summary = str(out.new_messages[0].get("content") or "") if out.new_messages else ""
874
+ # G12:摘要输出敏感复检——摘要模型可能是另一供应商,命中即整体
875
+ # 降级为占位(可见降级,不外泄敏感明文)。
876
+ if self._sensitive_policy is not None and summary:
877
+ hit = None
878
+ try:
879
+ hit = self._sensitive_policy.sensitive_match(summary)
880
+ except Exception: # noqa: BLE001 - 策略故障不阻断压缩
881
+ hit = None
882
+ if hit:
883
+ stats["summary_redacted"] = True
884
+ run.events.append(
885
+ self._event(
886
+ run,
887
+ EventType.CONTEXT_RECOVERED,
888
+ {
889
+ "reason": "compaction_summary_sensitive_redacted",
890
+ "policy": "sensitive_patterns",
891
+ },
892
+ )
893
+ )
894
+ summary = _REDACTED_SUMMARY_PLACEHOLDER
895
+ # G18 ① 摘要成功重置连续失败计数
896
+ _rs = getattr(run.state, "retry_state", None)
897
+ if _rs is not None and hasattr(_rs, "model_copy"):
898
+ run.state.retry_state = _rs.model_copy(update={"consecutive_compaction_failures": 0})
899
+ return summary, stats
900
+
901
+ async def _compact_history(
902
+ self,
903
+ run: Any,
904
+ messages: list[Message],
905
+ *,
906
+ trigger: str,
907
+ keep_recent: int,
908
+ budget_tokens: int,
909
+ keep_recent_tokens: int | None = None,
910
+ trigger_reason: str | None = None,
911
+ ) -> list[Message] | None:
912
+ """主动/紧急压缩:摘要 head + 保留 tail + 关键事实重注入,返回新历史。
913
+
914
+ keep 边界统一由 ``find_compaction_boundary`` 计算:条数上限 ``keep_recent``
915
+ 与 token 预算 ``keep_recent_tokens`` 取更严格者(floor 1),并回退到 Tool
916
+ Pair 之前。边界落在一个进行中回合内部时置 ``split_turn``,摘要 prompt 与
917
+ 压缩留痕(CompactionRecord / context.compaction.completed)一并带上该语义。
918
+ """
919
+ from ksadk.harness.context_engine import CompactionRequest
920
+
921
+ if len(messages) <= keep_recent:
922
+ return None
923
+ kept = find_compaction_boundary(
924
+ messages, keep_messages=keep_recent, keep_tokens=keep_recent_tokens
925
+ )
926
+ if kept >= len(messages):
927
+ return None
928
+ head = messages[: len(messages) - kept]
929
+ tail = messages[len(messages) - kept :]
930
+ split_turn = _is_split_turn(head, tail)
931
+ started_payload: dict[str, Any] = {"phase": "before", "trigger": trigger}
932
+ if trigger_reason is not None:
933
+ started_payload["trigger_reason"] = trigger_reason
934
+ run.events.append(
935
+ self._event(
936
+ run,
937
+ EventType.CONTEXT_COMPACTION_STARTED,
938
+ started_payload,
939
+ )
940
+ )
941
+ # 长任务方案 §6.4 主动压缩步骤 2:压缩前受控 Memory Flush——
942
+ # 被压缩历史先经提取管线落长期 Memory(审计事件并入事件流)。
943
+ memory_candidate_refs = self._flush_memory_before_compaction(run, head)
944
+ before_tokens = sum(count_tokens(m.content) for m in messages)
945
+ # G3 二期 §3.2.3 摘要链:run 内多次压缩逐代链接——上一次记录的摘要
946
+ # 作为本次合并输入,previous_compaction_id 形成链。
947
+ previous_record = run.compaction_records[-1] if run.compaction_records else None
948
+ previous_summary = previous_record.summary if previous_record is not None else ""
949
+ summary, summary_stats = await self._summarize(
950
+ run, head, split_turn=split_turn, previous_summary=previous_summary
951
+ )
952
+ # G12 §15.2:critical-facts 抽取器吃"敏感正则脱敏后"的原始消息——
953
+ # 工具结果里的 ID/金额参与抽取(与摘要模型输入分离),命中敏感
954
+ # 正则的内容替换为占位,不进任何模型输入。
955
+ masked_messages, sensitive_hits = self._mask_sensitive_messages(messages)
956
+ checkpoint = self._context_engine.compact(
957
+ CompactionRequest(
958
+ messages=masked_messages,
959
+ # 用实际保留条数(tail 长度)而非原始 keep_recent,使 compact 内部
960
+ # 的 head/tail 切分与这里的边界(可能被 token 预算收窄)严格一致,
961
+ # 关键事实后校验不会对着错误的 head 计算。
962
+ keep_recent=len(tail),
963
+ trigger=trigger,
964
+ summary=summary,
965
+ compacted_count=len(head),
966
+ )
967
+ )
968
+ compacted_text = (checkpoint.summary or "").strip()
969
+ if checkpoint.reinjection:
970
+ compacted_text = (compacted_text + "\n\n" + checkpoint.reinjection).strip()
971
+ new_messages: list[Message] = [
972
+ Message(role=MessageRole.SYSTEM, content=f"【历史摘要】\n{compacted_text}")
973
+ ]
974
+ new_messages.extend(tail)
975
+ after_tokens = sum(count_tokens(m.content) for m in new_messages)
976
+ # 长任务方案 §6.4:CompactionRecord(投影变化记录,非新事实源)。
977
+ # 摘要缺失但经重注入保留的事实不算最终丢弃(§8.4.1 "不静默丢弃")。
978
+ reinjected = tuple(checkpoint.dropped_critical_facts) if checkpoint.reinjection else ()
979
+ record = build_compaction_record(
980
+ run_id=run.handle.run_id,
981
+ trigger=trigger,
982
+ before_tokens=before_tokens,
983
+ after_tokens=after_tokens,
984
+ compacted_event_range=(0, int(checkpoint.compacted_until_seq_id)),
985
+ summary=compacted_text,
986
+ retained_critical_facts=tuple(checkpoint.retained_critical_facts),
987
+ dropped_critical_facts=tuple(checkpoint.dropped_critical_facts),
988
+ reinjected_critical_facts=reinjected,
989
+ summary_model_ref=run.compiled.spec.model.profile_ref,
990
+ memory_candidate_refs=tuple(memory_candidate_refs),
991
+ split_turn=split_turn,
992
+ sanitized_input=bool(summary_stats.get("tool_replacements") or sensitive_hits),
993
+ sanitized_replacements=int(summary_stats.get("tool_replacements") or 0)
994
+ + sensitive_hits,
995
+ previous_compaction_id=previous_record.compaction_id
996
+ if previous_record is not None
997
+ else "",
998
+ )
999
+ # G3 二期质量闸门(§9.2 评审决策:硬编码 + 事件可见,不阻塞):
1000
+ # 每 3 代压缩执行一次关键事实覆盖率比对——当代(retained ∪ reinjected)
1001
+ # 事实数低于上一代即标 quality_degraded。真实降级案例出现后再配置化。
1002
+ generation = len(run.compaction_records) + 1
1003
+ quality_degraded = False
1004
+ if previous_record is not None and generation % 3 == 0:
1005
+ current_facts = len(
1006
+ set(record.retained_critical_facts) | set(record.reinjected_critical_facts)
1007
+ )
1008
+ previous_facts = len(
1009
+ set(previous_record.retained_critical_facts)
1010
+ | set(previous_record.reinjected_critical_facts)
1011
+ )
1012
+ quality_degraded = current_facts < previous_facts
1013
+ run.compaction_records.append(record)
1014
+ run.events.append(
1015
+ self._event(
1016
+ run,
1017
+ EventType.CONTEXT_COMPACTION_COMPLETED,
1018
+ {
1019
+ "phase": "after",
1020
+ "trigger": trigger,
1021
+ "compacted_until_seq_id": checkpoint.compacted_until_seq_id,
1022
+ "budget_tokens": budget_tokens,
1023
+ "dropped_critical_facts": list(checkpoint.dropped_critical_facts),
1024
+ "reinjected_critical_facts": list(reinjected),
1025
+ # 长任务方案 §8:Compaction 投影(引用 + 前后 Token + 质量校验)。
1026
+ "compaction_id": record.compaction_id,
1027
+ "before_tokens": record.before_tokens,
1028
+ "after_tokens": record.after_tokens,
1029
+ "split_turn": split_turn,
1030
+ "sanitized_input": record.sanitized_input,
1031
+ "sanitized_replacements": record.sanitized_replacements,
1032
+ "summary_redacted": bool(summary_stats.get("summary_redacted")),
1033
+ "previous_compaction_id": record.previous_compaction_id,
1034
+ "generation": generation,
1035
+ "quality_degraded": quality_degraded,
1036
+ "quality_checks": record.quality_checks(),
1037
+ "memory_candidate_refs": list(record.memory_candidate_refs),
1038
+ },
1039
+ )
1040
+ )
1041
+ return new_messages
1042
+
1043
+ def _mask_sensitive_messages(self, messages: list[Message]) -> tuple[list[Message], int]:
1044
+ """G12:对 tool 消息内容做敏感正则替换(占位),返回 (掩码副本, 命中数)。
1045
+
1046
+ 仅 tool 消息参与掩码——摘要模型已经吃不到 tool 正文(§15.2 第一
1047
+ 管线),本函数服务 critical-facts 抽取通道;user/assistant 消息的
1048
+ 关键事实是压缩合同要保住的对象,不掩码。
1049
+ """
1050
+ policy = self._sensitive_policy
1051
+ if policy is None or not getattr(policy, "enabled", True):
1052
+ return messages, 0
1053
+ patterns = tuple(getattr(policy, "sensitive_patterns", ()) or ())
1054
+ if not patterns:
1055
+ return messages, 0
1056
+ masked: list[Message] = []
1057
+ hits = 0
1058
+ for message in messages:
1059
+ if message.role is not MessageRole.TOOL:
1060
+ masked.append(message)
1061
+ continue
1062
+ content = message.content
1063
+ replaced = 0
1064
+ for pattern in patterns:
1065
+ content, count = re.subn(pattern, "[已脱敏]", content)
1066
+ replaced += count
1067
+ if replaced:
1068
+ hits += replaced
1069
+ masked.append(message.model_copy(update={"content": content}))
1070
+ else:
1071
+ masked.append(message)
1072
+ return masked, hits
1073
+
1074
+ async def summarize_branch(self, run: Any, messages: list[Message]) -> CompactionRecord:
1075
+ """分支切换摘要(G2 二期 §2.2.2):复用 G3 摘要管线生成 BranchSummary。
1076
+
1077
+ 切分支时目标分支上下文过长 → 宿主调用本方法:输入走与压缩一致的
1078
+ 脱敏规则,产出 CompactionRecord(trigger="branch_switch")并落
1079
+ context.compaction.started/completed 事件。审计与普通压缩同构,
1080
+ 宿主可据 summary 重建目标分支上下文。
1081
+ """
1082
+ run.events.append(
1083
+ self._event(
1084
+ run,
1085
+ EventType.CONTEXT_COMPACTION_STARTED,
1086
+ {"phase": "before", "trigger": "branch_switch"},
1087
+ )
1088
+ )
1089
+ before_tokens = sum(count_tokens(m.content) for m in messages)
1090
+ summary, summary_stats = await self._summarize(run, messages)
1091
+ masked_messages, sensitive_hits = self._mask_sensitive_messages(messages)
1092
+ # 分支摘要不做 head/tail 切分:整个目标分支作为被摘要对象;关键
1093
+ # 事实经 compact 后校验,缺失的经重注入并入 BranchSummary("不静默
1094
+ # 丢弃"——record.critical_facts_preserved 语义与普通压缩一致)。
1095
+ from ksadk.harness.context_engine import CompactionRequest
1096
+
1097
+ checkpoint = self._context_engine.compact(
1098
+ CompactionRequest(
1099
+ messages=masked_messages,
1100
+ keep_recent=0,
1101
+ trigger="branch_switch",
1102
+ summary=summary,
1103
+ compacted_count=len(messages),
1104
+ )
1105
+ )
1106
+ if checkpoint.reinjection:
1107
+ summary = (summary + "\n\n" + checkpoint.reinjection).strip()
1108
+ record = build_compaction_record(
1109
+ run_id=run.handle.run_id,
1110
+ trigger="branch_switch",
1111
+ before_tokens=before_tokens,
1112
+ after_tokens=sum(count_tokens(m.content) for m in masked_messages),
1113
+ compacted_event_range=(0, len(messages)),
1114
+ summary=summary,
1115
+ retained_critical_facts=tuple(checkpoint.retained_critical_facts),
1116
+ dropped_critical_facts=tuple(checkpoint.dropped_critical_facts),
1117
+ reinjected_critical_facts=tuple(checkpoint.dropped_critical_facts),
1118
+ summary_model_ref=run.compiled.spec.model.profile_ref,
1119
+ split_turn=False,
1120
+ sanitized_input=bool(summary_stats.get("tool_replacements") or sensitive_hits),
1121
+ sanitized_replacements=int(summary_stats.get("tool_replacements") or 0)
1122
+ + sensitive_hits,
1123
+ )
1124
+ run.compaction_records.append(record)
1125
+ run.events.append(
1126
+ self._event(
1127
+ run,
1128
+ EventType.CONTEXT_COMPACTION_COMPLETED,
1129
+ {
1130
+ "phase": "after",
1131
+ "trigger": "branch_switch",
1132
+ "compacted_until_seq_id": len(messages),
1133
+ "compaction_id": record.compaction_id,
1134
+ "before_tokens": record.before_tokens,
1135
+ "after_tokens": record.after_tokens,
1136
+ "split_turn": False,
1137
+ "sanitized_input": record.sanitized_input,
1138
+ "sanitized_replacements": record.sanitized_replacements,
1139
+ "quality_checks": record.quality_checks(),
1140
+ },
1141
+ )
1142
+ )
1143
+ return record
1144
+
1145
+ def _flush_memory_before_compaction(self, run: Any, head: list[Message]) -> list[str]:
1146
+ """压缩前受控 Memory Flush(§6.4 步骤 2)。
1147
+
1148
+ 未注入 MemoryRuntime 或 policy 未启用时为 no-op;审计事件并入
1149
+ Run 事件流(memory.write / memory.conflict)。返回已提交候选引用。
1150
+ """
1151
+ if self._memory_runtime is None or not run.compiled.spec.memory_policy.enabled:
1152
+ return []
1153
+ from ksadk.harness.memory_loop import write_back_messages
1154
+
1155
+ committed: list[str] = []
1156
+
1157
+ def _sink(event: RuntimeEvent) -> None:
1158
+ if event.payload.get("decision") == "commit":
1159
+ committed.append(str(event.payload.get("memory_ref") or ""))
1160
+ run.events.append(self._event(run, event.event_type, dict(event.payload)))
1161
+
1162
+ try:
1163
+ write_back_messages(
1164
+ self._memory_runtime,
1165
+ run.compiled.spec,
1166
+ run_id=run.handle.run_id,
1167
+ agent_id=run.state.agent_id,
1168
+ user_id=run.state.user_id,
1169
+ messages=head,
1170
+ audit_sink=_sink,
1171
+ )
1172
+ except Exception: # noqa: BLE001 - Flush 是后置增强,失败不阻断压缩
1173
+ run.events.append(
1174
+ self._event(
1175
+ run,
1176
+ EventType.MEMORY_WRITE,
1177
+ {"scope": "agent", "memory_ref": "", "decision": "flush_failed"},
1178
+ )
1179
+ )
1180
+ return [ref for ref in committed if ref]
1181
+
1182
+
1183
+ def find_compaction_boundary(
1184
+ messages: list[Message], *, keep_messages: int, keep_tokens: int | None = None
1185
+ ) -> int:
1186
+ """三路压缩(proactive/emergency/overflow)共用的 keep 边界(G3 一期)。
1187
+
1188
+ 从尾部反向累计 count_tokens,达到 keep_tokens 停止;keep_messages 是条数
1189
+ 上限,两者取更严格者(floor 1:至少保留最后一条消息)。之后把边界回退到
1190
+ tool-pair 之前——首条保留消息是 tool 时其 assistant 调用会落在被摘要段,
1191
+ pair 完整性优先于 token 预算。返回保留尾部条数;返回 len(messages) 表示
1192
+ 无可压缩空间。
1193
+
1194
+ 注意:pair 回退也会把 keep 推到 total,因此返回值 ``== len(messages)`` 不
1195
+ 唯一对应"输入本就没有可压缩空间"这一早退分支——当边界之前的消息全部是
1196
+ tool(tool 结果链一路延伸到历史开头,每条 tool 都把边界再前移一格)时,
1197
+ 即便条数/token 预算本可压缩,也会返回 total。消费方请以返回值本身判断
1198
+ 是否有可压缩空间,勿以它反推与 keep_messages/keep_tokens 的条数关系。
1199
+ """
1200
+ if keep_messages < 1:
1201
+ raise ValueError("keep_messages 必须 >= 1")
1202
+ total = len(messages)
1203
+ if total <= keep_messages:
1204
+ return total
1205
+ keep = keep_messages
1206
+ if keep_tokens is not None:
1207
+ acc = 0
1208
+ token_fit = 0
1209
+ for message in reversed(messages):
1210
+ cost = count_tokens(message.content)
1211
+ if acc + cost > keep_tokens and token_fit > 0:
1212
+ break
1213
+ acc += cost
1214
+ token_fit += 1
1215
+ keep = min(keep_messages, max(1, token_fit))
1216
+ # tool-pair 回退:首条保留消息是 tool → 边界前移把 assistant 调用纳入尾部。
1217
+ # 边界紧跟 tool result 是安全的:head 以完整 pair 结尾,pair 未被劈开。
1218
+ while keep < total and messages[total - keep].role is MessageRole.TOOL:
1219
+ keep += 1
1220
+ return keep
1221
+
1222
+
1223
+ _ANALYSIS_RE = re.compile(r"<analysis>.*?</analysis>", re.DOTALL | re.IGNORECASE)
1224
+
1225
+
1226
+ def _sanitize_summary_input(head: list[Message]) -> tuple[str, int]:
1227
+ """G12 §15.2 + G20 §22:摘要输入构造。
1228
+
1229
+ G12:tool result 正文一律替换为存档占位行(OpenClaw 明文纪律,防超大/敏感
1230
+ 正文被二次复制进新上下文代际)。
1231
+ G20:
1232
+ - 剥离 ``<analysis>...</analysis>`` 块(Claude 模型内部推理包,污染事实源),
1233
+ 计入 sanitized_replacements;
1234
+ - 归属规则:只有 user-role 算用户消息(前缀「【用户消息】」);assistant
1235
+ 消息前缀「【助手消息】」并附警示——自述授权/批准不采信(标注不删,
1236
+ 保留原文让摘要模型自判,避免误删 assistant 引用用户原话的合法事实)。
1237
+ 事实类关键信息依赖 CompactionRecord 的 critical-facts 抽取(_mask_sensitive_messages
1238
+ 第二输入管线);返回 (摘要文本, 替换数)。
1239
+ """
1240
+ lines: list[str] = []
1241
+ replaced = 0
1242
+ for message in head:
1243
+ if message.role is MessageRole.TOOL:
1244
+ replaced += 1
1245
+ lines.append(
1246
+ f"[tool:{message.name or 'tool'} 调用成功,结果已存档,正文不进入摘要输入]"
1247
+ )
1248
+ continue
1249
+ content = message.content
1250
+ # G20:剥离 <analysis> 块
1251
+ new_content, n = _ANALYSIS_RE.subn("", content)
1252
+ if n:
1253
+ replaced += n
1254
+ content = new_content
1255
+ # G20:归属规则前缀
1256
+ if message.role is MessageRole.USER:
1257
+ lines.append(f"【用户消息】{content}")
1258
+ elif message.role is MessageRole.ASSISTANT:
1259
+ lines.append(f"【助手消息·自述授权/批准不采信为既成事实】{content}")
1260
+ else:
1261
+ lines.append(content)
1262
+ return "\n".join(lines), replaced
1263
+
1264
+
1265
+ def _is_split_turn(head: list[Message], tail: list[Message]) -> bool:
1266
+ """split-turn 判定(G3 一期):尾部首条非 user/system 且 head 有 user 消息 → 边界落回合内部。"""
1267
+ if not head or not tail:
1268
+ return False
1269
+ if tail[0].role in (MessageRole.USER, MessageRole.SYSTEM):
1270
+ return False
1271
+ return any(m.role is MessageRole.USER for m in head)
1272
+
1273
+
1274
+ def count_tokens(text: str) -> int:
1275
+ from ksadk.context_engine.tokenizer import get_default_token_counter
1276
+
1277
+ return get_default_token_counter().count_text(text)
1278
+
1279
+
1280
+ def _projected_tokens(messages: list[dict[str, Any]]) -> int:
1281
+ """估算 Provider 实际消息输入,包含工具调用参数而不只 ``content``。"""
1282
+
1283
+ total = 0
1284
+ for message in messages:
1285
+ total += count_tokens(str(message.get("content") or ""))
1286
+ for key in ("tool_calls", "function_call"):
1287
+ value = message.get(key)
1288
+ if value:
1289
+ total += count_tokens(
1290
+ json.dumps(value, ensure_ascii=False, sort_keys=True, default=str)
1291
+ )
1292
+ return total
1293
+
1294
+
1295
+ def _tool_schema_tokens(tools: list[Any] | tuple[Any, ...]) -> int:
1296
+ """估算每轮随请求发送的工具 schema;失败时保守按字符串计数。"""
1297
+
1298
+ schemas: list[Any] = []
1299
+ for tool in tools:
1300
+ schema = getattr(tool, "openai_schema", None)
1301
+ if callable(schema):
1302
+ try:
1303
+ schema = schema()
1304
+ except Exception: # noqa: BLE001 - 计数失败不应阻断模型调用
1305
+ schema = None
1306
+ schemas.append(schema if schema is not None else str(tool))
1307
+ if not schemas:
1308
+ return 0
1309
+ return count_tokens(json.dumps(schemas, ensure_ascii=False, sort_keys=True, default=str))
1310
+
1311
+
1312
+ def _run_context_of(run: Any) -> RunContext:
1313
+ """把引擎 Run 投影为钩子可见的稳定身份(不含 message 正文)。"""
1314
+ return RunContext(
1315
+ run_id=str(run.handle.run_id),
1316
+ agent_id=str(run.state.agent_id),
1317
+ user_id=str(run.state.user_id or ""),
1318
+ session_id=str(run.state.session_id or ""),
1319
+ )
1320
+
1321
+
1322
+ def _chat_message(message: dict[str, Any]) -> Message:
1323
+ """把 OpenAI 消息投影为压缩/规划使用的稳定 Message 形态。"""
1324
+ role_value = str(message.get("role") or "user")
1325
+ try:
1326
+ role = MessageRole(role_value)
1327
+ except ValueError:
1328
+ role = MessageRole.USER
1329
+ tool_call_id = str(message.get("tool_call_id") or "") or None
1330
+ if role is MessageRole.ASSISTANT and not tool_call_id:
1331
+ calls = message.get("tool_calls")
1332
+ if isinstance(calls, list) and calls and isinstance(calls[0], dict):
1333
+ tool_call_id = str(calls[0].get("id") or "") or None
1334
+ return Message(
1335
+ role=role,
1336
+ content=str(message.get("content") or ""),
1337
+ tool_call_id=tool_call_id,
1338
+ name=str(message.get("name") or "") or None,
1339
+ )
1340
+
1341
+
1342
+ def _keyword_score(query: str, content: str) -> float:
1343
+ """廉价关键词命中率(0~1):供 memory.recalled 的 items.score 观测。"""
1344
+ terms = [t for t in query.split() if len(t) >= 2]
1345
+ if not terms:
1346
+ return 0.0
1347
+ hits = sum(1 for t in terms if t in content)
1348
+ return round(hits / len(terms), 4)
1349
+
1350
+
1351
+ __all__ = ["EngineContextPipeline", "count_tokens", "find_compaction_boundary"]