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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1221) hide show
  1. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/METADATA +17 -10
  2. agentengine_sdk_python-0.8.6.dist-info/RECORD +1731 -0
  3. ksadk/_async_iterators.py +79 -0
  4. ksadk/_build_provenance.json +1 -1
  5. ksadk/_model_anthropic.py +49 -0
  6. ksadk/_model_input.py +86 -0
  7. ksadk/_model_json.py +40 -0
  8. ksadk/_model_reasoning.py +17 -0
  9. ksadk/_model_refusal.py +20 -0
  10. ksadk/_model_sse.py +163 -0
  11. ksadk/_process.py +83 -0
  12. ksadk/_str_enum.py +17 -0
  13. ksadk/a2a/__init__.py +157 -167
  14. ksadk/a2a/_invocation_state.py +86 -0
  15. ksadk/a2a/_space_client_events.py +33 -22
  16. ksadk/a2a/adk.py +194 -0
  17. ksadk/a2a/adk_invocation_context.py +242 -0
  18. ksadk/a2a/adk_runtime.py +126 -0
  19. ksadk/a2a/adk_tools.py +319 -0
  20. ksadk/a2a/bootstrap.py +149 -23
  21. ksadk/a2a/build_validation.py +147 -0
  22. ksadk/a2a/card.py +23 -15
  23. ksadk/a2a/codex.py +160 -0
  24. ksadk/a2a/codex_checkpoint.py +111 -0
  25. ksadk/a2a/codex_recovery.py +96 -0
  26. ksadk/a2a/codex_recovery_events.py +123 -0
  27. ksadk/a2a/codex_runtime.py +198 -0
  28. ksadk/a2a/codex_session_checkpoint.py +162 -0
  29. ksadk/a2a/composition.py +88 -0
  30. ksadk/a2a/context_store.py +118 -19
  31. ksadk/a2a/control_plane.py +108 -106
  32. ksadk/a2a/event_adapter.py +92 -193
  33. ksadk/a2a/executor.py +257 -85
  34. ksadk/a2a/exposure.py +106 -0
  35. ksadk/a2a/external_transport.py +3 -4
  36. ksadk/a2a/identity.py +106 -12
  37. ksadk/a2a/ids.py +14 -3
  38. ksadk/a2a/inbound_kernel.py +133 -0
  39. ksadk/a2a/interaction_wire.py +76 -0
  40. ksadk/a2a/invocation_checkpoint.py +274 -0
  41. ksadk/a2a/invocation_policy.py +87 -0
  42. ksadk/a2a/invocation_publication.py +210 -0
  43. ksadk/a2a/invocation_service.py +972 -0
  44. ksadk/a2a/invocation_types.py +459 -0
  45. ksadk/a2a/kernel_task_adapter.py +259 -0
  46. ksadk/a2a/langgraph.py +20 -7
  47. ksadk/a2a/langgraph_invocation_context.py +136 -0
  48. ksadk/a2a/langgraph_managed.py +150 -0
  49. ksadk/a2a/langgraph_recovery.py +32 -0
  50. ksadk/a2a/langgraph_runtime.py +89 -0
  51. ksadk/a2a/langgraph_tool_runtime.py +132 -0
  52. ksadk/a2a/langgraph_tools.py +63 -0
  53. ksadk/a2a/message_digest.py +40 -0
  54. ksadk/a2a/platform.py +389 -0
  55. ksadk/a2a/policy_refs.py +13 -0
  56. ksadk/a2a/presentation.py +402 -0
  57. ksadk/a2a/product_kernel_facts.py +177 -0
  58. ksadk/a2a/product_key.py +99 -0
  59. ksadk/a2a/protocol_errors.py +116 -0
  60. ksadk/a2a/result_text.py +49 -0
  61. ksadk/a2a/resume_store.py +93 -3
  62. ksadk/a2a/routes.py +6 -1
  63. ksadk/a2a/runtime_approval.py +198 -0
  64. ksadk/a2a/runtime_input.py +151 -0
  65. ksadk/a2a/server.py +16 -7
  66. ksadk/a2a/space_client.py +101 -16
  67. ksadk/a2a/task_adapter.py +19 -5
  68. ksadk/a2a/task_event_dispatcher.py +39 -2
  69. ksadk/a2a/task_event_outbox.py +215 -0
  70. ksadk/a2a/task_event_outbox_owned.py +130 -0
  71. ksadk/a2a/task_store.py +37 -0
  72. ksadk/a2a/tool_activity.py +176 -0
  73. ksadk/a2a/workload_tokens.py +134 -0
  74. ksadk/a2ui/core.py +3 -3
  75. ksadk/api/client.py +38 -79
  76. ksadk/api/sse_stream.py +96 -0
  77. ksadk/builders/code_builder.py +121 -118
  78. ksadk/builders/container_builder.py +11 -29
  79. ksadk/builders/framework_requirements.py +22 -2
  80. ksadk/builders/managed_runtime_builder.py +12 -0
  81. ksadk/builders/source_provenance.py +87 -0
  82. ksadk/cli/__init__.py +36 -0
  83. ksadk/cli/cmd_a2a.py +43 -0
  84. ksadk/cli/cmd_build.py +9 -0
  85. ksadk/cli/cmd_config.py +4 -4
  86. ksadk/cli/cmd_create.py +12 -12
  87. ksadk/cli/cmd_deploy.py +27 -2
  88. ksadk/cli/cmd_hermes.py +24 -2
  89. ksadk/cli/cmd_invoke.py +64 -88
  90. ksadk/cli/cmd_openclaw.py +26 -1
  91. ksadk/cli/cmd_plugin.py +70 -12
  92. ksadk/cli/cmd_studio.py +69 -17
  93. ksadk/cli/cmd_web.py +2 -0
  94. ksadk/cli/hosted_invoke.py +206 -0
  95. ksadk/cli/invoke_content.py +60 -0
  96. ksadk/cli/openclaw_env.py +1 -1
  97. ksadk/cli/resource_common.py +26 -0
  98. ksadk/cli/runtime_bootstrap.py +27 -5
  99. ksadk/codex/_expert_request_reader.py +48 -0
  100. ksadk/codex/a2a_tools.py +140 -0
  101. ksadk/codex/async_approval.py +169 -0
  102. ksadk/codex/async_client.py +938 -0
  103. ksadk/codex/async_proxy.py +216 -0
  104. ksadk/codex/base_runtime.py +25 -0
  105. ksadk/codex/client.py +3 -1047
  106. ksadk/codex/client_payloads.py +85 -0
  107. ksadk/codex/rollout_checkpoint.py +264 -0
  108. ksadk/codex/runtime.py +290 -54
  109. ksadk/common/auth.py +2 -2
  110. ksadk/common/cloud_headers.py +36 -0
  111. ksadk/common/diagnostics.py +34 -0
  112. ksadk/common/kop_client.py +2 -1
  113. ksadk/configs/__init__.py +1 -1
  114. ksadk/configs/env_registry.py +216 -143
  115. ksadk/configs/env_registry_a2a.py +173 -0
  116. ksadk/configs/env_registry_studio.py +134 -0
  117. ksadk/configs/global_config.py +2 -1
  118. ksadk/configs/settings.py +9 -3
  119. ksadk/connector/__init__.py +17 -0
  120. ksadk/connector/channel.py +477 -0
  121. ksadk/context_engine/assembler.py +9 -0
  122. ksadk/context_engine/capabilities.py +52 -4
  123. ksadk/context_engine/contributors.py +80 -17
  124. ksadk/context_engine/instruction_authority.py +18 -0
  125. ksadk/conversations/attachment_storage.py +10 -3
  126. ksadk/conversations/attachments.py +69 -20
  127. ksadk/conversations/contracts.py +28 -9
  128. ksadk/conversations/message_projection.py +51 -155
  129. ksadk/conversations/message_projection_blocks.py +137 -0
  130. ksadk/conversations/model_context.py +11 -3
  131. ksadk/conversations/normalize.py +28 -10
  132. ksadk/conversations/projector.py +63 -0
  133. ksadk/conversations/runtime_baseline.py +37 -0
  134. ksadk/conversations/runtime_compaction.py +7 -2
  135. ksadk/conversations/runtime_input.py +16 -4
  136. ksadk/conversations/runtime_invocation.py +17 -4
  137. ksadk/conversations/runtime_observability.py +39 -10
  138. ksadk/conversations/runtime_payloads.py +12 -0
  139. ksadk/conversations/runtime_persistence.py +296 -32
  140. ksadk/conversations/runtime_preparation.py +98 -13
  141. ksadk/conversations/runtime_projection.py +217 -0
  142. ksadk/conversations/runtime_resume.py +141 -70
  143. ksadk/conversations/runtime_stream_events.py +29 -35
  144. ksadk/conversations/runtime_streaming.py +8 -0
  145. ksadk/conversations/tool_receipt_resume.py +387 -0
  146. ksadk/conversations/tool_receipts.py +32 -0
  147. ksadk/deployment/env_forward.py +5 -0
  148. ksadk/deployment/manager.py +15 -6
  149. ksadk/deployment/providers/serverless.py +76 -136
  150. ksadk/deployment/providers/serverless_payloads.py +122 -0
  151. ksadk/evaluation/agent_eval_client.py +2 -1
  152. ksadk/evaluation/contracts.py +78 -3
  153. ksadk/evaluation/evaluators.py +166 -1
  154. ksadk/evaluation/evidence.py +271 -4
  155. ksadk/evaluation/local_adapter.py +76 -12
  156. ksadk/evaluation/studio_build_adapter.py +73 -9
  157. ksadk/events/adapters/_a2a_checkpoint.py +151 -0
  158. ksadk/events/adapters/_a2a_snapshot.py +18 -14
  159. ksadk/events/adapters/_a2a_support.py +15 -3
  160. ksadk/events/adapters/_a2a_tool_activity.py +123 -0
  161. ksadk/events/adapters/_codex_errors.py +49 -0
  162. ksadk/events/adapters/_codex_items.py +16 -8
  163. ksadk/events/adapters/_langgraph_support.py +46 -1
  164. ksadk/events/adapters/a2a.py +54 -26
  165. ksadk/events/adapters/adk.py +188 -30
  166. ksadk/events/adapters/codex.py +33 -7
  167. ksadk/events/adapters/langgraph.py +16 -6
  168. ksadk/events/canonical.py +5 -0
  169. ksadk/events/canonical_store.py +200 -4
  170. ksadk/events/reducer.py +82 -0
  171. ksadk/events/run_authority.py +176 -0
  172. ksadk/events/session_event.py +2 -2
  173. ksadk/harness/__init__.py +18 -0
  174. ksadk/harness/app.py +11 -0
  175. ksadk/harness/artifact_adapters/__init__.py +1 -0
  176. ksadk/harness/artifact_adapters/native_page_budget.py +172 -0
  177. ksadk/harness/artifact_adapters/native_search.py +249 -0
  178. ksadk/harness/artifact_adapters/native_search_budget.py +134 -0
  179. ksadk/harness/artifact_adapters/native_store.py +115 -0
  180. ksadk/harness/artifact_adapters/native_tool.py +222 -0
  181. ksadk/harness/artifact_store.py +230 -0
  182. ksadk/harness/browser_adapters/__init__.py +6 -0
  183. ksadk/harness/browser_adapters/native_browser_tool.py +92 -0
  184. ksadk/harness/browser_adapters/native_dom_snapshot.py +187 -0
  185. ksadk/harness/browser_adapters/native_playwright.py +953 -0
  186. ksadk/harness/browser_adapters/native_vision.py +295 -0
  187. ksadk/harness/capabilities.py +115 -0
  188. ksadk/harness/capability_adapters/__init__.py +1 -0
  189. ksadk/harness/capability_adapters/native_dsh.py +289 -0
  190. ksadk/harness/capability_runtime.py +332 -0
  191. ksadk/harness/closure_contract.py +92 -0
  192. ksadk/harness/compaction_record.py +153 -0
  193. ksadk/harness/compiler.py +284 -0
  194. ksadk/harness/config.py +28 -5
  195. ksadk/harness/conformance/__init__.py +33 -0
  196. ksadk/harness/conformance/contract.py +504 -0
  197. ksadk/harness/conformance/fixtures.py +102 -0
  198. ksadk/harness/context_engine.py +388 -0
  199. ksadk/harness/context_maintenance.py +259 -0
  200. ksadk/harness/context_manifest.py +188 -0
  201. ksadk/harness/context_sections.py +397 -0
  202. ksadk/harness/context_tuning.py +168 -0
  203. ksadk/harness/diagnostic_adapters/__init__.py +1 -0
  204. ksadk/harness/diagnostic_adapters/contracts.py +70 -0
  205. ksadk/harness/diagnostic_adapters/lsp_rpc.py +210 -0
  206. ksadk/harness/diagnostic_adapters/native_lsp.py +286 -0
  207. ksadk/harness/draft_runtime.py +322 -0
  208. ksadk/harness/engine/__init__.py +40 -0
  209. ksadk/harness/engine/base.py +122 -0
  210. ksadk/harness/engine/budgets.py +108 -0
  211. ksadk/harness/engine/capability_declarations.py +59 -0
  212. ksadk/harness/engine/completion_guard.py +57 -0
  213. ksadk/harness/engine/context_pipeline.py +1351 -0
  214. ksadk/harness/engine/graph_builder.py +352 -0
  215. ksadk/harness/engine/hooked_reasoner.py +380 -0
  216. ksadk/harness/engine/langgraph.py +1049 -0
  217. ksadk/harness/engine/mcp_disclosure.py +701 -0
  218. ksadk/harness/engine/phases/__init__.py +6 -0
  219. ksadk/harness/engine/phases/context.py +48 -0
  220. ksadk/harness/engine/phases/interaction.py +31 -0
  221. ksadk/harness/engine/phases/reason.py +552 -0
  222. ksadk/harness/engine/phases/tools.py +638 -0
  223. ksadk/harness/engine/policy_runtime.py +81 -0
  224. ksadk/harness/engine/postgres_checkpointer.py +386 -0
  225. ksadk/harness/engine/run_control_bridge.py +100 -0
  226. ksadk/harness/engine/run_types.py +98 -0
  227. ksadk/harness/engine/skill_disclosure.py +275 -0
  228. ksadk/harness/engine/spans.py +41 -0
  229. ksadk/harness/engine/steering.py +177 -0
  230. ksadk/harness/engine/subagents.py +360 -0
  231. ksadk/harness/engine/thread_ids.py +112 -0
  232. ksadk/harness/engine/tool_dispatch.py +249 -0
  233. ksadk/harness/event_tree.py +212 -0
  234. ksadk/harness/events.py +498 -0
  235. ksadk/harness/execution_policy.py +104 -0
  236. ksadk/harness/hooks.py +259 -0
  237. ksadk/harness/insights.py +210 -0
  238. ksadk/harness/lifecycle.py +578 -0
  239. ksadk/harness/lifecycle_conformance.py +233 -0
  240. ksadk/harness/lifecycle_local_plane.py +104 -0
  241. ksadk/harness/loop/__init__.py +44 -0
  242. ksadk/harness/loop/reason.py +699 -0
  243. ksadk/harness/loop/tools.py +907 -0
  244. ksadk/harness/managed_runtime.py +1044 -0
  245. ksadk/harness/mcp_disclosure_contract.py +85 -0
  246. ksadk/harness/mcp_matrix.py +474 -0
  247. ksadk/harness/mcp_result_policy.py +44 -0
  248. ksadk/harness/mcp_runtime.py +504 -0
  249. ksadk/harness/memory_consolidation.py +157 -0
  250. ksadk/harness/memory_loop.py +156 -0
  251. ksadk/harness/memory_runtime.py +541 -0
  252. ksadk/harness/metrics.py +90 -0
  253. ksadk/harness/micro_compact.py +69 -0
  254. ksadk/harness/model_adapters/__init__.py +1 -0
  255. ksadk/harness/model_adapters/native_mcp_media.py +100 -0
  256. ksadk/harness/model_adapters/native_mcp_result.py +36 -0
  257. ksadk/harness/model_adapters/native_openai.py +703 -0
  258. ksadk/harness/model_capability.py +468 -0
  259. ksadk/harness/model_provider.py +430 -0
  260. ksadk/harness/multimodal.py +57 -0
  261. ksadk/harness/native/__init__.py +1 -0
  262. ksadk/harness/native/activation_contract.py +25 -0
  263. ksadk/harness/native/activation_recovery.py +29 -0
  264. ksadk/harness/native/adapters.py +291 -0
  265. ksadk/harness/native/artifact_contract.py +14 -0
  266. ksadk/harness/native/artifact_partial_read_capacity.py +171 -0
  267. ksadk/harness/native/artifact_read_capacity.py +182 -0
  268. ksadk/harness/native/artifact_read_contract.py +27 -0
  269. ksadk/harness/native/artifact_runtime.py +408 -0
  270. ksadk/harness/native/artifact_search_capacity.py +206 -0
  271. ksadk/harness/native/artifact_search_contract.py +40 -0
  272. ksadk/harness/native/artifact_single_read_capacity.py +170 -0
  273. ksadk/harness/native/browser_contract.py +229 -0
  274. ksadk/harness/native/browser_recovery.py +183 -0
  275. ksadk/harness/native/capabilities.py +204 -0
  276. ksadk/harness/native/child_approval.py +60 -0
  277. ksadk/harness/native/child_budget.py +136 -0
  278. ksadk/harness/native/child_cancellation.py +80 -0
  279. ksadk/harness/native/child_input.py +98 -0
  280. ksadk/harness/native/child_input_runtime.py +59 -0
  281. ksadk/harness/native/child_interruption.py +81 -0
  282. ksadk/harness/native/child_lifecycle.py +246 -0
  283. ksadk/harness/native/child_lifecycle_contract.py +91 -0
  284. ksadk/harness/native/child_notifications.py +75 -0
  285. ksadk/harness/native/child_promotion.py +66 -0
  286. ksadk/harness/native/command_runtime.py +99 -0
  287. ksadk/harness/native/completion.py +302 -0
  288. ksadk/harness/native/completion_text.py +116 -0
  289. ksadk/harness/native/context.py +358 -0
  290. ksadk/harness/native/context_artifact_page.py +75 -0
  291. ksadk/harness/native/context_compaction_projection.py +131 -0
  292. ksadk/harness/native/context_contributions.py +320 -0
  293. ksadk/harness/native/context_contributor_contract.py +133 -0
  294. ksadk/harness/native/context_driver.py +820 -0
  295. ksadk/harness/native/context_fresh_tools.py +49 -0
  296. ksadk/harness/native/context_history.py +272 -0
  297. ksadk/harness/native/context_microcompact.py +61 -0
  298. ksadk/harness/native/context_partial_summary.py +58 -0
  299. ksadk/harness/native/context_partition.py +492 -0
  300. ksadk/harness/native/context_pruning.py +275 -0
  301. ksadk/harness/native/context_reduction.py +60 -0
  302. ksadk/harness/native/context_replay.py +148 -0
  303. ksadk/harness/native/context_request_projection.py +526 -0
  304. ksadk/harness/native/context_runtime.py +976 -0
  305. ksadk/harness/native/context_runtime_contracts.py +409 -0
  306. ksadk/harness/native/context_search.py +112 -0
  307. ksadk/harness/native/context_source_fragments.py +188 -0
  308. ksadk/harness/native/context_source_progress.py +119 -0
  309. ksadk/harness/native/context_summary_planning.py +788 -0
  310. ksadk/harness/native/context_summary_recovery.py +105 -0
  311. ksadk/harness/native/delivery_review.py +331 -0
  312. ksadk/harness/native/delivery_review_contract.py +54 -0
  313. ksadk/harness/native/effect_admission.py +82 -0
  314. ksadk/harness/native/effect_control.py +318 -0
  315. ksadk/harness/native/effect_receipts.py +729 -0
  316. ksadk/harness/native/effect_runtime.py +303 -0
  317. ksadk/harness/native/effective_configuration.py +28 -0
  318. ksadk/harness/native/engine.py +945 -0
  319. ksadk/harness/native/final_output.py +34 -0
  320. ksadk/harness/native/final_submission.py +58 -0
  321. ksadk/harness/native/finalization_workspace.py +96 -0
  322. ksadk/harness/native/fork.py +151 -0
  323. ksadk/harness/native/guidance.py +91 -0
  324. ksadk/harness/native/history.py +381 -0
  325. ksadk/harness/native/hook_executor.py +205 -0
  326. ksadk/harness/native/hook_runtime_contract.py +282 -0
  327. ksadk/harness/native/interaction_observation.py +117 -0
  328. ksadk/harness/native/lease.py +103 -0
  329. ksadk/harness/native/machine.py +974 -0
  330. ksadk/harness/native/mcp_result_governance.py +156 -0
  331. ksadk/harness/native/model.py +570 -0
  332. ksadk/harness/native/model_feedback.py +63 -0
  333. ksadk/harness/native/model_input.py +30 -0
  334. ksadk/harness/native/model_recovery_contract.py +35 -0
  335. ksadk/harness/native/model_replay.py +128 -0
  336. ksadk/harness/native/model_request.py +133 -0
  337. ksadk/harness/native/model_runtime.py +196 -0
  338. ksadk/harness/native/model_takeover.py +419 -0
  339. ksadk/harness/native/model_tool_batch.py +40 -0
  340. ksadk/harness/native/observed_progress.py +46 -0
  341. ksadk/harness/native/operator_guidance.py +201 -0
  342. ksadk/harness/native/output_contract.py +80 -0
  343. ksadk/harness/native/output_recovery.py +24 -0
  344. ksadk/harness/native/ports.py +749 -0
  345. ksadk/harness/native/precompact_hook_runtime.py +171 -0
  346. ksadk/harness/native/replay_context.py +149 -0
  347. ksadk/harness/native/request_media.py +112 -0
  348. ksadk/harness/native/restore_contract.py +16 -0
  349. ksadk/harness/native/run_clock.py +120 -0
  350. ksadk/harness/native/state.py +436 -0
  351. ksadk/harness/native/steering.py +170 -0
  352. ksadk/harness/native/stop_hook_runtime.py +151 -0
  353. ksadk/harness/native/studio_admission.py +29 -0
  354. ksadk/harness/native/subagents.py +86 -0
  355. ksadk/harness/native/task_policy.py +99 -0
  356. ksadk/harness/native/task_progress.py +86 -0
  357. ksadk/harness/native/terminal_verification.py +43 -0
  358. ksadk/harness/native/tool_argument_feedback.py +178 -0
  359. ksadk/harness/native/tool_budget.py +253 -0
  360. ksadk/harness/native/tool_error_streak.py +89 -0
  361. ksadk/harness/native/tool_hook_runtime.py +343 -0
  362. ksadk/harness/native/tool_input_validation.py +58 -0
  363. ksadk/harness/native/tool_interruption.py +96 -0
  364. ksadk/harness/native/tool_observation.py +259 -0
  365. ksadk/harness/native/tool_progress.py +223 -0
  366. ksadk/harness/native/tool_recovery.py +25 -0
  367. ksadk/harness/native/tool_scheduling.py +33 -0
  368. ksadk/harness/native/tool_schema.py +126 -0
  369. ksadk/harness/native/transitions.py +151 -0
  370. ksadk/harness/native/turn_control.py +98 -0
  371. ksadk/harness/native/user_document.py +98 -0
  372. ksadk/harness/native/user_document_capture.py +49 -0
  373. ksadk/harness/native/user_input.py +87 -0
  374. ksadk/harness/native/verification.py +432 -0
  375. ksadk/harness/native/verification_binding.py +40 -0
  376. ksadk/harness/native/verification_runtime.py +233 -0
  377. ksadk/harness/native/verification_workspace.py +67 -0
  378. ksadk/harness/native_driver_failure.py +123 -0
  379. ksadk/harness/native_facade.py +977 -0
  380. ksadk/harness/native_factory.py +244 -0
  381. ksadk/harness/native_projection.py +503 -0
  382. ksadk/harness/native_runtime.py +621 -0
  383. ksadk/harness/native_shadow.py +250 -0
  384. ksadk/harness/native_shadow_inputs.py +146 -0
  385. ksadk/harness/observability/__init__.py +29 -0
  386. ksadk/harness/observability/inspection.py +528 -0
  387. ksadk/harness/observability/metrics.py +167 -0
  388. ksadk/harness/observability/otel_exporter.py +218 -0
  389. ksadk/harness/progress_adapters/__init__.py +5 -0
  390. ksadk/harness/progress_adapters/native_todo.py +75 -0
  391. ksadk/harness/prompt_cache.py +132 -0
  392. ksadk/harness/public_activity.py +213 -0
  393. ksadk/harness/public_output.py +30 -0
  394. ksadk/harness/public_summary.py +36 -0
  395. ksadk/harness/readiness.py +249 -0
  396. ksadk/harness/reasoner.py +779 -17
  397. ksadk/harness/release_readiness.py +140 -0
  398. ksadk/harness/resource_ref.py +69 -0
  399. ksadk/harness/rpc.py +200 -0
  400. ksadk/harness/run_control.py +773 -0
  401. ksadk/harness/runtime.py +157 -113
  402. ksadk/harness/runtime_capabilities.py +228 -0
  403. ksadk/harness/runtime_server.py +514 -0
  404. ksadk/harness/sandbox_adapters.py +739 -0
  405. ksadk/harness/sandbox_backend.py +733 -0
  406. ksadk/harness/sandbox_conformance.py +288 -0
  407. ksadk/harness/sandbox_lease.py +77 -0
  408. ksadk/harness/sandbox_lease_conformance.py +259 -0
  409. ksadk/harness/sandbox_matrix.py +170 -0
  410. ksadk/harness/sandbox_reconciliation.py +140 -0
  411. ksadk/harness/sandbox_recovery.py +586 -0
  412. ksadk/harness/sandbox_recovery_conformance.py +246 -0
  413. ksadk/harness/sdk.py +153 -0
  414. ksadk/harness/session_store.py +589 -0
  415. ksadk/harness/skill_adapters/__init__.py +1 -0
  416. ksadk/harness/skill_adapters/native_bundle.py +148 -0
  417. ksadk/harness/skill_adapters/native_disclosure.py +306 -0
  418. ksadk/harness/skill_composition.py +212 -0
  419. ksadk/harness/skill_feedback.py +123 -0
  420. ksadk/harness/skill_intent.py +47 -0
  421. ksadk/harness/skill_matrix.py +233 -0
  422. ksadk/harness/skill_runtime.py +317 -0
  423. ksadk/harness/spec.py +342 -0
  424. ksadk/harness/state.py +155 -0
  425. ksadk/harness/stores/__init__.py +14 -0
  426. ksadk/harness/stores/native_command_settlement.py +65 -0
  427. ksadk/harness/stores/native_contract.py +311 -0
  428. ksadk/harness/stores/native_memory.py +326 -0
  429. ksadk/harness/stores/native_memory_archive.py +70 -0
  430. ksadk/harness/stores/native_migration_cli.py +91 -0
  431. ksadk/harness/stores/native_outbox.py +56 -0
  432. ksadk/harness/stores/native_sqlite.py +782 -0
  433. ksadk/harness/stores/native_sqlite_audit.py +29 -0
  434. ksadk/harness/stores/native_sqlite_migration.py +252 -0
  435. ksadk/harness/strategies.py +149 -0
  436. ksadk/harness/subagent.py +263 -0
  437. ksadk/harness/subagent_adapters/checkpoint_recovery.py +120 -0
  438. ksadk/harness/subagent_adapters/native_background_child.py +803 -0
  439. ksadk/harness/subagent_adapters/native_child.py +819 -0
  440. ksadk/harness/subagent_adapters/native_child_approval.py +128 -0
  441. ksadk/harness/subagent_adapters/native_child_continuation.py +51 -0
  442. ksadk/harness/subagent_adapters/native_child_result.py +392 -0
  443. ksadk/harness/subagent_adapters/prepared_recovery.py +120 -0
  444. ksadk/harness/tool_display.py +75 -0
  445. ksadk/harness/tool_display_contract.py +134 -0
  446. ksadk/harness/tool_output.py +141 -0
  447. ksadk/harness/tool_policy.py +134 -0
  448. ksadk/harness/tool_receipts.py +96 -0
  449. ksadk/harness/tool_reliability.py +81 -0
  450. ksadk/harness/tool_result_policy.py +216 -0
  451. ksadk/harness/tools.py +52 -0
  452. ksadk/harness/user_errors.py +69 -0
  453. ksadk/harness/working_context.py +81 -0
  454. ksadk/harness/working_context_patch.py +99 -0
  455. ksadk/harness/workspace_adapters/__init__.py +6 -0
  456. ksadk/harness/workspace_adapters/native_directory.py +180 -0
  457. ksadk/harness/workspace_adapters/native_git.py +208 -0
  458. ksadk/harness/workspace_adapters/native_isolation.py +350 -0
  459. ksadk/identity/resolver.py +18 -0
  460. ksadk/interaction/__init__.py +1 -1
  461. ksadk/interaction/ledger.py +1 -1
  462. ksadk/interaction/provider.py +1 -1
  463. ksadk/interaction/providers/__init__.py +3 -1
  464. ksadk/interaction/providers/adk.py +1 -1
  465. ksadk/interaction/providers/codex.py +1 -1
  466. ksadk/interaction/providers/harness.py +50 -0
  467. ksadk/interaction/providers/langgraph.py +9 -2
  468. ksadk/kernel/__init__.py +10 -0
  469. ksadk/kernel/approval_presentation.py +91 -0
  470. ksadk/kernel/authorization.py +1 -1
  471. ksadk/kernel/bootstrap.py +220 -252
  472. ksadk/kernel/contract_fingerprints.py +45 -1
  473. ksadk/kernel/contracts.py +30 -0
  474. ksadk/kernel/control.py +180 -29
  475. ksadk/kernel/execution_grants.py +428 -0
  476. ksadk/kernel/execution_grants_memory.py +252 -0
  477. ksadk/kernel/execution_grants_postgres.py +395 -0
  478. ksadk/kernel/execution_grants_sqlite.py +435 -0
  479. ksadk/kernel/execution_host_ingress.py +1071 -0
  480. ksadk/kernel/history_projection.py +120 -0
  481. ksadk/kernel/ingress.py +139 -226
  482. ksadk/kernel/ingress_bootstrap.py +268 -0
  483. ksadk/kernel/legacy_history.py +179 -0
  484. ksadk/kernel/mapping.py +1 -1
  485. ksadk/kernel/memory_store.py +61 -58
  486. ksadk/kernel/memory_store_projection.py +63 -0
  487. ksadk/kernel/postgres_event_log.py +181 -0
  488. ksadk/kernel/postgres_store.py +230 -231
  489. ksadk/kernel/readiness.py +125 -0
  490. ksadk/kernel/recovery.py +166 -16
  491. ksadk/kernel/recovery_projection.py +124 -0
  492. ksadk/kernel/runtime_checkpoint.py +34 -0
  493. ksadk/kernel/sql/001_agent_kernel.sql +28 -0
  494. ksadk/kernel/sqlite_schema.py +100 -0
  495. ksadk/kernel/sqlite_store.py +410 -200
  496. ksadk/kernel/state.py +2 -3
  497. ksadk/kernel/store.py +104 -5
  498. ksadk/kernel/teams_artifact_tools.py +392 -0
  499. ksadk/kernel/teams_effects.py +851 -0
  500. ksadk/kernel/teams_execution_context.py +408 -0
  501. ksadk/kernel/teams_host_http.py +237 -0
  502. ksadk/kernel/teams_material_transport.py +245 -0
  503. ksadk/kernel/teams_materials.py +318 -0
  504. ksadk/kernel/teams_runtime_bootstrap.py +604 -0
  505. ksadk/kernel/teams_tool_runtime.py +273 -0
  506. ksadk/kernel/teams_workspace.py +259 -0
  507. ksadk/kernel/worker.py +369 -340
  508. ksadk/kernel/worker_controls.py +454 -0
  509. ksadk/kernel/worker_history.py +72 -0
  510. ksadk/kernel/worker_identity.py +74 -0
  511. ksadk/kernel/worker_interactions.py +197 -0
  512. ksadk/knowledge_base/client.py +15 -1
  513. ksadk/managed_runtime.py +29 -2
  514. ksadk/memory/adk/backends/http_ltm_backend.py +2 -1
  515. ksadk/memory/adk/backends/sdk_ltm_backend.py +15 -1
  516. ksadk/memory/adk/bounded_database_session_service.py +232 -0
  517. ksadk/memory/adk/resilient_session_service.py +115 -15
  518. ksadk/memory/adk/short_term_memory.py +8 -9
  519. ksadk/memory/coordinator.py +22 -6
  520. ksadk/memory/extraction.py +159 -7
  521. ksadk/memory/models.py +77 -1
  522. ksadk/memory/provider_resolver.py +5 -0
  523. ksadk/memory/providers/local_candidates.py +183 -0
  524. ksadk/memory/providers/local_postgres.py +200 -0
  525. ksadk/memory/providers/local_sqlite.py +280 -67
  526. ksadk/memory/resolved_policy.py +12 -7
  527. ksadk/memory/retrieval.py +189 -0
  528. ksadk/memory/store_adapter.py +150 -0
  529. ksadk/model_gateway/__init__.py +29 -0
  530. ksadk/model_gateway/client.py +253 -0
  531. ksadk/model_gateway/events.py +113 -0
  532. ksadk/model_gateway/matrix.py +297 -0
  533. ksadk/model_policy.py +2 -2
  534. ksadk/model_proxy/compat.py +670 -0
  535. ksadk/model_proxy/detect.py +254 -0
  536. ksadk/model_proxy/server.py +14 -9
  537. ksadk/model_proxy/transform.py +72 -6
  538. ksadk/plugins/__init__.py +1 -1
  539. ksadk/plugins/bridges/dsh.py +29 -20
  540. ksadk/plugins/bridges/dsh_profile_manifest.py +36 -0
  541. ksadk/plugins/builtin_resources.py +199 -0
  542. ksadk/plugins/builtins.py +417 -185
  543. ksadk/plugins/companion_artifacts.py +83 -0
  544. ksadk/plugins/companions.py +368 -0
  545. ksadk/plugins/context_contributor.py +15 -4
  546. ksadk/plugins/contracts.py +1 -1
  547. ksadk/plugins/dsh_channels.py +156 -0
  548. ksadk/plugins/dsh_dependency_policy.py +41 -0
  549. ksadk/plugins/dsh_home.py +140 -0
  550. ksadk/plugins/dsh_teams.py +105 -0
  551. ksadk/plugins/dsh_toolchain.py +92 -21
  552. ksadk/plugins/execution_host.py +107 -0
  553. ksadk/plugins/host.py +73 -5
  554. ksadk/plugins/kernel_adapter.py +44 -1
  555. ksadk/plugins/memory_provider.py +180 -0
  556. ksadk/plugins/providers/_process_group.py +50 -0
  557. ksadk/plugins/providers/bundles/dsh-channels-client/client.js +19 -0
  558. ksadk/plugins/providers/bundles/dsh-channels-client/cordis.patch.yml +3 -0
  559. ksadk/plugins/providers/bundles/dsh-channels-client/index.mjs +7 -0
  560. ksadk/plugins/providers/bundles/dsh-channels-client/package.json +12 -0
  561. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +24 -2
  562. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +1 -1
  563. ksadk/plugins/providers/bundles/dsh-memory/package.json +1 -1
  564. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +1 -1
  565. ksadk/plugins/providers/bundles/dsh-teams-client/client.js +29 -0
  566. ksadk/plugins/providers/bundles/dsh-teams-client/cordis.patch.yml +3 -0
  567. ksadk/plugins/providers/bundles/dsh-teams-client/index.mjs +11 -0
  568. ksadk/plugins/providers/bundles/dsh-teams-client/package.json +35 -0
  569. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/cordis.patch.yml +3 -0
  570. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/index.mjs +13 -0
  571. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/package.json +27 -0
  572. ksadk/plugins/providers/bundles/dsh-teams-profile/cordis.patch.yml +3 -0
  573. ksadk/plugins/providers/bundles/dsh-teams-profile/index.mjs +12 -0
  574. ksadk/plugins/providers/bundles/dsh-teams-profile/package.json +26 -0
  575. ksadk/plugins/providers/bundles/dsh-teams-router/cordis.patch.yml +3 -0
  576. ksadk/plugins/providers/bundles/dsh-teams-router/index.mjs +16 -0
  577. ksadk/plugins/providers/bundles/dsh-teams-router/package.json +27 -0
  578. ksadk/plugins/providers/bundles/dsh-teams-tasks/cordis.patch.yml +3 -0
  579. ksadk/plugins/providers/bundles/dsh-teams-tasks/index.mjs +16 -0
  580. ksadk/plugins/providers/bundles/dsh-teams-tasks/package.json +27 -0
  581. ksadk/plugins/providers/bundles/dsh-teams-tools/cordis.patch.yml +3 -0
  582. ksadk/plugins/providers/bundles/dsh-teams-tools/index.mjs +25 -0
  583. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +29 -0
  584. ksadk/plugins/providers/bundles/dsh-teams-tools/tools.json +235 -0
  585. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +1 -1
  586. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +51 -1
  587. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +2 -2
  588. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/client.mjs +133 -0
  589. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/index.mjs +14 -0
  590. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +27 -4
  591. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +9 -5
  592. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +1 -1
  593. ksadk/plugins/providers/codex.py +52 -40
  594. ksadk/plugins/providers/codex_native.py +20 -0
  595. ksadk/plugins/providers/codex_skills.py +46 -0
  596. ksadk/plugins/providers/dsh_capabilities.py +49 -143
  597. ksadk/plugins/providers/dsh_connector_lease.py +225 -0
  598. ksadk/plugins/providers/dsh_mcp.py +163 -1
  599. ksadk/plugins/providers/harness.py +413 -52
  600. ksadk/plugins/providers/harness_context.py +61 -0
  601. ksadk/plugins/providers/harness_contributions.py +241 -0
  602. ksadk/plugins/providers/harness_delegation.py +670 -0
  603. ksadk/plugins/providers/harness_hooks.py +121 -0
  604. ksadk/plugins/providers/harness_managed.py +550 -0
  605. ksadk/plugins/providers/harness_tools.py +455 -0
  606. ksadk/plugins/providers/legacy_catalog.py +1 -1
  607. ksadk/plugins/providers/mcp_projection.py +100 -3
  608. ksadk/plugins/providers/platform_resources.py +16 -6
  609. ksadk/plugins/providers/shipped_dsh.py +4 -1
  610. ksadk/plugins/subagent_providers/codex.py +28 -6
  611. ksadk/plugins/teams/__init__.py +5 -0
  612. ksadk/plugins/teams/api.py +405 -0
  613. ksadk/plugins/teams/application.py +540 -0
  614. ksadk/plugins/teams/artifacts.py +60 -0
  615. ksadk/plugins/teams/build_artifacts.py +460 -0
  616. ksadk/plugins/teams/cloud_contract_fingerprints.py +22 -0
  617. ksadk/plugins/teams/cloud_contracts.py +928 -0
  618. ksadk/plugins/teams/cloud_permits.py +250 -0
  619. ksadk/plugins/teams/context.py +96 -0
  620. ksadk/plugins/teams/contracts.py +136 -0
  621. ksadk/plugins/teams/domain.py +1480 -0
  622. ksadk/plugins/teams/domain_values.py +24 -0
  623. ksadk/plugins/teams/effect_contracts.py +255 -0
  624. ksadk/plugins/teams/errors.py +13 -0
  625. ksadk/plugins/teams/execution_projection.py +255 -0
  626. ksadk/plugins/teams/leader_decisions.py +106 -0
  627. ksadk/plugins/teams/migration.py +311 -0
  628. ksadk/plugins/teams/migration_cli.py +322 -0
  629. ksadk/plugins/teams/postgres_store.py +352 -0
  630. ksadk/plugins/teams/release_contracts.py +60 -0
  631. ksadk/plugins/teams/runtime.py +853 -0
  632. ksadk/plugins/teams/source_projection.py +84 -0
  633. ksadk/plugins/teams/store.py +519 -0
  634. ksadk/plugins/teams/task_decisions.py +436 -0
  635. ksadk/plugins/teams/tool_service.py +152 -0
  636. ksadk/plugins/teams/transport.py +96 -0
  637. ksadk/plugins/teams/workspaces.py +255 -0
  638. ksadk/resource_runtime/skill_runtime.py +3 -0
  639. ksadk/resource_runtime/socket_server.py +11 -0
  640. ksadk/resource_runtime/worker.py +28 -4
  641. ksadk/runners/_adk_a2a_stream.py +122 -0
  642. ksadk/runners/_adk_canonical_stream.py +474 -0
  643. ksadk/runners/_langgraph_canonical_streams.py +527 -0
  644. ksadk/runners/_langgraph_runner_streams.py +83 -401
  645. ksadk/runners/_langgraph_state_reader.py +106 -0
  646. ksadk/runners/_langgraph_tool_projection.py +86 -0
  647. ksadk/runners/_langgraph_tools_transformer.py +27 -0
  648. ksadk/runners/_session_identity.py +285 -0
  649. ksadk/runners/adk_runner.py +220 -350
  650. ksadk/runners/base_runner.py +6 -5
  651. ksadk/runners/langgraph_runner.py +208 -195
  652. ksadk/runners/patch_langchain.py +47 -0
  653. ksadk/runners/usage_accumulator.py +11 -3
  654. ksadk/runners/utils/loader.py +28 -14
  655. ksadk/runtime/_runner_adapter/a2ui_surface.py +145 -0
  656. ksadk/runtime/_runner_adapter/gateway_approvals.py +93 -0
  657. ksadk/runtime/_runner_adapter/stream_mapping.py +134 -129
  658. ksadk/runtime/adapter.py +40 -3
  659. ksadk/runtime/conversation_execution.py +29 -3
  660. ksadk/runtime/executor.py +105 -7
  661. ksadk/runtime/factory.py +45 -3
  662. ksadk/runtime/framework_adapters.py +184 -10
  663. ksadk/runtime/hosted_finalizer.py +4 -6
  664. ksadk/runtime/launch.py +2 -0
  665. ksadk/runtime/preprocessing.py +11 -3
  666. ksadk/runtime/runner_adapter.py +160 -21
  667. ksadk/runtime/skill_eval_result.py +36 -0
  668. ksadk/runtime/timing.py +46 -0
  669. ksadk/runtime/usage.py +49 -18
  670. ksadk/runtime_context.py +105 -1
  671. ksadk/sandbox/backends/e2b.py +272 -24
  672. ksadk/sandbox/backends/local_process.py +73 -39
  673. ksadk/sandbox/base.py +62 -1
  674. ksadk/sandbox/diagnostics.py +82 -0
  675. ksadk/sandbox/e2b_connection.py +9 -1
  676. ksadk/sandbox/local_controls.py +776 -0
  677. ksadk/sandbox/local_launcher.py +124 -0
  678. ksadk/scheduler/dispatcher.py +1 -1
  679. ksadk/server/factory.py +178 -25
  680. ksadk/server/history_deadline.py +158 -0
  681. ksadk/server/history_page_cache.py +129 -0
  682. ksadk/server/invocation_identity.py +118 -0
  683. ksadk/server/routes/checkpoint_audit.py +88 -0
  684. ksadk/server/routes/checkpoint_listing.py +294 -0
  685. ksadk/server/routes/checkpoint_resolution.py +73 -20
  686. ksadk/server/routes/common.py +32 -3
  687. ksadk/server/routes/control.py +112 -9
  688. ksadk/server/routes/dependencies.py +2 -1
  689. ksadk/server/routes/display_projection.py +154 -0
  690. ksadk/server/routes/kernel_ingress.py +26 -3
  691. ksadk/server/routes/misc.py +331 -33
  692. ksadk/server/routes/models.py +28 -4
  693. ksadk/server/routes/openai_compat.py +82 -13
  694. ksadk/server/routes/projection.py +159 -216
  695. ksadk/server/routes/run.py +112 -37
  696. ksadk/server/routes/sessions.py +493 -358
  697. ksadk/server/routes/streaming.py +68 -15
  698. ksadk/server/routes/tool_receipt_claim_routes.py +107 -0
  699. ksadk/server/routes/workspace.py +135 -23
  700. ksadk/server/static/assets/{ArtifactsPanel-CGbWlMNh.js → ArtifactsPanel-CILaW-fC.js} +1 -1
  701. ksadk/server/static/assets/{CodeBlock-b4C7upmO.js → CodeBlock-BVrNVtJC.js} +10 -7
  702. ksadk/server/static/assets/MathMessageMarkdown-Dp7c4wWD.js +8 -0
  703. ksadk/server/static/assets/{MermaidBlock-BEBN4Ksz.js → MermaidBlock-Dxop8Rd7.js} +9 -9
  704. ksadk/server/static/assets/{NativeTerminalPanel-zvL-WpAn.js → NativeTerminalPanel-Cjjz8B30.js} +1 -1
  705. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-BYafW7Za.js → abnfDiagram-VCTEODGH-ckWDmOzw.js} +1 -1
  706. ksadk/server/static/assets/{arc-bTohInsS.js → arc-DqxJede-.js} +1 -1
  707. ksadk/server/static/assets/architecture-7GRP2DOG-pn_DuLy6.js +1 -0
  708. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-Ch5Lbzsi.js → architectureDiagram-5GKGNRK7-SEQA4bVi.js} +1 -1
  709. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-kqF4MDOG.js → blockDiagram-NRAW4CY4-pM0B-6NJ.js} +1 -1
  710. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-8uSRIODv.js → c4Diagram-UCG6FXSJ-m2tuCNVq.js} +1 -1
  711. ksadk/server/static/assets/channel-fySsnkft.js +1 -0
  712. ksadk/server/static/assets/chunk-2Q5K7J3B-BheGxKRQ.js +1 -0
  713. ksadk/server/static/assets/{chunk-5VM5RSS4-DkhehZDr.js → chunk-5VM5RSS4-GJHDr9Ww.js} +1 -1
  714. ksadk/server/static/assets/{chunk-F27PBJKO-BdXhtPe9.js → chunk-F27PBJKO-CbAN45AV.js} +1 -1
  715. ksadk/server/static/assets/{chunk-G27WJ6UU-DPTpvpwi.js → chunk-G27WJ6UU-D5ngbbzF.js} +1 -1
  716. ksadk/server/static/assets/{chunk-JWPE2WC7-Pqoh38el.js → chunk-JWPE2WC7-Cc5IwuYC.js} +1 -1
  717. ksadk/server/static/assets/{chunk-LCL6LL3I-DeU00qC-.js → chunk-LCL6LL3I-CprgDDdJ.js} +1 -1
  718. ksadk/server/static/assets/{chunk-POPQ4Y6H-CzxScFkr.js → chunk-POPQ4Y6H-CDZhSy82.js} +1 -1
  719. ksadk/server/static/assets/{chunk-RHFEMEQ7-DpqMx-ux.js → chunk-RHFEMEQ7-CZchUNro.js} +1 -1
  720. ksadk/server/static/assets/{chunk-SVP7TREG-C6t0SypQ.js → chunk-SVP7TREG-BVruqk6T.js} +1 -1
  721. ksadk/server/static/assets/{chunk-XXDRQBXY-DVaeafZk.js → chunk-XXDRQBXY-4ld9SxPN.js} +1 -1
  722. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DSfLtNYm.js +1 -0
  723. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DSfLtNYm.js +1 -0
  724. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-Bf9D3tzJ.js → cose-bilkent-JH36ORCC-Dmyyk_Vp.js} +1 -1
  725. ksadk/server/static/assets/cynefin-OW5HDTMX-PFWIGtvA.js +1 -0
  726. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-B9cY3iTz.js → cynefinDiagram-5FMLGOSQ-BIyq3EJb.js} +1 -1
  727. ksadk/server/static/assets/{dagre-3AP2YEHR-CSwlx3CB.js → dagre-3AP2YEHR-eBw08Qdk.js} +1 -1
  728. ksadk/server/static/assets/{dagre-UBpgon5q.js → dagre-DfvnEf45.js} +1 -1
  729. ksadk/server/static/assets/{diagram-S7CK7UJ4-C9akhN9a.js → diagram-S7CK7UJ4-CUSrE3Mg.js} +1 -1
  730. ksadk/server/static/assets/{diagram-UQ7AKVKN-CgedhTPI.js → diagram-UQ7AKVKN-Dq5Zw2gy.js} +1 -1
  731. ksadk/server/static/assets/{diagram-VSXAHHWV-Cjucz5BY.js → diagram-VSXAHHWV-DyUHfNwT.js} +1 -1
  732. ksadk/server/static/assets/{diagram-VX7I27RA-Dd4Vleyn.js → diagram-VX7I27RA-CREmM89O.js} +1 -1
  733. ksadk/server/static/assets/{diagram-Z3DM3KII-CZ2jGtYW.js → diagram-Z3DM3KII-Dw9zhHUK.js} +1 -1
  734. ksadk/server/static/assets/{dist-Bj730Ib4.js → dist-0uJ4tdx6.js} +1 -1
  735. ksadk/server/static/assets/{dist-BnaTiyzN.js → dist-AEv-vXf-.js} +1 -1
  736. ksadk/server/static/assets/{dist-BgV_owcB.js → dist-B49GzZDb.js} +1 -1
  737. ksadk/server/static/assets/{dist-D_ctSS2i.js → dist-B8Myiet9.js} +1 -1
  738. ksadk/server/static/assets/{dist-ufY3F5p6.js → dist-BBsYarrI.js} +2 -2
  739. ksadk/server/static/assets/{dist-ClYUxfeK.js → dist-BQMrUwdI.js} +1 -1
  740. ksadk/server/static/assets/{dist-CFzsn6BG.js → dist-BX_-FENW.js} +1 -1
  741. ksadk/server/static/assets/{dist-B3FR1SKK.js → dist-CD4L6ymH.js} +1 -1
  742. ksadk/server/static/assets/{dist-Cf125P_m.js → dist-CHpW1BHj.js} +1 -1
  743. ksadk/server/static/assets/{dist-DVCOWtha.js → dist-CVPau3tn.js} +1 -1
  744. ksadk/server/static/assets/{dist-DFD6Qa6T.js → dist-C_qdxcSH.js} +1 -1
  745. ksadk/server/static/assets/{dist-BIr4DSRq.js → dist-Co68Apq4.js} +1 -1
  746. ksadk/server/static/assets/{dist-DiixqL0J.js → dist-Cp2PaOMY.js} +1 -1
  747. ksadk/server/static/assets/{dist-fBO2v5Kt.js → dist-CuR5Bgme.js} +1 -1
  748. ksadk/server/static/assets/{dist-DoVSwoDb.js → dist-DDSyLEOX.js} +1 -1
  749. ksadk/server/static/assets/{dist-C5_ZAZsG.js → dist-DUxO0R99.js} +1 -1
  750. ksadk/server/static/assets/{dist-C1NMAY5a.js → dist-QzbGrED_.js} +1 -1
  751. ksadk/server/static/assets/dist-bupkyEBZ.js +1 -0
  752. ksadk/server/static/assets/{dist-DvFK7p5S.js → dist-cxTGfdqx.js} +1 -1
  753. ksadk/server/static/assets/{dist-CB9iJrvg.js → dist-hL5p1til.js} +1 -1
  754. ksadk/server/static/assets/{dist-btbmmX5O.js → dist-lOy23y43.js} +1 -1
  755. ksadk/server/static/assets/{dist-QfkEHOlb.js → dist-pq-nD33R.js} +1 -1
  756. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Ci8NqqZu.js → ebnfDiagram-PWID7BFC-BS5LdNoR.js} +1 -1
  757. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CCIOhLZG.js → erDiagram-SSCWMZ5O-Bv1QtiY-.js} +1 -1
  758. ksadk/server/static/assets/eventmodeling-NTZA5JFV-DsM4upQX.js +1 -0
  759. ksadk/server/static/assets/flowDiagram-A5DVABFB-D5NA16k9.js +1 -0
  760. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-Cp_r9Hb6.js → ganttDiagram-EL5Y4UJY-musi-e0G.js} +1 -1
  761. ksadk/server/static/assets/gitGraph-4MIJSDKK-DUCVz-ih.js +1 -0
  762. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-Dlhc8Wr8.js → gitGraphDiagram-WWUBYQGX-DH37EGkG.js} +1 -1
  763. ksadk/server/static/assets/index-CZdkAvsv.js +244 -0
  764. ksadk/server/static/assets/index-CvXdHgF3.css +2 -0
  765. ksadk/server/static/assets/info-A6RAGUB7-rw0ZNHZp.js +1 -0
  766. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CO0rRTRA.js → infoDiagram-RXCK75RN-C1kEtv2y.js} +1 -1
  767. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CHiaedSS.js → ishikawaDiagram-5VMMS53U-BCNPyMka.js} +1 -1
  768. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-CHcCIB09.js → journeyDiagram-EYS64GPL--cDbKnjP.js} +1 -1
  769. ksadk/server/static/assets/{kanban-definition-3QL26DDD-CJ_ebBZf.js → kanban-definition-3QL26DDD-R1rAVw2f.js} +1 -1
  770. ksadk/server/static/assets/{katex-B4weu383.js → katex-BT-X-V7U.js} +1 -1
  771. ksadk/server/static/assets/{linear-V-MgYHW1.js → linear-DTR631iG.js} +1 -1
  772. ksadk/server/static/assets/{mermaid-parser.core-CBijEX_c.js → mermaid-parser.core-DfFzJhX8.js} +2 -2
  773. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-Bc-pQvpp.js → mindmap-definition-FBJOCRG2-D4by_rmk.js} +1 -1
  774. ksadk/server/static/assets/packet-AYTQ26CC-Ca4Hvki9.js +1 -0
  775. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-D7genGLl.js → pegDiagram-XKGWAZYB-xWXPEh0c.js} +1 -1
  776. ksadk/server/static/assets/pie-WAS4IAKB-hwiz6fbw.js +1 -0
  777. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-Bxj32zwD.js → pieDiagram-E7YTZNPT-BudBDlCI.js} +1 -1
  778. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BURv2mGh.js → quadrantDiagram-AXDQQJYC-DXZ0PCJF.js} +1 -1
  779. ksadk/server/static/assets/radar-RG4KPBEZ-BR1oZXLM.js +1 -0
  780. ksadk/server/static/assets/railroad-74A4TZTK-DfgEISfX.js +1 -0
  781. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-CWOC3rdk.js +1 -0
  782. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CiRvHCLY.js +1 -0
  783. ksadk/server/static/assets/railroad-peg-WCYAUIDC-DSDDyJ2f.js +1 -0
  784. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-CCsh3avW.js → railroadDiagram-O6MQD6OU-BdAYRYB8.js} +1 -1
  785. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-_FRRBKEd.js → requirementDiagram-EFPCY7ZU-CBBmaL70.js} +1 -1
  786. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-C-gr2o9M.js → sankeyDiagram-P5KCCOFB-Doc3rdwp.js} +1 -1
  787. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-D97NmfKg.js → sequenceDiagram-WJ2MYXX4-0J8R8hWW.js} +1 -1
  788. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DjrPC5FX.js → sizeCapture-X5ZJPWSS-CfFLlWsK.js} +1 -1
  789. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DzMNg1hh.js → stateDiagram-HBIQ2CUA-jBwkjtTy.js} +1 -1
  790. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-Cw1fPb5w.js +1 -0
  791. ksadk/server/static/assets/{swimlanes-XN3QIQJK-Cssf_CsU.js → swimlanes-XN3QIQJK-B0WxTQf8.js} +1 -1
  792. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-Cc3JMBAF.js +8 -0
  793. ksadk/server/static/assets/{timeline-definition-24CTP7MA-BWTHzyS1.js → timeline-definition-24CTP7MA-BfCT_75A.js} +1 -1
  794. ksadk/server/static/assets/treeView-Q6P3EWNA-C05SJHxo.js +1 -0
  795. ksadk/server/static/assets/treemap-WGGIJYW6-BqNLAhc3.js +1 -0
  796. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-BSKgJsmR.js → vennDiagram-4TSXK5OY-9gX1VMDC.js} +1 -1
  797. ksadk/server/static/assets/wardley-WFR3VGLG-DokNktqB.js +1 -0
  798. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-eflHNoaZ.js → wardleyDiagram-VM6X3IG4-sEs_BP6O.js} +1 -1
  799. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-eYqrQ-v4.js → xychartDiagram-S5SC5T6Z-Ll4jvUN9.js} +1 -1
  800. ksadk/server/static/index.html +2 -2
  801. ksadk/server/terminal_sessions.py +34 -2
  802. ksadk/sessions/__init__.py +8 -1
  803. ksadk/sessions/_checkpoint_resume_audit.py +44 -0
  804. ksadk/sessions/_in_memory_query.py +112 -0
  805. ksadk/sessions/_local_service_sync.py +157 -156
  806. ksadk/sessions/_local_state_sync.py +152 -0
  807. ksadk/sessions/_local_tables.py +2 -0
  808. ksadk/sessions/_postgres_checkpoint_read.py +323 -0
  809. ksadk/sessions/_postgres_checkpoint_stats.py +330 -0
  810. ksadk/sessions/_postgres_history_read.py +678 -0
  811. ksadk/sessions/_postgres_schema.py +44 -2
  812. ksadk/sessions/_postgres_tables.py +2 -0
  813. ksadk/sessions/_postgres_tool_receipts.py +169 -0
  814. ksadk/sessions/_resilient_read.py +630 -0
  815. ksadk/sessions/_tool_receipt_sync.py +119 -0
  816. ksadk/sessions/agent_identity.py +16 -0
  817. ksadk/sessions/base.py +278 -0
  818. ksadk/sessions/db_budget.py +332 -0
  819. ksadk/sessions/errors.py +12 -0
  820. ksadk/sessions/history_budget.py +36 -0
  821. ksadk/sessions/history_identity.py +27 -0
  822. ksadk/sessions/in_memory.py +376 -113
  823. ksadk/sessions/invocation_identity.py +235 -0
  824. ksadk/sessions/local_service.py +345 -0
  825. ksadk/sessions/postgres_service.py +515 -549
  826. ksadk/sessions/resilience.py +21 -14
  827. ksadk/sessions/resilient.py +611 -504
  828. ksadk/skills/__init__.py +26 -0
  829. ksadk/skills/events.py +464 -0
  830. ksadk/skills/loader.py +44 -2
  831. ksadk/skills/manifest_cache.py +263 -0
  832. ksadk/skills/mcp_server/__init__.py +0 -0
  833. ksadk/skills/mcp_server/_registry.py +33 -0
  834. ksadk/skills/mcp_server/_routing.py +26 -0
  835. ksadk/skills/mcp_server/_workspace_files.py +160 -0
  836. ksadk/skills/mcp_server/register.py +415 -0
  837. ksadk/skills/mcp_server/server.py +218 -0
  838. ksadk/skills/models.py +11 -0
  839. ksadk/skills/observability.py +132 -0
  840. ksadk/skills/package_store.py +75 -2
  841. ksadk/skills/runtime/agent.py +38 -5
  842. ksadk/skills/runtime/artifacts.py +87 -0
  843. ksadk/skills/runtime/backends/e2b.py +400 -56
  844. ksadk/skills/runtime/backends/local.py +621 -119
  845. ksadk/skills/runtime/base.py +78 -7
  846. ksadk/skills/runtime/executor.py +266 -1
  847. ksadk/skills/runtime/loader.py +108 -3
  848. ksadk/skills/runtime/request.py +18 -0
  849. ksadk/skills/service_client.py +6 -1
  850. ksadk/skills/tool_defs.py +108 -3
  851. ksadk/studio/a2a_bindings.py +407 -0
  852. ksadk/studio/a2a_orchestration.py +178 -0
  853. ksadk/studio/active_run_output.py +92 -0
  854. ksadk/studio/activity_records.py +542 -0
  855. ksadk/studio/agent_configuration.py +173 -0
  856. ksadk/studio/api.py +784 -419
  857. ksadk/studio/api_a2a_routes.py +93 -0
  858. ksadk/studio/api_catalog_routes.py +13 -0
  859. ksadk/studio/api_cloud_chat_routes.py +382 -0
  860. ksadk/studio/api_contracts.py +31 -2
  861. ksadk/studio/api_plugin_routes.py +39 -12
  862. ksadk/studio/api_resource_connections.py +79 -41
  863. ksadk/studio/attachment_store.py +14 -2
  864. ksadk/studio/authoring.py +12 -6
  865. ksadk/studio/authoring_coordinator.py +4 -2
  866. ksadk/studio/build_resolution.py +117 -0
  867. ksadk/studio/build_singleflight.py +37 -0
  868. ksadk/studio/builder.py +32 -2
  869. ksadk/studio/capabilities.py +31 -9
  870. ksadk/studio/channel_connections.py +333 -0
  871. ksadk/studio/cloud.py +113 -387
  872. ksadk/studio/cloud_gateways.py +424 -0
  873. ksadk/studio/cloud_shared_web.py +82 -2
  874. ksadk/studio/codex_agent_service.py +19 -2
  875. ksadk/studio/codex_builder.py +1 -1
  876. ksadk/studio/codex_manifest.py +5 -1
  877. ksadk/studio/codex_provider_build.py +65 -0
  878. ksadk/studio/codex_run.py +6 -1
  879. ksadk/studio/compiler.py +112 -6
  880. ksadk/studio/configuration.py +182 -0
  881. ksadk/studio/contract_base.py +19 -0
  882. ksadk/studio/contracts.py +260 -202
  883. ksadk/studio/dsh_application.py +183 -27
  884. ksadk/studio/dsh_capability_service.py +302 -189
  885. ksadk/studio/dsh_lifecycle.py +58 -0
  886. ksadk/studio/dsh_mcp_transport.py +191 -0
  887. ksadk/studio/dsh_provider_registration.py +55 -16
  888. ksadk/studio/entry.py +53 -0
  889. ksadk/studio/event_store.py +53 -5
  890. ksadk/studio/execution_host.py +598 -0
  891. ksadk/studio/framework_run.py +50 -10
  892. ksadk/studio/hosted_kernel.py +1 -1
  893. ksadk/studio/interaction_submission.py +265 -0
  894. ksadk/studio/kernel_registry.py +429 -0
  895. ksadk/studio/kernel_sqlite_migration.py +181 -0
  896. ksadk/studio/lifecycle_status.py +43 -0
  897. ksadk/studio/model_buffered_wire.py +227 -0
  898. ksadk/studio/model_chat_tools.py +143 -0
  899. ksadk/studio/model_client.py +1939 -345
  900. ksadk/studio/model_content_stream.py +129 -0
  901. ksadk/studio/model_credentials.py +196 -0
  902. ksadk/studio/model_profile_service.py +89 -40
  903. ksadk/studio/model_request_projection.py +284 -0
  904. ksadk/studio/model_responses_content.py +296 -0
  905. ksadk/studio/model_usage.py +109 -0
  906. ksadk/studio/model_wire_failure.py +110 -0
  907. ksadk/studio/model_wire_identity.py +138 -0
  908. ksadk/studio/model_wire_snapshot.py +45 -0
  909. ksadk/studio/model_wire_tools.py +283 -0
  910. ksadk/studio/native_acceptance.py +68 -0
  911. ksadk/studio/native_approval.py +111 -0
  912. ksadk/studio/native_browser_port.py +861 -0
  913. ksadk/studio/native_child_mcp.py +87 -0
  914. ksadk/studio/native_child_publication.py +68 -0
  915. ksadk/studio/native_child_skills.py +72 -0
  916. ksadk/studio/native_child_workspace.py +176 -0
  917. ksadk/studio/native_command_policy.py +53 -0
  918. ksadk/studio/native_context_port.py +326 -0
  919. ksadk/studio/native_context_registration.py +54 -0
  920. ksadk/studio/native_document_input.py +88 -0
  921. ksadk/studio/native_documents.py +172 -0
  922. ksadk/studio/native_final_shape.py +852 -0
  923. ksadk/studio/native_gateway_stream.py +69 -0
  924. ksadk/studio/native_hook_port.py +145 -0
  925. ksadk/studio/native_hook_registration.py +70 -0
  926. ksadk/studio/native_inventory_disclosure.py +223 -0
  927. ksadk/studio/native_kernel_admission.py +84 -0
  928. ksadk/studio/native_language_diagnostics.py +320 -0
  929. ksadk/studio/native_mcp_disclosure.py +198 -0
  930. ksadk/studio/native_mcp_tool_port.py +219 -0
  931. ksadk/studio/native_memory_acceptance.py +362 -0
  932. ksadk/studio/native_memory_context.py +266 -0
  933. ksadk/studio/native_memory_flush.py +174 -0
  934. ksadk/studio/native_memory_sources.py +80 -0
  935. ksadk/studio/native_memory_tool_port.py +360 -0
  936. ksadk/studio/native_memory_turn.py +183 -0
  937. ksadk/studio/native_model_port.py +765 -0
  938. ksadk/studio/native_model_recovery.py +126 -0
  939. ksadk/studio/native_options.py +75 -0
  940. ksadk/studio/native_output_fields.py +58 -0
  941. ksadk/studio/native_planning.py +156 -0
  942. ksadk/studio/native_product.py +988 -0
  943. ksadk/studio/native_read_budget.py +426 -0
  944. ksadk/studio/native_recovery.py +171 -0
  945. ksadk/studio/native_scope.py +35 -0
  946. ksadk/studio/native_session_context_port.py +141 -0
  947. ksadk/studio/native_session_engine.py +14 -0
  948. ksadk/studio/native_skill_source.py +74 -0
  949. ksadk/studio/native_subagent_port.py +700 -0
  950. ksadk/studio/native_terminal_recovery.py +95 -0
  951. ksadk/studio/native_test_action.py +610 -0
  952. ksadk/studio/native_tool_port.py +477 -0
  953. ksadk/studio/native_user_input.py +60 -0
  954. ksadk/studio/native_verification_presentation.py +65 -0
  955. ksadk/studio/native_workspace_diagnostics.py +183 -0
  956. ksadk/studio/native_workspace_port.py +43 -0
  957. ksadk/studio/operations.py +34 -9
  958. ksadk/studio/plugin_composition.py +39 -12
  959. ksadk/studio/plugin_kernel_adapter.py +89 -0
  960. ksadk/studio/plugin_lifecycle.py +80 -0
  961. ksadk/studio/plugin_native_activation.py +163 -0
  962. ksadk/studio/plugin_runtime.py +832 -99
  963. ksadk/studio/plugin_runtime_admission.py +57 -0
  964. ksadk/studio/presentation.py +92 -0
  965. ksadk/studio/provider_recovery.py +59 -0
  966. ksadk/studio/public_output_store.py +69 -0
  967. ksadk/studio/recovery_page.py +70 -0
  968. ksadk/studio/resource_authority.py +69 -34
  969. ksadk/studio/resource_catalog.py +14 -12
  970. ksadk/studio/run_activity.py +848 -0
  971. ksadk/studio/run_controls.py +185 -0
  972. ksadk/studio/run_documents.py +127 -0
  973. ksadk/studio/run_service.py +1220 -335
  974. ksadk/studio/run_submission_receipts.py +68 -0
  975. ksadk/studio/runtime_catalog.py +73 -11
  976. ksadk/studio/runtime_prewarm.py +22 -0
  977. ksadk/studio/runtime_source.py +1 -1
  978. ksadk/studio/scheduler_assistant.py +4 -1
  979. ksadk/studio/scheduler_runtime.py +32 -289
  980. ksadk/studio/service.py +615 -246
  981. ksadk/studio/service_settings.py +229 -0
  982. ksadk/studio/shared_web.py +518 -181
  983. ksadk/studio/shared_web_response_events.py +180 -0
  984. ksadk/studio/shared_web_run_state.py +133 -0
  985. ksadk/studio/skill_discovery.py +305 -3
  986. ksadk/studio/static/assets/ChannelsPage-xX5HlMId.js +8 -0
  987. ksadk/studio/static/assets/CodeBlock-DMIf4h33-CkufcPYo.js +44 -0
  988. ksadk/studio/static/assets/ExecutionTree-v3HexvPo-Bk8wzGSy.js +1 -0
  989. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-DYG1Wzbx.js +8 -0
  990. ksadk/studio/static/assets/MermaidBlock-H_0qzQDf-BdXtxug_.js +11 -0
  991. ksadk/studio/static/assets/MessageMarkdown-CwMTvgFj-BeyLyQHu.js +59 -0
  992. ksadk/studio/static/assets/PrismRenderer-5pK6tUdb.js +3 -0
  993. ksadk/studio/static/assets/TeamsPage-CCaaGaVp.js +3 -0
  994. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-Bnb1O3tA.js +1 -0
  995. ksadk/studio/static/assets/architecture-7GRP2DOG-BMOPAkUC.js +1 -0
  996. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-5Zn1gqJv.js +36 -0
  997. ksadk/studio/static/assets/{blockDiagram-I7D4REHJ-CFmPl1de.js → blockDiagram-I7D4REHJ-CLB4L11u.js} +6 -6
  998. ksadk/studio/static/assets/{c4Diagram-7LVT6UL2-BRrGu8qt.js → c4Diagram-7LVT6UL2-BOma_Z_F.js} +7 -7
  999. ksadk/studio/static/assets/channel-r8itPEik.js +1 -0
  1000. ksadk/studio/static/assets/chunk-2E4U76K2-BFf_huql.js +2 -0
  1001. ksadk/studio/static/assets/chunk-2ZTRR5NV-C2qZJila.js +2 -0
  1002. ksadk/studio/static/assets/chunk-3Z5EZCMW-DMniOlPd.js +1 -0
  1003. ksadk/studio/static/assets/{chunk-4HAMMTFA-D220vUtq.js → chunk-4HAMMTFA-DVtDP4rm.js} +7 -7
  1004. ksadk/studio/static/assets/chunk-5V3GS4D5-i-ZDOEnP.js +1 -0
  1005. ksadk/studio/static/assets/chunk-6AZGARVD-BB6FqMl-.js +1 -0
  1006. ksadk/studio/static/assets/chunk-6EIED4P4-DdUJkP0f.js +1 -0
  1007. ksadk/studio/static/assets/chunk-6K3QC6MW-CqVsVn-y.js +1 -0
  1008. ksadk/studio/static/assets/chunk-6TQVIW2G-DKlLbNIP.js +1 -0
  1009. ksadk/studio/static/assets/chunk-747NJXEK-BFkZPlab.js +2 -0
  1010. ksadk/studio/static/assets/chunk-75Z2AOVW-BZNhM4vB.js +2 -0
  1011. ksadk/studio/static/assets/chunk-CLGD4ZFX-D-GTtyKs.js +1 -0
  1012. ksadk/studio/static/assets/{chunk-DU6HZSFF-C4DtVpCu.js → chunk-DU6HZSFF-CpEZCUgg.js} +1 -1
  1013. ksadk/studio/static/assets/chunk-F27PBJKO-D7pvKf0C.js +1 -0
  1014. ksadk/studio/static/assets/{chunk-GMAD6QVW-DiQA-u2N.js → chunk-GMAD6QVW-DE_8H717.js} +6 -6
  1015. ksadk/studio/static/assets/chunk-GVQU2GXP-BfEB0lNv.js +1 -0
  1016. ksadk/studio/static/assets/chunk-I5DQTOEV-Hm2LfiYI.js +1 -0
  1017. ksadk/studio/static/assets/chunk-ICYGCRZG-749o-pGJ.js +1 -0
  1018. ksadk/studio/static/assets/chunk-IH6LHLGP-CC6I9F3i.js +1 -0
  1019. ksadk/studio/static/assets/{chunk-IMKFNOWR-BSlbjT_b.js → chunk-IMKFNOWR-D38axYOR.js} +5 -5
  1020. ksadk/studio/static/assets/chunk-KI3K4JFJ-Rma-0k_M.js +1 -0
  1021. ksadk/studio/static/assets/chunk-L3NEJ4N5-Dq5xn7aL.js +1 -0
  1022. ksadk/studio/static/assets/chunk-LNGE3PJU-DWpGwHrW.js +34 -0
  1023. ksadk/studio/static/assets/{chunk-OSK3NFVY-M2m6G3j4.js → chunk-OSK3NFVY-DiCQjx9b.js} +5 -5
  1024. ksadk/studio/static/assets/chunk-OUJLGHUK-D0j2JRSg.js +2 -0
  1025. ksadk/studio/static/assets/{chunk-P2QGCYS3-DezaQxiK.js → chunk-P2QGCYS3-VdhKmfYq.js} +1 -1
  1026. ksadk/studio/static/assets/chunk-POPQ4Y6H-C1_rzO5M.js +1 -0
  1027. ksadk/studio/static/assets/chunk-PWAF6VOD-B45HvflI.js +1 -0
  1028. ksadk/studio/static/assets/{chunk-SHT3W25Y-DAyIVp5H.js → chunk-SHT3W25Y-DsCFnRVE.js} +9 -9
  1029. ksadk/studio/static/assets/{chunk-SVP7TREG-DulomOrS.js → chunk-SVP7TREG-DljApgRX.js} +1 -1
  1030. ksadk/studio/static/assets/{chunk-TICWLB2K-bHJYoflj.js → chunk-TICWLB2K-DWqRtyqa.js} +6 -6
  1031. ksadk/studio/static/assets/chunk-TLUHSLCS-DUeGgnD5.js +2 -0
  1032. ksadk/studio/static/assets/chunk-UY3FDG6J-CnmaAkG5.js +1 -0
  1033. ksadk/studio/static/assets/chunk-XHIXRSVI-BFQ6B8BE.js +1 -0
  1034. ksadk/studio/static/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
  1035. ksadk/studio/static/assets/classDiagram-ZZMXUADV-DjeMNJmu.js +1 -0
  1036. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-DjeMNJmu.js +1 -0
  1037. ksadk/studio/static/assets/clsx-DB0hHKMi.js +1 -0
  1038. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-om8AY0Mc.js +1 -0
  1039. ksadk/studio/static/assets/createLucideIcon-DR0LGTP5.js +1 -0
  1040. ksadk/studio/static/assets/cynefin-OW5HDTMX-7tP7QfM3.js +1 -0
  1041. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-6BrmK52S.js +62 -0
  1042. ksadk/studio/static/assets/dagre-GXQ25YYZ-buZBRlwz.js +4 -0
  1043. ksadk/studio/static/assets/{diagram-S7CK7UJ4-0BZ98mya.js → diagram-S7CK7UJ4-C6aH78c4.js} +3 -3
  1044. ksadk/studio/static/assets/diagram-UQ7AKVKN-DY_tQ6C_.js +41 -0
  1045. ksadk/studio/static/assets/diagram-VSXAHHWV-DX9p5cQT.js +3 -0
  1046. ksadk/studio/static/assets/diagram-VX7I27RA-DB2WSH8X.js +24 -0
  1047. ksadk/studio/static/assets/diagram-Z3DM3KII-Ce1BJwHE.js +24 -0
  1048. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-Daukxwqf.js +1 -0
  1049. ksadk/studio/static/assets/{erDiagram-RLTQ6QDP-DLGry2Ap.js → erDiagram-RLTQ6QDP-CGthTMmJ.js} +6 -6
  1050. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-BR2FzK4R.js +1 -0
  1051. ksadk/studio/static/assets/flowDiagram-HODETNUW-CZ1tEenp.js +1 -0
  1052. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BfoAZW9X.js +292 -0
  1053. ksadk/studio/static/assets/gitGraph-4MIJSDKK-DYlXv_yJ.js +1 -0
  1054. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-S985OIJF.js +106 -0
  1055. ksadk/studio/static/assets/iconfont-4HN3C9Pg.woff2 +0 -0
  1056. ksadk/studio/static/assets/index-C7DNDik2.css +2 -0
  1057. ksadk/studio/static/assets/index-Cy68gTlH.js +265 -0
  1058. ksadk/studio/static/assets/index.dom-BQenBtFm.js +1 -0
  1059. ksadk/studio/static/assets/info-A6RAGUB7-BlU-8_xu.js +1 -0
  1060. ksadk/studio/static/assets/infoDiagram-27XIBGKW-CO3W8tFn.js +2 -0
  1061. ksadk/studio/static/assets/{ishikawaDiagram-5VMMS53U-CljI2wyf.js → ishikawaDiagram-5VMMS53U-BUGEl8cO.js} +2 -2
  1062. ksadk/studio/static/assets/{journeyDiagram-3NMN7TZE-D50Fo2sL.js → journeyDiagram-3NMN7TZE-Ch2ZYxvr.js} +6 -6
  1063. ksadk/studio/static/assets/{kanban-definition-UXKFOSKX-DimfOTam.js → kanban-definition-UXKFOSKX-Da-Fp4vC.js} +3 -3
  1064. ksadk/studio/static/assets/kingsoft-cloud-BOcLiQ3e.ico +0 -0
  1065. ksadk/studio/static/assets/{line-CX5BOOUP.js → line-BDaeq300.js} +1 -1
  1066. ksadk/studio/static/assets/linear-DmucvK78.js +1 -0
  1067. ksadk/studio/static/assets/mermaid-parser.core-Cj5mYdBi.js +4 -0
  1068. ksadk/studio/static/assets/{mindmap-definition-YA3MSWOX-Bizzqy5R.js → mindmap-definition-YA3MSWOX-CvlsVQ38.js} +1 -1
  1069. ksadk/studio/static/assets/packet-AYTQ26CC-BSJEH9Lb.js +1 -0
  1070. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-BuHuNgT5.js +1 -0
  1071. ksadk/studio/static/assets/pie-WAS4IAKB-qxv01Y8W.js +1 -0
  1072. ksadk/studio/static/assets/{pieDiagram-E7YTZNPT-B9mrFSDF.js → pieDiagram-E7YTZNPT-DlrWiSOv.js} +1 -1
  1073. ksadk/studio/static/assets/preload-helper-CO68xz6u.js +1 -0
  1074. ksadk/studio/static/assets/presentation-yYw7xK60-BmcZriri.js +1 -0
  1075. ksadk/studio/static/assets/{quadrantDiagram-AXDQQJYC-NzUfCbMR.js → quadrantDiagram-AXDQQJYC-BA3hpUZM.js} +6 -6
  1076. ksadk/studio/static/assets/radar-RG4KPBEZ-B6h6pWOs.js +1 -0
  1077. ksadk/studio/static/assets/railroad-74A4TZTK-CGtTWdGc.js +1 -0
  1078. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-Cq7y22IA.js +1 -0
  1079. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-V0aQVv9m.js +1 -0
  1080. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-BQiIsX_p.js +1 -0
  1081. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-BxpAazym.js +1 -0
  1082. ksadk/studio/static/assets/{requirementDiagram-BXWQKSXE-BF3d103U.js → requirementDiagram-BXWQKSXE-E-Ge0FcV.js} +1 -1
  1083. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-CA6YKhQ3.js +40 -0
  1084. ksadk/studio/static/assets/{sequenceDiagram-WJ2MYXX4-Dh4wZtUm.js → sequenceDiagram-WJ2MYXX4-CcElXGg4.js} +9 -9
  1085. ksadk/studio/static/assets/src-B6xuSHsQ.js +1 -0
  1086. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DdXZOFqY.js +1 -0
  1087. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-CJbOM-QK.js +1 -0
  1088. ksadk/studio/static/assets/swimlanes-42K2YHIH-NtgEEHLY.js +1 -0
  1089. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-D-AVlW8B.js +8 -0
  1090. ksadk/studio/static/assets/{timeline-definition-24CTP7MA-DxmSSjRB.js → timeline-definition-24CTP7MA-CIuYhNy3.js} +7 -7
  1091. ksadk/studio/static/assets/treeView-Q6P3EWNA-BTTYcvrF.js +1 -0
  1092. ksadk/studio/static/assets/treemap-WGGIJYW6-Cg7tyfH8.js +1 -0
  1093. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-7HbApbrv.js +34 -0
  1094. ksadk/studio/static/assets/wardley-WFR3VGLG-C6N1rULY.js +1 -0
  1095. ksadk/studio/static/assets/{wardleyDiagram-VM6X3IG4-Ba1AOWoe.js → wardleyDiagram-VM6X3IG4-CMJiaedy.js} +1 -1
  1096. ksadk/studio/static/assets/{xychartDiagram-S5SC5T6Z-Cr5pt5Y-.js → xychartDiagram-S5SC5T6Z-BdgtMvW2.js} +6 -6
  1097. ksadk/studio/static/index.html +8 -2
  1098. ksadk/studio/teams_catalog.py +166 -0
  1099. ksadk/studio/teams_installation.py +217 -0
  1100. ksadk/studio/teams_node.py +549 -0
  1101. ksadk/studio/teams_node_factory.py +558 -0
  1102. ksadk/studio/teams_node_runner.py +72 -0
  1103. ksadk/studio/teams_node_v1.py +935 -0
  1104. ksadk/studio/teams_remote.py +496 -0
  1105. ksadk/studio/templates.py +41 -19
  1106. ksadk/studio/validator.py +13 -0
  1107. ksadk/studio/workspace.py +19 -4
  1108. ksadk/studio/workspace_plugins.py +138 -0
  1109. ksadk/studio/workspace_registry.py +286 -0
  1110. ksadk/tools/a2a_policy.py +5 -0
  1111. ksadk/tools/artifact_observation.py +53 -0
  1112. ksadk/tools/captured_source_artifact.py +68 -0
  1113. ksadk/tools/schema.py +34 -0
  1114. ksadk/toolsets/__init__.py +93 -88
  1115. ksadk/toolsets/a2a.py +89 -89
  1116. ksadk/toolsets/sandbox.py +377 -6
  1117. ksadk/toolsets/skill_management.py +315 -0
  1118. ksadk/toolsets/skills.py +446 -378
  1119. ksadk/toolsets/tool_selection.py +94 -0
  1120. ksadk/toolsets/workspace.py +344 -326
  1121. ksadk/toolsets/workspace_editing.py +291 -0
  1122. ksadk/toolsets/workspace_identity.py +15 -0
  1123. ksadk/toolsets/workspace_model_observation.py +104 -0
  1124. ksadk/toolsets/workspace_mutation.py +75 -0
  1125. ksadk/toolsets/workspace_read_budget.py +216 -0
  1126. ksadk/toolsets/workspace_search.py +192 -0
  1127. ksadk/toolsets/workspace_search_process.py +129 -0
  1128. ksadk/toolsets/workspace_state.py +6 -0
  1129. ksadk/version.py +1 -1
  1130. ksadk_runtime_common/http_headers.py +18 -0
  1131. ksadk_runtime_common/memory_backend/providers/lancedb.py +56 -2
  1132. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -148
  1133. ksadk_runtime_common/workspace_files/router.py +28 -14
  1134. agentengine_sdk_python-0.8.4.dist-info/RECORD +0 -1070
  1135. ksadk/server/static/assets/MathMessageMarkdown-DbdW5A4_.js +0 -8
  1136. ksadk/server/static/assets/architecture-7GRP2DOG-BW5UtSnx.js +0 -1
  1137. ksadk/server/static/assets/channel-CF5Up3hQ.js +0 -1
  1138. ksadk/server/static/assets/chunk-2Q5K7J3B-KkXX47WI.js +0 -1
  1139. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Cz81acRQ.js +0 -1
  1140. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Cz81acRQ.js +0 -1
  1141. ksadk/server/static/assets/cynefin-OW5HDTMX-DVWs8a2t.js +0 -1
  1142. ksadk/server/static/assets/dist-B2_CVgKv.js +0 -1
  1143. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CQqR2hg3.js +0 -1
  1144. ksadk/server/static/assets/flowDiagram-A5DVABFB-DDRRbGPm.js +0 -1
  1145. ksadk/server/static/assets/gitGraph-4MIJSDKK-fgWEf7UD.js +0 -1
  1146. ksadk/server/static/assets/index-DcTML1Up.css +0 -2
  1147. ksadk/server/static/assets/index-Dh2XHqPK.js +0 -244
  1148. ksadk/server/static/assets/info-A6RAGUB7-BUecLTdt.js +0 -1
  1149. ksadk/server/static/assets/packet-AYTQ26CC-BeW-btFv.js +0 -1
  1150. ksadk/server/static/assets/pie-WAS4IAKB-X0xh4SaT.js +0 -1
  1151. ksadk/server/static/assets/radar-RG4KPBEZ-DzRMSqjd.js +0 -1
  1152. ksadk/server/static/assets/railroad-74A4TZTK-Cc44icX-.js +0 -1
  1153. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-D6S4BdV-.js +0 -1
  1154. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-vD3aVE2o.js +0 -1
  1155. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CYbW_b4T.js +0 -1
  1156. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BIcjKFhF.js +0 -1
  1157. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-tq3K3Ybl.js +0 -8
  1158. ksadk/server/static/assets/treeView-Q6P3EWNA-DBXt3GdU.js +0 -1
  1159. ksadk/server/static/assets/treemap-WGGIJYW6-DrCy4E_l.js +0 -1
  1160. ksadk/server/static/assets/wardley-WFR3VGLG-CefhOliM.js +0 -1
  1161. ksadk/studio/static/assets/CodeBlock-DCUUY0PL-BLjA7kbS.js +0 -41
  1162. ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--CUYIXwgI.js +0 -8
  1163. ksadk/studio/static/assets/MermaidBlock-DBFTztfQ-BTYKWEbD.js +0 -44
  1164. ksadk/studio/static/assets/PrismRenderer-wiXRHURw.js +0 -3
  1165. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-CLETGjKq.js +0 -1
  1166. ksadk/studio/static/assets/architecture-7GRP2DOG-hXMiO_AU.js +0 -1
  1167. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-B5EQysk6.js +0 -36
  1168. ksadk/studio/static/assets/channel-BqO-gtEw.js +0 -1
  1169. ksadk/studio/static/assets/chunk-75Z2AOVW-C8lLv_qc.js +0 -2
  1170. ksadk/studio/static/assets/chunk-F27PBJKO-Cpw14SNG.js +0 -1
  1171. ksadk/studio/static/assets/chunk-GVQU2GXP-DUdNBUCi.js +0 -1
  1172. ksadk/studio/static/assets/chunk-L3NEJ4N5-Db8Ab22W.js +0 -1
  1173. ksadk/studio/static/assets/chunk-POPQ4Y6H-DOpufJ3t.js +0 -1
  1174. ksadk/studio/static/assets/chunk-PWAF6VOD-CfLb1gSc.js +0 -1
  1175. ksadk/studio/static/assets/chunk-XXDRQBXY-7PcdR2B1.js +0 -1
  1176. ksadk/studio/static/assets/classDiagram-ZZMXUADV-D_bW8JjA.js +0 -1
  1177. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-D_bW8JjA.js +0 -1
  1178. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-snL88wkX.js +0 -1
  1179. ksadk/studio/static/assets/cynefin-OW5HDTMX-Bd1YhRo1.js +0 -1
  1180. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-BBrIG_mI.js +0 -62
  1181. ksadk/studio/static/assets/dagre-GXQ25YYZ-DtF1nGdY.js +0 -4
  1182. ksadk/studio/static/assets/diagram-UQ7AKVKN-6mLKEo6L.js +0 -41
  1183. ksadk/studio/static/assets/diagram-VSXAHHWV-CJBIaiZ2.js +0 -3
  1184. ksadk/studio/static/assets/diagram-VX7I27RA-BohLEE1C.js +0 -24
  1185. ksadk/studio/static/assets/diagram-Z3DM3KII-D8KIGonG.js +0 -24
  1186. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-C99HU61t.js +0 -1
  1187. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-B1_5Ac8j.js +0 -1
  1188. ksadk/studio/static/assets/flowDiagram-HODETNUW-DD5hmicn.js +0 -1
  1189. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BPJrVLSG.js +0 -292
  1190. ksadk/studio/static/assets/gitGraph-4MIJSDKK-Cy_ZQBGi.js +0 -1
  1191. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-CZCUz4MT.js +0 -106
  1192. ksadk/studio/static/assets/index-CeHL9ARV.css +0 -2
  1193. ksadk/studio/static/assets/index-D9QEcVpL.js +0 -320
  1194. ksadk/studio/static/assets/info-A6RAGUB7-DBzDQB_I.js +0 -1
  1195. ksadk/studio/static/assets/infoDiagram-27XIBGKW-B-sq07Hi.js +0 -2
  1196. ksadk/studio/static/assets/linear-BCxN9JLv.js +0 -1
  1197. ksadk/studio/static/assets/mermaid-parser.core-BdCz8fkS.js +0 -7
  1198. ksadk/studio/static/assets/packet-AYTQ26CC-gPln-_kG.js +0 -1
  1199. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-Dy3fB-gW.js +0 -1
  1200. ksadk/studio/static/assets/pie-WAS4IAKB-qZdHMr7B.js +0 -1
  1201. ksadk/studio/static/assets/radar-RG4KPBEZ-BZlnaea9.js +0 -1
  1202. ksadk/studio/static/assets/railroad-74A4TZTK-Ce3__H9c.js +0 -1
  1203. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-DqQn7EzD.js +0 -1
  1204. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-B55kCA8F.js +0 -1
  1205. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-DfQnvkHd.js +0 -1
  1206. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-DnhMjZCk.js +0 -1
  1207. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-Bo-JTwt0.js +0 -40
  1208. ksadk/studio/static/assets/src-SFn9St9H.js +0 -1
  1209. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DH774G6d.js +0 -1
  1210. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-DZvVWPBo.js +0 -1
  1211. ksadk/studio/static/assets/swimlanes-42K2YHIH-Bl13OvTX.js +0 -1
  1212. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-BnFOTALJ.js +0 -8
  1213. ksadk/studio/static/assets/treeView-Q6P3EWNA-D5Nn9Swz.js +0 -1
  1214. ksadk/studio/static/assets/treemap-WGGIJYW6-CgHgnQhE.js +0 -1
  1215. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-B9QEXcJq.js +0 -34
  1216. ksadk/studio/static/assets/wardley-WFR3VGLG-DXrK2RRY.js +0 -1
  1217. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/WHEEL +0 -0
  1218. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/entry_points.txt +0 -0
  1219. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/licenses/LICENSE +0 -0
  1220. {agentengine_sdk_python-0.8.4.dist-info → agentengine_sdk_python-0.8.6.dist-info}/top_level.txt +0 -0
  1221. /ksadk/studio/static/assets/{MathMessageMarkdown-CBcDrAw--BEOyPC3w.css → MathMessageMarkdown-BesSeCYl-BEOyPC3w.css} +0 -0
