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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (851) hide show
  1. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/METADATA +12 -8
  2. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/RECORD +823 -388
  3. ksadk/_async_iterators.py +79 -0
  4. ksadk/_build_provenance.json +1 -1
  5. ksadk/_model_anthropic.py +49 -0
  6. ksadk/_model_input.py +86 -0
  7. ksadk/_model_json.py +40 -0
  8. ksadk/_model_reasoning.py +17 -0
  9. ksadk/_model_refusal.py +20 -0
  10. ksadk/_model_sse.py +163 -0
  11. ksadk/a2a/__init__.py +157 -167
  12. ksadk/a2a/_invocation_state.py +86 -0
  13. ksadk/a2a/_space_client_events.py +33 -22
  14. ksadk/a2a/adk.py +194 -0
  15. ksadk/a2a/adk_invocation_context.py +242 -0
  16. ksadk/a2a/adk_runtime.py +126 -0
  17. ksadk/a2a/adk_tools.py +319 -0
  18. ksadk/a2a/bootstrap.py +149 -23
  19. ksadk/a2a/build_validation.py +147 -0
  20. ksadk/a2a/card.py +23 -15
  21. ksadk/a2a/codex.py +160 -0
  22. ksadk/a2a/codex_checkpoint.py +111 -0
  23. ksadk/a2a/codex_recovery.py +96 -0
  24. ksadk/a2a/codex_recovery_events.py +123 -0
  25. ksadk/a2a/codex_runtime.py +198 -0
  26. ksadk/a2a/codex_session_checkpoint.py +162 -0
  27. ksadk/a2a/composition.py +88 -0
  28. ksadk/a2a/context_store.py +118 -19
  29. ksadk/a2a/control_plane.py +108 -106
  30. ksadk/a2a/event_adapter.py +92 -193
  31. ksadk/a2a/executor.py +257 -85
  32. ksadk/a2a/exposure.py +106 -0
  33. ksadk/a2a/external_transport.py +3 -4
  34. ksadk/a2a/identity.py +106 -12
  35. ksadk/a2a/ids.py +14 -3
  36. ksadk/a2a/inbound_kernel.py +133 -0
  37. ksadk/a2a/interaction_wire.py +76 -0
  38. ksadk/a2a/invocation_checkpoint.py +274 -0
  39. ksadk/a2a/invocation_policy.py +87 -0
  40. ksadk/a2a/invocation_publication.py +210 -0
  41. ksadk/a2a/invocation_service.py +972 -0
  42. ksadk/a2a/invocation_types.py +459 -0
  43. ksadk/a2a/kernel_task_adapter.py +259 -0
  44. ksadk/a2a/langgraph.py +20 -7
  45. ksadk/a2a/langgraph_invocation_context.py +136 -0
  46. ksadk/a2a/langgraph_managed.py +150 -0
  47. ksadk/a2a/langgraph_recovery.py +32 -0
  48. ksadk/a2a/langgraph_runtime.py +89 -0
  49. ksadk/a2a/langgraph_tool_runtime.py +132 -0
  50. ksadk/a2a/langgraph_tools.py +63 -0
  51. ksadk/a2a/message_digest.py +40 -0
  52. ksadk/a2a/platform.py +389 -0
  53. ksadk/a2a/policy_refs.py +13 -0
  54. ksadk/a2a/presentation.py +402 -0
  55. ksadk/a2a/product_kernel_facts.py +177 -0
  56. ksadk/a2a/product_key.py +99 -0
  57. ksadk/a2a/protocol_errors.py +116 -0
  58. ksadk/a2a/result_text.py +49 -0
  59. ksadk/a2a/resume_store.py +93 -3
  60. ksadk/a2a/routes.py +6 -1
  61. ksadk/a2a/runtime_approval.py +198 -0
  62. ksadk/a2a/runtime_input.py +151 -0
  63. ksadk/a2a/server.py +16 -7
  64. ksadk/a2a/space_client.py +101 -16
  65. ksadk/a2a/task_adapter.py +19 -5
  66. ksadk/a2a/task_event_dispatcher.py +39 -2
  67. ksadk/a2a/task_event_outbox.py +215 -0
  68. ksadk/a2a/task_event_outbox_owned.py +130 -0
  69. ksadk/a2a/task_store.py +37 -0
  70. ksadk/a2a/tool_activity.py +176 -0
  71. ksadk/a2a/workload_tokens.py +134 -0
  72. ksadk/api/client.py +32 -79
  73. ksadk/api/sse_stream.py +96 -0
  74. ksadk/builders/code_builder.py +83 -106
  75. ksadk/builders/container_builder.py +11 -29
  76. ksadk/builders/framework_requirements.py +2 -0
  77. ksadk/builders/managed_runtime_builder.py +12 -0
  78. ksadk/builders/source_provenance.py +87 -0
  79. ksadk/cli/cmd_a2a.py +43 -0
  80. ksadk/cli/cmd_build.py +9 -0
  81. ksadk/cli/cmd_deploy.py +27 -2
  82. ksadk/cli/cmd_invoke.py +45 -92
  83. ksadk/cli/cmd_studio.py +5 -1
  84. ksadk/cli/cmd_web.py +2 -0
  85. ksadk/cli/hosted_invoke.py +206 -0
  86. ksadk/cli/invoke_content.py +60 -0
  87. ksadk/cli/runtime_bootstrap.py +27 -5
  88. ksadk/codex/_expert_request_reader.py +48 -0
  89. ksadk/codex/a2a_tools.py +140 -0
  90. ksadk/codex/async_approval.py +169 -0
  91. ksadk/codex/async_client.py +938 -0
  92. ksadk/codex/async_proxy.py +216 -0
  93. ksadk/codex/base_runtime.py +25 -0
  94. ksadk/codex/client.py +3 -1048
  95. ksadk/codex/client_payloads.py +85 -0
  96. ksadk/codex/rollout_checkpoint.py +264 -0
  97. ksadk/codex/runtime.py +290 -54
  98. ksadk/common/auth.py +2 -2
  99. ksadk/common/cloud_headers.py +36 -0
  100. ksadk/common/diagnostics.py +34 -0
  101. ksadk/common/kop_client.py +2 -1
  102. ksadk/configs/env_registry.py +106 -127
  103. ksadk/configs/env_registry_a2a.py +173 -0
  104. ksadk/configs/env_registry_studio.py +53 -5
  105. ksadk/configs/global_config.py +1 -0
  106. ksadk/configs/settings.py +6 -0
  107. ksadk/context_engine/assembler.py +9 -0
  108. ksadk/context_engine/contributors.py +80 -17
  109. ksadk/context_engine/instruction_authority.py +18 -0
  110. ksadk/conversations/attachments.py +53 -15
  111. ksadk/conversations/contracts.py +28 -9
  112. ksadk/conversations/message_projection.py +30 -125
  113. ksadk/conversations/message_projection_blocks.py +137 -0
  114. ksadk/conversations/model_context.py +11 -3
  115. ksadk/conversations/projector.py +63 -0
  116. ksadk/conversations/runtime_compaction.py +7 -2
  117. ksadk/conversations/runtime_input.py +16 -4
  118. ksadk/conversations/runtime_payloads.py +4 -0
  119. ksadk/conversations/runtime_persistence.py +192 -24
  120. ksadk/conversations/runtime_preparation.py +85 -6
  121. ksadk/conversations/runtime_projection.py +217 -0
  122. ksadk/conversations/runtime_resume.py +141 -70
  123. ksadk/conversations/tool_receipt_resume.py +387 -0
  124. ksadk/conversations/tool_receipts.py +32 -0
  125. ksadk/deployment/env_forward.py +5 -0
  126. ksadk/deployment/manager.py +15 -6
  127. ksadk/deployment/providers/serverless.py +76 -136
  128. ksadk/deployment/providers/serverless_payloads.py +122 -0
  129. ksadk/evaluation/agent_eval_client.py +2 -1
  130. ksadk/evaluation/contracts.py +78 -3
  131. ksadk/evaluation/evaluators.py +166 -1
  132. ksadk/evaluation/evidence.py +271 -4
  133. ksadk/evaluation/local_adapter.py +76 -12
  134. ksadk/evaluation/studio_build_adapter.py +73 -9
  135. ksadk/events/adapters/_a2a_checkpoint.py +151 -0
  136. ksadk/events/adapters/_a2a_snapshot.py +18 -14
  137. ksadk/events/adapters/_a2a_support.py +15 -3
  138. ksadk/events/adapters/_a2a_tool_activity.py +123 -0
  139. ksadk/events/adapters/_codex_errors.py +49 -0
  140. ksadk/events/adapters/_langgraph_support.py +12 -1
  141. ksadk/events/adapters/a2a.py +54 -26
  142. ksadk/events/adapters/adk.py +188 -30
  143. ksadk/events/adapters/codex.py +33 -7
  144. ksadk/events/adapters/langgraph.py +16 -6
  145. ksadk/events/canonical.py +5 -0
  146. ksadk/events/canonical_store.py +200 -4
  147. ksadk/events/reducer.py +82 -0
  148. ksadk/events/run_authority.py +176 -0
  149. ksadk/harness/__init__.py +4 -0
  150. ksadk/harness/artifact_adapters/__init__.py +1 -0
  151. ksadk/harness/artifact_adapters/native_page_budget.py +172 -0
  152. ksadk/harness/artifact_adapters/native_search.py +249 -0
  153. ksadk/harness/artifact_adapters/native_search_budget.py +134 -0
  154. ksadk/harness/artifact_adapters/native_store.py +115 -0
  155. ksadk/harness/artifact_adapters/native_tool.py +222 -0
  156. ksadk/harness/artifact_store.py +26 -9
  157. ksadk/harness/browser_adapters/__init__.py +6 -0
  158. ksadk/harness/browser_adapters/native_browser_tool.py +92 -0
  159. ksadk/harness/browser_adapters/native_dom_snapshot.py +187 -0
  160. ksadk/harness/browser_adapters/native_playwright.py +953 -0
  161. ksadk/harness/browser_adapters/native_vision.py +295 -0
  162. ksadk/harness/capability_adapters/__init__.py +1 -0
  163. ksadk/harness/capability_adapters/native_dsh.py +289 -0
  164. ksadk/harness/capability_runtime.py +104 -9
  165. ksadk/harness/compaction_record.py +31 -0
  166. ksadk/harness/compiler.py +3 -3
  167. ksadk/harness/config.py +28 -5
  168. ksadk/harness/conformance/contract.py +9 -11
  169. ksadk/harness/context_engine.py +18 -33
  170. ksadk/harness/context_sections.py +397 -0
  171. ksadk/harness/diagnostic_adapters/__init__.py +1 -0
  172. ksadk/harness/diagnostic_adapters/contracts.py +70 -0
  173. ksadk/harness/diagnostic_adapters/lsp_rpc.py +210 -0
  174. ksadk/harness/diagnostic_adapters/native_lsp.py +286 -0
  175. ksadk/harness/engine/completion_guard.py +16 -1
  176. ksadk/harness/engine/context_pipeline.py +864 -92
  177. ksadk/harness/engine/graph_builder.py +123 -630
  178. ksadk/harness/engine/hooked_reasoner.py +380 -0
  179. ksadk/harness/engine/langgraph.py +126 -8
  180. ksadk/harness/engine/mcp_disclosure.py +65 -114
  181. ksadk/harness/engine/phases/__init__.py +6 -0
  182. ksadk/harness/engine/phases/context.py +48 -0
  183. ksadk/harness/engine/phases/interaction.py +31 -0
  184. ksadk/harness/engine/phases/reason.py +552 -0
  185. ksadk/harness/engine/phases/tools.py +638 -0
  186. ksadk/harness/engine/policy_runtime.py +21 -10
  187. ksadk/harness/engine/postgres_checkpointer.py +325 -2
  188. ksadk/harness/engine/run_control_bridge.py +21 -1
  189. ksadk/harness/engine/run_types.py +10 -0
  190. ksadk/harness/engine/skill_disclosure.py +98 -12
  191. ksadk/harness/engine/steering.py +177 -0
  192. ksadk/harness/engine/subagents.py +18 -1
  193. ksadk/harness/engine/tool_dispatch.py +112 -7
  194. ksadk/harness/events.py +39 -2
  195. ksadk/harness/execution_policy.py +10 -0
  196. ksadk/harness/hooks.py +259 -0
  197. ksadk/harness/loop/reason.py +281 -36
  198. ksadk/harness/loop/tools.py +157 -12
  199. ksadk/harness/managed_runtime.py +254 -94
  200. ksadk/harness/mcp_disclosure_contract.py +85 -0
  201. ksadk/harness/mcp_result_policy.py +44 -0
  202. ksadk/harness/mcp_runtime.py +33 -0
  203. ksadk/harness/micro_compact.py +69 -0
  204. ksadk/harness/model_adapters/__init__.py +1 -0
  205. ksadk/harness/model_adapters/native_mcp_media.py +100 -0
  206. ksadk/harness/model_adapters/native_mcp_result.py +36 -0
  207. ksadk/harness/model_adapters/native_openai.py +703 -0
  208. ksadk/harness/model_capability.py +223 -8
  209. ksadk/harness/model_provider.py +214 -4
  210. ksadk/harness/multimodal.py +57 -0
  211. ksadk/harness/native/__init__.py +1 -0
  212. ksadk/harness/native/activation_contract.py +25 -0
  213. ksadk/harness/native/activation_recovery.py +29 -0
  214. ksadk/harness/native/adapters.py +291 -0
  215. ksadk/harness/native/artifact_contract.py +14 -0
  216. ksadk/harness/native/artifact_partial_read_capacity.py +171 -0
  217. ksadk/harness/native/artifact_read_capacity.py +182 -0
  218. ksadk/harness/native/artifact_read_contract.py +27 -0
  219. ksadk/harness/native/artifact_runtime.py +408 -0
  220. ksadk/harness/native/artifact_search_capacity.py +206 -0
  221. ksadk/harness/native/artifact_search_contract.py +40 -0
  222. ksadk/harness/native/artifact_single_read_capacity.py +170 -0
  223. ksadk/harness/native/browser_contract.py +229 -0
  224. ksadk/harness/native/browser_recovery.py +183 -0
  225. ksadk/harness/native/capabilities.py +204 -0
  226. ksadk/harness/native/child_approval.py +60 -0
  227. ksadk/harness/native/child_budget.py +136 -0
  228. ksadk/harness/native/child_cancellation.py +80 -0
  229. ksadk/harness/native/child_input.py +98 -0
  230. ksadk/harness/native/child_input_runtime.py +59 -0
  231. ksadk/harness/native/child_interruption.py +81 -0
  232. ksadk/harness/native/child_lifecycle.py +246 -0
  233. ksadk/harness/native/child_lifecycle_contract.py +91 -0
  234. ksadk/harness/native/child_notifications.py +75 -0
  235. ksadk/harness/native/child_promotion.py +66 -0
  236. ksadk/harness/native/command_runtime.py +99 -0
  237. ksadk/harness/native/completion.py +302 -0
  238. ksadk/harness/native/completion_text.py +116 -0
  239. ksadk/harness/native/context.py +358 -0
  240. ksadk/harness/native/context_artifact_page.py +75 -0
  241. ksadk/harness/native/context_compaction_projection.py +131 -0
  242. ksadk/harness/native/context_contributions.py +320 -0
  243. ksadk/harness/native/context_contributor_contract.py +133 -0
  244. ksadk/harness/native/context_driver.py +820 -0
  245. ksadk/harness/native/context_fresh_tools.py +49 -0
  246. ksadk/harness/native/context_history.py +272 -0
  247. ksadk/harness/native/context_microcompact.py +61 -0
  248. ksadk/harness/native/context_partial_summary.py +58 -0
  249. ksadk/harness/native/context_partition.py +492 -0
  250. ksadk/harness/native/context_pruning.py +275 -0
  251. ksadk/harness/native/context_reduction.py +60 -0
  252. ksadk/harness/native/context_replay.py +148 -0
  253. ksadk/harness/native/context_request_projection.py +526 -0
  254. ksadk/harness/native/context_runtime.py +976 -0
  255. ksadk/harness/native/context_runtime_contracts.py +409 -0
  256. ksadk/harness/native/context_search.py +112 -0
  257. ksadk/harness/native/context_source_fragments.py +188 -0
  258. ksadk/harness/native/context_source_progress.py +119 -0
  259. ksadk/harness/native/context_summary_planning.py +788 -0
  260. ksadk/harness/native/context_summary_recovery.py +105 -0
  261. ksadk/harness/native/delivery_review.py +331 -0
  262. ksadk/harness/native/delivery_review_contract.py +54 -0
  263. ksadk/harness/native/effect_admission.py +82 -0
  264. ksadk/harness/native/effect_control.py +318 -0
  265. ksadk/harness/native/effect_receipts.py +729 -0
  266. ksadk/harness/native/effect_runtime.py +303 -0
  267. ksadk/harness/native/effective_configuration.py +28 -0
  268. ksadk/harness/native/engine.py +945 -0
  269. ksadk/harness/native/final_output.py +34 -0
  270. ksadk/harness/native/final_submission.py +58 -0
  271. ksadk/harness/native/finalization_workspace.py +96 -0
  272. ksadk/harness/native/fork.py +151 -0
  273. ksadk/harness/native/guidance.py +91 -0
  274. ksadk/harness/native/history.py +381 -0
  275. ksadk/harness/native/hook_executor.py +205 -0
  276. ksadk/harness/native/hook_runtime_contract.py +282 -0
  277. ksadk/harness/native/interaction_observation.py +117 -0
  278. ksadk/harness/native/lease.py +103 -0
  279. ksadk/harness/native/machine.py +974 -0
  280. ksadk/harness/native/mcp_result_governance.py +156 -0
  281. ksadk/harness/native/model.py +570 -0
  282. ksadk/harness/native/model_feedback.py +63 -0
  283. ksadk/harness/native/model_input.py +30 -0
  284. ksadk/harness/native/model_recovery_contract.py +35 -0
  285. ksadk/harness/native/model_replay.py +128 -0
  286. ksadk/harness/native/model_request.py +133 -0
  287. ksadk/harness/native/model_runtime.py +196 -0
  288. ksadk/harness/native/model_takeover.py +419 -0
  289. ksadk/harness/native/model_tool_batch.py +40 -0
  290. ksadk/harness/native/observed_progress.py +46 -0
  291. ksadk/harness/native/operator_guidance.py +201 -0
  292. ksadk/harness/native/output_contract.py +80 -0
  293. ksadk/harness/native/output_recovery.py +24 -0
  294. ksadk/harness/native/ports.py +749 -0
  295. ksadk/harness/native/precompact_hook_runtime.py +171 -0
  296. ksadk/harness/native/replay_context.py +149 -0
  297. ksadk/harness/native/request_media.py +112 -0
  298. ksadk/harness/native/restore_contract.py +16 -0
  299. ksadk/harness/native/run_clock.py +120 -0
  300. ksadk/harness/native/state.py +436 -0
  301. ksadk/harness/native/steering.py +170 -0
  302. ksadk/harness/native/stop_hook_runtime.py +151 -0
  303. ksadk/harness/native/studio_admission.py +29 -0
  304. ksadk/harness/native/subagents.py +86 -0
  305. ksadk/harness/native/task_policy.py +99 -0
  306. ksadk/harness/native/task_progress.py +86 -0
  307. ksadk/harness/native/terminal_verification.py +43 -0
  308. ksadk/harness/native/tool_argument_feedback.py +178 -0
  309. ksadk/harness/native/tool_budget.py +253 -0
  310. ksadk/harness/native/tool_error_streak.py +89 -0
  311. ksadk/harness/native/tool_hook_runtime.py +343 -0
  312. ksadk/harness/native/tool_input_validation.py +58 -0
  313. ksadk/harness/native/tool_interruption.py +96 -0
  314. ksadk/harness/native/tool_observation.py +259 -0
  315. ksadk/harness/native/tool_progress.py +223 -0
  316. ksadk/harness/native/tool_recovery.py +25 -0
  317. ksadk/harness/native/tool_scheduling.py +33 -0
  318. ksadk/harness/native/tool_schema.py +126 -0
  319. ksadk/harness/native/transitions.py +151 -0
  320. ksadk/harness/native/turn_control.py +98 -0
  321. ksadk/harness/native/user_document.py +98 -0
  322. ksadk/harness/native/user_document_capture.py +49 -0
  323. ksadk/harness/native/user_input.py +87 -0
  324. ksadk/harness/native/verification.py +432 -0
  325. ksadk/harness/native/verification_binding.py +40 -0
  326. ksadk/harness/native/verification_runtime.py +233 -0
  327. ksadk/harness/native/verification_workspace.py +67 -0
  328. ksadk/harness/native_driver_failure.py +123 -0
  329. ksadk/harness/native_facade.py +977 -0
  330. ksadk/harness/native_factory.py +244 -0
  331. ksadk/harness/native_projection.py +503 -0
  332. ksadk/harness/native_runtime.py +621 -0
  333. ksadk/harness/native_shadow.py +250 -0
  334. ksadk/harness/native_shadow_inputs.py +146 -0
  335. ksadk/harness/progress_adapters/__init__.py +5 -0
  336. ksadk/harness/progress_adapters/native_todo.py +75 -0
  337. ksadk/harness/prompt_cache.py +65 -3
  338. ksadk/harness/public_activity.py +59 -0
  339. ksadk/harness/public_output.py +30 -0
  340. ksadk/harness/public_summary.py +36 -0
  341. ksadk/harness/reasoner.py +331 -22
  342. ksadk/harness/rpc.py +200 -0
  343. ksadk/harness/run_control.py +107 -2
  344. ksadk/harness/runtime.py +11 -2
  345. ksadk/harness/runtime_capabilities.py +71 -1
  346. ksadk/harness/sandbox_backend.py +203 -0
  347. ksadk/harness/sdk.py +153 -0
  348. ksadk/harness/session_store.py +370 -24
  349. ksadk/harness/skill_adapters/__init__.py +1 -0
  350. ksadk/harness/skill_adapters/native_bundle.py +148 -0
  351. ksadk/harness/skill_adapters/native_disclosure.py +306 -0
  352. ksadk/harness/skill_intent.py +47 -0
  353. ksadk/harness/skill_runtime.py +74 -16
  354. ksadk/harness/spec.py +20 -10
  355. ksadk/harness/state.py +2 -0
  356. ksadk/harness/stores/__init__.py +14 -0
  357. ksadk/harness/stores/native_command_settlement.py +65 -0
  358. ksadk/harness/stores/native_contract.py +311 -0
  359. ksadk/harness/stores/native_memory.py +326 -0
  360. ksadk/harness/stores/native_memory_archive.py +70 -0
  361. ksadk/harness/stores/native_migration_cli.py +91 -0
  362. ksadk/harness/stores/native_outbox.py +56 -0
  363. ksadk/harness/stores/native_sqlite.py +782 -0
  364. ksadk/harness/stores/native_sqlite_audit.py +29 -0
  365. ksadk/harness/stores/native_sqlite_migration.py +252 -0
  366. ksadk/harness/subagent.py +12 -2
  367. ksadk/harness/subagent_adapters/checkpoint_recovery.py +120 -0
  368. ksadk/harness/subagent_adapters/native_background_child.py +803 -0
  369. ksadk/harness/subagent_adapters/native_child.py +819 -0
  370. ksadk/harness/subagent_adapters/native_child_approval.py +128 -0
  371. ksadk/harness/subagent_adapters/native_child_continuation.py +51 -0
  372. ksadk/harness/subagent_adapters/native_child_result.py +392 -0
  373. ksadk/harness/subagent_adapters/prepared_recovery.py +120 -0
  374. ksadk/harness/tool_display.py +75 -0
  375. ksadk/harness/tool_display_contract.py +134 -0
  376. ksadk/harness/tool_output.py +141 -0
  377. ksadk/harness/tool_policy.py +3 -0
  378. ksadk/harness/tool_result_policy.py +216 -0
  379. ksadk/harness/tools.py +52 -0
  380. ksadk/harness/workspace_adapters/__init__.py +6 -0
  381. ksadk/harness/workspace_adapters/native_directory.py +180 -0
  382. ksadk/harness/workspace_adapters/native_git.py +208 -0
  383. ksadk/harness/workspace_adapters/native_isolation.py +350 -0
  384. ksadk/interaction/providers/langgraph.py +8 -1
  385. ksadk/kernel/bootstrap.py +144 -160
  386. ksadk/kernel/contract_fingerprints.py +45 -1
  387. ksadk/kernel/contracts.py +25 -0
  388. ksadk/kernel/control.py +153 -33
  389. ksadk/kernel/execution_grants.py +209 -2
  390. ksadk/kernel/execution_grants_memory.py +127 -8
  391. ksadk/kernel/execution_grants_postgres.py +188 -10
  392. ksadk/kernel/execution_grants_sqlite.py +235 -9
  393. ksadk/kernel/execution_host_ingress.py +1071 -0
  394. ksadk/kernel/history_projection.py +120 -0
  395. ksadk/kernel/ingress.py +117 -204
  396. ksadk/kernel/ingress_bootstrap.py +268 -0
  397. ksadk/kernel/legacy_history.py +179 -0
  398. ksadk/kernel/memory_store.py +38 -48
  399. ksadk/kernel/memory_store_projection.py +63 -0
  400. ksadk/kernel/postgres_event_log.py +181 -0
  401. ksadk/kernel/postgres_store.py +167 -198
  402. ksadk/kernel/readiness.py +125 -0
  403. ksadk/kernel/recovery.py +89 -3
  404. ksadk/kernel/recovery_projection.py +124 -0
  405. ksadk/kernel/runtime_checkpoint.py +34 -0
  406. ksadk/kernel/sql/001_agent_kernel.sql +5 -0
  407. ksadk/kernel/sqlite_schema.py +100 -0
  408. ksadk/kernel/sqlite_store.py +147 -216
  409. ksadk/kernel/store.py +47 -15
  410. ksadk/kernel/teams_artifact_tools.py +392 -0
  411. ksadk/kernel/teams_effects.py +851 -0
  412. ksadk/kernel/teams_execution_context.py +408 -0
  413. ksadk/kernel/teams_host_http.py +237 -0
  414. ksadk/kernel/teams_material_transport.py +245 -0
  415. ksadk/kernel/teams_materials.py +318 -0
  416. ksadk/kernel/teams_runtime_bootstrap.py +604 -0
  417. ksadk/kernel/teams_tool_runtime.py +273 -0
  418. ksadk/kernel/teams_workspace.py +259 -0
  419. ksadk/kernel/worker.py +323 -332
  420. ksadk/kernel/worker_controls.py +454 -0
  421. ksadk/kernel/worker_identity.py +27 -0
  422. ksadk/kernel/worker_interactions.py +197 -0
  423. ksadk/knowledge_base/client.py +15 -1
  424. ksadk/managed_runtime.py +29 -2
  425. ksadk/memory/adk/backends/http_ltm_backend.py +2 -1
  426. ksadk/memory/adk/backends/sdk_ltm_backend.py +15 -1
  427. ksadk/memory/adk/bounded_database_session_service.py +232 -0
  428. ksadk/memory/adk/resilient_session_service.py +115 -15
  429. ksadk/memory/adk/short_term_memory.py +8 -9
  430. ksadk/memory/extraction.py +120 -7
  431. ksadk/memory/providers/local_candidates.py +183 -0
  432. ksadk/memory/providers/local_sqlite.py +252 -78
  433. ksadk/memory/resolved_policy.py +12 -7
  434. ksadk/model_gateway/__init__.py +29 -0
  435. ksadk/model_gateway/client.py +253 -0
  436. ksadk/model_gateway/events.py +113 -0
  437. ksadk/model_gateway/matrix.py +297 -0
  438. ksadk/model_proxy/compat.py +670 -0
  439. ksadk/model_proxy/server.py +10 -7
  440. ksadk/model_proxy/transform.py +37 -9
  441. ksadk/plugins/bridges/dsh.py +18 -20
  442. ksadk/plugins/bridges/dsh_profile_manifest.py +36 -0
  443. ksadk/plugins/builtin_resources.py +199 -0
  444. ksadk/plugins/builtins.py +380 -186
  445. ksadk/plugins/context_contributor.py +15 -4
  446. ksadk/plugins/dsh_dependency_policy.py +41 -0
  447. ksadk/plugins/dsh_toolchain.py +24 -35
  448. ksadk/plugins/execution_host.py +8 -0
  449. ksadk/plugins/host.py +73 -5
  450. ksadk/plugins/kernel_adapter.py +44 -1
  451. ksadk/plugins/memory_provider.py +180 -0
  452. ksadk/plugins/providers/_process_group.py +50 -0
  453. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +24 -2
  454. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +1 -1
  455. ksadk/plugins/providers/bundles/dsh-memory/package.json +1 -1
  456. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +1 -1
  457. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +1 -1
  458. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +1 -1
  459. ksadk/plugins/providers/codex.py +42 -38
  460. ksadk/plugins/providers/codex_native.py +20 -0
  461. ksadk/plugins/providers/codex_skills.py +46 -0
  462. ksadk/plugins/providers/dsh_capabilities.py +16 -171
  463. ksadk/plugins/providers/dsh_connector_lease.py +225 -0
  464. ksadk/plugins/providers/dsh_mcp.py +163 -1
  465. ksadk/plugins/providers/harness.py +247 -34
  466. ksadk/plugins/providers/harness_context.py +61 -0
  467. ksadk/plugins/providers/harness_contributions.py +241 -0
  468. ksadk/plugins/providers/harness_delegation.py +91 -14
  469. ksadk/plugins/providers/harness_hooks.py +121 -0
  470. ksadk/plugins/providers/harness_managed.py +269 -175
  471. ksadk/plugins/providers/harness_tools.py +165 -36
  472. ksadk/plugins/providers/legacy_catalog.py +1 -1
  473. ksadk/plugins/providers/mcp_projection.py +100 -3
  474. ksadk/plugins/providers/platform_resources.py +16 -6
  475. ksadk/plugins/teams/application.py +3 -143
  476. ksadk/plugins/teams/build_artifacts.py +460 -0
  477. ksadk/plugins/teams/cloud_contract_fingerprints.py +22 -0
  478. ksadk/plugins/teams/cloud_contracts.py +928 -0
  479. ksadk/plugins/teams/cloud_permits.py +250 -0
  480. ksadk/plugins/teams/domain.py +201 -148
  481. ksadk/plugins/teams/effect_contracts.py +255 -0
  482. ksadk/plugins/teams/execution_projection.py +255 -0
  483. ksadk/plugins/teams/leader_decisions.py +106 -0
  484. ksadk/plugins/teams/postgres_store.py +299 -85
  485. ksadk/plugins/teams/release_contracts.py +60 -0
  486. ksadk/plugins/teams/runtime.py +116 -40
  487. ksadk/plugins/teams/store.py +214 -6
  488. ksadk/plugins/teams/task_decisions.py +21 -8
  489. ksadk/plugins/teams/tool_service.py +152 -0
  490. ksadk/plugins/teams/transport.py +8 -3
  491. ksadk/resource_runtime/skill_runtime.py +3 -0
  492. ksadk/resource_runtime/socket_server.py +11 -0
  493. ksadk/resource_runtime/worker.py +28 -4
  494. ksadk/runners/_adk_a2a_stream.py +122 -0
  495. ksadk/runners/_adk_canonical_stream.py +474 -0
  496. ksadk/runners/_langgraph_canonical_streams.py +527 -0
  497. ksadk/runners/_langgraph_runner_streams.py +6 -400
  498. ksadk/runners/_langgraph_tool_projection.py +86 -0
  499. ksadk/runners/_langgraph_tools_transformer.py +27 -0
  500. ksadk/runners/adk_runner.py +195 -290
  501. ksadk/runners/base_runner.py +6 -5
  502. ksadk/runners/langgraph_runner.py +82 -86
  503. ksadk/runners/utils/loader.py +28 -14
  504. ksadk/runtime/_runner_adapter/a2ui_surface.py +145 -0
  505. ksadk/runtime/_runner_adapter/gateway_approvals.py +93 -0
  506. ksadk/runtime/_runner_adapter/stream_mapping.py +83 -128
  507. ksadk/runtime/adapter.py +40 -3
  508. ksadk/runtime/conversation_execution.py +4 -2
  509. ksadk/runtime/executor.py +97 -7
  510. ksadk/runtime/factory.py +13 -6
  511. ksadk/runtime/framework_adapters.py +184 -10
  512. ksadk/runtime/hosted_finalizer.py +4 -6
  513. ksadk/runtime/launch.py +2 -0
  514. ksadk/runtime/runner_adapter.py +123 -13
  515. ksadk/runtime_context.py +2 -0
  516. ksadk/sandbox/backends/e2b.py +30 -4
  517. ksadk/sandbox/backends/local_process.py +10 -0
  518. ksadk/sandbox/e2b_connection.py +9 -1
  519. ksadk/sandbox/local_controls.py +32 -2
  520. ksadk/sandbox/local_launcher.py +34 -0
  521. ksadk/server/factory.py +178 -25
  522. ksadk/server/history_deadline.py +158 -0
  523. ksadk/server/history_page_cache.py +129 -0
  524. ksadk/server/routes/checkpoint_audit.py +88 -0
  525. ksadk/server/routes/checkpoint_listing.py +294 -0
  526. ksadk/server/routes/checkpoint_resolution.py +73 -20
  527. ksadk/server/routes/control.py +51 -3
  528. ksadk/server/routes/display_projection.py +154 -0
  529. ksadk/server/routes/kernel_ingress.py +17 -2
  530. ksadk/server/routes/misc.py +102 -12
  531. ksadk/server/routes/models.py +25 -1
  532. ksadk/server/routes/openai_compat.py +6 -0
  533. ksadk/server/routes/projection.py +159 -216
  534. ksadk/server/routes/run.py +6 -2
  535. ksadk/server/routes/sessions.py +301 -342
  536. ksadk/server/routes/streaming.py +68 -15
  537. ksadk/server/routes/tool_receipt_claim_routes.py +107 -0
  538. ksadk/server/routes/workspace.py +5 -2
  539. ksadk/server/static/assets/{ArtifactsPanel-C1YoaKhx.js → ArtifactsPanel-CILaW-fC.js} +1 -1
  540. ksadk/server/static/assets/{CodeBlock-DHuAWfr5.js → CodeBlock-BVrNVtJC.js} +1 -1
  541. ksadk/server/static/assets/{MathMessageMarkdown-cvdrBwYr.js → MathMessageMarkdown-Dp7c4wWD.js} +1 -1
  542. ksadk/server/static/assets/{MermaidBlock-DeBkbJvI.js → MermaidBlock-Dxop8Rd7.js} +6 -6
  543. ksadk/server/static/assets/{NativeTerminalPanel-oJj44_sV.js → NativeTerminalPanel-Cjjz8B30.js} +1 -1
  544. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-Dhfv25o2.js → abnfDiagram-VCTEODGH-ckWDmOzw.js} +1 -1
  545. ksadk/server/static/assets/{arc-C35w-pn1.js → arc-DqxJede-.js} +1 -1
  546. ksadk/server/static/assets/architecture-7GRP2DOG-pn_DuLy6.js +1 -0
  547. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-FoMY_u6D.js → architectureDiagram-5GKGNRK7-SEQA4bVi.js} +1 -1
  548. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-zD4Rt7oE.js → blockDiagram-NRAW4CY4-pM0B-6NJ.js} +1 -1
  549. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BCtGGkhN.js → c4Diagram-UCG6FXSJ-m2tuCNVq.js} +1 -1
  550. ksadk/server/static/assets/channel-fySsnkft.js +1 -0
  551. ksadk/server/static/assets/chunk-2Q5K7J3B-BheGxKRQ.js +1 -0
  552. ksadk/server/static/assets/{chunk-5VM5RSS4-C2Ms13_k.js → chunk-5VM5RSS4-GJHDr9Ww.js} +1 -1
  553. ksadk/server/static/assets/{chunk-F27PBJKO-BoTj-qgx.js → chunk-F27PBJKO-CbAN45AV.js} +1 -1
  554. ksadk/server/static/assets/{chunk-G27WJ6UU-DOMyyjHH.js → chunk-G27WJ6UU-D5ngbbzF.js} +1 -1
  555. ksadk/server/static/assets/{chunk-JWPE2WC7-DbJJqDli.js → chunk-JWPE2WC7-Cc5IwuYC.js} +1 -1
  556. ksadk/server/static/assets/{chunk-LCL6LL3I-CLuRCt_W.js → chunk-LCL6LL3I-CprgDDdJ.js} +1 -1
  557. ksadk/server/static/assets/{chunk-POPQ4Y6H-D0Dz847e.js → chunk-POPQ4Y6H-CDZhSy82.js} +1 -1
  558. ksadk/server/static/assets/{chunk-RHFEMEQ7-BWSRzEcd.js → chunk-RHFEMEQ7-CZchUNro.js} +1 -1
  559. ksadk/server/static/assets/{chunk-SVP7TREG-CPoHqkCY.js → chunk-SVP7TREG-BVruqk6T.js} +1 -1
  560. ksadk/server/static/assets/{chunk-XXDRQBXY-Bx1jS-X-.js → chunk-XXDRQBXY-4ld9SxPN.js} +1 -1
  561. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DSfLtNYm.js +1 -0
  562. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DSfLtNYm.js +1 -0
  563. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-LzyWm4m0.js → cose-bilkent-JH36ORCC-Dmyyk_Vp.js} +1 -1
  564. ksadk/server/static/assets/cynefin-OW5HDTMX-PFWIGtvA.js +1 -0
  565. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-BlW_bHED.js → cynefinDiagram-5FMLGOSQ-BIyq3EJb.js} +1 -1
  566. ksadk/server/static/assets/{dagre-3AP2YEHR-Bu_S86_i.js → dagre-3AP2YEHR-eBw08Qdk.js} +1 -1
  567. ksadk/server/static/assets/{dagre-B7nCawed.js → dagre-DfvnEf45.js} +1 -1
  568. ksadk/server/static/assets/{diagram-S7CK7UJ4-W_Zow2Km.js → diagram-S7CK7UJ4-CUSrE3Mg.js} +1 -1
  569. ksadk/server/static/assets/{diagram-UQ7AKVKN-CLIKAHON.js → diagram-UQ7AKVKN-Dq5Zw2gy.js} +1 -1
  570. ksadk/server/static/assets/{diagram-VSXAHHWV-Dv6_QAlN.js → diagram-VSXAHHWV-DyUHfNwT.js} +1 -1
  571. ksadk/server/static/assets/{diagram-VX7I27RA-BWAWRDtZ.js → diagram-VX7I27RA-CREmM89O.js} +1 -1
  572. ksadk/server/static/assets/{diagram-Z3DM3KII-XA_rWMss.js → diagram-Z3DM3KII-Dw9zhHUK.js} +1 -1
  573. ksadk/server/static/assets/{dist-CGt_UGeO.js → dist-0uJ4tdx6.js} +1 -1
  574. ksadk/server/static/assets/{dist-C0J5_3qM.js → dist-AEv-vXf-.js} +1 -1
  575. ksadk/server/static/assets/{dist-CIpWk_5f.js → dist-B49GzZDb.js} +1 -1
  576. ksadk/server/static/assets/{dist-B3bA05-e.js → dist-B8Myiet9.js} +1 -1
  577. ksadk/server/static/assets/{dist-DWfdmz9s.js → dist-BBsYarrI.js} +1 -1
  578. ksadk/server/static/assets/{dist-BLpRy_Yx.js → dist-BQMrUwdI.js} +1 -1
  579. ksadk/server/static/assets/{dist-CIRMvUM4.js → dist-BX_-FENW.js} +1 -1
  580. ksadk/server/static/assets/{dist-BdNFAney.js → dist-CD4L6ymH.js} +1 -1
  581. ksadk/server/static/assets/{dist-n3n6t_FO.js → dist-CHpW1BHj.js} +1 -1
  582. ksadk/server/static/assets/{dist-DppE_r-D.js → dist-CVPau3tn.js} +1 -1
  583. ksadk/server/static/assets/{dist-qe8xjesy.js → dist-C_qdxcSH.js} +1 -1
  584. ksadk/server/static/assets/{dist-2vL2sAdF.js → dist-Co68Apq4.js} +1 -1
  585. ksadk/server/static/assets/{dist-1nXCdsej.js → dist-Cp2PaOMY.js} +1 -1
  586. ksadk/server/static/assets/{dist-DNKuMzWc.js → dist-CuR5Bgme.js} +1 -1
  587. ksadk/server/static/assets/{dist-t6MzE0jU.js → dist-DDSyLEOX.js} +1 -1
  588. ksadk/server/static/assets/{dist-CPyieXEf.js → dist-DUxO0R99.js} +1 -1
  589. ksadk/server/static/assets/{dist-DyG6Ya-z.js → dist-QzbGrED_.js} +1 -1
  590. ksadk/server/static/assets/{dist-0X_j2Rcc.js → dist-bupkyEBZ.js} +1 -1
  591. ksadk/server/static/assets/{dist-mqD5TZup.js → dist-cxTGfdqx.js} +1 -1
  592. ksadk/server/static/assets/{dist-M-SrdhhZ.js → dist-hL5p1til.js} +1 -1
  593. ksadk/server/static/assets/{dist-D-92S-Fd.js → dist-lOy23y43.js} +1 -1
  594. ksadk/server/static/assets/{dist-BO_UwatH.js → dist-pq-nD33R.js} +1 -1
  595. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-BfCzF1Xi.js → ebnfDiagram-PWID7BFC-BS5LdNoR.js} +1 -1
  596. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-Dpz9_0zn.js → erDiagram-SSCWMZ5O-Bv1QtiY-.js} +1 -1
  597. ksadk/server/static/assets/eventmodeling-NTZA5JFV-DsM4upQX.js +1 -0
  598. ksadk/server/static/assets/flowDiagram-A5DVABFB-D5NA16k9.js +1 -0
  599. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DDaG1f4_.js → ganttDiagram-EL5Y4UJY-musi-e0G.js} +1 -1
  600. ksadk/server/static/assets/gitGraph-4MIJSDKK-DUCVz-ih.js +1 -0
  601. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DcxzRwYC.js → gitGraphDiagram-WWUBYQGX-DH37EGkG.js} +1 -1
  602. ksadk/server/static/assets/index-CZdkAvsv.js +244 -0
  603. ksadk/server/static/assets/index-CvXdHgF3.css +2 -0
  604. ksadk/server/static/assets/info-A6RAGUB7-rw0ZNHZp.js +1 -0
  605. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CYMdn6lQ.js → infoDiagram-RXCK75RN-C1kEtv2y.js} +1 -1
  606. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CLHFAD6c.js → ishikawaDiagram-5VMMS53U-BCNPyMka.js} +1 -1
  607. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-BHSKQGAl.js → journeyDiagram-EYS64GPL--cDbKnjP.js} +1 -1
  608. ksadk/server/static/assets/{kanban-definition-3QL26DDD-D5W3tjTT.js → kanban-definition-3QL26DDD-R1rAVw2f.js} +1 -1
  609. ksadk/server/static/assets/{katex-mtjOi4KM.js → katex-BT-X-V7U.js} +1 -1
  610. ksadk/server/static/assets/{linear-BETqsxE_.js → linear-DTR631iG.js} +1 -1
  611. ksadk/server/static/assets/{mermaid-parser.core-DPWrvs90.js → mermaid-parser.core-DfFzJhX8.js} +2 -2
  612. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-CJG2mfBP.js → mindmap-definition-FBJOCRG2-D4by_rmk.js} +1 -1
  613. ksadk/server/static/assets/packet-AYTQ26CC-Ca4Hvki9.js +1 -0
  614. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-GjAPNaqn.js → pegDiagram-XKGWAZYB-xWXPEh0c.js} +1 -1
  615. ksadk/server/static/assets/pie-WAS4IAKB-hwiz6fbw.js +1 -0
  616. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-ToIewrqr.js → pieDiagram-E7YTZNPT-BudBDlCI.js} +1 -1
  617. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-4d78KiEY.js → quadrantDiagram-AXDQQJYC-DXZ0PCJF.js} +1 -1
  618. ksadk/server/static/assets/radar-RG4KPBEZ-BR1oZXLM.js +1 -0
  619. ksadk/server/static/assets/railroad-74A4TZTK-DfgEISfX.js +1 -0
  620. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-CWOC3rdk.js +1 -0
  621. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CiRvHCLY.js +1 -0
  622. ksadk/server/static/assets/railroad-peg-WCYAUIDC-DSDDyJ2f.js +1 -0
  623. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-DKzx4xfv.js → railroadDiagram-O6MQD6OU-BdAYRYB8.js} +1 -1
  624. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-CJYljxQS.js → requirementDiagram-EFPCY7ZU-CBBmaL70.js} +1 -1
  625. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-DLU2fV1w.js → sankeyDiagram-P5KCCOFB-Doc3rdwp.js} +1 -1
  626. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CVqysrA9.js → sequenceDiagram-WJ2MYXX4-0J8R8hWW.js} +1 -1
  627. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-BUxfmTHc.js → sizeCapture-X5ZJPWSS-CfFLlWsK.js} +1 -1
  628. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-CNFgYI9E.js → stateDiagram-HBIQ2CUA-jBwkjtTy.js} +1 -1
  629. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-Cw1fPb5w.js +1 -0
  630. ksadk/server/static/assets/{swimlanes-XN3QIQJK-B6qCMe8N.js → swimlanes-XN3QIQJK-B0WxTQf8.js} +1 -1
  631. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-Cc3JMBAF.js +8 -0
  632. ksadk/server/static/assets/{timeline-definition-24CTP7MA-CMD3x_U_.js → timeline-definition-24CTP7MA-BfCT_75A.js} +1 -1
  633. ksadk/server/static/assets/treeView-Q6P3EWNA-C05SJHxo.js +1 -0
  634. ksadk/server/static/assets/treemap-WGGIJYW6-BqNLAhc3.js +1 -0
  635. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-BqtUqvXM.js → vennDiagram-4TSXK5OY-9gX1VMDC.js} +1 -1
  636. ksadk/server/static/assets/wardley-WFR3VGLG-DokNktqB.js +1 -0
  637. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-B5KfDjI-.js → wardleyDiagram-VM6X3IG4-sEs_BP6O.js} +1 -1
  638. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BaUlSZrn.js → xychartDiagram-S5SC5T6Z-Ll4jvUN9.js} +1 -1
  639. ksadk/server/static/index.html +2 -2
  640. ksadk/sessions/__init__.py +8 -1
  641. ksadk/sessions/_checkpoint_resume_audit.py +44 -0
  642. ksadk/sessions/_in_memory_query.py +112 -0
  643. ksadk/sessions/_local_service_sync.py +157 -156
  644. ksadk/sessions/_local_state_sync.py +152 -0
  645. ksadk/sessions/_local_tables.py +2 -0
  646. ksadk/sessions/_postgres_checkpoint_read.py +323 -0
  647. ksadk/sessions/_postgres_checkpoint_stats.py +330 -0
  648. ksadk/sessions/_postgres_history_read.py +678 -0
  649. ksadk/sessions/_postgres_schema.py +44 -2
  650. ksadk/sessions/_postgres_tables.py +2 -0
  651. ksadk/sessions/_postgres_tool_receipts.py +169 -0
  652. ksadk/sessions/_resilient_read.py +630 -0
  653. ksadk/sessions/_tool_receipt_sync.py +119 -0
  654. ksadk/sessions/agent_identity.py +16 -0
  655. ksadk/sessions/base.py +278 -0
  656. ksadk/sessions/db_budget.py +332 -0
  657. ksadk/sessions/errors.py +12 -0
  658. ksadk/sessions/history_budget.py +36 -0
  659. ksadk/sessions/history_identity.py +27 -0
  660. ksadk/sessions/in_memory.py +376 -113
  661. ksadk/sessions/local_service.py +345 -0
  662. ksadk/sessions/postgres_service.py +515 -549
  663. ksadk/sessions/resilience.py +21 -14
  664. ksadk/sessions/resilient.py +611 -504
  665. ksadk/skills/loader.py +44 -2
  666. ksadk/skills/runtime/backends/e2b.py +17 -14
  667. ksadk/skills/service_client.py +6 -1
  668. ksadk/studio/a2a_bindings.py +407 -0
  669. ksadk/studio/a2a_orchestration.py +178 -0
  670. ksadk/studio/active_run_output.py +92 -0
  671. ksadk/studio/activity_records.py +542 -0
  672. ksadk/studio/agent_configuration.py +173 -0
  673. ksadk/studio/api.py +219 -389
  674. ksadk/studio/api_a2a_routes.py +93 -0
  675. ksadk/studio/api_catalog_routes.py +13 -0
  676. ksadk/studio/api_cloud_chat_routes.py +382 -0
  677. ksadk/studio/api_contracts.py +23 -0
  678. ksadk/studio/attachment_store.py +14 -2
  679. ksadk/studio/build_resolution.py +117 -0
  680. ksadk/studio/build_singleflight.py +37 -0
  681. ksadk/studio/builder.py +20 -2
  682. ksadk/studio/capabilities.py +8 -3
  683. ksadk/studio/cloud.py +83 -377
  684. ksadk/studio/cloud_gateways.py +424 -0
  685. ksadk/studio/cloud_shared_web.py +7 -0
  686. ksadk/studio/codex_agent_service.py +17 -0
  687. ksadk/studio/codex_manifest.py +5 -1
  688. ksadk/studio/codex_provider_build.py +65 -0
  689. ksadk/studio/compiler.py +102 -6
  690. ksadk/studio/contract_base.py +19 -0
  691. ksadk/studio/contracts.py +231 -201
  692. ksadk/studio/dsh_application.py +58 -12
  693. ksadk/studio/dsh_capability_service.py +17 -171
  694. ksadk/studio/dsh_mcp_transport.py +191 -0
  695. ksadk/studio/event_store.py +17 -0
  696. ksadk/studio/execution_host.py +84 -11
  697. ksadk/studio/framework_run.py +18 -0
  698. ksadk/studio/interaction_submission.py +265 -0
  699. ksadk/studio/kernel_registry.py +12 -1
  700. ksadk/studio/lifecycle_status.py +43 -0
  701. ksadk/studio/model_buffered_wire.py +227 -0
  702. ksadk/studio/model_chat_tools.py +143 -0
  703. ksadk/studio/model_client.py +1241 -761
  704. ksadk/studio/model_content_stream.py +129 -0
  705. ksadk/studio/model_credentials.py +196 -0
  706. ksadk/studio/model_profile_service.py +65 -31
  707. ksadk/studio/model_request_projection.py +284 -0
  708. ksadk/studio/model_responses_content.py +296 -0
  709. ksadk/studio/model_usage.py +109 -0
  710. ksadk/studio/model_wire_failure.py +110 -0
  711. ksadk/studio/model_wire_identity.py +138 -0
  712. ksadk/studio/model_wire_snapshot.py +45 -0
  713. ksadk/studio/model_wire_tools.py +283 -0
  714. ksadk/studio/native_acceptance.py +68 -0
  715. ksadk/studio/native_approval.py +111 -0
  716. ksadk/studio/native_browser_port.py +861 -0
  717. ksadk/studio/native_child_mcp.py +87 -0
  718. ksadk/studio/native_child_publication.py +68 -0
  719. ksadk/studio/native_child_skills.py +72 -0
  720. ksadk/studio/native_child_workspace.py +176 -0
  721. ksadk/studio/native_command_policy.py +53 -0
  722. ksadk/studio/native_context_port.py +326 -0
  723. ksadk/studio/native_context_registration.py +54 -0
  724. ksadk/studio/native_document_input.py +88 -0
  725. ksadk/studio/native_final_shape.py +852 -0
  726. ksadk/studio/native_gateway_stream.py +69 -0
  727. ksadk/studio/native_hook_port.py +145 -0
  728. ksadk/studio/native_hook_registration.py +70 -0
  729. ksadk/studio/native_inventory_disclosure.py +223 -0
  730. ksadk/studio/native_kernel_admission.py +84 -0
  731. ksadk/studio/native_language_diagnostics.py +320 -0
  732. ksadk/studio/native_mcp_disclosure.py +198 -0
  733. ksadk/studio/native_mcp_tool_port.py +219 -0
  734. ksadk/studio/native_memory_acceptance.py +362 -0
  735. ksadk/studio/native_memory_context.py +266 -0
  736. ksadk/studio/native_memory_flush.py +174 -0
  737. ksadk/studio/native_memory_sources.py +80 -0
  738. ksadk/studio/native_memory_tool_port.py +360 -0
  739. ksadk/studio/native_memory_turn.py +183 -0
  740. ksadk/studio/native_model_port.py +765 -0
  741. ksadk/studio/native_model_recovery.py +126 -0
  742. ksadk/studio/native_options.py +75 -0
  743. ksadk/studio/native_output_fields.py +58 -0
  744. ksadk/studio/native_planning.py +156 -0
  745. ksadk/studio/native_product.py +988 -0
  746. ksadk/studio/native_read_budget.py +426 -0
  747. ksadk/studio/native_recovery.py +171 -0
  748. ksadk/studio/native_scope.py +35 -0
  749. ksadk/studio/native_session_context_port.py +141 -0
  750. ksadk/studio/native_session_engine.py +14 -0
  751. ksadk/studio/native_skill_source.py +74 -0
  752. ksadk/studio/native_subagent_port.py +700 -0
  753. ksadk/studio/native_terminal_recovery.py +95 -0
  754. ksadk/studio/native_test_action.py +610 -0
  755. ksadk/studio/native_tool_port.py +477 -0
  756. ksadk/studio/native_user_input.py +60 -0
  757. ksadk/studio/native_verification_presentation.py +65 -0
  758. ksadk/studio/native_workspace_diagnostics.py +183 -0
  759. ksadk/studio/native_workspace_port.py +43 -0
  760. ksadk/studio/operations.py +34 -9
  761. ksadk/studio/plugin_composition.py +26 -10
  762. ksadk/studio/plugin_kernel_adapter.py +75 -1
  763. ksadk/studio/plugin_native_activation.py +163 -0
  764. ksadk/studio/plugin_runtime.py +639 -119
  765. ksadk/studio/plugin_runtime_admission.py +57 -0
  766. ksadk/studio/presentation.py +92 -0
  767. ksadk/studio/public_output_store.py +69 -0
  768. ksadk/studio/resource_authority.py +11 -3
  769. ksadk/studio/resource_catalog.py +8 -12
  770. ksadk/studio/run_activity.py +338 -385
  771. ksadk/studio/run_controls.py +185 -0
  772. ksadk/studio/run_service.py +908 -319
  773. ksadk/studio/run_submission_receipts.py +68 -0
  774. ksadk/studio/runtime_catalog.py +23 -4
  775. ksadk/studio/runtime_prewarm.py +22 -0
  776. ksadk/studio/scheduler_assistant.py +4 -1
  777. ksadk/studio/service.py +356 -282
  778. ksadk/studio/service_settings.py +229 -0
  779. ksadk/studio/shared_web.py +393 -169
  780. ksadk/studio/shared_web_response_events.py +180 -0
  781. ksadk/studio/shared_web_run_state.py +133 -0
  782. ksadk/studio/skill_discovery.py +305 -3
  783. ksadk/studio/static/assets/ChannelsPage-xX5HlMId.js +8 -0
  784. ksadk/studio/static/assets/{CodeBlock-DMIf4h33-UIqo-BPW.js → CodeBlock-DMIf4h33-CkufcPYo.js} +3 -3
  785. ksadk/studio/static/assets/{MathMessageMarkdown-BesSeCYl-OhNwH4K9.js → MathMessageMarkdown-BesSeCYl-DYG1Wzbx.js} +1 -1
  786. ksadk/studio/static/assets/{MessageMarkdown-CwMTvgFj-g0I-I4dD.js → MessageMarkdown-CwMTvgFj-BeyLyQHu.js} +2 -2
  787. ksadk/studio/static/assets/TeamsPage-CCaaGaVp.js +3 -0
  788. ksadk/studio/static/assets/index-C7DNDik2.css +2 -0
  789. ksadk/studio/static/assets/index-Cy68gTlH.js +265 -0
  790. ksadk/studio/static/index.html +3 -3
  791. ksadk/studio/teams_catalog.py +33 -0
  792. ksadk/studio/teams_installation.py +4 -1
  793. ksadk/studio/teams_node.py +4 -0
  794. ksadk/studio/teams_node_factory.py +558 -0
  795. ksadk/studio/teams_node_runner.py +3 -0
  796. ksadk/studio/teams_node_v1.py +935 -0
  797. ksadk/studio/teams_remote.py +259 -37
  798. ksadk/studio/templates.py +1 -0
  799. ksadk/studio/workspace_plugins.py +3 -1
  800. ksadk/tools/a2a_policy.py +5 -0
  801. ksadk/tools/artifact_observation.py +53 -0
  802. ksadk/tools/captured_source_artifact.py +68 -0
  803. ksadk/tools/schema.py +34 -0
  804. ksadk/toolsets/__init__.py +82 -88
  805. ksadk/toolsets/a2a.py +89 -89
  806. ksadk/toolsets/sandbox.py +377 -6
  807. ksadk/toolsets/skill_management.py +315 -0
  808. ksadk/toolsets/tool_selection.py +94 -0
  809. ksadk/toolsets/workspace.py +342 -324
  810. ksadk/toolsets/workspace_editing.py +291 -0
  811. ksadk/toolsets/workspace_model_observation.py +104 -0
  812. ksadk/toolsets/workspace_mutation.py +75 -0
  813. ksadk/toolsets/workspace_read_budget.py +216 -0
  814. ksadk/toolsets/workspace_search.py +192 -0
  815. ksadk/toolsets/workspace_search_process.py +129 -0
  816. ksadk/toolsets/workspace_state.py +6 -0
  817. ksadk/version.py +1 -1
  818. ksadk_runtime_common/http_headers.py +18 -0
  819. ksadk_runtime_common/workspace_files/router.py +2 -1
  820. ksadk/server/static/assets/architecture-7GRP2DOG-BCsa26zi.js +0 -1
  821. ksadk/server/static/assets/channel-_KDifNys.js +0 -1
  822. ksadk/server/static/assets/chunk-2Q5K7J3B-HdVkJ9F0.js +0 -1
  823. ksadk/server/static/assets/classDiagram-DTDB5LWJ-BVCW3ZqZ.js +0 -1
  824. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-BVCW3ZqZ.js +0 -1
  825. ksadk/server/static/assets/cynefin-OW5HDTMX-CNXjFctL.js +0 -1
  826. ksadk/server/static/assets/eventmodeling-NTZA5JFV-B5-8RH9c.js +0 -1
  827. ksadk/server/static/assets/flowDiagram-A5DVABFB-BppFxEKw.js +0 -1
  828. ksadk/server/static/assets/gitGraph-4MIJSDKK-B-AhYj4C.js +0 -1
  829. ksadk/server/static/assets/index-BMd2mucF.css +0 -2
  830. ksadk/server/static/assets/index-D5qyyhTH.js +0 -244
  831. ksadk/server/static/assets/info-A6RAGUB7-0uiKrC35.js +0 -1
  832. ksadk/server/static/assets/packet-AYTQ26CC-BVTmZ_cw.js +0 -1
  833. ksadk/server/static/assets/pie-WAS4IAKB-DyfxBU7V.js +0 -1
  834. ksadk/server/static/assets/radar-RG4KPBEZ-FFontjL2.js +0 -1
  835. ksadk/server/static/assets/railroad-74A4TZTK-D0Uidzen.js +0 -1
  836. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BOo_9T2h.js +0 -1
  837. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-D6-BjW7Z.js +0 -1
  838. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CXx__yMm.js +0 -1
  839. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BXAFScz8.js +0 -1
  840. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uIQ2lJKH.js +0 -8
  841. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5GgucZ.js +0 -1
  842. ksadk/server/static/assets/treemap-WGGIJYW6-Bq1u1SpG.js +0 -1
  843. ksadk/server/static/assets/wardley-WFR3VGLG-QAt06uEz.js +0 -1
  844. ksadk/studio/static/assets/ChannelsPage-D_PGmKVq.js +0 -8
  845. ksadk/studio/static/assets/TeamsPage-DqX4HWKQ.js +0 -3
  846. ksadk/studio/static/assets/index-CfEnms6Y.css +0 -2
  847. ksadk/studio/static/assets/index-Dp61rOWZ.js +0 -0
  848. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/WHEEL +0 -0
  849. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/entry_points.txt +0 -0
  850. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/licenses/LICENSE +0 -0
  851. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
