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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (851) hide show
  1. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/METADATA +12 -8
  2. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/RECORD +823 -388
  3. ksadk/_async_iterators.py +79 -0
  4. ksadk/_build_provenance.json +1 -1
  5. ksadk/_model_anthropic.py +49 -0
  6. ksadk/_model_input.py +86 -0
  7. ksadk/_model_json.py +40 -0
  8. ksadk/_model_reasoning.py +17 -0
  9. ksadk/_model_refusal.py +20 -0
  10. ksadk/_model_sse.py +163 -0
  11. ksadk/a2a/__init__.py +157 -167
  12. ksadk/a2a/_invocation_state.py +86 -0
  13. ksadk/a2a/_space_client_events.py +33 -22
  14. ksadk/a2a/adk.py +194 -0
  15. ksadk/a2a/adk_invocation_context.py +242 -0
  16. ksadk/a2a/adk_runtime.py +126 -0
  17. ksadk/a2a/adk_tools.py +319 -0
  18. ksadk/a2a/bootstrap.py +149 -23
  19. ksadk/a2a/build_validation.py +147 -0
  20. ksadk/a2a/card.py +23 -15
  21. ksadk/a2a/codex.py +160 -0
  22. ksadk/a2a/codex_checkpoint.py +111 -0
  23. ksadk/a2a/codex_recovery.py +96 -0
  24. ksadk/a2a/codex_recovery_events.py +123 -0
  25. ksadk/a2a/codex_runtime.py +198 -0
  26. ksadk/a2a/codex_session_checkpoint.py +162 -0
  27. ksadk/a2a/composition.py +88 -0
  28. ksadk/a2a/context_store.py +118 -19
  29. ksadk/a2a/control_plane.py +108 -106
  30. ksadk/a2a/event_adapter.py +92 -193
  31. ksadk/a2a/executor.py +257 -85
  32. ksadk/a2a/exposure.py +106 -0
  33. ksadk/a2a/external_transport.py +3 -4
  34. ksadk/a2a/identity.py +106 -12
  35. ksadk/a2a/ids.py +14 -3
  36. ksadk/a2a/inbound_kernel.py +133 -0
  37. ksadk/a2a/interaction_wire.py +76 -0
  38. ksadk/a2a/invocation_checkpoint.py +274 -0
  39. ksadk/a2a/invocation_policy.py +87 -0
  40. ksadk/a2a/invocation_publication.py +210 -0
  41. ksadk/a2a/invocation_service.py +972 -0
  42. ksadk/a2a/invocation_types.py +459 -0
  43. ksadk/a2a/kernel_task_adapter.py +259 -0
  44. ksadk/a2a/langgraph.py +20 -7
  45. ksadk/a2a/langgraph_invocation_context.py +136 -0
  46. ksadk/a2a/langgraph_managed.py +150 -0
  47. ksadk/a2a/langgraph_recovery.py +32 -0
  48. ksadk/a2a/langgraph_runtime.py +89 -0
  49. ksadk/a2a/langgraph_tool_runtime.py +132 -0
  50. ksadk/a2a/langgraph_tools.py +63 -0
  51. ksadk/a2a/message_digest.py +40 -0
  52. ksadk/a2a/platform.py +389 -0
  53. ksadk/a2a/policy_refs.py +13 -0
  54. ksadk/a2a/presentation.py +402 -0
  55. ksadk/a2a/product_kernel_facts.py +177 -0
  56. ksadk/a2a/product_key.py +99 -0
  57. ksadk/a2a/protocol_errors.py +116 -0
  58. ksadk/a2a/result_text.py +49 -0
  59. ksadk/a2a/resume_store.py +93 -3
  60. ksadk/a2a/routes.py +6 -1
  61. ksadk/a2a/runtime_approval.py +198 -0
  62. ksadk/a2a/runtime_input.py +151 -0
  63. ksadk/a2a/server.py +16 -7
  64. ksadk/a2a/space_client.py +101 -16
  65. ksadk/a2a/task_adapter.py +19 -5
  66. ksadk/a2a/task_event_dispatcher.py +39 -2
  67. ksadk/a2a/task_event_outbox.py +215 -0
  68. ksadk/a2a/task_event_outbox_owned.py +130 -0
  69. ksadk/a2a/task_store.py +37 -0
  70. ksadk/a2a/tool_activity.py +176 -0
  71. ksadk/a2a/workload_tokens.py +134 -0
  72. ksadk/api/client.py +32 -79
  73. ksadk/api/sse_stream.py +96 -0
  74. ksadk/builders/code_builder.py +83 -106
  75. ksadk/builders/container_builder.py +11 -29
  76. ksadk/builders/framework_requirements.py +2 -0
  77. ksadk/builders/managed_runtime_builder.py +12 -0
  78. ksadk/builders/source_provenance.py +87 -0
  79. ksadk/cli/cmd_a2a.py +43 -0
  80. ksadk/cli/cmd_build.py +9 -0
  81. ksadk/cli/cmd_deploy.py +27 -2
  82. ksadk/cli/cmd_invoke.py +45 -92
  83. ksadk/cli/cmd_studio.py +5 -1
  84. ksadk/cli/cmd_web.py +2 -0
  85. ksadk/cli/hosted_invoke.py +206 -0
  86. ksadk/cli/invoke_content.py +60 -0
  87. ksadk/cli/runtime_bootstrap.py +27 -5
  88. ksadk/codex/_expert_request_reader.py +48 -0
  89. ksadk/codex/a2a_tools.py +140 -0
  90. ksadk/codex/async_approval.py +169 -0
  91. ksadk/codex/async_client.py +938 -0
  92. ksadk/codex/async_proxy.py +216 -0
  93. ksadk/codex/base_runtime.py +25 -0
  94. ksadk/codex/client.py +3 -1048
  95. ksadk/codex/client_payloads.py +85 -0
  96. ksadk/codex/rollout_checkpoint.py +264 -0
  97. ksadk/codex/runtime.py +290 -54
  98. ksadk/common/auth.py +2 -2
  99. ksadk/common/cloud_headers.py +36 -0
  100. ksadk/common/diagnostics.py +34 -0
  101. ksadk/common/kop_client.py +2 -1
  102. ksadk/configs/env_registry.py +106 -127
  103. ksadk/configs/env_registry_a2a.py +173 -0
  104. ksadk/configs/env_registry_studio.py +53 -5
  105. ksadk/configs/global_config.py +1 -0
  106. ksadk/configs/settings.py +6 -0
  107. ksadk/context_engine/assembler.py +9 -0
  108. ksadk/context_engine/contributors.py +80 -17
  109. ksadk/context_engine/instruction_authority.py +18 -0
  110. ksadk/conversations/attachments.py +53 -15
  111. ksadk/conversations/contracts.py +28 -9
  112. ksadk/conversations/message_projection.py +30 -125
  113. ksadk/conversations/message_projection_blocks.py +137 -0
  114. ksadk/conversations/model_context.py +11 -3
  115. ksadk/conversations/projector.py +63 -0
  116. ksadk/conversations/runtime_compaction.py +7 -2
  117. ksadk/conversations/runtime_input.py +16 -4
  118. ksadk/conversations/runtime_payloads.py +4 -0
  119. ksadk/conversations/runtime_persistence.py +192 -24
  120. ksadk/conversations/runtime_preparation.py +85 -6
  121. ksadk/conversations/runtime_projection.py +217 -0
  122. ksadk/conversations/runtime_resume.py +141 -70
  123. ksadk/conversations/tool_receipt_resume.py +387 -0
  124. ksadk/conversations/tool_receipts.py +32 -0
  125. ksadk/deployment/env_forward.py +5 -0
  126. ksadk/deployment/manager.py +15 -6
  127. ksadk/deployment/providers/serverless.py +76 -136
  128. ksadk/deployment/providers/serverless_payloads.py +122 -0
  129. ksadk/evaluation/agent_eval_client.py +2 -1
  130. ksadk/evaluation/contracts.py +78 -3
  131. ksadk/evaluation/evaluators.py +166 -1
  132. ksadk/evaluation/evidence.py +271 -4
  133. ksadk/evaluation/local_adapter.py +76 -12
  134. ksadk/evaluation/studio_build_adapter.py +73 -9
  135. ksadk/events/adapters/_a2a_checkpoint.py +151 -0
  136. ksadk/events/adapters/_a2a_snapshot.py +18 -14
  137. ksadk/events/adapters/_a2a_support.py +15 -3
  138. ksadk/events/adapters/_a2a_tool_activity.py +123 -0
  139. ksadk/events/adapters/_codex_errors.py +49 -0
  140. ksadk/events/adapters/_langgraph_support.py +12 -1
  141. ksadk/events/adapters/a2a.py +54 -26
  142. ksadk/events/adapters/adk.py +188 -30
  143. ksadk/events/adapters/codex.py +33 -7
  144. ksadk/events/adapters/langgraph.py +16 -6
  145. ksadk/events/canonical.py +5 -0
  146. ksadk/events/canonical_store.py +200 -4
  147. ksadk/events/reducer.py +82 -0
  148. ksadk/events/run_authority.py +176 -0
  149. ksadk/harness/__init__.py +4 -0
  150. ksadk/harness/artifact_adapters/__init__.py +1 -0
  151. ksadk/harness/artifact_adapters/native_page_budget.py +172 -0
  152. ksadk/harness/artifact_adapters/native_search.py +249 -0
  153. ksadk/harness/artifact_adapters/native_search_budget.py +134 -0
  154. ksadk/harness/artifact_adapters/native_store.py +115 -0
  155. ksadk/harness/artifact_adapters/native_tool.py +222 -0
  156. ksadk/harness/artifact_store.py +26 -9
  157. ksadk/harness/browser_adapters/__init__.py +6 -0
  158. ksadk/harness/browser_adapters/native_browser_tool.py +92 -0
  159. ksadk/harness/browser_adapters/native_dom_snapshot.py +187 -0
  160. ksadk/harness/browser_adapters/native_playwright.py +953 -0
  161. ksadk/harness/browser_adapters/native_vision.py +295 -0
  162. ksadk/harness/capability_adapters/__init__.py +1 -0
  163. ksadk/harness/capability_adapters/native_dsh.py +289 -0
  164. ksadk/harness/capability_runtime.py +104 -9
  165. ksadk/harness/compaction_record.py +31 -0
  166. ksadk/harness/compiler.py +3 -3
  167. ksadk/harness/config.py +28 -5
  168. ksadk/harness/conformance/contract.py +9 -11
  169. ksadk/harness/context_engine.py +18 -33
  170. ksadk/harness/context_sections.py +397 -0
  171. ksadk/harness/diagnostic_adapters/__init__.py +1 -0
  172. ksadk/harness/diagnostic_adapters/contracts.py +70 -0
  173. ksadk/harness/diagnostic_adapters/lsp_rpc.py +210 -0
  174. ksadk/harness/diagnostic_adapters/native_lsp.py +286 -0
  175. ksadk/harness/engine/completion_guard.py +16 -1
  176. ksadk/harness/engine/context_pipeline.py +864 -92
  177. ksadk/harness/engine/graph_builder.py +123 -630
  178. ksadk/harness/engine/hooked_reasoner.py +380 -0
  179. ksadk/harness/engine/langgraph.py +126 -8
  180. ksadk/harness/engine/mcp_disclosure.py +65 -114
  181. ksadk/harness/engine/phases/__init__.py +6 -0
  182. ksadk/harness/engine/phases/context.py +48 -0
  183. ksadk/harness/engine/phases/interaction.py +31 -0
  184. ksadk/harness/engine/phases/reason.py +552 -0
  185. ksadk/harness/engine/phases/tools.py +638 -0
  186. ksadk/harness/engine/policy_runtime.py +21 -10
  187. ksadk/harness/engine/postgres_checkpointer.py +325 -2
  188. ksadk/harness/engine/run_control_bridge.py +21 -1
  189. ksadk/harness/engine/run_types.py +10 -0
  190. ksadk/harness/engine/skill_disclosure.py +98 -12
  191. ksadk/harness/engine/steering.py +177 -0
  192. ksadk/harness/engine/subagents.py +18 -1
  193. ksadk/harness/engine/tool_dispatch.py +112 -7
  194. ksadk/harness/events.py +39 -2
  195. ksadk/harness/execution_policy.py +10 -0
  196. ksadk/harness/hooks.py +259 -0
  197. ksadk/harness/loop/reason.py +281 -36
  198. ksadk/harness/loop/tools.py +157 -12
  199. ksadk/harness/managed_runtime.py +254 -94
  200. ksadk/harness/mcp_disclosure_contract.py +85 -0
  201. ksadk/harness/mcp_result_policy.py +44 -0
  202. ksadk/harness/mcp_runtime.py +33 -0
  203. ksadk/harness/micro_compact.py +69 -0
  204. ksadk/harness/model_adapters/__init__.py +1 -0
  205. ksadk/harness/model_adapters/native_mcp_media.py +100 -0
  206. ksadk/harness/model_adapters/native_mcp_result.py +36 -0
  207. ksadk/harness/model_adapters/native_openai.py +703 -0
  208. ksadk/harness/model_capability.py +223 -8
  209. ksadk/harness/model_provider.py +214 -4
  210. ksadk/harness/multimodal.py +57 -0
  211. ksadk/harness/native/__init__.py +1 -0
  212. ksadk/harness/native/activation_contract.py +25 -0
  213. ksadk/harness/native/activation_recovery.py +29 -0
  214. ksadk/harness/native/adapters.py +291 -0
  215. ksadk/harness/native/artifact_contract.py +14 -0
  216. ksadk/harness/native/artifact_partial_read_capacity.py +171 -0
  217. ksadk/harness/native/artifact_read_capacity.py +182 -0
  218. ksadk/harness/native/artifact_read_contract.py +27 -0
  219. ksadk/harness/native/artifact_runtime.py +408 -0
  220. ksadk/harness/native/artifact_search_capacity.py +206 -0
  221. ksadk/harness/native/artifact_search_contract.py +40 -0
  222. ksadk/harness/native/artifact_single_read_capacity.py +170 -0
  223. ksadk/harness/native/browser_contract.py +229 -0
  224. ksadk/harness/native/browser_recovery.py +183 -0
  225. ksadk/harness/native/capabilities.py +204 -0
  226. ksadk/harness/native/child_approval.py +60 -0
  227. ksadk/harness/native/child_budget.py +136 -0
  228. ksadk/harness/native/child_cancellation.py +80 -0
  229. ksadk/harness/native/child_input.py +98 -0
  230. ksadk/harness/native/child_input_runtime.py +59 -0
  231. ksadk/harness/native/child_interruption.py +81 -0
  232. ksadk/harness/native/child_lifecycle.py +246 -0
  233. ksadk/harness/native/child_lifecycle_contract.py +91 -0
  234. ksadk/harness/native/child_notifications.py +75 -0
  235. ksadk/harness/native/child_promotion.py +66 -0
  236. ksadk/harness/native/command_runtime.py +99 -0
  237. ksadk/harness/native/completion.py +302 -0
  238. ksadk/harness/native/completion_text.py +116 -0
  239. ksadk/harness/native/context.py +358 -0
  240. ksadk/harness/native/context_artifact_page.py +75 -0
  241. ksadk/harness/native/context_compaction_projection.py +131 -0
  242. ksadk/harness/native/context_contributions.py +320 -0
  243. ksadk/harness/native/context_contributor_contract.py +133 -0
  244. ksadk/harness/native/context_driver.py +820 -0
  245. ksadk/harness/native/context_fresh_tools.py +49 -0
  246. ksadk/harness/native/context_history.py +272 -0
  247. ksadk/harness/native/context_microcompact.py +61 -0
  248. ksadk/harness/native/context_partial_summary.py +58 -0
  249. ksadk/harness/native/context_partition.py +492 -0
  250. ksadk/harness/native/context_pruning.py +275 -0
  251. ksadk/harness/native/context_reduction.py +60 -0
  252. ksadk/harness/native/context_replay.py +148 -0
  253. ksadk/harness/native/context_request_projection.py +526 -0
  254. ksadk/harness/native/context_runtime.py +976 -0
  255. ksadk/harness/native/context_runtime_contracts.py +409 -0
  256. ksadk/harness/native/context_search.py +112 -0
  257. ksadk/harness/native/context_source_fragments.py +188 -0
  258. ksadk/harness/native/context_source_progress.py +119 -0
  259. ksadk/harness/native/context_summary_planning.py +788 -0
  260. ksadk/harness/native/context_summary_recovery.py +105 -0
  261. ksadk/harness/native/delivery_review.py +331 -0
  262. ksadk/harness/native/delivery_review_contract.py +54 -0
  263. ksadk/harness/native/effect_admission.py +82 -0
  264. ksadk/harness/native/effect_control.py +318 -0
  265. ksadk/harness/native/effect_receipts.py +729 -0
  266. ksadk/harness/native/effect_runtime.py +303 -0
  267. ksadk/harness/native/effective_configuration.py +28 -0
  268. ksadk/harness/native/engine.py +945 -0
  269. ksadk/harness/native/final_output.py +34 -0
  270. ksadk/harness/native/final_submission.py +58 -0
  271. ksadk/harness/native/finalization_workspace.py +96 -0
  272. ksadk/harness/native/fork.py +151 -0
  273. ksadk/harness/native/guidance.py +91 -0
  274. ksadk/harness/native/history.py +381 -0
  275. ksadk/harness/native/hook_executor.py +205 -0
  276. ksadk/harness/native/hook_runtime_contract.py +282 -0
  277. ksadk/harness/native/interaction_observation.py +117 -0
  278. ksadk/harness/native/lease.py +103 -0
  279. ksadk/harness/native/machine.py +974 -0
  280. ksadk/harness/native/mcp_result_governance.py +156 -0
  281. ksadk/harness/native/model.py +570 -0
  282. ksadk/harness/native/model_feedback.py +63 -0
  283. ksadk/harness/native/model_input.py +30 -0
  284. ksadk/harness/native/model_recovery_contract.py +35 -0
  285. ksadk/harness/native/model_replay.py +128 -0
  286. ksadk/harness/native/model_request.py +133 -0
  287. ksadk/harness/native/model_runtime.py +196 -0
  288. ksadk/harness/native/model_takeover.py +419 -0
  289. ksadk/harness/native/model_tool_batch.py +40 -0
  290. ksadk/harness/native/observed_progress.py +46 -0
  291. ksadk/harness/native/operator_guidance.py +201 -0
  292. ksadk/harness/native/output_contract.py +80 -0
  293. ksadk/harness/native/output_recovery.py +24 -0
  294. ksadk/harness/native/ports.py +749 -0
  295. ksadk/harness/native/precompact_hook_runtime.py +171 -0
  296. ksadk/harness/native/replay_context.py +149 -0
  297. ksadk/harness/native/request_media.py +112 -0
  298. ksadk/harness/native/restore_contract.py +16 -0
  299. ksadk/harness/native/run_clock.py +120 -0
  300. ksadk/harness/native/state.py +436 -0
  301. ksadk/harness/native/steering.py +170 -0
  302. ksadk/harness/native/stop_hook_runtime.py +151 -0
  303. ksadk/harness/native/studio_admission.py +29 -0
  304. ksadk/harness/native/subagents.py +86 -0
  305. ksadk/harness/native/task_policy.py +99 -0
  306. ksadk/harness/native/task_progress.py +86 -0
  307. ksadk/harness/native/terminal_verification.py +43 -0
  308. ksadk/harness/native/tool_argument_feedback.py +178 -0
  309. ksadk/harness/native/tool_budget.py +253 -0
  310. ksadk/harness/native/tool_error_streak.py +89 -0
  311. ksadk/harness/native/tool_hook_runtime.py +343 -0
  312. ksadk/harness/native/tool_input_validation.py +58 -0
  313. ksadk/harness/native/tool_interruption.py +96 -0
  314. ksadk/harness/native/tool_observation.py +259 -0
  315. ksadk/harness/native/tool_progress.py +223 -0
  316. ksadk/harness/native/tool_recovery.py +25 -0
  317. ksadk/harness/native/tool_scheduling.py +33 -0
  318. ksadk/harness/native/tool_schema.py +126 -0
  319. ksadk/harness/native/transitions.py +151 -0
  320. ksadk/harness/native/turn_control.py +98 -0
  321. ksadk/harness/native/user_document.py +98 -0
  322. ksadk/harness/native/user_document_capture.py +49 -0
  323. ksadk/harness/native/user_input.py +87 -0
  324. ksadk/harness/native/verification.py +432 -0
  325. ksadk/harness/native/verification_binding.py +40 -0
  326. ksadk/harness/native/verification_runtime.py +233 -0
  327. ksadk/harness/native/verification_workspace.py +67 -0
  328. ksadk/harness/native_driver_failure.py +123 -0
  329. ksadk/harness/native_facade.py +977 -0
  330. ksadk/harness/native_factory.py +244 -0
  331. ksadk/harness/native_projection.py +503 -0
  332. ksadk/harness/native_runtime.py +621 -0
  333. ksadk/harness/native_shadow.py +250 -0
  334. ksadk/harness/native_shadow_inputs.py +146 -0
  335. ksadk/harness/progress_adapters/__init__.py +5 -0
  336. ksadk/harness/progress_adapters/native_todo.py +75 -0
  337. ksadk/harness/prompt_cache.py +65 -3
  338. ksadk/harness/public_activity.py +59 -0
  339. ksadk/harness/public_output.py +30 -0
  340. ksadk/harness/public_summary.py +36 -0
  341. ksadk/harness/reasoner.py +331 -22
  342. ksadk/harness/rpc.py +200 -0
  343. ksadk/harness/run_control.py +107 -2
  344. ksadk/harness/runtime.py +11 -2
  345. ksadk/harness/runtime_capabilities.py +71 -1
  346. ksadk/harness/sandbox_backend.py +203 -0
  347. ksadk/harness/sdk.py +153 -0
  348. ksadk/harness/session_store.py +370 -24
  349. ksadk/harness/skill_adapters/__init__.py +1 -0
  350. ksadk/harness/skill_adapters/native_bundle.py +148 -0
  351. ksadk/harness/skill_adapters/native_disclosure.py +306 -0
  352. ksadk/harness/skill_intent.py +47 -0
  353. ksadk/harness/skill_runtime.py +74 -16
  354. ksadk/harness/spec.py +20 -10
  355. ksadk/harness/state.py +2 -0
  356. ksadk/harness/stores/__init__.py +14 -0
  357. ksadk/harness/stores/native_command_settlement.py +65 -0
  358. ksadk/harness/stores/native_contract.py +311 -0
  359. ksadk/harness/stores/native_memory.py +326 -0
  360. ksadk/harness/stores/native_memory_archive.py +70 -0
  361. ksadk/harness/stores/native_migration_cli.py +91 -0
  362. ksadk/harness/stores/native_outbox.py +56 -0
  363. ksadk/harness/stores/native_sqlite.py +782 -0
  364. ksadk/harness/stores/native_sqlite_audit.py +29 -0
  365. ksadk/harness/stores/native_sqlite_migration.py +252 -0
  366. ksadk/harness/subagent.py +12 -2
  367. ksadk/harness/subagent_adapters/checkpoint_recovery.py +120 -0
  368. ksadk/harness/subagent_adapters/native_background_child.py +803 -0
  369. ksadk/harness/subagent_adapters/native_child.py +819 -0
  370. ksadk/harness/subagent_adapters/native_child_approval.py +128 -0
  371. ksadk/harness/subagent_adapters/native_child_continuation.py +51 -0
  372. ksadk/harness/subagent_adapters/native_child_result.py +392 -0
  373. ksadk/harness/subagent_adapters/prepared_recovery.py +120 -0
  374. ksadk/harness/tool_display.py +75 -0
  375. ksadk/harness/tool_display_contract.py +134 -0
  376. ksadk/harness/tool_output.py +141 -0
  377. ksadk/harness/tool_policy.py +3 -0
  378. ksadk/harness/tool_result_policy.py +216 -0
  379. ksadk/harness/tools.py +52 -0
  380. ksadk/harness/workspace_adapters/__init__.py +6 -0
  381. ksadk/harness/workspace_adapters/native_directory.py +180 -0
  382. ksadk/harness/workspace_adapters/native_git.py +208 -0
  383. ksadk/harness/workspace_adapters/native_isolation.py +350 -0
  384. ksadk/interaction/providers/langgraph.py +8 -1
  385. ksadk/kernel/bootstrap.py +144 -160
  386. ksadk/kernel/contract_fingerprints.py +45 -1
  387. ksadk/kernel/contracts.py +25 -0
  388. ksadk/kernel/control.py +153 -33
  389. ksadk/kernel/execution_grants.py +209 -2
  390. ksadk/kernel/execution_grants_memory.py +127 -8
  391. ksadk/kernel/execution_grants_postgres.py +188 -10
  392. ksadk/kernel/execution_grants_sqlite.py +235 -9
  393. ksadk/kernel/execution_host_ingress.py +1071 -0
  394. ksadk/kernel/history_projection.py +120 -0
  395. ksadk/kernel/ingress.py +117 -204
  396. ksadk/kernel/ingress_bootstrap.py +268 -0
  397. ksadk/kernel/legacy_history.py +179 -0
  398. ksadk/kernel/memory_store.py +38 -48
  399. ksadk/kernel/memory_store_projection.py +63 -0
  400. ksadk/kernel/postgres_event_log.py +181 -0
  401. ksadk/kernel/postgres_store.py +167 -198
  402. ksadk/kernel/readiness.py +125 -0
  403. ksadk/kernel/recovery.py +89 -3
  404. ksadk/kernel/recovery_projection.py +124 -0
  405. ksadk/kernel/runtime_checkpoint.py +34 -0
  406. ksadk/kernel/sql/001_agent_kernel.sql +5 -0
  407. ksadk/kernel/sqlite_schema.py +100 -0
  408. ksadk/kernel/sqlite_store.py +147 -216
  409. ksadk/kernel/store.py +47 -15
  410. ksadk/kernel/teams_artifact_tools.py +392 -0
  411. ksadk/kernel/teams_effects.py +851 -0
  412. ksadk/kernel/teams_execution_context.py +408 -0
  413. ksadk/kernel/teams_host_http.py +237 -0
  414. ksadk/kernel/teams_material_transport.py +245 -0
  415. ksadk/kernel/teams_materials.py +318 -0
  416. ksadk/kernel/teams_runtime_bootstrap.py +604 -0
  417. ksadk/kernel/teams_tool_runtime.py +273 -0
  418. ksadk/kernel/teams_workspace.py +259 -0
  419. ksadk/kernel/worker.py +323 -332
  420. ksadk/kernel/worker_controls.py +454 -0
  421. ksadk/kernel/worker_identity.py +27 -0
  422. ksadk/kernel/worker_interactions.py +197 -0
  423. ksadk/knowledge_base/client.py +15 -1
  424. ksadk/managed_runtime.py +29 -2
  425. ksadk/memory/adk/backends/http_ltm_backend.py +2 -1
  426. ksadk/memory/adk/backends/sdk_ltm_backend.py +15 -1
  427. ksadk/memory/adk/bounded_database_session_service.py +232 -0
  428. ksadk/memory/adk/resilient_session_service.py +115 -15
  429. ksadk/memory/adk/short_term_memory.py +8 -9
  430. ksadk/memory/extraction.py +120 -7
  431. ksadk/memory/providers/local_candidates.py +183 -0
  432. ksadk/memory/providers/local_sqlite.py +252 -78
  433. ksadk/memory/resolved_policy.py +12 -7
  434. ksadk/model_gateway/__init__.py +29 -0
  435. ksadk/model_gateway/client.py +253 -0
  436. ksadk/model_gateway/events.py +113 -0
  437. ksadk/model_gateway/matrix.py +297 -0
  438. ksadk/model_proxy/compat.py +670 -0
  439. ksadk/model_proxy/server.py +10 -7
  440. ksadk/model_proxy/transform.py +37 -9
  441. ksadk/plugins/bridges/dsh.py +18 -20
  442. ksadk/plugins/bridges/dsh_profile_manifest.py +36 -0
  443. ksadk/plugins/builtin_resources.py +199 -0
  444. ksadk/plugins/builtins.py +380 -186
  445. ksadk/plugins/context_contributor.py +15 -4
  446. ksadk/plugins/dsh_dependency_policy.py +41 -0
  447. ksadk/plugins/dsh_toolchain.py +24 -35
  448. ksadk/plugins/execution_host.py +8 -0
  449. ksadk/plugins/host.py +73 -5
  450. ksadk/plugins/kernel_adapter.py +44 -1
  451. ksadk/plugins/memory_provider.py +180 -0
  452. ksadk/plugins/providers/_process_group.py +50 -0
  453. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +24 -2
  454. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +1 -1
  455. ksadk/plugins/providers/bundles/dsh-memory/package.json +1 -1
  456. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +1 -1
  457. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +1 -1
  458. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +1 -1
  459. ksadk/plugins/providers/codex.py +42 -38
  460. ksadk/plugins/providers/codex_native.py +20 -0
  461. ksadk/plugins/providers/codex_skills.py +46 -0
  462. ksadk/plugins/providers/dsh_capabilities.py +16 -171
  463. ksadk/plugins/providers/dsh_connector_lease.py +225 -0
  464. ksadk/plugins/providers/dsh_mcp.py +163 -1
  465. ksadk/plugins/providers/harness.py +247 -34
  466. ksadk/plugins/providers/harness_context.py +61 -0
  467. ksadk/plugins/providers/harness_contributions.py +241 -0
  468. ksadk/plugins/providers/harness_delegation.py +91 -14
  469. ksadk/plugins/providers/harness_hooks.py +121 -0
  470. ksadk/plugins/providers/harness_managed.py +269 -175
  471. ksadk/plugins/providers/harness_tools.py +165 -36
  472. ksadk/plugins/providers/legacy_catalog.py +1 -1
  473. ksadk/plugins/providers/mcp_projection.py +100 -3
  474. ksadk/plugins/providers/platform_resources.py +16 -6
  475. ksadk/plugins/teams/application.py +3 -143
  476. ksadk/plugins/teams/build_artifacts.py +460 -0
  477. ksadk/plugins/teams/cloud_contract_fingerprints.py +22 -0
  478. ksadk/plugins/teams/cloud_contracts.py +928 -0
  479. ksadk/plugins/teams/cloud_permits.py +250 -0
  480. ksadk/plugins/teams/domain.py +201 -148
  481. ksadk/plugins/teams/effect_contracts.py +255 -0
  482. ksadk/plugins/teams/execution_projection.py +255 -0
  483. ksadk/plugins/teams/leader_decisions.py +106 -0
  484. ksadk/plugins/teams/postgres_store.py +299 -85
  485. ksadk/plugins/teams/release_contracts.py +60 -0
  486. ksadk/plugins/teams/runtime.py +116 -40
  487. ksadk/plugins/teams/store.py +214 -6
  488. ksadk/plugins/teams/task_decisions.py +21 -8
  489. ksadk/plugins/teams/tool_service.py +152 -0
  490. ksadk/plugins/teams/transport.py +8 -3
  491. ksadk/resource_runtime/skill_runtime.py +3 -0
  492. ksadk/resource_runtime/socket_server.py +11 -0
  493. ksadk/resource_runtime/worker.py +28 -4
  494. ksadk/runners/_adk_a2a_stream.py +122 -0
  495. ksadk/runners/_adk_canonical_stream.py +474 -0
  496. ksadk/runners/_langgraph_canonical_streams.py +527 -0
  497. ksadk/runners/_langgraph_runner_streams.py +6 -400
  498. ksadk/runners/_langgraph_tool_projection.py +86 -0
  499. ksadk/runners/_langgraph_tools_transformer.py +27 -0
  500. ksadk/runners/adk_runner.py +195 -290
  501. ksadk/runners/base_runner.py +6 -5
  502. ksadk/runners/langgraph_runner.py +82 -86
  503. ksadk/runners/utils/loader.py +28 -14
  504. ksadk/runtime/_runner_adapter/a2ui_surface.py +145 -0
  505. ksadk/runtime/_runner_adapter/gateway_approvals.py +93 -0
  506. ksadk/runtime/_runner_adapter/stream_mapping.py +83 -128
  507. ksadk/runtime/adapter.py +40 -3
  508. ksadk/runtime/conversation_execution.py +4 -2
  509. ksadk/runtime/executor.py +97 -7
  510. ksadk/runtime/factory.py +13 -6
  511. ksadk/runtime/framework_adapters.py +184 -10
  512. ksadk/runtime/hosted_finalizer.py +4 -6
  513. ksadk/runtime/launch.py +2 -0
  514. ksadk/runtime/runner_adapter.py +123 -13
  515. ksadk/runtime_context.py +2 -0
  516. ksadk/sandbox/backends/e2b.py +30 -4
  517. ksadk/sandbox/backends/local_process.py +10 -0
  518. ksadk/sandbox/e2b_connection.py +9 -1
  519. ksadk/sandbox/local_controls.py +32 -2
  520. ksadk/sandbox/local_launcher.py +34 -0
  521. ksadk/server/factory.py +178 -25
  522. ksadk/server/history_deadline.py +158 -0
  523. ksadk/server/history_page_cache.py +129 -0
  524. ksadk/server/routes/checkpoint_audit.py +88 -0
  525. ksadk/server/routes/checkpoint_listing.py +294 -0
  526. ksadk/server/routes/checkpoint_resolution.py +73 -20
  527. ksadk/server/routes/control.py +51 -3
  528. ksadk/server/routes/display_projection.py +154 -0
  529. ksadk/server/routes/kernel_ingress.py +17 -2
  530. ksadk/server/routes/misc.py +102 -12
  531. ksadk/server/routes/models.py +25 -1
  532. ksadk/server/routes/openai_compat.py +6 -0
  533. ksadk/server/routes/projection.py +159 -216
  534. ksadk/server/routes/run.py +6 -2
  535. ksadk/server/routes/sessions.py +301 -342
  536. ksadk/server/routes/streaming.py +68 -15
  537. ksadk/server/routes/tool_receipt_claim_routes.py +107 -0
  538. ksadk/server/routes/workspace.py +5 -2
  539. ksadk/server/static/assets/{ArtifactsPanel-C1YoaKhx.js → ArtifactsPanel-CILaW-fC.js} +1 -1
  540. ksadk/server/static/assets/{CodeBlock-DHuAWfr5.js → CodeBlock-BVrNVtJC.js} +1 -1
  541. ksadk/server/static/assets/{MathMessageMarkdown-cvdrBwYr.js → MathMessageMarkdown-Dp7c4wWD.js} +1 -1
  542. ksadk/server/static/assets/{MermaidBlock-DeBkbJvI.js → MermaidBlock-Dxop8Rd7.js} +6 -6
  543. ksadk/server/static/assets/{NativeTerminalPanel-oJj44_sV.js → NativeTerminalPanel-Cjjz8B30.js} +1 -1
  544. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-Dhfv25o2.js → abnfDiagram-VCTEODGH-ckWDmOzw.js} +1 -1
  545. ksadk/server/static/assets/{arc-C35w-pn1.js → arc-DqxJede-.js} +1 -1
  546. ksadk/server/static/assets/architecture-7GRP2DOG-pn_DuLy6.js +1 -0
  547. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-FoMY_u6D.js → architectureDiagram-5GKGNRK7-SEQA4bVi.js} +1 -1
  548. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-zD4Rt7oE.js → blockDiagram-NRAW4CY4-pM0B-6NJ.js} +1 -1
  549. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BCtGGkhN.js → c4Diagram-UCG6FXSJ-m2tuCNVq.js} +1 -1
  550. ksadk/server/static/assets/channel-fySsnkft.js +1 -0
  551. ksadk/server/static/assets/chunk-2Q5K7J3B-BheGxKRQ.js +1 -0
  552. ksadk/server/static/assets/{chunk-5VM5RSS4-C2Ms13_k.js → chunk-5VM5RSS4-GJHDr9Ww.js} +1 -1
  553. ksadk/server/static/assets/{chunk-F27PBJKO-BoTj-qgx.js → chunk-F27PBJKO-CbAN45AV.js} +1 -1
  554. ksadk/server/static/assets/{chunk-G27WJ6UU-DOMyyjHH.js → chunk-G27WJ6UU-D5ngbbzF.js} +1 -1
  555. ksadk/server/static/assets/{chunk-JWPE2WC7-DbJJqDli.js → chunk-JWPE2WC7-Cc5IwuYC.js} +1 -1
  556. ksadk/server/static/assets/{chunk-LCL6LL3I-CLuRCt_W.js → chunk-LCL6LL3I-CprgDDdJ.js} +1 -1
  557. ksadk/server/static/assets/{chunk-POPQ4Y6H-D0Dz847e.js → chunk-POPQ4Y6H-CDZhSy82.js} +1 -1
  558. ksadk/server/static/assets/{chunk-RHFEMEQ7-BWSRzEcd.js → chunk-RHFEMEQ7-CZchUNro.js} +1 -1
  559. ksadk/server/static/assets/{chunk-SVP7TREG-CPoHqkCY.js → chunk-SVP7TREG-BVruqk6T.js} +1 -1
  560. ksadk/server/static/assets/{chunk-XXDRQBXY-Bx1jS-X-.js → chunk-XXDRQBXY-4ld9SxPN.js} +1 -1
  561. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DSfLtNYm.js +1 -0
  562. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DSfLtNYm.js +1 -0
  563. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-LzyWm4m0.js → cose-bilkent-JH36ORCC-Dmyyk_Vp.js} +1 -1
  564. ksadk/server/static/assets/cynefin-OW5HDTMX-PFWIGtvA.js +1 -0
  565. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-BlW_bHED.js → cynefinDiagram-5FMLGOSQ-BIyq3EJb.js} +1 -1
  566. ksadk/server/static/assets/{dagre-3AP2YEHR-Bu_S86_i.js → dagre-3AP2YEHR-eBw08Qdk.js} +1 -1
  567. ksadk/server/static/assets/{dagre-B7nCawed.js → dagre-DfvnEf45.js} +1 -1
  568. ksadk/server/static/assets/{diagram-S7CK7UJ4-W_Zow2Km.js → diagram-S7CK7UJ4-CUSrE3Mg.js} +1 -1
  569. ksadk/server/static/assets/{diagram-UQ7AKVKN-CLIKAHON.js → diagram-UQ7AKVKN-Dq5Zw2gy.js} +1 -1
  570. ksadk/server/static/assets/{diagram-VSXAHHWV-Dv6_QAlN.js → diagram-VSXAHHWV-DyUHfNwT.js} +1 -1
  571. ksadk/server/static/assets/{diagram-VX7I27RA-BWAWRDtZ.js → diagram-VX7I27RA-CREmM89O.js} +1 -1
  572. ksadk/server/static/assets/{diagram-Z3DM3KII-XA_rWMss.js → diagram-Z3DM3KII-Dw9zhHUK.js} +1 -1
  573. ksadk/server/static/assets/{dist-CGt_UGeO.js → dist-0uJ4tdx6.js} +1 -1
  574. ksadk/server/static/assets/{dist-C0J5_3qM.js → dist-AEv-vXf-.js} +1 -1
  575. ksadk/server/static/assets/{dist-CIpWk_5f.js → dist-B49GzZDb.js} +1 -1
  576. ksadk/server/static/assets/{dist-B3bA05-e.js → dist-B8Myiet9.js} +1 -1
  577. ksadk/server/static/assets/{dist-DWfdmz9s.js → dist-BBsYarrI.js} +1 -1
  578. ksadk/server/static/assets/{dist-BLpRy_Yx.js → dist-BQMrUwdI.js} +1 -1
  579. ksadk/server/static/assets/{dist-CIRMvUM4.js → dist-BX_-FENW.js} +1 -1
  580. ksadk/server/static/assets/{dist-BdNFAney.js → dist-CD4L6ymH.js} +1 -1
  581. ksadk/server/static/assets/{dist-n3n6t_FO.js → dist-CHpW1BHj.js} +1 -1
  582. ksadk/server/static/assets/{dist-DppE_r-D.js → dist-CVPau3tn.js} +1 -1
  583. ksadk/server/static/assets/{dist-qe8xjesy.js → dist-C_qdxcSH.js} +1 -1
  584. ksadk/server/static/assets/{dist-2vL2sAdF.js → dist-Co68Apq4.js} +1 -1
  585. ksadk/server/static/assets/{dist-1nXCdsej.js → dist-Cp2PaOMY.js} +1 -1
  586. ksadk/server/static/assets/{dist-DNKuMzWc.js → dist-CuR5Bgme.js} +1 -1
  587. ksadk/server/static/assets/{dist-t6MzE0jU.js → dist-DDSyLEOX.js} +1 -1
  588. ksadk/server/static/assets/{dist-CPyieXEf.js → dist-DUxO0R99.js} +1 -1
  589. ksadk/server/static/assets/{dist-DyG6Ya-z.js → dist-QzbGrED_.js} +1 -1
  590. ksadk/server/static/assets/{dist-0X_j2Rcc.js → dist-bupkyEBZ.js} +1 -1
  591. ksadk/server/static/assets/{dist-mqD5TZup.js → dist-cxTGfdqx.js} +1 -1
  592. ksadk/server/static/assets/{dist-M-SrdhhZ.js → dist-hL5p1til.js} +1 -1
  593. ksadk/server/static/assets/{dist-D-92S-Fd.js → dist-lOy23y43.js} +1 -1
  594. ksadk/server/static/assets/{dist-BO_UwatH.js → dist-pq-nD33R.js} +1 -1
  595. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-BfCzF1Xi.js → ebnfDiagram-PWID7BFC-BS5LdNoR.js} +1 -1
  596. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-Dpz9_0zn.js → erDiagram-SSCWMZ5O-Bv1QtiY-.js} +1 -1
  597. ksadk/server/static/assets/eventmodeling-NTZA5JFV-DsM4upQX.js +1 -0
  598. ksadk/server/static/assets/flowDiagram-A5DVABFB-D5NA16k9.js +1 -0
  599. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DDaG1f4_.js → ganttDiagram-EL5Y4UJY-musi-e0G.js} +1 -1
  600. ksadk/server/static/assets/gitGraph-4MIJSDKK-DUCVz-ih.js +1 -0
  601. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DcxzRwYC.js → gitGraphDiagram-WWUBYQGX-DH37EGkG.js} +1 -1
  602. ksadk/server/static/assets/index-CZdkAvsv.js +244 -0
  603. ksadk/server/static/assets/index-CvXdHgF3.css +2 -0
  604. ksadk/server/static/assets/info-A6RAGUB7-rw0ZNHZp.js +1 -0
  605. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CYMdn6lQ.js → infoDiagram-RXCK75RN-C1kEtv2y.js} +1 -1
  606. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CLHFAD6c.js → ishikawaDiagram-5VMMS53U-BCNPyMka.js} +1 -1
  607. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-BHSKQGAl.js → journeyDiagram-EYS64GPL--cDbKnjP.js} +1 -1
  608. ksadk/server/static/assets/{kanban-definition-3QL26DDD-D5W3tjTT.js → kanban-definition-3QL26DDD-R1rAVw2f.js} +1 -1
  609. ksadk/server/static/assets/{katex-mtjOi4KM.js → katex-BT-X-V7U.js} +1 -1
  610. ksadk/server/static/assets/{linear-BETqsxE_.js → linear-DTR631iG.js} +1 -1
  611. ksadk/server/static/assets/{mermaid-parser.core-DPWrvs90.js → mermaid-parser.core-DfFzJhX8.js} +2 -2
  612. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-CJG2mfBP.js → mindmap-definition-FBJOCRG2-D4by_rmk.js} +1 -1
  613. ksadk/server/static/assets/packet-AYTQ26CC-Ca4Hvki9.js +1 -0
  614. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-GjAPNaqn.js → pegDiagram-XKGWAZYB-xWXPEh0c.js} +1 -1
  615. ksadk/server/static/assets/pie-WAS4IAKB-hwiz6fbw.js +1 -0
  616. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-ToIewrqr.js → pieDiagram-E7YTZNPT-BudBDlCI.js} +1 -1
  617. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-4d78KiEY.js → quadrantDiagram-AXDQQJYC-DXZ0PCJF.js} +1 -1
  618. ksadk/server/static/assets/radar-RG4KPBEZ-BR1oZXLM.js +1 -0
  619. ksadk/server/static/assets/railroad-74A4TZTK-DfgEISfX.js +1 -0
  620. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-CWOC3rdk.js +1 -0
  621. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CiRvHCLY.js +1 -0
  622. ksadk/server/static/assets/railroad-peg-WCYAUIDC-DSDDyJ2f.js +1 -0
  623. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-DKzx4xfv.js → railroadDiagram-O6MQD6OU-BdAYRYB8.js} +1 -1
  624. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-CJYljxQS.js → requirementDiagram-EFPCY7ZU-CBBmaL70.js} +1 -1
  625. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-DLU2fV1w.js → sankeyDiagram-P5KCCOFB-Doc3rdwp.js} +1 -1
  626. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CVqysrA9.js → sequenceDiagram-WJ2MYXX4-0J8R8hWW.js} +1 -1
  627. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-BUxfmTHc.js → sizeCapture-X5ZJPWSS-CfFLlWsK.js} +1 -1
  628. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-CNFgYI9E.js → stateDiagram-HBIQ2CUA-jBwkjtTy.js} +1 -1
  629. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-Cw1fPb5w.js +1 -0
  630. ksadk/server/static/assets/{swimlanes-XN3QIQJK-B6qCMe8N.js → swimlanes-XN3QIQJK-B0WxTQf8.js} +1 -1
  631. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-Cc3JMBAF.js +8 -0
  632. ksadk/server/static/assets/{timeline-definition-24CTP7MA-CMD3x_U_.js → timeline-definition-24CTP7MA-BfCT_75A.js} +1 -1
  633. ksadk/server/static/assets/treeView-Q6P3EWNA-C05SJHxo.js +1 -0
  634. ksadk/server/static/assets/treemap-WGGIJYW6-BqNLAhc3.js +1 -0
  635. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-BqtUqvXM.js → vennDiagram-4TSXK5OY-9gX1VMDC.js} +1 -1
  636. ksadk/server/static/assets/wardley-WFR3VGLG-DokNktqB.js +1 -0
  637. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-B5KfDjI-.js → wardleyDiagram-VM6X3IG4-sEs_BP6O.js} +1 -1
  638. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BaUlSZrn.js → xychartDiagram-S5SC5T6Z-Ll4jvUN9.js} +1 -1
  639. ksadk/server/static/index.html +2 -2
  640. ksadk/sessions/__init__.py +8 -1
  641. ksadk/sessions/_checkpoint_resume_audit.py +44 -0
  642. ksadk/sessions/_in_memory_query.py +112 -0
  643. ksadk/sessions/_local_service_sync.py +157 -156
  644. ksadk/sessions/_local_state_sync.py +152 -0
  645. ksadk/sessions/_local_tables.py +2 -0
  646. ksadk/sessions/_postgres_checkpoint_read.py +323 -0
  647. ksadk/sessions/_postgres_checkpoint_stats.py +330 -0
  648. ksadk/sessions/_postgres_history_read.py +678 -0
  649. ksadk/sessions/_postgres_schema.py +44 -2
  650. ksadk/sessions/_postgres_tables.py +2 -0
  651. ksadk/sessions/_postgres_tool_receipts.py +169 -0
  652. ksadk/sessions/_resilient_read.py +630 -0
  653. ksadk/sessions/_tool_receipt_sync.py +119 -0
  654. ksadk/sessions/agent_identity.py +16 -0
  655. ksadk/sessions/base.py +278 -0
  656. ksadk/sessions/db_budget.py +332 -0
  657. ksadk/sessions/errors.py +12 -0
  658. ksadk/sessions/history_budget.py +36 -0
  659. ksadk/sessions/history_identity.py +27 -0
  660. ksadk/sessions/in_memory.py +376 -113
  661. ksadk/sessions/local_service.py +345 -0
  662. ksadk/sessions/postgres_service.py +515 -549
  663. ksadk/sessions/resilience.py +21 -14
  664. ksadk/sessions/resilient.py +611 -504
  665. ksadk/skills/loader.py +44 -2
  666. ksadk/skills/runtime/backends/e2b.py +17 -14
  667. ksadk/skills/service_client.py +6 -1
  668. ksadk/studio/a2a_bindings.py +407 -0
  669. ksadk/studio/a2a_orchestration.py +178 -0
  670. ksadk/studio/active_run_output.py +92 -0
  671. ksadk/studio/activity_records.py +542 -0
  672. ksadk/studio/agent_configuration.py +173 -0
  673. ksadk/studio/api.py +219 -389
  674. ksadk/studio/api_a2a_routes.py +93 -0
  675. ksadk/studio/api_catalog_routes.py +13 -0
  676. ksadk/studio/api_cloud_chat_routes.py +382 -0
  677. ksadk/studio/api_contracts.py +23 -0
  678. ksadk/studio/attachment_store.py +14 -2
  679. ksadk/studio/build_resolution.py +117 -0
  680. ksadk/studio/build_singleflight.py +37 -0
  681. ksadk/studio/builder.py +20 -2
  682. ksadk/studio/capabilities.py +8 -3
  683. ksadk/studio/cloud.py +83 -377
  684. ksadk/studio/cloud_gateways.py +424 -0
  685. ksadk/studio/cloud_shared_web.py +7 -0
  686. ksadk/studio/codex_agent_service.py +17 -0
  687. ksadk/studio/codex_manifest.py +5 -1
  688. ksadk/studio/codex_provider_build.py +65 -0
  689. ksadk/studio/compiler.py +102 -6
  690. ksadk/studio/contract_base.py +19 -0
  691. ksadk/studio/contracts.py +231 -201
  692. ksadk/studio/dsh_application.py +58 -12
  693. ksadk/studio/dsh_capability_service.py +17 -171
  694. ksadk/studio/dsh_mcp_transport.py +191 -0
  695. ksadk/studio/event_store.py +17 -0
  696. ksadk/studio/execution_host.py +84 -11
  697. ksadk/studio/framework_run.py +18 -0
  698. ksadk/studio/interaction_submission.py +265 -0
  699. ksadk/studio/kernel_registry.py +12 -1
  700. ksadk/studio/lifecycle_status.py +43 -0
  701. ksadk/studio/model_buffered_wire.py +227 -0
  702. ksadk/studio/model_chat_tools.py +143 -0
  703. ksadk/studio/model_client.py +1241 -761
  704. ksadk/studio/model_content_stream.py +129 -0
  705. ksadk/studio/model_credentials.py +196 -0
  706. ksadk/studio/model_profile_service.py +65 -31
  707. ksadk/studio/model_request_projection.py +284 -0
  708. ksadk/studio/model_responses_content.py +296 -0
  709. ksadk/studio/model_usage.py +109 -0
  710. ksadk/studio/model_wire_failure.py +110 -0
  711. ksadk/studio/model_wire_identity.py +138 -0
  712. ksadk/studio/model_wire_snapshot.py +45 -0
  713. ksadk/studio/model_wire_tools.py +283 -0
  714. ksadk/studio/native_acceptance.py +68 -0
  715. ksadk/studio/native_approval.py +111 -0
  716. ksadk/studio/native_browser_port.py +861 -0
  717. ksadk/studio/native_child_mcp.py +87 -0
  718. ksadk/studio/native_child_publication.py +68 -0
  719. ksadk/studio/native_child_skills.py +72 -0
  720. ksadk/studio/native_child_workspace.py +176 -0
  721. ksadk/studio/native_command_policy.py +53 -0
  722. ksadk/studio/native_context_port.py +326 -0
  723. ksadk/studio/native_context_registration.py +54 -0
  724. ksadk/studio/native_document_input.py +88 -0
  725. ksadk/studio/native_final_shape.py +852 -0
  726. ksadk/studio/native_gateway_stream.py +69 -0
  727. ksadk/studio/native_hook_port.py +145 -0
  728. ksadk/studio/native_hook_registration.py +70 -0
  729. ksadk/studio/native_inventory_disclosure.py +223 -0
  730. ksadk/studio/native_kernel_admission.py +84 -0
  731. ksadk/studio/native_language_diagnostics.py +320 -0
  732. ksadk/studio/native_mcp_disclosure.py +198 -0
  733. ksadk/studio/native_mcp_tool_port.py +219 -0
  734. ksadk/studio/native_memory_acceptance.py +362 -0
  735. ksadk/studio/native_memory_context.py +266 -0
  736. ksadk/studio/native_memory_flush.py +174 -0
  737. ksadk/studio/native_memory_sources.py +80 -0
  738. ksadk/studio/native_memory_tool_port.py +360 -0
  739. ksadk/studio/native_memory_turn.py +183 -0
  740. ksadk/studio/native_model_port.py +765 -0
  741. ksadk/studio/native_model_recovery.py +126 -0
  742. ksadk/studio/native_options.py +75 -0
  743. ksadk/studio/native_output_fields.py +58 -0
  744. ksadk/studio/native_planning.py +156 -0
  745. ksadk/studio/native_product.py +988 -0
  746. ksadk/studio/native_read_budget.py +426 -0
  747. ksadk/studio/native_recovery.py +171 -0
  748. ksadk/studio/native_scope.py +35 -0
  749. ksadk/studio/native_session_context_port.py +141 -0
  750. ksadk/studio/native_session_engine.py +14 -0
  751. ksadk/studio/native_skill_source.py +74 -0
  752. ksadk/studio/native_subagent_port.py +700 -0
  753. ksadk/studio/native_terminal_recovery.py +95 -0
  754. ksadk/studio/native_test_action.py +610 -0
  755. ksadk/studio/native_tool_port.py +477 -0
  756. ksadk/studio/native_user_input.py +60 -0
  757. ksadk/studio/native_verification_presentation.py +65 -0
  758. ksadk/studio/native_workspace_diagnostics.py +183 -0
  759. ksadk/studio/native_workspace_port.py +43 -0
  760. ksadk/studio/operations.py +34 -9
  761. ksadk/studio/plugin_composition.py +26 -10
  762. ksadk/studio/plugin_kernel_adapter.py +75 -1
  763. ksadk/studio/plugin_native_activation.py +163 -0
  764. ksadk/studio/plugin_runtime.py +639 -119
  765. ksadk/studio/plugin_runtime_admission.py +57 -0
  766. ksadk/studio/presentation.py +92 -0
  767. ksadk/studio/public_output_store.py +69 -0
  768. ksadk/studio/resource_authority.py +11 -3
  769. ksadk/studio/resource_catalog.py +8 -12
  770. ksadk/studio/run_activity.py +338 -385
  771. ksadk/studio/run_controls.py +185 -0
  772. ksadk/studio/run_service.py +908 -319
  773. ksadk/studio/run_submission_receipts.py +68 -0
  774. ksadk/studio/runtime_catalog.py +23 -4
  775. ksadk/studio/runtime_prewarm.py +22 -0
  776. ksadk/studio/scheduler_assistant.py +4 -1
  777. ksadk/studio/service.py +356 -282
  778. ksadk/studio/service_settings.py +229 -0
  779. ksadk/studio/shared_web.py +393 -169
  780. ksadk/studio/shared_web_response_events.py +180 -0
  781. ksadk/studio/shared_web_run_state.py +133 -0
  782. ksadk/studio/skill_discovery.py +305 -3
  783. ksadk/studio/static/assets/ChannelsPage-xX5HlMId.js +8 -0
  784. ksadk/studio/static/assets/{CodeBlock-DMIf4h33-UIqo-BPW.js → CodeBlock-DMIf4h33-CkufcPYo.js} +3 -3
  785. ksadk/studio/static/assets/{MathMessageMarkdown-BesSeCYl-OhNwH4K9.js → MathMessageMarkdown-BesSeCYl-DYG1Wzbx.js} +1 -1
  786. ksadk/studio/static/assets/{MessageMarkdown-CwMTvgFj-g0I-I4dD.js → MessageMarkdown-CwMTvgFj-BeyLyQHu.js} +2 -2
  787. ksadk/studio/static/assets/TeamsPage-CCaaGaVp.js +3 -0
  788. ksadk/studio/static/assets/index-C7DNDik2.css +2 -0
  789. ksadk/studio/static/assets/index-Cy68gTlH.js +265 -0
  790. ksadk/studio/static/index.html +3 -3
  791. ksadk/studio/teams_catalog.py +33 -0
  792. ksadk/studio/teams_installation.py +4 -1
  793. ksadk/studio/teams_node.py +4 -0
  794. ksadk/studio/teams_node_factory.py +558 -0
  795. ksadk/studio/teams_node_runner.py +3 -0
  796. ksadk/studio/teams_node_v1.py +935 -0
  797. ksadk/studio/teams_remote.py +259 -37
  798. ksadk/studio/templates.py +1 -0
  799. ksadk/studio/workspace_plugins.py +3 -1
  800. ksadk/tools/a2a_policy.py +5 -0
  801. ksadk/tools/artifact_observation.py +53 -0
  802. ksadk/tools/captured_source_artifact.py +68 -0
  803. ksadk/tools/schema.py +34 -0
  804. ksadk/toolsets/__init__.py +82 -88
  805. ksadk/toolsets/a2a.py +89 -89
  806. ksadk/toolsets/sandbox.py +377 -6
  807. ksadk/toolsets/skill_management.py +315 -0
  808. ksadk/toolsets/tool_selection.py +94 -0
  809. ksadk/toolsets/workspace.py +342 -324
  810. ksadk/toolsets/workspace_editing.py +291 -0
  811. ksadk/toolsets/workspace_model_observation.py +104 -0
  812. ksadk/toolsets/workspace_mutation.py +75 -0
  813. ksadk/toolsets/workspace_read_budget.py +216 -0
  814. ksadk/toolsets/workspace_search.py +192 -0
  815. ksadk/toolsets/workspace_search_process.py +129 -0
  816. ksadk/toolsets/workspace_state.py +6 -0
  817. ksadk/version.py +1 -1
  818. ksadk_runtime_common/http_headers.py +18 -0
  819. ksadk_runtime_common/workspace_files/router.py +2 -1
  820. ksadk/server/static/assets/architecture-7GRP2DOG-BCsa26zi.js +0 -1
  821. ksadk/server/static/assets/channel-_KDifNys.js +0 -1
  822. ksadk/server/static/assets/chunk-2Q5K7J3B-HdVkJ9F0.js +0 -1
  823. ksadk/server/static/assets/classDiagram-DTDB5LWJ-BVCW3ZqZ.js +0 -1
  824. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-BVCW3ZqZ.js +0 -1
  825. ksadk/server/static/assets/cynefin-OW5HDTMX-CNXjFctL.js +0 -1
  826. ksadk/server/static/assets/eventmodeling-NTZA5JFV-B5-8RH9c.js +0 -1
  827. ksadk/server/static/assets/flowDiagram-A5DVABFB-BppFxEKw.js +0 -1
  828. ksadk/server/static/assets/gitGraph-4MIJSDKK-B-AhYj4C.js +0 -1
  829. ksadk/server/static/assets/index-BMd2mucF.css +0 -2
  830. ksadk/server/static/assets/index-D5qyyhTH.js +0 -244
  831. ksadk/server/static/assets/info-A6RAGUB7-0uiKrC35.js +0 -1
  832. ksadk/server/static/assets/packet-AYTQ26CC-BVTmZ_cw.js +0 -1
  833. ksadk/server/static/assets/pie-WAS4IAKB-DyfxBU7V.js +0 -1
  834. ksadk/server/static/assets/radar-RG4KPBEZ-FFontjL2.js +0 -1
  835. ksadk/server/static/assets/railroad-74A4TZTK-D0Uidzen.js +0 -1
  836. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BOo_9T2h.js +0 -1
  837. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-D6-BjW7Z.js +0 -1
  838. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CXx__yMm.js +0 -1
  839. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BXAFScz8.js +0 -1
  840. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uIQ2lJKH.js +0 -8
  841. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5GgucZ.js +0 -1
  842. ksadk/server/static/assets/treemap-WGGIJYW6-Bq1u1SpG.js +0 -1
  843. ksadk/server/static/assets/wardley-WFR3VGLG-QAt06uEz.js +0 -1
  844. ksadk/studio/static/assets/ChannelsPage-D_PGmKVq.js +0 -8
  845. ksadk/studio/static/assets/TeamsPage-DqX4HWKQ.js +0 -3
  846. ksadk/studio/static/assets/index-CfEnms6Y.css +0 -2
  847. ksadk/studio/static/assets/index-Dp61rOWZ.js +0 -0
  848. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/WHEEL +0 -0
  849. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/entry_points.txt +0 -0
  850. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/licenses/LICENSE +0 -0
  851. {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,245 @@
1
+ """Fixed Server-only byte transport for prepared Teams materials/artifacts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from contextlib import asynccontextmanager
7
+ from dataclasses import dataclass, field
8
+ from typing import Mapping
9
+ from urllib.parse import quote
10
+
11
+ import httpx
12
+ from pydantic import TypeAdapter
13
+
14
+ from ksadk.kernel.teams_materials import CHUNK_BYTES, ReadyMaterial
15
+ from ksadk.plugins.teams.cloud_contracts import MAX_FILE_BYTES, Digest, Identifier
16
+ from ksadk.plugins.teams.errors import TeamsError
17
+ from ksadk.plugins.teams.transport import TeamsHTTPClient
18
+
19
+ MAX_JSON_BYTES = 2 * 1024 * 1024
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class MaterialHTTPAuthorization:
24
+ headers: Mapping[str, str] = field(repr=False)
25
+ node_command_id: str | None = None
26
+
27
+
28
+ def _segment(value):
29
+ TypeAdapter(Identifier).validate_python(value)
30
+ if value in {".", ".."} or any(c in value for c in "/\\?#%"):
31
+ raise ValueError("material endpoint requires one fixed identifier segment")
32
+ return quote(value, safe="")
33
+
34
+
35
+ def _failure(code="material_transport_unavailable", status=503):
36
+ return TeamsError(code, "材料传输未完成,请核对原操作后重试", status=status)
37
+
38
+
39
+ class TeamsHTTPMaterialTransport:
40
+ """Use configured ``.../teams`` base_url, with fresh authorization per call.
41
+
42
+ ``authorization(context, operation)`` is async and returns
43
+ MaterialHTTPAuthorization. Node mode accepts only X-Teams-Node-Token and
44
+ optionally the original prepare nodeCommandId. Runtime mode accepts exactly
45
+ one X-Teams-Execution-Permit (prepare reads) or X-Teams-Callback-Permit. No
46
+ owner credentials, redirects or response-supplied storage URLs are used.
47
+ """
48
+
49
+ def __init__(self, base_url, *, authorization, node_id=None, transport=None):
50
+ self.client = TeamsHTTPClient(base_url, transport=transport)
51
+ self.authorization = authorization
52
+ self.node_id = node_id
53
+ self.prefix = "/runtime" if node_id is None else "/nodes/" + _segment(node_id)
54
+
55
+ async def close(self):
56
+ await self.client.close()
57
+
58
+ async def _scope(self, context, operation):
59
+ auth = await self.authorization(context, operation)
60
+ if not isinstance(auth, MaterialHTTPAuthorization):
61
+ raise _failure("material_authorization_invalid", 403)
62
+ headers = {}
63
+ for name, value in auth.headers.items():
64
+ if not isinstance(name, str) or not isinstance(value, str) or name.lower() in headers:
65
+ raise _failure("material_authorization_invalid", 403)
66
+ if (
67
+ not value
68
+ or len(value.encode()) > 16384
69
+ or any(ord(c) < 32 or ord(c) > 126 for c in value)
70
+ ):
71
+ raise _failure("material_authorization_invalid", 403)
72
+ headers[name.lower()] = value
73
+ allowed = (
74
+ ({"x-teams-node-token"},)
75
+ if self.node_id
76
+ else ({"x-teams-execution-permit"}, {"x-teams-callback-permit"})
77
+ )
78
+ if set(headers) not in allowed or (
79
+ operation != "read_material" and "x-teams-execution-permit" in headers
80
+ ):
81
+ raise _failure("material_authorization_invalid", 403)
82
+ params = {"contextRef": context.context_ref}
83
+ if auth.node_command_id is not None:
84
+ if self.node_id is None:
85
+ raise _failure("material_authorization_invalid", 403)
86
+ TypeAdapter(Identifier).validate_python(auth.node_command_id)
87
+ params["nodeCommandId"] = auth.node_command_id
88
+ headers["Accept-Encoding"] = "identity"
89
+ return headers, params
90
+
91
+ @asynccontextmanager
92
+ async def _response(
93
+ self, context, operation, method, path, *, content=None, content_length=None
94
+ ):
95
+ headers, params = await self._scope(context, operation)
96
+ if content_length is not None:
97
+ headers.update(
98
+ {"Content-Type": "application/octet-stream", "Content-Length": str(content_length)}
99
+ )
100
+ elif content is not None:
101
+ headers["Content-Type"] = "application/json"
102
+ try:
103
+ async with self.client.http.stream(
104
+ method,
105
+ self.client.base_url + self.prefix + path,
106
+ params=params,
107
+ headers=headers,
108
+ content=content,
109
+ follow_redirects=False,
110
+ ) as response:
111
+ if not 200 <= response.status_code < 300:
112
+ # Do not echo remote bodies or Location values: either may
113
+ # contain credentials. A failed mutation is never retried.
114
+ code = "material_request_rejected"
115
+ if (
116
+ response.status_code == 409
117
+ and response.headers.get("Content-Encoding", "identity").lower()
118
+ == "identity"
119
+ ):
120
+ data = bytearray()
121
+ async for chunk in response.aiter_bytes(4096):
122
+ if len(data) + len(chunk) > 4096:
123
+ data.clear()
124
+ break
125
+ data.extend(chunk)
126
+ try:
127
+ body = json.loads(data)
128
+ except (ValueError, UnicodeDecodeError):
129
+ body = None
130
+ # This one public constant distinguishes the original
131
+ # submit-report race. Never expose arbitrary server data.
132
+ if isinstance(body, dict) and any(
133
+ isinstance(body.get(key), dict)
134
+ and body[key].get("code") == "original_run_unverified"
135
+ for key in ("error", "detail")
136
+ ):
137
+ code = "original_run_unverified"
138
+ raise _failure(
139
+ code,
140
+ response.status_code if response.status_code >= 400 else 502,
141
+ )
142
+ if response.headers.get("Content-Encoding", "identity").lower() != "identity":
143
+ raise _failure("material_response_encoding_invalid", 502)
144
+ yield response
145
+ except httpx.RequestError:
146
+ raise _failure() from None
147
+
148
+ async def _json(self, context, operation, method, path, body=None, *, content=None, size=None):
149
+ if body is not None:
150
+ content = json.dumps(body, ensure_ascii=True, separators=(",", ":")).encode()
151
+ if len(content) > MAX_JSON_BYTES:
152
+ raise _failure("material_request_too_large", 413)
153
+ async with self._response(
154
+ context, operation, method, path, content=content, content_length=size
155
+ ) as response:
156
+ data = bytearray()
157
+ async for chunk in response.aiter_bytes(CHUNK_BYTES):
158
+ data.extend(chunk)
159
+ if len(data) > MAX_JSON_BYTES:
160
+ raise _failure("material_response_too_large", 502)
161
+ try:
162
+ value = json.loads(data)
163
+ except (UnicodeDecodeError, ValueError):
164
+ raise _failure("material_response_invalid", 502) from None
165
+ if not isinstance(value, dict):
166
+ raise _failure("material_response_invalid", 502)
167
+ return value
168
+
169
+ async def fetch_manifest(self, context, material_ref):
170
+ if context.material_manifest_ref != material_ref:
171
+ raise _failure("material_scope_mismatch", 403)
172
+ result = await self._json(
173
+ context, "read_material", "GET", "/materials/" + _segment(material_ref)
174
+ )
175
+ return ReadyMaterial.model_validate(result).model_dump(mode="json", exclude_none=True)
176
+
177
+ @asynccontextmanager
178
+ async def open_blob(self, context, material_ref, fingerprint):
179
+ if context.material_manifest_ref != material_ref:
180
+ raise _failure("material_scope_mismatch", 403)
181
+ TypeAdapter(Digest).validate_python(fingerprint)
182
+ path = "/materials/" + _segment(material_ref) + "/blobs/" + _segment(fingerprint)
183
+ async with self._open_bytes(context, path) as chunks:
184
+ yield chunks
185
+
186
+ @asynccontextmanager
187
+ async def open_artifact(self, context, group_id, artifact_id):
188
+ if context.ref.groupId != group_id:
189
+ raise _failure("artifact_scope_mismatch", 403)
190
+ path = "/groups/" + _segment(group_id) + "/artifacts/" + _segment(artifact_id) + "/content"
191
+ async with self._open_bytes(context, path) as chunks:
192
+ yield chunks
193
+
194
+ @asynccontextmanager
195
+ async def _open_bytes(self, context, path):
196
+ async with self._response(context, "read_material", "GET", path) as response:
197
+
198
+ async def chunks():
199
+ size = 0
200
+ async for chunk in response.aiter_bytes(CHUNK_BYTES):
201
+ size += len(chunk)
202
+ if size > MAX_FILE_BYTES:
203
+ raise _failure("material_response_too_large", 413)
204
+ yield chunk
205
+
206
+ yield chunks()
207
+
208
+ async def create_artifact(self, context, body):
209
+ if set(body) != {"name", "mediaType", "sizeBytes", "digest", "idempotencyKey"}:
210
+ raise _failure("artifact_request_invalid", 422)
211
+ return await self._json(context, "create_artifact", "POST", "/artifacts", body)
212
+
213
+ async def upload_artifact(self, context, artifact_id, chunks, *, size_bytes):
214
+ if type(size_bytes) is not int or not 0 <= size_bytes <= MAX_FILE_BYTES:
215
+ raise _failure("artifact_size_invalid", 413)
216
+
217
+ async def bounded():
218
+ total = 0
219
+ async for chunk in chunks:
220
+ if not isinstance(chunk, bytes) or len(chunk) > CHUNK_BYTES:
221
+ raise _failure("artifact_bytes_invalid", 422)
222
+ total += len(chunk)
223
+ if total > size_bytes:
224
+ raise _failure("artifact_size_invalid", 422)
225
+ yield chunk
226
+ if total != size_bytes:
227
+ raise _failure("artifact_size_invalid", 422)
228
+
229
+ return await self._json(
230
+ context,
231
+ "upload_artifact",
232
+ "PUT",
233
+ "/artifacts/" + _segment(artifact_id) + "/content",
234
+ content=bounded(),
235
+ size=size_bytes,
236
+ )
237
+
238
+ async def finalize_artifact(self, context, artifact_id, *, idempotency_key):
239
+ return await self._json(
240
+ context,
241
+ "finalize_artifact",
242
+ "POST",
243
+ "/artifacts/" + _segment(artifact_id) + "/finalize",
244
+ {"idempotencyKey": idempotency_key},
245
+ )
@@ -0,0 +1,318 @@
1
+ """Verified Teams material downloads into a private, execution-scoped cache.
2
+
3
+ The transport is injected by the trusted Node/runtime assembly. It receives the
4
+ original preparation, never a model-supplied URL, bucket credential or local
5
+ destination. No archive extraction, git command or symlink traversal is used.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import errno
12
+ import hashlib
13
+ import os
14
+ import shutil
15
+ import stat
16
+ import tempfile
17
+ from dataclasses import dataclass
18
+ from pathlib import Path
19
+ from typing import AsyncContextManager, AsyncIterable, Awaitable, Callable
20
+
21
+ from pydantic import Field
22
+
23
+ from ksadk.kernel.teams_execution_context import ContextConflict, PreparedTeamsContext
24
+ from ksadk.plugins.teams.cloud_contracts import (
25
+ Digest,
26
+ Identifier,
27
+ MaterialManifest,
28
+ MaterialProof,
29
+ WireModel,
30
+ digest,
31
+ )
32
+
33
+ CHUNK_BYTES = 64 * 1024
34
+
35
+
36
+ class ReadyMaterial(WireModel):
37
+ materialId: Identifier
38
+ manifestDigest: Digest
39
+ state: str
40
+ sizeBytes: int = Field(strict=True, ge=0, le=64 * 1024 * 1024)
41
+ manifest: MaterialManifest
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class PreparedMaterial:
46
+ proof: MaterialProof
47
+ directory: Path
48
+
49
+
50
+ def _open_directory(path, *, dir_fd=None):
51
+ return os.open(path, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW, dir_fd=dir_fd)
52
+
53
+
54
+ def _parent(root_fd, path, *, create=False):
55
+ """Return an owned parent fd; every component is opened without symlinks."""
56
+ parts = path.split("/")
57
+ parent = os.dup(root_fd)
58
+ try:
59
+ for part in parts[:-1]:
60
+ if create:
61
+ try:
62
+ os.mkdir(part, mode=0o700, dir_fd=parent)
63
+ os.fsync(parent)
64
+ except FileExistsError:
65
+ pass
66
+ child = _open_directory(part, dir_fd=parent)
67
+ os.close(parent)
68
+ parent = child
69
+ return parent, parts[-1]
70
+ except BaseException:
71
+ os.close(parent)
72
+ raise
73
+
74
+
75
+ def _verify_file(root_fd, entry):
76
+ parent, name = _parent(root_fd, entry.path)
77
+ try:
78
+ fd = os.open(name, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK, dir_fd=parent)
79
+ with os.fdopen(fd, "rb") as source:
80
+ before = os.fstat(source.fileno())
81
+ if (
82
+ not stat.S_ISREG(before.st_mode)
83
+ or before.st_nlink != 1
84
+ or before.st_size != entry.sizeBytes
85
+ ):
86
+ raise ContextConflict("material cache entry is not the original regular file")
87
+ fingerprint, size = hashlib.sha256(), 0
88
+ while chunk := source.read(min(CHUNK_BYTES, entry.sizeBytes - size + 1)):
89
+ size += len(chunk)
90
+ if size > entry.sizeBytes:
91
+ raise ContextConflict("material cache file changed while reading")
92
+ fingerprint.update(chunk)
93
+ after = os.fstat(source.fileno())
94
+ if (
95
+ size != entry.sizeBytes
96
+ or "sha256:" + fingerprint.hexdigest() != entry.digest
97
+ or (before.st_ino, before.st_size, before.st_mtime_ns, before.st_ctime_ns)
98
+ != (after.st_ino, after.st_size, after.st_mtime_ns, after.st_ctime_ns)
99
+ ):
100
+ raise ContextConflict("material cache file checksum changed")
101
+ finally:
102
+ os.close(parent)
103
+
104
+
105
+ def _verify_tree(root_fd, name, manifest):
106
+ fd = _open_directory(name, dir_fd=root_fd)
107
+ try:
108
+ expected_files = {entry.path for entry in manifest.entries}
109
+ expected_dirs = {
110
+ str(parent)
111
+ for path in expected_files
112
+ for parent in Path(path).parents
113
+ if str(parent) != "."
114
+ }
115
+
116
+ def walk(directory, prefix=""):
117
+ for child in os.listdir(directory):
118
+ path = prefix + child
119
+ info = os.stat(child, dir_fd=directory, follow_symlinks=False)
120
+ if stat.S_ISDIR(info.st_mode) and path in expected_dirs:
121
+ child_fd = _open_directory(child, dir_fd=directory)
122
+ try:
123
+ walk(child_fd, path + "/")
124
+ finally:
125
+ os.close(child_fd)
126
+ elif not stat.S_ISREG(info.st_mode) or path not in expected_files:
127
+ raise ContextConflict("material cache contains an unexpected file or link")
128
+
129
+ walk(fd)
130
+ for entry in manifest.entries:
131
+ _verify_file(fd, entry)
132
+ return os.fstat(fd).st_ino
133
+ finally:
134
+ os.close(fd)
135
+
136
+
137
+ async def _verify_async(root_fd, name, manifest):
138
+ # A cancelled asyncio.to_thread does not stop its OS thread. Give that
139
+ # thread an independent fd and shield scheduling so cancellation cannot
140
+ # leak it or close/reuse the caller's descriptor while it is being read.
141
+ owned_fd = os.dup(root_fd)
142
+
143
+ def verify():
144
+ try:
145
+ return _verify_tree(owned_fd, name, manifest)
146
+ finally:
147
+ os.close(owned_fd)
148
+
149
+ task = asyncio.create_task(asyncio.to_thread(verify))
150
+ try:
151
+ return await asyncio.shield(task)
152
+ except asyncio.CancelledError:
153
+ task.add_done_callback(lambda result: None if result.cancelled() else result.exception())
154
+ raise
155
+
156
+
157
+ class TeamsMaterializer:
158
+ """Materialize a trusted preparation before native execution admission.
159
+
160
+ ``fetch_manifest(context, material_ref)`` returns the Server's ready manifest
161
+ after current command/grant authorization. ``open_blob(context, ref, digest)``
162
+ is an async context manager yielding an async iterator of raw byte chunks.
163
+ Both callbacks must use the configured Server and current short-lived Node
164
+ or runtime authorization; cached files do not skip this manifest check.
165
+ """
166
+
167
+ def __init__(
168
+ self,
169
+ root: Path | str,
170
+ *,
171
+ fetch_manifest: Callable[[PreparedTeamsContext, str], Awaitable[dict]],
172
+ open_blob: Callable[
173
+ [PreparedTeamsContext, str, str], AsyncContextManager[AsyncIterable[bytes]]
174
+ ],
175
+ ):
176
+ if not hasattr(os, "O_NOFOLLOW") or not hasattr(os, "O_DIRECTORY"):
177
+ raise RuntimeError("Teams materialization requires no-follow directory operations")
178
+ path = Path(root)
179
+ if not path.is_absolute():
180
+ raise ValueError("material cache root must be an absolute trusted path")
181
+ path.mkdir(mode=0o700, parents=True, exist_ok=True)
182
+ if path.is_symlink():
183
+ raise ValueError("material cache root must not be a symlink")
184
+ self.root = path.resolve(strict=True)
185
+ self.fetch_manifest, self.open_blob = fetch_manifest, open_blob
186
+
187
+ async def prepare(self, context: PreparedTeamsContext) -> MaterialProof:
188
+ return (await self.materialize(context)).proof
189
+
190
+ async def materialize(self, context: PreparedTeamsContext) -> PreparedMaterial:
191
+ # Revalidation prevents model_copy or a caller's mutable dict bypassing
192
+ # the original command/grant/context validator.
193
+ context = PreparedTeamsContext.model_validate_json(context.model_dump_json())
194
+ ref, fingerprint = context.material_manifest_ref, context.material_manifest_digest
195
+ if ref is None or fingerprint is None:
196
+ raise ContextConflict("preparation has no frozen material manifest")
197
+ response = ReadyMaterial.model_validate(await self.fetch_manifest(context, ref))
198
+ manifest = response.manifest
199
+ if (
200
+ response.state != "ready"
201
+ or response.materialId != ref
202
+ or response.manifestDigest != fingerprint
203
+ or manifest.manifest_digest != fingerprint
204
+ or response.sizeBytes != sum(entry.sizeBytes for entry in manifest.entries)
205
+ ):
206
+ raise ContextConflict("downloaded manifest differs from trusted preparation")
207
+ name = (
208
+ "material_"
209
+ + digest(
210
+ {
211
+ "authority": context.ref.authorityId,
212
+ "owner": context.owner_subject,
213
+ "group": context.ref.groupId,
214
+ "teamRun": context.ref.teamRunId,
215
+ "command": context.ref.commandId,
216
+ "contextRef": context.context_ref,
217
+ "manifestRef": ref,
218
+ "manifestDigest": fingerprint,
219
+ }
220
+ )[7:]
221
+ )
222
+ root_fd = _open_directory(self.root)
223
+ stage = None
224
+ try:
225
+ try:
226
+ await _verify_async(root_fd, name, manifest)
227
+ except FileNotFoundError:
228
+ # Only a missing cache *directory* allows download. A damaged
229
+ # existing directory remains evidence, never overwritten.
230
+ try:
231
+ os.stat(name, dir_fd=root_fd, follow_symlinks=False)
232
+ except FileNotFoundError:
233
+ pass
234
+ else:
235
+ raise ContextConflict("existing material cache is incomplete")
236
+ else:
237
+ return PreparedMaterial(
238
+ MaterialProof(manifestRef=ref, digest=fingerprint), self.root / name
239
+ )
240
+ stage = Path(tempfile.mkdtemp(prefix=".teams-material-", dir=self.root))
241
+ stage_fd = _open_directory(stage.name, dir_fd=root_fd)
242
+ try:
243
+ for entry in sorted(manifest.entries, key=lambda item: item.path):
244
+ parent, leaf = _parent(stage_fd, entry.path, create=True)
245
+ try:
246
+ fd = os.open(
247
+ leaf,
248
+ os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW,
249
+ mode=0o600,
250
+ dir_fd=parent,
251
+ )
252
+ with os.fdopen(fd, "wb") as target:
253
+ hasher, size = hashlib.sha256(), 0
254
+ async with self.open_blob(context, ref, entry.digest) as chunks:
255
+ async for chunk in chunks:
256
+ if not isinstance(chunk, bytes) or len(chunk) > CHUNK_BYTES:
257
+ raise ContextConflict(
258
+ "material stream must use bounded byte chunks"
259
+ )
260
+ size += len(chunk)
261
+ if size > entry.sizeBytes:
262
+ raise ContextConflict(
263
+ "material stream exceeded declared size"
264
+ )
265
+ target.write(chunk)
266
+ hasher.update(chunk)
267
+ if (
268
+ size != entry.sizeBytes
269
+ or "sha256:" + hasher.hexdigest() != entry.digest
270
+ ):
271
+ raise ContextConflict(
272
+ "downloaded bytes differ from frozen material digest"
273
+ )
274
+ target.flush()
275
+ os.fsync(target.fileno())
276
+ os.fchmod(target.fileno(), 0o400)
277
+ os.fsync(parent)
278
+ finally:
279
+ os.close(parent)
280
+ # Reauthorize after network I/O and before exposing a complete
281
+ # directory. Expired or revoked grants must fail this callback.
282
+ current = ReadyMaterial.model_validate(await self.fetch_manifest(context, ref))
283
+ if current != response:
284
+ raise ContextConflict(
285
+ "material authorization or manifest changed during download"
286
+ )
287
+ os.fsync(stage_fd)
288
+ inode = os.fstat(stage_fd).st_ino
289
+ finally:
290
+ os.close(stage_fd)
291
+ if await _verify_async(root_fd, stage.name, manifest) != inode:
292
+ raise ContextConflict("material staging directory was replaced")
293
+ try:
294
+ os.rename(stage.name, name, src_dir_fd=root_fd, dst_dir_fd=root_fd)
295
+ except OSError as exc:
296
+ if exc.errno not in {errno.EEXIST, errno.ENOTEMPTY}:
297
+ raise
298
+ # An independent preparation may have completed the same
299
+ # immutable target. Verify its actual bytes before using it.
300
+ await _verify_async(root_fd, name, manifest)
301
+ else:
302
+ stage = None
303
+ if await _verify_async(root_fd, name, manifest) != inode:
304
+ raise ContextConflict("material destination changed while committing")
305
+ os.fsync(root_fd)
306
+ return PreparedMaterial(
307
+ MaterialProof(manifestRef=ref, digest=fingerprint), self.root / name
308
+ )
309
+ except OSError as exc:
310
+ raise ContextConflict(
311
+ "material filesystem rejected an unsafe or unavailable path"
312
+ ) from exc
313
+ finally:
314
+ os.close(root_fd)
315
+ if stage is not None:
316
+ # Python's fd-based rmtree avoids following malicious links.
317
+ # Only this request's private unfinished staging dir is removed.
318
+ shutil.rmtree(stage, ignore_errors=True)