@@ -0,0 +1,1480 @@
1
+ """Persistent collaboration decisions. No models, network calls or Kernel loops.
2
+
3
+ The plugin dispatcher submits this domain's outbox through Host Services.
4
+ Provider tools invoke it with a verified Actor. Kernel facts return through
5
+ the projector; a model's result candidate never completes a task by itself.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from copy import deepcopy
11
+ from datetime import datetime
12
+ from typing import Any, Callable
13
+
14
+ from .contracts import (
15
+ API_VERSION,
16
+ TERMINAL,
17
+ Actor,
18
+ Budget,
19
+ GroupCreateInput,
20
+ MemberInput,
21
+ MessageInput,
22
+ plain_text,
23
+ )
24
+ from .domain_values import member_key, public, run_member_key
25
+ from .errors import TeamsError
26
+ from .execution_projection import ExecutionCompletionProjection
27
+ from .leader_decisions import LeaderDecisions
28
+ from .store import TeamsStore, Transaction, digest, new_id, now
29
+ from .task_decisions import TaskDecisions
30
+
31
+
32
+ class TeamsDomain(TaskDecisions, ExecutionCompletionProjection, LeaderDecisions):
33
+ def __init__(self, store: TeamsStore, *, authority_ref: str) -> None:
34
+ self.store = store
35
+ self.authority_ref = authority_ref
36
+
37
+ def authorize(
38
+ self,
39
+ tx: Transaction,
40
+ actor: Actor,
41
+ group_id: str,
42
+ *,
43
+ owner: bool = False,
44
+ leader: bool = False,
45
+ ) -> dict[str, Any]:
46
+ group = tx.get("group", group_id)
47
+ if group["tenantId"] != actor.tenant_id:
48
+ raise TeamsError("not_found", "团队不存在或不可访问", status=404)
49
+ if actor.kind == "human":
50
+ if group["ownerSubject"] != actor.subject:
51
+ raise TeamsError("forbidden", "没有访问该团队的权限", status=403)
52
+ elif actor.kind == "member":
53
+ if owner or actor.group_id != group_id or not actor.member_id:
54
+ raise TeamsError("forbidden", "成员无权执行此操作", status=403)
55
+ if not actor.team_run_id:
56
+ raise TeamsError("invocation_required", "缺少受信执行上下文", status=403)
57
+ run = tx.get("team_run", actor.team_run_id)
58
+ if (
59
+ run["groupId"] != group_id
60
+ or run["status"] in TERMINAL
61
+ or run["status"] == "cancel_requested"
62
+ ):
63
+ raise TeamsError("team_run_closed", "本轮已停止,不能继续协作")
64
+ member = self.run_member(tx, actor.team_run_id, actor.member_id)
65
+ if member["status"] != "active" or (leader and member["role"] != "leader"):
66
+ raise TeamsError("forbidden", "成员授权已失效", status=403)
67
+ elif actor.kind != "host":
68
+ raise TeamsError("forbidden", "无效操作主体", status=403)
69
+ return group
70
+
71
+ @staticmethod
72
+ def run_member(tx: Transaction, run_id: str, member_id: str) -> dict[str, Any]:
73
+ """Resolve the frozen invocation identity, including pre-RunMember history."""
74
+ key = run_member_key(run_id, member_id)
75
+ stored = tx.get("run_member", key, required=False)
76
+ if stored:
77
+ return stored
78
+ run = tx.get("team_run", run_id)
79
+ frozen = next((m for m in run.get("_roster", []) if m["memberId"] == member_id), None)
80
+ if not frozen or frozen["status"] != "active":
81
+ raise TeamsError("member_unavailable", "成员不属于本轮冻结配置", status=409)
82
+ return {
83
+ **deepcopy(frozen),
84
+ "runMemberId": key,
85
+ "teamRunId": run_id,
86
+ "groupRevision": run["groupRevision"],
87
+ }
88
+
89
+ @staticmethod
90
+ def delivery_member(tx: Transaction, delivery: dict[str, Any]) -> dict[str, Any]:
91
+ """Historical execution identity must survive a Leader session takeover."""
92
+ if delivery.get("_memberSnapshot"):
93
+ return deepcopy(delivery["_memberSnapshot"])
94
+ run = tx.get("team_run", delivery["teamRunId"])
95
+ frozen = next(
96
+ (
97
+ m
98
+ for m in run.get("_roster", [])
99
+ if m["memberId"] == delivery["memberId"]
100
+ and m["sessionId"] == delivery["_sessionId"]
101
+ ),
102
+ None,
103
+ )
104
+ if frozen is None:
105
+ raise TeamsError(
106
+ "delivery_scope_unavailable", "原始执行身份不可用,需要核对历史来源", status=409
107
+ )
108
+ return {
109
+ **deepcopy(frozen),
110
+ "runMemberId": run_member_key(run["teamRunId"], frozen["memberId"]),
111
+ "teamRunId": run["teamRunId"],
112
+ "groupRevision": run["groupRevision"],
113
+ }
114
+
115
+ @staticmethod
116
+ def run_policy(tx: Transaction, run: dict[str, Any]) -> dict[str, Any]:
117
+ if "_policy" in run:
118
+ return run["_policy"]
119
+ revision = tx.get(
120
+ "group_revision", f"{run['groupId']}:{run['groupRevision']}", required=False
121
+ )
122
+ return (revision or tx.get("group", run["groupId"]))["_policy"]
123
+
124
+ def publish_run_member(self, tx: Transaction, member: dict[str, Any]) -> None:
125
+ self.publish(tx, "run_member", member["runMemberId"], member)
126
+ current = tx.get("member", member_key(member["groupId"], member["memberId"]))
127
+ active = [
128
+ m
129
+ for m in tx.list("run_member", member["groupId"])
130
+ if m["memberId"] == member["memberId"] and m["executionStatus"] != "idle"
131
+ ]
132
+ state = next(
133
+ (
134
+ state
135
+ for state in ("running", "waiting", "queued")
136
+ if any(m["executionStatus"] == state for m in active)
137
+ ),
138
+ "idle",
139
+ )
140
+ current.update(
141
+ executionStatus=state,
142
+ activeRunId=active[0].get("activeRunId") if len(active) == 1 else None,
143
+ activeTeamRunIds=[m["teamRunId"] for m in active],
144
+ revision=current["revision"] + 1,
145
+ )
146
+ self.publish(tx, "member", member_key(member["groupId"], member["memberId"]), current)
147
+
148
+ def update_active_clock(self, tx: Transaction, run: dict[str, Any]) -> None:
149
+ timestamp = now()
150
+ previous = run.get("activeDurationSeconds", 0)
151
+ if run.get("_activeSince"):
152
+ elapsed = (
153
+ datetime.fromisoformat(timestamp) - datetime.fromisoformat(run["_activeSince"])
154
+ ).total_seconds()
155
+ total = previous + run.get("_activeRemainderSeconds", 0) + max(0, elapsed)
156
+ run["activeDurationSeconds"] = int(total)
157
+ run["_activeRemainderSeconds"] = total - int(total)
158
+ executing = run["status"] not in TERMINAL | {
159
+ "cancel_requested",
160
+ "awaiting_acceptance",
161
+ } and any(
162
+ d.get("_runStatus") == "running"
163
+ and not d.get("_terminalState")
164
+ and not d.get("_fenced")
165
+ for d in tx.list("delivery", run["groupId"], team_run_id=run["teamRunId"])
166
+ )
167
+ run["_activeSince"] = timestamp if executing else None
168
+ if run.get("activeDurationSeconds", 0) != previous:
169
+ run["revision"] += 1
170
+ self.publish(tx, "team_run", run["teamRunId"], run)
171
+
172
+ def mutate(
173
+ self,
174
+ actor: Actor,
175
+ group_id: str,
176
+ key: str,
177
+ payload: Any,
178
+ operation: Callable[[Transaction], Any],
179
+ *,
180
+ owner: bool = False,
181
+ leader: bool = False,
182
+ ) -> Any:
183
+ return self.store.mutate(
184
+ f"{actor.tenant_id}:{group_id}:{actor.kind}:{actor.subject}:{actor.member_id or ''}",
185
+ key,
186
+ payload,
187
+ operation,
188
+ authorize=lambda tx: self.authorize(tx, actor, group_id, owner=owner, leader=leader),
189
+ )
190
+
191
+ @staticmethod
192
+ def publish(
193
+ tx: Transaction,
194
+ kind: str,
195
+ key: str,
196
+ value: dict[str, Any],
197
+ *,
198
+ created: bool = False,
199
+ **refs: Any,
200
+ ) -> None:
201
+ tx.put(kind, key, value)
202
+ event_type = {
203
+ "team_run": "team_run.updated",
204
+ "message": "message.created" if created else "message.updated",
205
+ }.get(kind, f"{kind}.updated")
206
+ payload_key = {"team_run": "teamRun", "run_member": "runMember"}.get(kind, kind)
207
+ event = tx.event(value["groupId"], event_type, {payload_key: public(value)}, **refs)
208
+ if kind == "message" and created:
209
+ value["_createdSeq"] = event["groupSeq"]
210
+ tx.put(kind, key, value)
211
+
212
+ def create_group(
213
+ self, actor: Actor, request: GroupCreateInput, bindings: dict[str, dict[str, Any]]
214
+ ) -> dict[str, Any]:
215
+ if actor.kind != "human" or not actor.subject or not actor.tenant_id:
216
+ raise TeamsError("human_owner_required", "需要真实用户创建团队", status=403)
217
+ for member in request.members:
218
+ binding = bindings.get(member.bindingRef)
219
+ if not binding or not binding.get("capabilities", {}).get("enqueue"):
220
+ raise TeamsError("binding_unavailable", "所选成员尚不支持团队执行", status=422)
221
+ if member.memberId == request.leaderMemberId and not binding["capabilities"].get(
222
+ "leader"
223
+ ):
224
+ raise TeamsError("leader_unavailable", "所选成员尚不支持协调团队", status=422)
225
+
226
+ def create(tx: Transaction) -> dict[str, Any]:
227
+ group_id, timestamp = new_id("grp"), now()
228
+ group = {
229
+ "groupId": group_id,
230
+ "name": request.name,
231
+ "authorityRef": self.authority_ref,
232
+ "tenantId": actor.tenant_id,
233
+ "ownerSubject": actor.subject,
234
+ "leaderMemberId": request.leaderMemberId,
235
+ "revision": 1,
236
+ "status": "active",
237
+ "createdAt": timestamp,
238
+ "updatedAt": timestamp,
239
+ "_policy": {"taskAcceptance": request.taskAcceptance, "peerWake": False},
240
+ }
241
+ if request.leaderStandbyBindingRef:
242
+ group["_leaderStandbyBindingRef"] = request.leaderStandbyBindingRef
243
+ self.publish(tx, "group", group_id, group)
244
+ for selected in request.members:
245
+ member = {
246
+ "memberId": selected.memberId,
247
+ "groupId": group_id,
248
+ "name": selected.name,
249
+ "role": "leader" if selected.memberId == request.leaderMemberId else "member",
250
+ "bindingRef": selected.bindingRef,
251
+ "binding": deepcopy(bindings[selected.bindingRef]),
252
+ "responsibility": selected.responsibility,
253
+ "sessionId": new_id("ses"),
254
+ "revision": 1,
255
+ "status": "active",
256
+ "executionStatus": "idle",
257
+ }
258
+ self.publish(tx, "member", member_key(group_id, selected.memberId), member)
259
+ tx.put(
260
+ "group_revision", f"{group_id}:1", {**group, "members": tx.list("member", group_id)}
261
+ )
262
+ return self._snapshot(tx, group_id)
263
+
264
+ return self.store.mutate(
265
+ f"{actor.tenant_id}:{actor.subject}:create_group",
266
+ request.idempotencyKey,
267
+ request.model_dump(),
268
+ create,
269
+ )
270
+
271
+ def snapshot(
272
+ self, actor: Actor, group_id: str, team_run_id: str | None = None
273
+ ) -> dict[str, Any]:
274
+ with self.store.transaction() as tx:
275
+ self.authorize(tx, actor, group_id)
276
+ if actor.kind == "member" and team_run_id and team_run_id != actor.team_run_id:
277
+ raise TeamsError("forbidden", "不能读取其他轮次", status=403)
278
+ if team_run_id and tx.get("team_run", team_run_id)["groupId"] != group_id:
279
+ raise TeamsError("not_found", "轮次不存在", status=404)
280
+ return self._snapshot(tx, group_id, actor=actor, team_run_id=team_run_id)
281
+
282
+ def _snapshot(
283
+ self,
284
+ tx: Transaction,
285
+ group_id: str,
286
+ *,
287
+ actor: Actor | None = None,
288
+ team_run_id: str | None = None,
289
+ ) -> dict[str, Any]:
290
+ snapshot = {
291
+ "apiVersion": API_VERSION,
292
+ "group": tx.get("group", group_id),
293
+ "watermark": tx.watermark(group_id),
294
+ }
295
+ for key, kind in {
296
+ "members": "member",
297
+ "runMembers": "run_member",
298
+ "messages": "message",
299
+ "teamRuns": "team_run",
300
+ "tasks": "task",
301
+ "deliveries": "delivery",
302
+ "interactions": "interaction",
303
+ "artifacts": "artifact",
304
+ }.items():
305
+ values = tx.list(kind, group_id)
306
+ if kind == "run_member":
307
+ indexed = {m["runMemberId"]: m for m in values}
308
+ for run in tx.list("team_run", group_id):
309
+ for frozen in run.get("_roster", []):
310
+ if frozen["status"] == "active":
311
+ identity = run_member_key(run["teamRunId"], frozen["memberId"])
312
+ indexed.setdefault(
313
+ identity, self.run_member(tx, run["teamRunId"], frozen["memberId"])
314
+ )
315
+ values = list(indexed.values())
316
+ selected_run = actor.team_run_id if actor and actor.kind == "member" else team_run_id
317
+ if selected_run and kind != "member":
318
+ values = [v for v in values if v.get("teamRunId") == selected_run]
319
+ if key == "messages":
320
+ values = [value for value in values if value.get("visibility") != "internal"]
321
+ if actor and actor.kind == "member" and key == "interactions":
322
+ values = [value for value in values if value["ref"]["memberId"] == actor.member_id]
323
+ snapshot[key] = values
324
+ return public(snapshot)
325
+
326
+ def list_groups(
327
+ self, actor: Actor, *, cursor: str | None = None, limit: int = 50
328
+ ) -> dict[str, Any]:
329
+ if actor.kind != "human" or not 1 <= limit <= 100:
330
+ raise TeamsError("forbidden", "无法列出团队", status=403)
331
+ with self.store.transaction() as tx:
332
+ groups = sorted(
333
+ (
334
+ group
335
+ for group in tx.list("group")
336
+ if group["tenantId"] == actor.tenant_id
337
+ and group["ownerSubject"] == actor.subject
338
+ ),
339
+ key=lambda group: group["groupId"],
340
+ )
341
+ groups = [group for group in groups if not cursor or group["groupId"] > cursor]
342
+ items = []
343
+ for group in groups[:limit]:
344
+ gid = group["groupId"]
345
+ runs = tx.list("team_run", gid)
346
+ active = next(
347
+ (run for run in reversed(runs) if run["status"] not in TERMINAL), None
348
+ )
349
+ messages = tx.list("message", gid)
350
+ read = tx.get("read_watermark", f"{gid}:{actor.subject}", required=False)
351
+ items.append(
352
+ {
353
+ **group,
354
+ "memberCount": sum(
355
+ member["status"] == "active" for member in tx.list("member", gid)
356
+ ),
357
+ "pendingCount": sum(
358
+ item["status"] == "pending" for item in tx.list("interaction", gid)
359
+ )
360
+ + sum(
361
+ task["status"] == "awaiting_acceptance" for task in tx.list("task", gid)
362
+ )
363
+ + sum(run["status"] == "awaiting_acceptance" for run in runs),
364
+ "unreadCount": sum(
365
+ message.get("_createdSeq", 0) > (read or {}).get("watermark", 0)
366
+ and message.get("senderPrincipal") != actor.subject
367
+ for message in messages
368
+ ),
369
+ "activeTeamRunId": active["teamRunId"] if active else None,
370
+ "activeTeamRunIds": [
371
+ r["teamRunId"] for r in runs if r["status"] not in TERMINAL
372
+ ],
373
+ "activeStatus": active["status"] if active else None,
374
+ "lastMessage": plain_text(messages[-1]["parts"])[:160] if messages else "",
375
+ }
376
+ )
377
+ return {
378
+ "items": public(items),
379
+ "nextCursor": items[-1]["groupId"] if len(groups) > limit else None,
380
+ }
381
+
382
+ @staticmethod
383
+ def active_run(tx: Transaction, group_id: str) -> dict[str, Any] | None:
384
+ return next(
385
+ (
386
+ run
387
+ for run in reversed(tx.list("team_run", group_id))
388
+ if run["status"] not in TERMINAL
389
+ ),
390
+ None,
391
+ )
392
+
393
+ def _start(
394
+ self,
395
+ tx: Transaction,
396
+ group: dict[str, Any],
397
+ message: dict[str, Any],
398
+ budget: Budget | None = None,
399
+ ) -> dict[str, Any]:
400
+ existing = next(
401
+ (
402
+ run
403
+ for run in tx.list("team_run", group["groupId"])
404
+ if run["goalMessageId"] == message["messageId"]
405
+ ),
406
+ None,
407
+ )
408
+ if existing:
409
+ return existing
410
+ if group.get("legacySource"):
411
+ raise TeamsError(
412
+ "legacy_history_read_only", "导入历史只读,请创建新团队执行任务", status=409
413
+ )
414
+ if group["status"] != "active":
415
+ raise TeamsError("group_archived", "团队已归档", status=409)
416
+ timestamp = now()
417
+ run_id = new_id("tr")
418
+ roster = []
419
+ for current in tx.list("member", group["groupId"]):
420
+ if current["status"] != "active":
421
+ continue
422
+ member = {
423
+ **deepcopy(current),
424
+ "runMemberId": run_member_key(run_id, current["memberId"]),
425
+ "teamRunId": run_id,
426
+ "groupRevision": group["revision"],
427
+ "sessionId": new_id("ses"),
428
+ "revision": 1,
429
+ "executionStatus": "idle",
430
+ "activeRunId": None,
431
+ }
432
+ member.pop("_bindingHistory", None)
433
+ member.pop("activeTeamRunIds", None)
434
+ roster.append(member)
435
+ run = {
436
+ "teamRunId": run_id,
437
+ "groupId": group["groupId"],
438
+ "groupRevision": group["revision"],
439
+ "revision": 1,
440
+ "goalMessageId": message["messageId"],
441
+ "goal": plain_text(message["parts"]),
442
+ "leaderMemberId": group["leaderMemberId"],
443
+ "status": "planning",
444
+ "dispatchSuspended": False,
445
+ "dispatchEpoch": 1,
446
+ "budget": (budget or Budget()).model_dump(),
447
+ "createdAt": timestamp,
448
+ "updatedAt": timestamp,
449
+ "_roster": roster,
450
+ "_leaderStandbyBindingRef": group.get("_leaderStandbyBindingRef"),
451
+ "_leaderStandbyReleaseRef": group.get("_leaderStandbyReleaseRef"),
452
+ "_policy": deepcopy(group["_policy"]),
453
+ "activeDurationSeconds": 0,
454
+ "workspace": deepcopy(message.get("workspace")),
455
+ }
456
+ self.publish(tx, "team_run", run["teamRunId"], run)
457
+ for member in roster:
458
+ self.publish(tx, "run_member", member["runMemberId"], member)
459
+ return run
460
+
461
+ def message_run(self, tx: Transaction, group_id: str, request: MessageInput):
462
+ if request.teamRunId:
463
+ run = tx.get("team_run", request.teamRunId)
464
+ if run["groupId"] != group_id:
465
+ raise TeamsError("not_found", "轮次不属于当前团队", status=404)
466
+ if request.intent != "note":
467
+ self._task_run(tx, group_id, request.teamRunId)
468
+ return run
469
+ if request.intent in {"start_goal", "note"}:
470
+ return None
471
+ active = [r for r in tx.list("team_run", group_id) if r["status"] not in TERMINAL]
472
+ if len(active) > 1:
473
+ raise TeamsError(
474
+ "team_run_ambiguous", "团队有多个进行中的任务,请选择本条消息所属任务", status=422
475
+ )
476
+ return active[0] if active else None
477
+
478
+ def send(self, actor: Actor, group_id: str, request: MessageInput) -> dict[str, Any]:
479
+ def send(tx: Transaction) -> dict[str, Any]:
480
+ group = self.authorize(tx, actor, group_id)
481
+ if group["status"] != "active":
482
+ raise TeamsError("group_archived", "团队已归档")
483
+ if request.replyTo:
484
+ parent = tx.get("message", request.replyTo)
485
+ if parent["groupId"] != group_id:
486
+ raise TeamsError("invalid_reply", "不能引用其他团队的消息", status=422)
487
+ if actor.kind != "human" and request.intent == "start_goal":
488
+ raise TeamsError("human_goal_required", "只有群主可以发起新目标", status=403)
489
+ run = None if actor.kind == "member" else self.message_run(tx, group_id, request)
490
+ if actor.kind == "member":
491
+ if request.teamRunId and request.teamRunId != actor.team_run_id:
492
+ raise TeamsError("forbidden", "不能发送到其他轮次", status=403)
493
+ run = self._task_run(tx, group_id, actor.team_run_id)
494
+ member = (
495
+ self.run_member(tx, actor.team_run_id, actor.member_id) if actor.member_id else None
496
+ )
497
+ message = {
498
+ "messageId": new_id("gm"),
499
+ "groupId": group_id,
500
+ "revision": 1,
501
+ "createdAt": now(),
502
+ "senderPrincipal": actor.subject,
503
+ "senderName": member["name"] if member else "我",
504
+ "groupRole": member["role"] if member else "owner",
505
+ "memberId": actor.member_id,
506
+ "parts": [part.model_dump(exclude_none=True) for part in request.parts],
507
+ "mentions": request.mentions,
508
+ "intent": request.intent,
509
+ "replyTo": request.replyTo,
510
+ "visibility": "public",
511
+ "workspace": request.workspace.model_dump() if request.workspace else None,
512
+ }
513
+ starting = request.intent == "start_goal" or (
514
+ request.intent == "directed" and run is None and actor.kind == "human"
515
+ )
516
+ if starting:
517
+ run = self._start(tx, group, message)
518
+ elif request.intent != "note" and run is None:
519
+ raise TeamsError("team_run_required", "请先发起本轮目标,或选择仅留言", status=422)
520
+ if run:
521
+ message["teamRunId"] = run["teamRunId"]
522
+ if request.replyTo and parent.get("teamRunId") != message.get("teamRunId"):
523
+ raise TeamsError("invalid_reply", "回复必须属于同一轮次", status=422)
524
+ for member_id in request.mentions:
525
+ self.run_member(tx, run["teamRunId"], member_id) if run else self._member(
526
+ tx, group_id, member_id
527
+ )
528
+ for part in request.parts:
529
+ if part.kind == "attachment":
530
+ artifact = tx.get("artifact", part.attachmentRef)
531
+ if artifact["groupId"] != group_id:
532
+ raise TeamsError("attachment_forbidden", "附件不属于该团队", status=403)
533
+ # Explicit attachment sharing grants only this destination round access.
534
+ if run and artifact.get("teamRunId") != run["teamRunId"]:
535
+ if actor.kind != "human":
536
+ raise TeamsError(
537
+ "attachment_forbidden", "跨任务交付物只能由群主显式分享", status=403
538
+ )
539
+ grants = run.setdefault("_sharedArtifactIds", [])
540
+ if part.attachmentRef not in grants:
541
+ grants.append(part.attachmentRef)
542
+ tx.put("team_run", run["teamRunId"], run)
543
+ self.publish(tx, "message", message["messageId"], message, created=True)
544
+ if request.intent != "note":
545
+ if actor.kind == "member":
546
+ # Member text is never a trigger. Explicit tool wake is separate.
547
+ pass
548
+ elif run["status"] == "cancel_requested":
549
+ raise TeamsError("stop_in_progress", "本轮正在停止,请等待执行结束")
550
+ else:
551
+ targets = (
552
+ [run["leaderMemberId"]]
553
+ if starting
554
+ else request.mentions or [run["leaderMemberId"]]
555
+ )
556
+ for target in targets:
557
+ self.dispatch(
558
+ tx,
559
+ run,
560
+ message,
561
+ target,
562
+ source=message["messageId"],
563
+ purpose="goal" if starting else "message",
564
+ )
565
+ return {
566
+ "status": "accepted",
567
+ "groupId": group_id,
568
+ "messageId": message["messageId"],
569
+ "teamRunId": run["teamRunId"] if run else None,
570
+ "groupSeq": tx.watermark(group_id),
571
+ }
572
+
573
+ return self.mutate(
574
+ actor,
575
+ group_id,
576
+ request.idempotencyKey,
577
+ {"operation": "send", **request.model_dump()},
578
+ send,
579
+ )
580
+
581
+ def start_goal(self, actor: Actor, group_id: str, message_id: str, key: str) -> dict[str, Any]:
582
+ def start(tx: Transaction) -> dict[str, Any]:
583
+ group = tx.get("group", group_id)
584
+ message = tx.get("message", message_id)
585
+ if message["groupId"] != group_id or message["groupRole"] != "owner":
586
+ raise TeamsError("invalid_goal", "目标必须引用本群的用户消息", status=422)
587
+ run = self._start(tx, group, message)
588
+ self.dispatch(
589
+ tx, run, message, run["leaderMemberId"], source=message_id, purpose="goal"
590
+ )
591
+ return public(run)
592
+
593
+ return self.mutate(
594
+ actor, group_id, key, {"operation": "start", "messageId": message_id}, start, owner=True
595
+ )
596
+
597
+ @staticmethod
598
+ def _member(tx: Transaction, group_id: str, member_id: str) -> dict[str, Any]:
599
+ member = tx.get("member", member_key(group_id, member_id))
600
+ if member["status"] != "active":
601
+ raise TeamsError("member_unavailable", "目标成员已移除或不可用")
602
+ return member
603
+
604
+ def dispatch(
605
+ self,
606
+ tx: Transaction,
607
+ run: dict[str, Any],
608
+ message: dict[str, Any],
609
+ target: str,
610
+ *,
611
+ source: str,
612
+ purpose: str,
613
+ hop: int = 0,
614
+ root: str | None = None,
615
+ task_id: str | None = None,
616
+ attempt_id: str | None = None,
617
+ ) -> dict[str, Any] | None:
618
+ # Always re-read the budget: several targets can be dispatched in one tx.
619
+ run = tx.get("team_run", run["teamRunId"])
620
+ decision_id = "td_" + digest([run["teamRunId"], source, target, purpose])[7:]
621
+ previous = tx.get("trigger", decision_id, required=False)
622
+ if previous:
623
+ return (
624
+ tx.get("delivery", previous["deliveryId"], required=False)
625
+ if previous.get("deliveryId")
626
+ else None
627
+ )
628
+ member = self.run_member(tx, run["teamRunId"], target)
629
+ pending = sum(
630
+ delivery["memberId"] == target and delivery["status"] in {"pending", "uncertain"}
631
+ for delivery in tx.list("delivery", run["groupId"], team_run_id=run["teamRunId"])
632
+ )
633
+ reason = None
634
+ takeover = (
635
+ tx.get("leader_takeover", run["_leaderTakeoverId"])
636
+ if member["role"] == "leader" and run.get("_leaderTakeoverId")
637
+ else None
638
+ )
639
+ if run["status"] in TERMINAL or run["status"] == "cancel_requested":
640
+ reason = "team_run_closed"
641
+ elif takeover and takeover["phase"] != "active" and not (
642
+ purpose == "leader_takeover"
643
+ and source == takeover["takeoverId"]
644
+ and member["sessionId"] == takeover["newSessionId"]
645
+ ):
646
+ # Preserve the public message for the confirmed checkpoint while
647
+ # preventing a new epoch from granting the old Leader a new run.
648
+ reason = "leader_takeover_pending"
649
+ elif member["binding"].get("memberClass") == "task_worker" and not task_id:
650
+ reason = "task_worker_requires_task"
651
+ elif hop > run["budget"]["maxHops"]:
652
+ reason = "hop_limit"
653
+ elif run["budget"]["startsUsed"] >= run["budget"]["maxStarts"]:
654
+ reason = "start_budget_exhausted"
655
+ elif pending >= 64:
656
+ reason = "member_queue_full"
657
+ decision = {
658
+ "decisionId": decision_id,
659
+ "groupId": run["groupId"],
660
+ "teamRunId": run["teamRunId"],
661
+ "sourceEventRef": source,
662
+ "rootTriggerId": root or source,
663
+ "hop": hop,
664
+ "targetMemberId": target,
665
+ "purpose": purpose,
666
+ "blockedReason": reason,
667
+ }
668
+ if reason:
669
+ tx.put("trigger", decision_id, decision)
670
+ if run["status"] not in TERMINAL and run["status"] != "cancel_requested":
671
+ run.update(
672
+ status="needs_attention",
673
+ reason=reason,
674
+ revision=run["revision"] + 1,
675
+ updatedAt=now(),
676
+ )
677
+ self.publish(tx, "team_run", run["teamRunId"], run)
678
+ tx.event(run["groupId"], "trigger.blocked", {"decision": decision})
679
+ return None
680
+ delivery = {
681
+ "deliveryId": new_id("gd"),
682
+ "groupId": run["groupId"],
683
+ "teamRunId": run["teamRunId"],
684
+ "messageId": message["messageId"],
685
+ "memberId": target,
686
+ "revision": 1,
687
+ "status": "pending",
688
+ "_decisionId": decision_id,
689
+ "_bindingRef": member["bindingRef"],
690
+ "_sessionId": member["sessionId"],
691
+ "_memberSnapshot": deepcopy(member),
692
+ "_dispatchEpoch": run["dispatchEpoch"],
693
+ "_payload": plain_text(message["parts"]),
694
+ "_parts": message["parts"],
695
+ "_taskId": task_id,
696
+ "_attemptId": attempt_id,
697
+ "_candidateMode": (
698
+ "canonical_terminal"
699
+ if member["binding"].get("memberClass") == "task_worker"
700
+ else "team_tool"
701
+ ),
702
+ "_nextRetryAt": 0,
703
+ "_createdAt": now(),
704
+ }
705
+ delivery["_payloadDigest"] = digest(
706
+ {
707
+ "content": delivery["_payload"],
708
+ "parts": delivery["_parts"],
709
+ "taskId": task_id,
710
+ "attemptId": attempt_id,
711
+ }
712
+ )
713
+ decision["deliveryId"] = delivery["deliveryId"]
714
+ tx.put("trigger", decision_id, decision)
715
+ self.publish(tx, "delivery", delivery["deliveryId"], delivery)
716
+ run["budget"]["startsUsed"] += 1
717
+ run.update(revision=run["revision"] + 1, updatedAt=now())
718
+ self.publish(tx, "team_run", run["teamRunId"], run)
719
+ if member["executionStatus"] == "idle":
720
+ member.update(executionStatus="queued", revision=member["revision"] + 1)
721
+ self.publish_run_member(tx, member)
722
+ return delivery
723
+
724
+ def control(
725
+ self,
726
+ actor: Actor,
727
+ group_id: str,
728
+ run_id: str,
729
+ action: str,
730
+ expected_revision: int,
731
+ key: str,
732
+ ) -> dict[str, Any]:
733
+ if action not in {"suspend_dispatch", "resume_dispatch", "stop"}:
734
+ raise TeamsError("unsupported_control", "不支持该团队控制", status=422)
735
+
736
+ def control(tx: Transaction) -> dict[str, Any]:
737
+ run = tx.get("team_run", run_id)
738
+ if run["groupId"] != group_id:
739
+ raise TeamsError("not_found", "本轮不存在", status=404)
740
+ if run["revision"] != expected_revision:
741
+ raise TeamsError("revision_conflict", "本轮状态已更新,请刷新后重试")
742
+ if run["status"] in TERMINAL:
743
+ raise TeamsError("team_run_closed", "本轮已结束")
744
+ if run["status"] == "cancel_requested" and action != "stop":
745
+ raise TeamsError("stop_in_progress", "已请求停止,不能恢复旧命令")
746
+ run["dispatchEpoch"] += 1
747
+ # Only admission changes here. Running members retain execution and
748
+ # tool authority; resume waits for the independent admission barrier.
749
+ run["dispatchSuspended"] = True
750
+ if action == "stop":
751
+ run["status"] = "cancel_requested"
752
+ run.update(revision=run["revision"] + 1, updatedAt=now())
753
+ self.update_active_clock(tx, run)
754
+ self.publish(tx, "team_run", run_id, run)
755
+ for delivery in tx.list("delivery", group_id, team_run_id=run_id):
756
+ if delivery["status"] == "pending":
757
+ if action == "stop":
758
+ delivery["status"] = "cancelled"
759
+ delivery.update(
760
+ _dispatchEpoch=run["dispatchEpoch"], revision=delivery["revision"] + 1
761
+ )
762
+ self.publish(tx, "delivery", delivery["deliveryId"], delivery)
763
+ # Freeze exact historical scopes before a Leader changes sessions.
764
+ targets = self._control_targets(tx, run, include_terminal=action == "resume_dispatch")
765
+ control_id = new_id("gc")
766
+ tx.put(
767
+ "control",
768
+ control_id,
769
+ {
770
+ "controlId": control_id,
771
+ "groupId": group_id,
772
+ "teamRunId": run_id,
773
+ "action": action,
774
+ "epoch": run["dispatchEpoch"],
775
+ "status": "pending",
776
+ "barriers": {},
777
+ "targets": targets,
778
+ },
779
+ )
780
+ return public(run)
781
+
782
+ return self.mutate(
783
+ actor,
784
+ group_id,
785
+ key,
786
+ {
787
+ "operation": "control",
788
+ "runId": run_id,
789
+ "action": action,
790
+ "expectedRevision": expected_revision,
791
+ },
792
+ control,
793
+ owner=True,
794
+ )
795
+
796
+ def events(
797
+ self, actor: Actor, group_id: str, after: int = 0, limit: int = 200
798
+ ) -> list[dict[str, Any]]:
799
+ with self.store.transaction() as tx:
800
+ self.authorize(tx, actor, group_id)
801
+ if actor.kind == "member":
802
+ raise TeamsError("owner_stream_only", "成员通过受限上下文读取群信息", status=403)
803
+ return self.store.events(group_id, after, limit)
804
+
805
+ def project_run(
806
+ self,
807
+ *,
808
+ delivery_id: str,
809
+ event_id: str,
810
+ run_id: str,
811
+ status: str,
812
+ output: str = "",
813
+ tokens: int = 0,
814
+ ) -> dict[str, Any]:
815
+ """Trusted host projection after consulting the canonical Run record.
816
+
817
+ The plugin transport does not expose this operation to models/browsers.
818
+ Run state, output and usage must be obtained through Host Services.
819
+ """
820
+ if status not in {
821
+ "running",
822
+ "awaiting_approval",
823
+ "waiting_for_node",
824
+ "succeeded",
825
+ "failed",
826
+ "cancelled",
827
+ "interrupted",
828
+ }:
829
+ raise TeamsError("invalid_run_state", "无法识别执行状态", status=422)
830
+
831
+ return self.store.mutate(
832
+ f"projection:{delivery_id}",
833
+ event_id,
834
+ {"runId": run_id, "status": status, "output": output, "tokens": tokens},
835
+ lambda tx: self._project_run(
836
+ tx,
837
+ delivery_id=delivery_id,
838
+ run_id=run_id,
839
+ status=status,
840
+ output=output,
841
+ tokens=tokens,
842
+ ),
843
+ )
844
+
845
+ def _project_run(
846
+ self,
847
+ tx: Transaction,
848
+ *,
849
+ delivery_id: str,
850
+ run_id: str,
851
+ status: str,
852
+ output: str = "",
853
+ tokens: int = 0,
854
+ completion_projection: bool = False,
855
+ ) -> dict[str, Any]:
856
+ delivery = tx.get("delivery", delivery_id)
857
+ run = tx.get("team_run", delivery["teamRunId"])
858
+ member = self.delivery_member(tx, delivery)
859
+ if delivery.get("runId") and delivery["runId"] != run_id:
860
+ raise TeamsError("run_identity_conflict", "投递与执行引用不一致")
861
+ if delivery.get("_terminalState"):
862
+ return {"status": delivery["_terminalState"]}
863
+ if (
864
+ delivery.get("_candidateMode") == "canonical_terminal"
865
+ and status
866
+ in {
867
+ "succeeded",
868
+ "failed",
869
+ "cancelled",
870
+ "interrupted",
871
+ }
872
+ and not completion_projection
873
+ ):
874
+ raise TeamsError(
875
+ "completion_projection_required",
876
+ "此成员需要完整的终态结果投影",
877
+ status=409,
878
+ )
879
+ if delivery.get("resultState") == "pending" and not completion_projection:
880
+ return {"status": "result_pending"}
881
+ delivery.update(runId=run_id, status="accepted", revision=delivery["revision"] + 1)
882
+ delivery["_runStatus"] = status
883
+ terminal = status in {"succeeded", "failed", "cancelled", "interrupted"}
884
+ if terminal:
885
+ delivery["_terminalState"] = status
886
+ self.publish(tx, "delivery", delivery_id, delivery)
887
+ self.update_active_clock(tx, run)
888
+ tx.put("team_run", run["teamRunId"], run)
889
+ source = {
890
+ "authorityRef": self.authority_ref,
891
+ "groupId": run["groupId"],
892
+ "memberId": member["memberId"],
893
+ "bindingRef": member["bindingRef"],
894
+ "providerRef": member["binding"]["providerRef"],
895
+ "sessionId": member["sessionId"],
896
+ "runId": run_id,
897
+ }
898
+ member.update(
899
+ activeRunId=None if terminal else run_id,
900
+ executionStatus="idle"
901
+ if terminal
902
+ else "waiting"
903
+ if status in {"awaiting_approval", "waiting_for_node"}
904
+ else "running",
905
+ revision=member["revision"] + 1,
906
+ )
907
+ current_member = self.run_member(tx, run["teamRunId"], delivery["memberId"])
908
+ if current_member["sessionId"] == member["sessionId"]:
909
+ member["revision"] = current_member["revision"] + 1
910
+ self.publish_run_member(tx, member)
911
+ if status == "running" and run["status"] == "planning":
912
+ run.update(status="running", revision=run["revision"] + 1, updatedAt=now())
913
+ self.publish(tx, "team_run", run["teamRunId"], run)
914
+ if delivery.get("_taskId"):
915
+ task = tx.get("task", delivery["_taskId"])
916
+ attempt = task["attempts"][-1]
917
+ if attempt["attemptId"] == delivery.get("_attemptId"):
918
+ attempt["source"] = source
919
+ if run_id not in attempt["_runIds"]:
920
+ attempt["_runIds"].append(run_id)
921
+ attempt.setdefault("startedAt", now())
922
+ if terminal:
923
+ attempt["endedAt"] = now()
924
+ candidate = attempt.get("_candidate")
925
+ if (
926
+ status == "succeeded"
927
+ and candidate
928
+ and candidate["runId"] == run_id
929
+ and not delivery.get("_fenced")
930
+ ):
931
+ attempt.update(result=candidate["result"], artifacts=candidate["artifacts"])
932
+ task["status"] = (
933
+ "succeeded"
934
+ if task["_acceptancePolicy"] == "result"
935
+ else "awaiting_acceptance"
936
+ )
937
+ else:
938
+ task["status"] = "cancelled" if status == "cancelled" else "failed"
939
+ task["reason"] = (
940
+ "执行结束但未提交可核验结果" if status == "succeeded" else status
941
+ )
942
+ attempt["status"] = task["status"]
943
+ else:
944
+ task["status"] = attempt["status"] = "running"
945
+ if status == "awaiting_approval":
946
+ task["reason"] = "等待人工审批"
947
+ elif status == "waiting_for_node":
948
+ task["reason"] = "等待设备上线"
949
+ elif task.get("reason") in {"等待人工审批", "等待设备上线"}:
950
+ task.pop("reason", None)
951
+ task["revision"] += 1
952
+ self.publish(tx, "task", task["taskId"], task)
953
+ if terminal:
954
+ run = tx.get("team_run", run["teamRunId"])
955
+ run["budget"]["tokensUsed"] += max(0, tokens)
956
+ if (
957
+ member["memberId"] == run["leaderMemberId"]
958
+ and not delivery.get("_fenced")
959
+ and status in {"failed", "cancelled", "interrupted"}
960
+ and run["status"] not in TERMINAL | {"cancel_requested"}
961
+ ):
962
+ run.update(
963
+ status="needs_attention", dispatchSuspended=True, reason=f"leader_{status}"
964
+ )
965
+ if (
966
+ run["budget"]["tokensUsed"] >= run["budget"]["maxTokens"]
967
+ and run["status"] not in TERMINAL
968
+ and run["status"] != "cancel_requested"
969
+ ):
970
+ run.update(
971
+ status="needs_attention",
972
+ dispatchSuspended=True,
973
+ reason="token_budget_exhausted",
974
+ )
975
+ run.update(revision=run["revision"] + 1, updatedAt=now())
976
+ self.publish(tx, "team_run", run["teamRunId"], run)
977
+ if output.strip():
978
+ message = {
979
+ "messageId": "result_" + digest([delivery_id, run_id])[7:],
980
+ "groupId": run["groupId"],
981
+ "teamRunId": run["teamRunId"],
982
+ "revision": 1,
983
+ "createdAt": now(),
984
+ "senderPrincipal": f"member:{member['memberId']}",
985
+ "senderName": member["name"],
986
+ "groupRole": member["role"],
987
+ "memberId": member["memberId"],
988
+ "parts": [{"kind": "text", "text": output}],
989
+ "mentions": [],
990
+ "intent": "result",
991
+ "visibility": "public",
992
+ "sourceRefs": [source],
993
+ }
994
+ self.publish(tx, "message", message["messageId"], message, created=True)
995
+ self._advance(tx, run)
996
+ if not delivery.get("_fenced"):
997
+ self.finalize_if_ready(tx, run["teamRunId"])
998
+ return {"status": status}
999
+
1000
+ def finalize_if_ready(self, tx, run_id):
1001
+ run = tx.get("team_run", run_id)
1002
+ candidate = run.get("_finalCandidate")
1003
+ if not candidate or run["status"] in TERMINAL | {"cancel_requested", "awaiting_acceptance"}:
1004
+ return
1005
+ deliveries = tx.list("delivery", run["groupId"], team_run_id=run_id)
1006
+ if not any(
1007
+ d.get("runId") == candidate["runId"]
1008
+ and d.get("_terminalState") == "succeeded"
1009
+ and not d.get("_fenced")
1010
+ for d in deliveries
1011
+ ):
1012
+ return
1013
+ if any(
1014
+ d["status"] in {"pending", "uncertain"}
1015
+ or (d["status"] == "accepted" and not d.get("_terminalState"))
1016
+ for d in deliveries
1017
+ ):
1018
+ return
1019
+ if any(
1020
+ task["status"] != "succeeded"
1021
+ for task in tx.list("task", run["groupId"], team_run_id=run_id)
1022
+ ):
1023
+ return
1024
+ run.update(
1025
+ status="awaiting_acceptance",
1026
+ result=candidate["result"],
1027
+ revision=run["revision"] + 1,
1028
+ updatedAt=now(),
1029
+ )
1030
+ self.publish(tx, "team_run", run_id, run)
1031
+
1032
+ def finish_candidate(self, actor: Actor, result: str, key: str) -> dict[str, Any]:
1033
+ if (
1034
+ actor.kind != "member"
1035
+ or not actor.group_id
1036
+ or not actor.team_run_id
1037
+ or not actor.run_id
1038
+ ):
1039
+ raise TeamsError("invocation_required", "需要 Leader 的受信执行上下文", status=403)
1040
+ if not result.strip() or len(result) > 100_000:
1041
+ raise TeamsError("invalid_result", "请提供有效的交付结果", status=422)
1042
+
1043
+ def finish(tx: Transaction) -> dict[str, Any]:
1044
+ run = self._task_run(tx, actor.group_id, actor.team_run_id)
1045
+ tasks = tx.list("task", actor.group_id, team_run_id=actor.team_run_id)
1046
+ if any(task["status"] != "succeeded" for task in tasks):
1047
+ raise TeamsError("tasks_unsettled", "仍有任务未通过验收,不能提交最终成果")
1048
+ run["_finalCandidate"] = {"runId": actor.run_id, "result": result}
1049
+ run["revision"] += 1
1050
+ tx.put("team_run", run["teamRunId"], run)
1051
+ return {"status": "candidate_received", "teamRunId": run["teamRunId"]}
1052
+
1053
+ return self.mutate(
1054
+ actor,
1055
+ actor.group_id,
1056
+ key,
1057
+ {"operation": "finish", "result": result},
1058
+ finish,
1059
+ leader=True,
1060
+ )
1061
+
1062
+ def member_message(
1063
+ self,
1064
+ actor: Actor,
1065
+ *,
1066
+ content: str,
1067
+ target_member_id: str | None,
1068
+ wake: bool,
1069
+ source_delivery_id: str,
1070
+ key: str,
1071
+ ) -> dict[str, Any]:
1072
+ """Explicit member communication; prose mentions never trigger work."""
1073
+ if actor.kind != "member" or not actor.group_id or not actor.team_run_id:
1074
+ raise TeamsError("invocation_required", "需要受信的成员执行上下文", status=403)
1075
+ if not content.strip() or len(content) > 100_000:
1076
+ raise TeamsError("invalid_message", "消息不能为空或超过大小限制", status=422)
1077
+
1078
+ def send(tx: Transaction) -> dict[str, Any]:
1079
+ run = self._task_run(tx, actor.group_id, actor.team_run_id)
1080
+ member = self.run_member(tx, actor.team_run_id, actor.member_id)
1081
+ source_delivery = tx.get("delivery", source_delivery_id)
1082
+ if (
1083
+ source_delivery["memberId"] != actor.member_id
1084
+ or source_delivery["teamRunId"] != actor.team_run_id
1085
+ or source_delivery.get("runId") not in {None, actor.run_id}
1086
+ ):
1087
+ raise TeamsError("invocation_scope_mismatch", "消息来源执行不一致", status=403)
1088
+ if target_member_id:
1089
+ self.run_member(tx, actor.team_run_id, target_member_id)
1090
+ if wake:
1091
+ if not target_member_id:
1092
+ raise TeamsError("member_required", "唤醒需要明确接收成员", status=422)
1093
+ if (
1094
+ member["role"] != "leader"
1095
+ and target_member_id != run["leaderMemberId"]
1096
+ and not self.run_policy(tx, run)["peerWake"]
1097
+ ):
1098
+ raise TeamsError(
1099
+ "peer_wake_forbidden", "当前策略只允许向 Leader 请求后续处理", status=403
1100
+ )
1101
+ message = {
1102
+ "messageId": new_id("gm"),
1103
+ "groupId": actor.group_id,
1104
+ "teamRunId": actor.team_run_id,
1105
+ "revision": 1,
1106
+ "createdAt": now(),
1107
+ "senderPrincipal": f"member:{actor.member_id}",
1108
+ "senderName": member["name"],
1109
+ "groupRole": member["role"],
1110
+ "memberId": actor.member_id,
1111
+ "parts": [{"kind": "text", "text": content.strip()}],
1112
+ "mentions": [target_member_id] if target_member_id else [],
1113
+ "intent": "directed" if wake else "progress",
1114
+ "visibility": "public",
1115
+ }
1116
+ self.publish(tx, "message", message["messageId"], message, created=True)
1117
+ delivery = None
1118
+ if wake:
1119
+ previous = tx.get("trigger", source_delivery["_decisionId"])
1120
+ delivery = self.dispatch(
1121
+ tx,
1122
+ run,
1123
+ message,
1124
+ target_member_id,
1125
+ source=f"{actor.run_id}:{key}",
1126
+ purpose="member_request",
1127
+ hop=previous["hop"] + 1,
1128
+ root=previous["rootTriggerId"],
1129
+ )
1130
+ return {
1131
+ "status": "accepted" if not wake or delivery else "blocked",
1132
+ "messageId": message["messageId"],
1133
+ "groupId": actor.group_id,
1134
+ "deliveryId": delivery["deliveryId"] if delivery else None,
1135
+ }
1136
+
1137
+ return self.mutate(
1138
+ actor,
1139
+ actor.group_id,
1140
+ key,
1141
+ {
1142
+ "operation": "member_message",
1143
+ "content": content,
1144
+ "target": target_member_id,
1145
+ "wake": wake,
1146
+ "sourceDeliveryId": source_delivery_id,
1147
+ },
1148
+ send,
1149
+ )
1150
+
1151
+ def accept_run(
1152
+ self,
1153
+ actor: Actor,
1154
+ group_id: str,
1155
+ run_id: str,
1156
+ expected_revision: int,
1157
+ key: str,
1158
+ *,
1159
+ accepted: bool | None = None,
1160
+ action: str | None = None,
1161
+ reason: str | None = None,
1162
+ ) -> dict[str, Any]:
1163
+ chosen = action or ("accept" if accepted else "reject")
1164
+ if chosen not in {"accept", "reject", "request_changes"}:
1165
+ raise TeamsError("invalid_acceptance_action", "不支持该验收操作", status=422)
1166
+ if action is None and accepted is None:
1167
+ raise TeamsError("acceptance_action_required", "请选择验收操作", status=422)
1168
+ if action and accepted is not None and (action != ("accept" if accepted else "reject")):
1169
+ raise TeamsError("acceptance_action_conflict", "验收操作不能互相冲突", status=422)
1170
+ if chosen == "request_changes" and not (reason or "").strip():
1171
+ raise TeamsError("change_reason_required", "请说明需要修改的内容", status=422)
1172
+ if reason and len(reason) > 2000:
1173
+ raise TeamsError("invalid_reason", "修改理由不能超过2000字", status=422)
1174
+
1175
+ def accept(tx: Transaction) -> dict[str, Any]:
1176
+ run = self._task_run(tx, group_id, run_id)
1177
+ if run["revision"] != expected_revision:
1178
+ raise TeamsError("revision_conflict", "本轮状态已更新,请刷新后重试")
1179
+ if run["status"] != "awaiting_acceptance":
1180
+ raise TeamsError("not_awaiting_acceptance", "本轮尚未提交最终成果")
1181
+ if any(
1182
+ delivery["status"] in {"pending", "uncertain"}
1183
+ or (delivery["status"] == "accepted" and not delivery.get("_terminalState"))
1184
+ for delivery in tx.list("delivery", group_id, team_run_id=run_id)
1185
+ ):
1186
+ raise TeamsError("execution_in_flight", "仍有执行未结束,请等待真实终态")
1187
+ if chosen == "request_changes":
1188
+ run.setdefault("resultHistory", []).append(
1189
+ {
1190
+ "result": run.get("result", ""),
1191
+ "reason": reason.strip(),
1192
+ "revision": run["revision"],
1193
+ "requestedAt": now(),
1194
+ }
1195
+ )
1196
+ run.pop("_finalCandidate", None)
1197
+ run.pop("result", None)
1198
+ run.update(
1199
+ status="running"
1200
+ if chosen == "request_changes"
1201
+ else "succeeded"
1202
+ if chosen == "accept"
1203
+ else "failed",
1204
+ revision=run["revision"] + 1,
1205
+ updatedAt=now(),
1206
+ _acceptedBy=actor.subject,
1207
+ _acceptedAt=now(),
1208
+ )
1209
+ if reason:
1210
+ run["reason"] = reason.strip()
1211
+ self.publish(tx, "team_run", run_id, run)
1212
+ if chosen == "request_changes":
1213
+ message = {
1214
+ "messageId": new_id("gm"),
1215
+ "groupId": group_id,
1216
+ "teamRunId": run_id,
1217
+ "revision": 1,
1218
+ "createdAt": now(),
1219
+ "senderPrincipal": actor.subject,
1220
+ "senderName": "我",
1221
+ "groupRole": "owner",
1222
+ "parts": [
1223
+ {
1224
+ "kind": "text",
1225
+ "text": f"最终成果需要修改:{reason.strip()}\n请在本轮继续处理,"
1226
+ "保留已验收的有效结果,必要时创建修订子任务,完成后重新提交最终成果。",
1227
+ }
1228
+ ],
1229
+ "mentions": [run["leaderMemberId"]],
1230
+ "intent": "followup",
1231
+ "visibility": "public",
1232
+ }
1233
+ self.publish(tx, "message", message["messageId"], message, created=True)
1234
+ self.dispatch(
1235
+ tx,
1236
+ run,
1237
+ message,
1238
+ run["leaderMemberId"],
1239
+ source=message["messageId"],
1240
+ purpose="revision",
1241
+ )
1242
+ return public(tx.get("team_run", run_id))
1243
+
1244
+ return self.mutate(
1245
+ actor,
1246
+ group_id,
1247
+ key,
1248
+ {
1249
+ "operation": "accept_run",
1250
+ "runId": run_id,
1251
+ "expectedRevision": expected_revision,
1252
+ "accepted": accepted,
1253
+ "action": action,
1254
+ "reason": reason,
1255
+ },
1256
+ accept,
1257
+ owner=True,
1258
+ )
1259
+
1260
+ def update_group(
1261
+ self,
1262
+ actor: Actor,
1263
+ group_id: str,
1264
+ expected_revision: int,
1265
+ key: str,
1266
+ *,
1267
+ name: str | None = None,
1268
+ leader_member_id: str | None = None,
1269
+ remove_member_id: str | None = None,
1270
+ task_acceptance: str | None = None,
1271
+ peer_wake: bool | None = None,
1272
+ archived: bool | None = None,
1273
+ add_member: MemberInput | None = None,
1274
+ rebind_member: MemberInput | None = None,
1275
+ bindings: dict[str, dict[str, Any]] | None = None,
1276
+ ) -> dict[str, Any]:
1277
+ if name is not None and (not name.strip() or len(name.strip()) > 120):
1278
+ raise TeamsError("invalid_name", "群名不能为空且不能超过120字", status=422)
1279
+ if task_acceptance is not None and task_acceptance not in {"leader", "human", "result"}:
1280
+ raise TeamsError("invalid_policy", "验收策略无效", status=422)
1281
+ payload = {
1282
+ "operation": "update_group",
1283
+ "expectedRevision": expected_revision,
1284
+ "name": name,
1285
+ "leaderMemberId": leader_member_id,
1286
+ "removeMemberId": remove_member_id,
1287
+ "taskAcceptance": task_acceptance,
1288
+ "peerWake": peer_wake,
1289
+ "archived": archived,
1290
+ "addMember": add_member.model_dump() if add_member else None,
1291
+ "rebindMember": rebind_member.model_dump() if rebind_member else None,
1292
+ }
1293
+
1294
+ def update(tx: Transaction) -> dict[str, Any]:
1295
+ group = tx.get("group", group_id)
1296
+ if group.get("legacySource"):
1297
+ raise TeamsError(
1298
+ "legacy_history_read_only", "导入历史只读,请创建新团队", status=409
1299
+ )
1300
+ if group["revision"] != expected_revision:
1301
+ raise TeamsError("revision_conflict", "团队配置已更新,请刷新后重试")
1302
+ if name is not None:
1303
+ group["name"] = name.strip()
1304
+ for selected, adding in ((add_member, True), (rebind_member, False)):
1305
+ if selected is None:
1306
+ continue
1307
+ binding = (bindings or {}).get(selected.bindingRef)
1308
+ if not binding or not binding.get("capabilities", {}).get("enqueue"):
1309
+ raise TeamsError("binding_unavailable", "所选Build不支持团队执行", status=422)
1310
+ if adding:
1311
+ if (
1312
+ len([m for m in tx.list("member", group_id) if m["status"] == "active"])
1313
+ >= 8
1314
+ ):
1315
+ raise TeamsError("member_limit", "一个团队最多8位成员", status=422)
1316
+ if tx.get("member", member_key(group_id, selected.memberId), required=False):
1317
+ raise TeamsError(
1318
+ "member_id_exists", "成员标识已使用,请使用新标识", status=409
1319
+ )
1320
+ member = {
1321
+ "memberId": selected.memberId,
1322
+ "groupId": group_id,
1323
+ "role": "member",
1324
+ "revision": 1,
1325
+ "status": "active",
1326
+ "executionStatus": "idle",
1327
+ }
1328
+ else:
1329
+ member = self._member(tx, group_id, selected.memberId)
1330
+ if member["role"] == "leader" and not binding["capabilities"].get("leader"):
1331
+ raise TeamsError(
1332
+ "leader_unavailable", "新Build不支持Leader策略", status=422
1333
+ )
1334
+ member.setdefault("_bindingHistory", []).append(
1335
+ {
1336
+ key: deepcopy(member[key])
1337
+ for key in ("bindingRef", "binding", "sessionId")
1338
+ }
1339
+ )
1340
+ member["revision"] += 1
1341
+ member.update(
1342
+ name=selected.name,
1343
+ bindingRef=selected.bindingRef,
1344
+ binding=deepcopy(binding),
1345
+ sessionId=new_id("ses"),
1346
+ responsibility=selected.responsibility,
1347
+ )
1348
+ self.publish(tx, "member", member_key(group_id, selected.memberId), member)
1349
+ if leader_member_id:
1350
+ new_leader = self._member(tx, group_id, leader_member_id)
1351
+ if not new_leader["binding"]["capabilities"].get("leader"):
1352
+ raise TeamsError("leader_unavailable", "该成员不支持协调团队", status=422)
1353
+ for member in tx.list("member", group_id):
1354
+ role = "leader" if member["memberId"] == leader_member_id else "member"
1355
+ if member["role"] != role:
1356
+ member.update(role=role, revision=member["revision"] + 1)
1357
+ self.publish(tx, "member", member_key(group_id, member["memberId"]), member)
1358
+ group["leaderMemberId"] = leader_member_id
1359
+ if remove_member_id:
1360
+ if group["leaderMemberId"] == remove_member_id:
1361
+ raise TeamsError(
1362
+ "leader_required", "移除 Leader 前请指定新的 Leader", status=422
1363
+ )
1364
+ member = self._member(tx, group_id, remove_member_id)
1365
+ member.update(status="removed", revision=member["revision"] + 1)
1366
+ self.publish(tx, "member", member_key(group_id, remove_member_id), member)
1367
+ if task_acceptance is not None:
1368
+ group["_policy"]["taskAcceptance"] = task_acceptance
1369
+ if peer_wake is not None:
1370
+ group["_policy"]["peerWake"] = peer_wake
1371
+ if archived is not None:
1372
+ group["status"] = "archived" if archived else "active"
1373
+ group.update(revision=group["revision"] + 1, updatedAt=now())
1374
+ self.publish(tx, "group", group_id, group)
1375
+ tx.put(
1376
+ "group_revision",
1377
+ f"{group_id}:{group['revision']}",
1378
+ {**group, "members": tx.list("member", group_id)},
1379
+ )
1380
+ return self._snapshot(tx, group_id)
1381
+
1382
+ return self.mutate(actor, group_id, key, payload, update, owner=True)
1383
+
1384
+ def mark_read(self, actor: Actor, group_id: str, watermark: int) -> dict[str, int]:
1385
+ with self.store.transaction() as tx:
1386
+ self.authorize(tx, actor, group_id, owner=True)
1387
+ if watermark < 0 or watermark > tx.watermark(group_id):
1388
+ raise TeamsError("invalid_cursor", "已读水位无效", status=422)
1389
+ key = f"{group_id}:{actor.subject}"
1390
+ previous = tx.get("read_watermark", key, required=False)
1391
+ value = max(watermark, (previous or {}).get("watermark", 0))
1392
+ tx.put("read_watermark", key, {"groupId": group_id, "watermark": value})
1393
+ return {"watermark": value}
1394
+
1395
+ def execution(self, actor: Actor, group_id: str, run_id: str) -> dict[str, Any]:
1396
+ with self.store.transaction() as tx:
1397
+ self.authorize(tx, actor, group_id)
1398
+ if actor.kind == "member" and run_id != actor.team_run_id:
1399
+ raise TeamsError("forbidden", "不能读取其他轮次执行", status=403)
1400
+ snapshot = self._snapshot(tx, group_id)
1401
+ deliveries = tx.list("delivery", group_id, team_run_id=run_id)
1402
+ children = tx.list("child_invocation", group_id, team_run_id=run_id)
1403
+ members = {d["deliveryId"]: self.delivery_member(tx, d) for d in deliveries}
1404
+ watermark = tx.watermark(group_id)
1405
+ if not any(run["teamRunId"] == run_id for run in snapshot["teamRuns"]):
1406
+ raise TeamsError("not_found", "执行轮次不存在", status=404)
1407
+ nodes, edges = [], []
1408
+ for task in snapshot["tasks"]:
1409
+ if task["teamRunId"] != run_id:
1410
+ continue
1411
+ attempt = task["attempts"][-1] if task["attempts"] else None
1412
+ node = {
1413
+ "nodeId": task["taskId"],
1414
+ "kind": "task",
1415
+ "title": task["title"],
1416
+ "status": task["status"],
1417
+ "taskId": task["taskId"],
1418
+ "memberId": task["ownerMemberId"],
1419
+ "reason": task.get("reason"),
1420
+ }
1421
+ if attempt:
1422
+ node.update(attemptId=attempt["attemptId"], source=attempt.get("source"))
1423
+ nodes.append(node)
1424
+ edges.extend(
1425
+ {"source": dependency, "target": task["taskId"], "kind": "dependency"}
1426
+ for dependency in task["dependencies"]
1427
+ )
1428
+ run_nodes = {}
1429
+ for delivery in deliveries:
1430
+ if not delivery.get("runId"):
1431
+ continue
1432
+ member = members[delivery["deliveryId"]]
1433
+ binding = member
1434
+ node_id = "run_" + digest([delivery["_sessionId"], delivery["runId"]])[7:]
1435
+ run_nodes[(delivery["_sessionId"], delivery["runId"])] = node_id
1436
+ node = {
1437
+ "nodeId": node_id,
1438
+ "kind": "run",
1439
+ "title": member["name"],
1440
+ "status": delivery.get("_terminalState") or delivery.get("_runStatus") or "queued",
1441
+ "reason": "execution_uncertain_fenced"
1442
+ if delivery.get("_fenced")
1443
+ else delivery.get("reason"),
1444
+ "memberId": member["memberId"],
1445
+ "source": {
1446
+ "authorityRef": self.authority_ref,
1447
+ "groupId": group_id,
1448
+ "memberId": member["memberId"],
1449
+ "bindingRef": binding["bindingRef"],
1450
+ "providerRef": binding["binding"]["providerRef"],
1451
+ "sessionId": binding["sessionId"],
1452
+ "runId": delivery["runId"],
1453
+ },
1454
+ }
1455
+ if delivery.get("_taskId"):
1456
+ node.update(
1457
+ taskId=delivery["_taskId"],
1458
+ attemptId=delivery["_attemptId"],
1459
+ parentNodeId=delivery["_taskId"],
1460
+ )
1461
+ edges.append(
1462
+ {"source": delivery["_taskId"], "target": node_id, "kind": "invocation"}
1463
+ )
1464
+ nodes.append(node)
1465
+ for child in children:
1466
+ run_nodes[(child["source"]["sessionId"], child["_nativeRunId"])] = child["nodeId"]
1467
+ for child in children:
1468
+ node = public(child)
1469
+ parent = run_nodes.get((child["source"]["sessionId"], child["_parentRunId"]))
1470
+ if parent:
1471
+ node["parentNodeId"] = parent
1472
+ edges.append({"source": parent, "target": child["nodeId"], "kind": "invocation"})
1473
+ nodes.append(node)
1474
+ return {
1475
+ "groupId": group_id,
1476
+ "teamRunId": run_id,
1477
+ "watermark": watermark,
1478
+ "nodes": nodes,
1479
+ "edges": edges,
1480
+ }