+ from dataclasses import dataclass
5
6
  from typing import Any, Optional
6
7
 
7
8
  from ksadk.compat.adk_compat import (
@@ -12,11 +13,22 @@ from ksadk.compat.adk_compat import (
12
13
  ListSessionsResponse,
13
14
  Session,
14
15
  )
16
+ from ksadk.sessions.db_budget import DatabaseOperationDeadline, session_db_budget
15
17
  from ksadk.sessions.resilience import is_session_backend_failure
16
18
 
17
19
  logger = logging.getLogger(__name__)
18
20
 
19
21
 
22
+ @dataclass(frozen=True)
23
+ class ADKEventCommitUnknown:
24
+ """Fail-open live event whose durable COMMIT cannot be confirmed."""
25
+
26
+ app_name: str
27
+ user_id: str
28
+ session_id: str
29
+ event_id: str
30
+
31
+
20
32
  class ResilientADKSessionService(BaseSessionService):
21
33
  """Run ADK sessions locally while mirroring them to durable storage."""
22
34
 
@@ -26,6 +38,11 @@ class ResilientADKSessionService(BaseSessionService):
26
38
  self.primary = primary
27
39
  self.live = InMemorySessionService()
28
40
  self._primary_sessions: dict[tuple[str, str, str], Session] = {}
41
+ # A failed write has an unknown commit outcome. Never replay it or
42
+ # hydrate stale durable state over the live session after recovery.
43
+ self._dirty_sessions: set[tuple[str, str, str]] = set()
44
+ self._deleted_sessions: set[tuple[str, str, str]] = set()
45
+ self.unknown_event_commits: set[ADKEventCommitUnknown] = set()
29
46
  self._primary_enabled = True
30
47
  self._probe_task: asyncio.Task[None] | None = None
31
48
 
@@ -92,7 +109,42 @@ class ResilientADKSessionService(BaseSessionService):
92
109
  def _key(app_name: str, user_id: str, session_id: str) -> tuple[str, str, str]:
93
110
  return app_name, user_id, session_id
94
111
 
112
+ def _write_deadline(self) -> DatabaseOperationDeadline:
113
+ return DatabaseOperationDeadline(
114
+ getattr(self.primary, "db_budget", None) or session_db_budget()
115
+ )
116
+
117
+ async def reconcile_event_commit(
118
+ self, *, app_name: str, user_id: str, session_id: str, event_id: str
119
+ ) -> str:
120
+ """Read back a stable ADK event ID after a write's outcome is unknown.
121
+
122
+ Absence is still ``unknown`` because an in-flight commit may finish
123
+ after this read. This method never replays an event or clears dirty
124
+ local state.
125
+ """
126
+ try:
127
+ durable = await self.primary.get_session(
128
+ app_name=app_name, user_id=user_id, session_id=session_id
129
+ )
130
+ except Exception:
131
+ return "unknown"
132
+ if durable and any(event.id == event_id for event in durable.events):
133
+ self.unknown_event_commits.discard(
134
+ ADKEventCommitUnknown(app_name, user_id, session_id, event_id)
135
+ )
136
+ return "committed"
137
+ return "unknown"
138
+
95
139
  async def _hydrate(self, durable: Session) -> Session:
140
+ key = self._key(durable.app_name, durable.user_id, durable.id)
141
+ if key in self._dirty_sessions:
142
+ existing = await self.live.get_session(
143
+ app_name=durable.app_name, user_id=durable.user_id, session_id=durable.id
144
+ )
145
+ if existing is None:
146
+ raise RuntimeError("Dirty ADK session has no live state")
147
+ return existing
96
148
  existing = await self.live.get_session(
97
149
  app_name=durable.app_name,
98
150
  user_id=durable.user_id,
@@ -128,12 +180,15 @@ class ResilientADKSessionService(BaseSessionService):
128
180
  session_id: Optional[str] = None,
129
181
  ) -> Session:
130
182
  if session_id:
183
+ key = self._key(app_name, user_id, session_id)
131
184
  existing = await self.live.get_session(
132
185
  app_name=app_name,
133
186
  user_id=user_id,
134
187
  session_id=session_id,
135
188
  )
136
- if self._primary_enabled:
189
+ if key in self._dirty_sessions and existing is not None:
190
+ return existing
191
+ if self._primary_enabled and key not in self._dirty_sessions:
137
192
  try:
138
193
  durable = await self.primary.get_session(
139
194
  app_name=app_name,
@@ -154,7 +209,9 @@ class ResilientADKSessionService(BaseSessionService):
154
209
  state=state,
155
210
  session_id=session_id,
156
211
  )
157
- if self._primary_enabled:
212
+ key = self._key(app_name, user_id, live.id)
213
+ self._deleted_sessions.discard(key)
214
+ if self._primary_enabled and key not in self._dirty_sessions:
158
215
  try:
159
216
  durable = await self.primary.create_session(
160
217
  app_name=app_name,
@@ -164,8 +221,11 @@ class ResilientADKSessionService(BaseSessionService):
164
221
  )
165
222
  self._primary_sessions[self._key(app_name, user_id, live.id)] = durable
166
223
  except Exception as exc:
224
+ self._dirty_sessions.add(key)
167
225
  if not self._handle_primary_failure(exc):
168
226
  raise
227
+ else:
228
+ self._dirty_sessions.add(key)
169
229
  return live
170
230
 
171
231
  async def get_session(
@@ -176,13 +236,16 @@ class ResilientADKSessionService(BaseSessionService):
176
236
  session_id: str,
177
237
  config: Optional[GetSessionConfig] = None,
178
238
  ) -> Optional[Session]:
239
+ key = self._key(app_name, user_id, session_id)
179
240
  live = await self.live.get_session(
180
241
  app_name=app_name,
181
242
  user_id=user_id,
182
243
  session_id=session_id,
183
244
  config=config,
184
245
  )
185
- if not self._primary_enabled:
246
+ if key in self._deleted_sessions:
247
+ return None
248
+ if not self._primary_enabled or key in self._dirty_sessions:
186
249
  return live
187
250
  try:
188
251
  durable = await self.primary.get_session(
@@ -207,6 +270,9 @@ class ResilientADKSessionService(BaseSessionService):
207
270
  try:
208
271
  durable = await self.primary.list_sessions(app_name=app_name, user_id=user_id)
209
272
  for session in durable.sessions:
273
+ key = self._key(session.app_name, session.user_id, session.id)
274
+ if key in self._dirty_sessions:
275
+ continue
210
276
  await self._hydrate(session)
211
277
  except Exception as exc:
212
278
  if not self._handle_primary_failure(exc):
@@ -214,8 +280,11 @@ class ResilientADKSessionService(BaseSessionService):
214
280
  return await self.live.list_sessions(app_name=app_name, user_id=user_id)
215
281
 
216
282
  async def delete_session(self, *, app_name: str, user_id: str, session_id: str) -> None:
283
+ key = self._key(app_name, user_id, session_id)
217
284
  await self.live.delete_session(app_name=app_name, user_id=user_id, session_id=session_id)
218
- self._primary_sessions.pop(self._key(app_name, user_id, session_id), None)
285
+ self._primary_sessions.pop(key, None)
286
+ self._dirty_sessions.add(key)
287
+ self._deleted_sessions.add(key)
219
288
  if self._primary_enabled:
220
289
  try:
221
290
  await self.primary.delete_session(
@@ -223,33 +292,64 @@ class ResilientADKSessionService(BaseSessionService):
223
292
  user_id=user_id,
224
293
  session_id=session_id,
225
294
  )
295
+ self._dirty_sessions.discard(key)
296
+ self._deleted_sessions.discard(key)
226
297
  except Exception as exc:
227
298
  if not self._handle_primary_failure(exc):
228
299
  raise
229
300
 
230
301
  async def append_event(self, session: Session, event: Event) -> Event:
231
302
  stored = await self.live.append_event(session, event)
232
- if not self._primary_enabled:
233
- return stored
303
+ deadline = self._write_deadline()
234
304
  key = self._key(session.app_name, session.user_id, session.id)
305
+ if not self._primary_enabled or key in self._dirty_sessions:
306
+ self._dirty_sessions.add(key)
307
+ return stored
235
308
  durable_session = self._primary_sessions.get(key)
236
309
  try:
237
310
  if durable_session is None:
238
- durable_session = await self.primary.get_session(
239
- app_name=session.app_name,
240
- user_id=session.user_id,
241
- session_id=session.id,
242
- )
243
- if durable_session is None:
244
- durable_session = await self.primary.create_session(
311
+ durable_session = await deadline.run(
312
+ self.primary.get_session(
245
313
  app_name=session.app_name,
246
314
  user_id=session.user_id,
247
- state=session.state,
248
315
  session_id=session.id,
249
316
  )
317
+ )
318
+ if durable_session is None:
319
+ durable_session = await deadline.run(
320
+ self.primary.create_session(
321
+ app_name=session.app_name,
322
+ user_id=session.user_id,
323
+ state=session.state,
324
+ session_id=session.id,
325
+ )
326
+ )
250
327
  self._primary_sessions[key] = durable_session
251
- await self.primary.append_event(durable_session, event)
328
+ await deadline.run(self.primary.append_event(durable_session, event))
252
329
  except Exception as exc:
330
+ if is_session_backend_failure(exc):
331
+ try:
332
+ outcome = await deadline.run(
333
+ self.reconcile_event_commit(
334
+ app_name=session.app_name,
335
+ user_id=session.user_id,
336
+ session_id=session.id,
337
+ event_id=event.id,
338
+ )
339
+ )
340
+ except Exception:
341
+ outcome = "unknown"
342
+ if outcome == "committed":
343
+ # A lost acknowledgement is not a failed write. Reload the
344
+ # exact durable revision before the next append.
345
+ self._primary_sessions.pop(key, None)
346
+ return stored
347
+ self.unknown_event_commits.add(ADKEventCommitUnknown(*key, event.id))
348
+ logger.warning(
349
+ "ADK event commit outcome unknown; retaining dirty live state",
350
+ extra={"session_backend_reason_code": "ADK_EVENT_COMMIT_UNKNOWN"},
351
+ )
352
+ self._dirty_sessions.add(key)
253
353
  if not self._handle_primary_failure(exc):
254
354
  raise
255
355
  return stored
@@ -153,18 +153,17 @@ class ShortTermMemory(BaseModel):
153
153
  try:
154
154
  from ksadk.compat.adk_compat import DatabaseSessionService
155
155
  from ksadk.memory.adk.resilient_session_service import ResilientADKSessionService
156
- from ksadk.sessions.resilience import session_backend_timeout_seconds
157
-
158
- service_kwargs = {}
159
156
  if normalized_db_url.startswith(("postgresql://", "postgresql+asyncpg://")):
160
- timeout = session_backend_timeout_seconds()
161
- service_kwargs["connect_args"] = {
162
- "timeout": timeout,
163
- "command_timeout": timeout,
164
- }
157
+ from ksadk.memory.adk.bounded_database_session_service import (
158
+ BoundedADKDatabaseSessionService,
159
+ )
160
+
161
+ primary = BoundedADKDatabaseSessionService(db_url=normalized_db_url)
162
+ else:
163
+ primary = DatabaseSessionService(db_url=normalized_db_url)
165
164
 
166
165
  self._session_service = ResilientADKSessionService(
167
- DatabaseSessionService(db_url=normalized_db_url, **service_kwargs)
166
+ primary
168
167
  )
169
168
  logger.info("ShortTermMemory: using DatabaseSessionService")
170
169
  except ImportError:
@@ -12,8 +12,12 @@
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
+ import hashlib
16
+ import json
15
17
  import re
16
18
  import uuid
19
+ from dataclasses import replace
20
+ from types import SimpleNamespace
17
21
  from typing import Sequence
18
22
 
19
23
  from ksadk.memory.models import MemoryCandidate, MemoryScope
@@ -25,6 +29,23 @@ _EXPLICIT_PATTERNS: tuple[re.Pattern[str], ...] = (
25
29
  re.compile(r"(?i)remember\s+(?:that\s+)?(.+)", re.IGNORECASE),
26
30
  re.compile(r"(?i)请记[::]?\s*(.+)"),
27
31
  )
32
+ # A declared conversation/turn horizon belongs to Session history, not the
33
+ # cross-session Memory provider. Inspect the memory-bearing first statement:
34
+ # a later "For this turn reply ACK" only scopes the answer format.
35
+ _SESSION_RETENTION = re.compile(
36
+ r"\b(?:for|during|within|in)\s+(?:only\s+)?(?:this|the\s+current)\s+"
37
+ r"(?:conversation|chat|session|turn)\b"
38
+ r"|(?:本次|这次|此次|当前|这个|本)(?:会话|对话|聊天)"
39
+ r"|(?:本轮|这轮)",
40
+ re.IGNORECASE,
41
+ )
42
+
43
+
44
+ def _session_only_memory(text: str) -> bool:
45
+ statement = re.split(r"[。!?!?\r\n]|\.(?=\s|$)", text.strip(), maxsplit=1)[0]
46
+ return _SESSION_RETENTION.search(statement) is not None
47
+
48
+
28
49
  # 明确纠正同一偏好槽位。首期只覆盖语义边界清晰的动作型偏好,避免把
29
50
  # “喜欢音乐”和“喜欢运动”等无关事实误判为冲突。
30
51
  _PREFERENCE_CORRECTION = re.compile(
@@ -95,17 +116,44 @@ def derive_profile_slot_key(content: str) -> str:
95
116
  return f"profile.preference.{labels[action]}"
96
117
 
97
118
 
119
+ def is_explicit_memory_instruction(text: str) -> bool:
120
+ """Recognize a complete durable instruction, not a quoted substring.
121
+
122
+ Candidate extraction intentionally searches larger transcripts. A host
123
+ granting an immediate explicit write needs the narrower whole-input test.
124
+ Unsupported wording can use the host's exact-call consent path; this is
125
+ not a general semantic intent classifier.
126
+ """
127
+ text = text.strip()
128
+ if _session_only_memory(text):
129
+ return False
130
+ if any(pattern.fullmatch(text) for pattern in _EXPLICIT_PATTERNS):
131
+ return True
132
+ if _PREFERENCE_CORRECTION.fullmatch(text) or _GENERAL_CORRECTION.fullmatch(text):
133
+ return True
134
+ hobby = _HOBBY_DECLARATION.fullmatch(text)
135
+ return bool(hobby and hobby.group("correction"))
136
+
137
+
98
138
  def propose_memory_candidates(
99
139
  events: Sequence[any], # type: ignore[name-defined]
100
140
  *,
101
141
  scope: MemoryScope = "user",
102
142
  scope_id: str = "",
143
+ max_content_chars: int | None = 1000,
103
144
  ) -> list[MemoryCandidate]:
104
145
  """从待压缩事件提取记忆候选(方案 §9.2)。
105
146
 
106
147
  纯确定性、无 LLM。返回候选列表交 Coordinator flush;Policy 决定 commit/reject。
107
148
  """
108
149
  candidates: list[MemoryCandidate] = []
150
+ if max_content_chars is not None and (
151
+ type(max_content_chars) is not int or max_content_chars < 1
152
+ ):
153
+ raise ValueError("memory candidate limit must be a positive integer or None")
154
+
155
+ def bounded(content):
156
+ return content if max_content_chars is None else content[:max_content_chars]
109
157
  if not events:
110
158
  return candidates
111
159
  for event in events:
@@ -119,6 +167,8 @@ def propose_memory_candidates(
119
167
 
120
168
  # 1. 用户显式记忆意图
121
169
  if author == "user" or event_type == "user_message":
170
+ if _session_only_memory(text):
171
+ continue
122
172
  hobby = _HOBBY_DECLARATION.search(text)
123
173
  if hobby and hobby.group("correction"):
124
174
  new_value = hobby.group("value").strip().strip("。.,, ")
@@ -131,7 +181,7 @@ def propose_memory_candidates(
131
181
  memory_type="profile",
132
182
  scope=scope,
133
183
  scope_id=scope_id,
134
- content=content[:1000],
184
+ content=bounded(content),
135
185
  confidence=0.95,
136
186
  importance=0.9,
137
187
  source_event_ids=[event_id],
@@ -153,7 +203,7 @@ def propose_memory_candidates(
153
203
  memory_type="profile",
154
204
  scope=scope,
155
205
  scope_id=scope_id,
156
- content=content[:1000],
206
+ content=bounded(content),
157
207
  confidence=0.9,
158
208
  importance=0.8,
159
209
  source_event_ids=[event_id],
@@ -175,7 +225,7 @@ def propose_memory_candidates(
175
225
  memory_type="profile",
176
226
  scope=scope,
177
227
  scope_id=scope_id,
178
- content=content[:1000],
228
+ content=bounded(content),
179
229
  confidence=0.95,
180
230
  importance=0.9,
181
231
  source_event_ids=[event_id],
@@ -197,7 +247,7 @@ def propose_memory_candidates(
197
247
  memory_type="profile",
198
248
  scope=scope,
199
249
  scope_id=scope_id,
200
- content=content[:1000],
250
+ content=bounded(content),
201
251
  confidence=0.9,
202
252
  importance=0.8,
203
253
  source_event_ids=[event_id],
@@ -221,7 +271,7 @@ def propose_memory_candidates(
221
271
  memory_type="profile",
222
272
  scope=scope,
223
273
  scope_id=scope_id,
224
- content=content[:1000],
274
+ content=bounded(content),
225
275
  confidence=0.75,
226
276
  importance=0.65,
227
277
  source_event_ids=[event_id],
@@ -242,7 +292,7 @@ def propose_memory_candidates(
242
292
  memory_type="fact",
243
293
  scope=scope,
244
294
  scope_id=scope_id,
245
- content=text[:1000],
295
+ content=bounded(text),
246
296
  confidence=0.7,
247
297
  importance=0.6,
248
298
  source_event_ids=[event_id],
@@ -253,6 +303,65 @@ def propose_memory_candidates(
253
303
  return candidates
254
304
 
255
305
 
306
+ def explicit_memory_target(text: str) -> tuple[str, str] | None:
307
+ """Decode one whole explicit goal without truncating its requested fact.
308
+
309
+ This is a pure intent interpretation. The synthetic extraction input never
310
+ supplies persisted provenance or write authorization; those remain the
311
+ host's actual goal, approval and Run event identities.
312
+ """
313
+ if not is_explicit_memory_instruction(text):
314
+ return None
315
+ candidates = propose_memory_candidates(
316
+ (SimpleNamespace(text=text, author="user", event_type="user_message"),),
317
+ max_content_chars=None,
318
+ )
319
+ explicit = [candidate for candidate in candidates
320
+ if candidate.reason.startswith("explicit_user")]
321
+ if len(explicit) != 1:
322
+ return None
323
+ return explicit[0].operation, explicit[0].content
324
+
325
+
326
+ NATIVE_USER_EXTRACTION_POLICY = "native-original-user-profile/v2"
327
+
328
+
329
+ def native_user_memory_candidate(
330
+ text: str, *, source_event_id: str, scope: MemoryScope, scope_id: str,
331
+ ) -> MemoryCandidate | None:
332
+ """Interpret a complete original user statement, never a transcript substring.
333
+
334
+ The host must supply canonical user input and its durable source identity.
335
+ Confidence describes known user authorship, not the truth of a preference
336
+ or permission to persist it. The existing Policy still requires independent
337
+ observations for implicit declarations. No model/summary/tool text is admitted.
338
+ """
339
+ text = text.strip()
340
+ explicit = is_explicit_memory_instruction(text)
341
+ implicit = any(pattern.fullmatch(text) for pattern in _IMPLICIT_PREFERENCE_PATTERNS)
342
+ hobby = _HOBBY_DECLARATION.fullmatch(text)
343
+ if not source_event_id.strip() or not (explicit or implicit or hobby):
344
+ return None
345
+ proposed = propose_memory_candidates(
346
+ (SimpleNamespace(text=text, author="user", event_type="user_message"),),
347
+ scope=scope, scope_id=scope_id, max_content_chars=None,
348
+ )
349
+ if not proposed and hobby and not hobby.group("correction"):
350
+ proposed = [MemoryCandidate(
351
+ candidate_id="pending", operation="add", memory_type="profile", scope=scope,
352
+ scope_id=scope_id, content=f"我的爱好是{hobby.group('value').strip()}",
353
+ confidence=1, importance=0.65, source_event_ids=[source_event_id],
354
+ reason="implicit_user_preference", slot_key="profile.preference.hobby",
355
+ )]
356
+ if len(proposed) != 1 or (not explicit and proposed[0].reason != "implicit_user_preference"):
357
+ return None
358
+ value = proposed[0]
359
+ identity = json.dumps((NATIVE_USER_EXTRACTION_POLICY, scope, scope_id, source_event_id,
360
+ value.operation, value.content), ensure_ascii=False)
361
+ return replace(value, candidate_id="candidate_" + hashlib.sha256(identity.encode()).hexdigest(),
362
+ confidence=1, source_event_ids=[source_event_id])
363
+
364
+
256
365
  class MemoryExtractor:
257
366
  """方案 §9.2 的 ``MemoryExtractor.propose()`` 接口封装。"""
258
367
 
@@ -264,4 +373,8 @@ class MemoryExtractor:
264
373
  return propose_memory_candidates(events, scope=self._scope, scope_id=self._scope_id)
265
374
 
266
375
 
267
- __all__ = ["MemoryExtractor", "derive_profile_slot_key", "propose_memory_candidates"]
376
+ __all__ = [
377
+ "MemoryExtractor", "derive_profile_slot_key", "explicit_memory_target",
378
+ "is_explicit_memory_instruction", "propose_memory_candidates",
379
+ "native_user_memory_candidate", "NATIVE_USER_EXTRACTION_POLICY",
380
+ ]
@@ -0,0 +1,183 @@
1
+ """Local candidate consumption under the owning Provider's writer transaction.
2
+
3
+ No candidate body is retained while pending/rejected. Original source markers
4
+ outlive a forget so replay cannot count old prose as new evidence or resurrect it.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ import json
11
+ from dataclasses import replace
12
+
13
+ from ksadk.memory.extraction import NATIVE_USER_EXTRACTION_POLICY, derive_profile_slot_key
14
+ from ksadk.memory.models import MemoryRecord
15
+ from ksadk.memory.policy import MemoryPolicy, content_hash
16
+
17
+ from .local_sqlite import VersionConflict, _now_iso, _row_to_record
18
+
19
+
20
+ def namespace(tenant_id, workspace_id, scope, scope_id, memory_type):
21
+ identity = (tenant_id, None if scope == "org" else workspace_id, scope, scope_id, memory_type)
22
+ return hashlib.sha256(json.dumps(identity, ensure_ascii=False).encode()).hexdigest()
23
+
24
+
25
+ def discard_slot_observations(conn, record):
26
+ key = namespace(record.tenant_id, record.workspace_id, record.scope,
27
+ record.scope_id, record.memory_type)
28
+ slot = str(record.metadata.get("slot_key") or derive_profile_slot_key(record.content))
29
+ conn.execute(
30
+ "DELETE FROM memory_candidate_observations WHERE namespace=? "
31
+ "AND (content_hash=? OR (slot_key<>'' AND slot_key=?))",
32
+ (key, record.content_hash, slot),
33
+ )
34
+
35
+
36
+ def consume_explicit_write_horizon(conn, record, original, candidates):
37
+ """A confirmed write consumes earlier eligible inputs in its actual slot.
38
+
39
+ This is part of the same writer transaction as the fact and receipt. Keep only
40
+ original identities/digests, and preserve unrelated slots for later extraction.
41
+ """
42
+ targets = (original, record) if original is not None else (record,)
43
+ slots = {value for target in targets if (
44
+ value := target.metadata.get("slot_key") or derive_profile_slot_key(target.content)
45
+ )}
46
+ hashes = {target.content_hash for target in targets}
47
+ for candidate, source_digest in candidates:
48
+ if (candidate.scope, candidate.scope_id) != (record.scope, record.scope_id):
49
+ raise VersionConflict("candidate_write_horizon_scope_unbound")
50
+ if not (candidate.slot_key in slots or content_hash(candidate.content) in hashes):
51
+ continue
52
+ key = namespace(record.tenant_id, record.workspace_id, candidate.scope,
53
+ candidate.scope_id, candidate.memory_type)
54
+ for target in targets:
55
+ conn.execute(
56
+ "DELETE FROM memory_candidate_observations WHERE namespace=? "
57
+ "AND (content_hash=? OR (slot_key<>'' AND slot_key=?))",
58
+ (key, target.content_hash,
59
+ target.metadata.get("slot_key") or derive_profile_slot_key(target.content)),
60
+ )
61
+ source = candidate.source_event_ids[0]
62
+ previous = conn.execute(
63
+ "SELECT source_digest FROM memory_candidate_sources "
64
+ "WHERE namespace=? AND source_event_id=?", (key, source),
65
+ ).fetchone()
66
+ if previous is not None and previous["source_digest"] != source_digest:
67
+ raise VersionConflict("candidate_source_changed")
68
+ conn.execute("INSERT OR IGNORE INTO memory_candidate_sources VALUES (?,?,?)",
69
+ (key, source, source_digest))
70
+
71
+
72
+ def consume(provider, candidate, *, operation_key, request_digest, source_session_id,
73
+ source_digest, tenant_id, workspace_id):
74
+ # The caller holds the Provider lock and BEGIN IMMEDIATE. Fact, source,
75
+ # independent observations and receipt commit/roll back together.
76
+ prior = provider._mutation_receipt_locked(operation_key, request_digest)
77
+ if prior is not None:
78
+ return prior
79
+ if tenant_id != provider._tenant_id or len(candidate.source_event_ids) != 1:
80
+ raise VersionConflict("candidate_source_or_tenant_unbound")
81
+ conn, source = provider._conn, candidate.source_event_ids[0]
82
+ key = namespace(tenant_id, workspace_id, candidate.scope, candidate.scope_id,
83
+ candidate.memory_type)
84
+ fact_hash = content_hash(candidate.content)
85
+ fingerprint = hashlib.sha256(json.dumps(
86
+ (NATIVE_USER_EXTRACTION_POLICY, candidate.slot_key, fact_hash),
87
+ ).encode()).hexdigest()
88
+
89
+ def seal(decision, *, reason, observations=0, record=None, action=None):
90
+ result = {"committed": decision == "committed", "decision": decision,
91
+ "code": reason, "observations": observations}
92
+ if record is not None:
93
+ result.update(memory_id=record.memory_id, version=record.version,
94
+ status=record.status, content_hash=record.content_hash,
95
+ action=action)
96
+ conn.execute("INSERT INTO memory_operation_receipts VALUES (?,?,?)",
97
+ (operation_key, request_digest, json.dumps(result, ensure_ascii=False)))
98
+ return result
99
+
100
+ policy = MemoryPolicy()
101
+ early = policy.evaluate(candidate)
102
+ if early.decision == "reject":
103
+ return seal("rejected", reason=early.reason)
104
+ if len(candidate.content) > provider.capabilities().max_record_chars:
105
+ return seal("rejected", reason="candidate_content_over_budget")
106
+ original = conn.execute(
107
+ "SELECT source_digest FROM memory_candidate_sources "
108
+ "WHERE namespace=? AND source_event_id=?",
109
+ (key, source),
110
+ ).fetchone()
111
+ if original is not None:
112
+ if original["source_digest"] != source_digest:
113
+ raise VersionConflict("candidate_source_changed")
114
+ count = conn.execute(
115
+ "SELECT COUNT(*) FROM memory_candidate_observations "
116
+ "WHERE namespace=? AND candidate_key=?",
117
+ (key, fingerprint),
118
+ ).fetchone()[0]
119
+ return seal("duplicate_source", reason="original_source_already_consumed",
120
+ observations=count)
121
+
122
+ # Native writes have a slot key. For older records derive only the same
123
+ # deterministic slot inside the exact tenant/workspace/scope/type partition.
124
+ rows = conn.execute(
125
+ "SELECT * FROM memory_records WHERE tenant_id=? AND scope=? AND scope_id=? "
126
+ "AND memory_type=? AND status='active' "
127
+ "AND (scope='org' OR workspace_id=?)",
128
+ (tenant_id, candidate.scope, candidate.scope_id, candidate.memory_type, workspace_id),
129
+ ).fetchall()
130
+ matches = [record for row in rows if (
131
+ (record := _row_to_record(row)).content_hash == fact_hash
132
+ or bool(candidate.slot_key) and (
133
+ record.metadata.get("slot_key") or derive_profile_slot_key(record.content)
134
+ ) == candidate.slot_key
135
+ )]
136
+ if len(matches) > 1:
137
+ return seal("rejected", reason="candidate_slot_ambiguous")
138
+ existing = matches[0] if matches else None
139
+ if existing is not None and existing.write_policy == "locked":
140
+ return seal("rejected", reason="candidate_slot_locked")
141
+ if candidate.operation != "add" and existing is None:
142
+ return seal("rejected", reason="candidate_correction_target_missing")
143
+ conn.execute("INSERT INTO memory_candidate_sources VALUES (?,?,?)",
144
+ (key, source, source_digest))
145
+ conn.execute("INSERT INTO memory_candidate_observations VALUES (?,?,?,?,?,?)",
146
+ (key, fingerprint, source, fact_hash, candidate.slot_key, _now_iso()))
147
+ observed = conn.execute(
148
+ "SELECT source_event_id FROM memory_candidate_observations "
149
+ "WHERE namespace=? AND candidate_key=? ORDER BY source_event_id",
150
+ (key, fingerprint),
151
+ ).fetchall()
152
+ count = len(observed)
153
+ effective = replace(candidate, operation="update") if existing else candidate
154
+ evaluated = policy.evaluate(effective, existing=existing, observations=count)
155
+ if evaluated.decision != "commit":
156
+ return seal(evaluated.decision, reason=evaluated.reason, observations=count)
157
+ if existing is not None and existing.content_hash == fact_hash:
158
+ return seal("duplicate", reason="same_current_fact", observations=count, record=existing)
159
+ from uuid import uuid4
160
+
161
+ record = MemoryRecord(
162
+ memory_id=existing.memory_id if existing else "memory_" + uuid4().hex,
163
+ tenant_id=tenant_id, workspace_id=workspace_id, scope=candidate.scope,
164
+ scope_id=candidate.scope_id, memory_type=candidate.memory_type,
165
+ content=candidate.content, summary=candidate.content, status="active",
166
+ confidence=candidate.confidence, importance=candidate.importance,
167
+ valid_from=existing.valid_from if existing else _now_iso(), valid_to="",
168
+ expires_at=candidate.expires_at,
169
+ source_session_id=existing.source_session_id if existing else source_session_id,
170
+ source_event_ids=list(dict.fromkeys((
171
+ *(existing.source_event_ids if existing else ()),
172
+ *(row["source_event_id"] for row in observed),
173
+ ))), source_seq_range=None, content_hash=fact_hash, version=1,
174
+ metadata={**(existing.metadata if existing else {}),
175
+ "slot_key": candidate.slot_key,
176
+ "extraction_policy": NATIVE_USER_EXTRACTION_POLICY,
177
+ "mutation_session_id": source_session_id, "source_input_digest": source_digest},
178
+ write_policy=existing.write_policy if existing else
179
+ "user_confirm" if candidate.reason.startswith("explicit_user") else "auto",
180
+ )
181
+ saved = provider._upsert_locked(record, expected_version=existing.version if existing else None)
182
+ return seal("committed", reason=evaluated.reason, observations=count, record=saved,
183
+ action="correct" if existing else "remember")