agentengine-sdk-python 0.8.3__py3-none-any.whl → 0.8.5__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 (819) hide show
  1. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/METADATA +13 -9
  2. agentengine_sdk_python-0.8.5.dist-info/RECORD +1296 -0
  3. ksadk/_build_provenance.json +1 -1
  4. ksadk/_process.py +83 -0
  5. ksadk/_str_enum.py +17 -0
  6. ksadk/a2ui/core.py +3 -3
  7. ksadk/api/client.py +111 -91
  8. ksadk/builders/code_builder.py +74 -21
  9. ksadk/builders/framework_requirements.py +22 -3
  10. ksadk/builders/ks3_uploader.py +36 -7
  11. ksadk/builders/managed_runtime_builder.py +1 -0
  12. ksadk/cli/__init__.py +68 -3
  13. ksadk/cli/cmd_config.py +4 -4
  14. ksadk/cli/cmd_create.py +12 -12
  15. ksadk/cli/cmd_hermes.py +24 -2
  16. ksadk/cli/cmd_invoke.py +28 -5
  17. ksadk/cli/cmd_managed_runtime.py +13 -1
  18. ksadk/cli/cmd_openclaw.py +26 -1
  19. ksadk/cli/cmd_plugin.py +76 -13
  20. ksadk/cli/cmd_studio.py +64 -16
  21. ksadk/cli/cmd_web.py +2 -5
  22. ksadk/cli/openclaw_env.py +1 -1
  23. ksadk/cli/resource_common.py +26 -0
  24. ksadk/cli/runtime_bootstrap.py +23 -1
  25. ksadk/codex/client.py +425 -96
  26. ksadk/codex/projection.py +24 -0
  27. ksadk/codex/runtime.py +56 -298
  28. ksadk/common/auth.py +16 -10
  29. ksadk/configs/__init__.py +1 -1
  30. ksadk/configs/env_registry.py +153 -31
  31. ksadk/configs/env_registry_studio.py +86 -0
  32. ksadk/configs/global_config.py +1 -1
  33. ksadk/configs/settings.py +3 -3
  34. ksadk/connector/__init__.py +17 -0
  35. ksadk/connector/channel.py +477 -0
  36. ksadk/context_engine/capabilities.py +52 -4
  37. ksadk/conversations/attachment_storage.py +10 -3
  38. ksadk/conversations/attachments.py +16 -5
  39. ksadk/conversations/message_projection.py +133 -21
  40. ksadk/conversations/normalize.py +28 -10
  41. ksadk/conversations/projector.py +4 -6
  42. ksadk/conversations/runtime_baseline.py +37 -0
  43. ksadk/conversations/runtime_invocation.py +22 -4
  44. ksadk/conversations/runtime_observability.py +39 -10
  45. ksadk/conversations/runtime_payloads.py +9 -0
  46. ksadk/conversations/runtime_persistence.py +105 -9
  47. ksadk/conversations/runtime_preparation.py +42 -33
  48. ksadk/conversations/runtime_resume.py +50 -2
  49. ksadk/conversations/runtime_stream_events.py +34 -35
  50. ksadk/conversations/runtime_streaming.py +33 -7
  51. ksadk/deployment/env_forward.py +2 -2
  52. ksadk/deployment/providers/serverless.py +1 -1
  53. ksadk/events/adapters/_codex_items.py +16 -8
  54. ksadk/events/adapters/_codex_validators.py +18 -7
  55. ksadk/events/adapters/_langgraph_support.py +34 -0
  56. ksadk/events/adapters/langgraph.py +15 -1
  57. ksadk/events/canonical_store.py +3 -1
  58. ksadk/events/projections.py +1 -1
  59. ksadk/events/session_event.py +2 -2
  60. ksadk/harness/__init__.py +14 -0
  61. ksadk/harness/app.py +11 -0
  62. ksadk/harness/artifact_store.py +213 -0
  63. ksadk/harness/capabilities.py +115 -0
  64. ksadk/harness/capability_runtime.py +237 -0
  65. ksadk/harness/closure_contract.py +92 -0
  66. ksadk/harness/compaction_record.py +122 -0
  67. ksadk/harness/compiler.py +284 -0
  68. ksadk/harness/config.py +2 -2
  69. ksadk/harness/conformance/__init__.py +33 -0
  70. ksadk/harness/conformance/contract.py +506 -0
  71. ksadk/harness/conformance/fixtures.py +102 -0
  72. ksadk/harness/context_engine.py +403 -0
  73. ksadk/harness/context_maintenance.py +259 -0
  74. ksadk/harness/context_manifest.py +188 -0
  75. ksadk/harness/context_tuning.py +168 -0
  76. ksadk/harness/draft_runtime.py +322 -0
  77. ksadk/harness/engine/__init__.py +40 -0
  78. ksadk/harness/engine/base.py +122 -0
  79. ksadk/harness/engine/budgets.py +108 -0
  80. ksadk/harness/engine/capability_declarations.py +59 -0
  81. ksadk/harness/engine/completion_guard.py +42 -0
  82. ksadk/harness/engine/context_pipeline.py +579 -0
  83. ksadk/harness/engine/graph_builder.py +859 -0
  84. ksadk/harness/engine/langgraph.py +931 -0
  85. ksadk/harness/engine/mcp_disclosure.py +750 -0
  86. ksadk/harness/engine/policy_runtime.py +70 -0
  87. ksadk/harness/engine/postgres_checkpointer.py +63 -0
  88. ksadk/harness/engine/run_control_bridge.py +80 -0
  89. ksadk/harness/engine/run_types.py +88 -0
  90. ksadk/harness/engine/skill_disclosure.py +189 -0
  91. ksadk/harness/engine/spans.py +41 -0
  92. ksadk/harness/engine/subagents.py +343 -0
  93. ksadk/harness/engine/thread_ids.py +112 -0
  94. ksadk/harness/engine/tool_dispatch.py +144 -0
  95. ksadk/harness/event_tree.py +212 -0
  96. ksadk/harness/events.py +461 -0
  97. ksadk/harness/execution_policy.py +94 -0
  98. ksadk/harness/insights.py +210 -0
  99. ksadk/harness/lifecycle.py +578 -0
  100. ksadk/harness/lifecycle_conformance.py +233 -0
  101. ksadk/harness/lifecycle_local_plane.py +104 -0
  102. ksadk/harness/loop/__init__.py +44 -0
  103. ksadk/harness/loop/reason.py +454 -0
  104. ksadk/harness/loop/tools.py +762 -0
  105. ksadk/harness/managed_runtime.py +884 -0
  106. ksadk/harness/mcp_matrix.py +474 -0
  107. ksadk/harness/mcp_runtime.py +471 -0
  108. ksadk/harness/memory_consolidation.py +157 -0
  109. ksadk/harness/memory_loop.py +156 -0
  110. ksadk/harness/memory_runtime.py +541 -0
  111. ksadk/harness/metrics.py +90 -0
  112. ksadk/harness/model_capability.py +253 -0
  113. ksadk/harness/model_provider.py +220 -0
  114. ksadk/harness/observability/__init__.py +29 -0
  115. ksadk/harness/observability/inspection.py +528 -0
  116. ksadk/harness/observability/metrics.py +167 -0
  117. ksadk/harness/observability/otel_exporter.py +218 -0
  118. ksadk/harness/prompt_cache.py +70 -0
  119. ksadk/harness/public_activity.py +154 -0
  120. ksadk/harness/readiness.py +249 -0
  121. ksadk/harness/reasoner.py +466 -13
  122. ksadk/harness/release_readiness.py +140 -0
  123. ksadk/harness/resource_ref.py +69 -0
  124. ksadk/harness/run_control.py +668 -0
  125. ksadk/harness/runtime.py +171 -136
  126. ksadk/harness/runtime_capabilities.py +158 -0
  127. ksadk/harness/runtime_server.py +514 -0
  128. ksadk/harness/sandbox_adapters.py +739 -0
  129. ksadk/harness/sandbox_backend.py +530 -0
  130. ksadk/harness/sandbox_conformance.py +288 -0
  131. ksadk/harness/sandbox_lease.py +77 -0
  132. ksadk/harness/sandbox_lease_conformance.py +259 -0
  133. ksadk/harness/sandbox_matrix.py +170 -0
  134. ksadk/harness/sandbox_reconciliation.py +140 -0
  135. ksadk/harness/sandbox_recovery.py +586 -0
  136. ksadk/harness/sandbox_recovery_conformance.py +246 -0
  137. ksadk/harness/session_store.py +243 -0
  138. ksadk/harness/skill_composition.py +212 -0
  139. ksadk/harness/skill_feedback.py +123 -0
  140. ksadk/harness/skill_matrix.py +233 -0
  141. ksadk/harness/skill_runtime.py +259 -0
  142. ksadk/harness/spec.py +332 -0
  143. ksadk/harness/state.py +153 -0
  144. ksadk/harness/strategies.py +149 -0
  145. ksadk/harness/subagent.py +253 -0
  146. ksadk/harness/tool_policy.py +131 -0
  147. ksadk/harness/tool_receipts.py +96 -0
  148. ksadk/harness/tool_reliability.py +81 -0
  149. ksadk/harness/tools.py +38 -13
  150. ksadk/harness/user_errors.py +69 -0
  151. ksadk/harness/working_context.py +81 -0
  152. ksadk/harness/working_context_patch.py +99 -0
  153. ksadk/identity/resolver.py +18 -0
  154. ksadk/interaction/__init__.py +1 -1
  155. ksadk/interaction/ledger.py +1 -1
  156. ksadk/interaction/provider.py +2 -1
  157. ksadk/interaction/providers/__init__.py +3 -1
  158. ksadk/interaction/providers/adk.py +1 -1
  159. ksadk/interaction/providers/codex.py +1 -1
  160. ksadk/interaction/providers/harness.py +50 -0
  161. ksadk/interaction/providers/langgraph.py +2 -1
  162. ksadk/kernel/__init__.py +10 -0
  163. ksadk/kernel/approval_presentation.py +91 -0
  164. ksadk/kernel/authorization.py +1 -1
  165. ksadk/kernel/bootstrap.py +114 -106
  166. ksadk/kernel/contract_fingerprints.py +1 -1
  167. ksadk/kernel/contracts.py +5 -0
  168. ksadk/kernel/control.py +32 -1
  169. ksadk/kernel/execution_grants.py +221 -0
  170. ksadk/kernel/execution_grants_memory.py +133 -0
  171. ksadk/kernel/execution_grants_postgres.py +217 -0
  172. ksadk/kernel/execution_grants_sqlite.py +209 -0
  173. ksadk/kernel/ingress.py +42 -29
  174. ksadk/kernel/mapping.py +1 -1
  175. ksadk/kernel/memory_store.py +24 -11
  176. ksadk/kernel/postgres_store.py +63 -33
  177. ksadk/kernel/recovery.py +78 -14
  178. ksadk/kernel/sql/001_agent_kernel.sql +23 -0
  179. ksadk/kernel/sqlite_store.py +331 -25
  180. ksadk/kernel/state.py +2 -3
  181. ksadk/kernel/store.py +72 -2
  182. ksadk/kernel/worker.py +144 -51
  183. ksadk/kernel/worker_history.py +72 -0
  184. ksadk/kernel/worker_identity.py +47 -0
  185. ksadk/knowledge_base/client.py +57 -27
  186. ksadk/mcp_runtime/__init__.py +12 -4
  187. ksadk/memory/adk/backends/sdk_ltm_backend.py +161 -41
  188. ksadk/memory/adk/resilient_session_service.py +25 -17
  189. ksadk/memory/adk/short_term_memory.py +26 -9
  190. ksadk/memory/coordinator.py +22 -6
  191. ksadk/memory/extraction.py +40 -1
  192. ksadk/memory/models.py +84 -5
  193. ksadk/memory/provider_resolver.py +8 -0
  194. ksadk/memory/providers/local_postgres.py +200 -0
  195. ksadk/memory/providers/local_sqlite.py +42 -3
  196. ksadk/memory/retrieval.py +189 -0
  197. ksadk/memory/store_adapter.py +150 -0
  198. ksadk/model_policy.py +2 -2
  199. ksadk/model_proxy/detect.py +254 -0
  200. ksadk/model_proxy/server.py +14 -7
  201. ksadk/model_proxy/transform.py +40 -2
  202. ksadk/plugins/__init__.py +5 -1
  203. ksadk/plugins/artifacts.py +275 -0
  204. ksadk/plugins/bridges/__init__.py +4 -2
  205. ksadk/plugins/bridges/codex.py +120 -13
  206. ksadk/plugins/bridges/dsh.py +351 -156
  207. ksadk/plugins/builtins.py +72 -35
  208. ksadk/plugins/bundle_security.py +28 -4
  209. ksadk/plugins/codex_manifest.py +983 -0
  210. ksadk/plugins/companion_artifacts.py +83 -0
  211. ksadk/plugins/companions.py +368 -0
  212. ksadk/plugins/composition.py +8 -0
  213. ksadk/plugins/contracts.py +119 -1
  214. ksadk/plugins/delivery.py +153 -0
  215. ksadk/plugins/dsh_channels.py +156 -0
  216. ksadk/plugins/dsh_home.py +140 -0
  217. ksadk/plugins/dsh_installation_digest.py +71 -0
  218. ksadk/plugins/dsh_teams.py +105 -0
  219. ksadk/plugins/dsh_toolchain.py +203 -32
  220. ksadk/plugins/ecosystem_probe.py +6 -6
  221. ksadk/plugins/execution_host.py +99 -0
  222. ksadk/plugins/host.py +102 -39
  223. ksadk/plugins/kernel_adapter.py +205 -0
  224. ksadk/plugins/providers/__init__.py +23 -0
  225. ksadk/plugins/providers/bundles/dsh-channels-client/client.js +19 -0
  226. ksadk/plugins/providers/bundles/dsh-channels-client/cordis.patch.yml +3 -0
  227. ksadk/plugins/providers/bundles/dsh-channels-client/index.mjs +7 -0
  228. ksadk/plugins/providers/bundles/dsh-channels-client/package.json +12 -0
  229. ksadk/plugins/providers/bundles/dsh-knowledge/cordis.patch.yml +3 -0
  230. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +53 -0
  231. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +16 -0
  232. ksadk/plugins/providers/bundles/dsh-memory/cordis.patch.yml +3 -0
  233. ksadk/plugins/providers/bundles/dsh-memory/index.mjs +175 -0
  234. ksadk/plugins/providers/bundles/dsh-memory/package.json +16 -0
  235. ksadk/plugins/providers/bundles/dsh-platform-resources/client.mjs +166 -0
  236. ksadk/plugins/providers/bundles/dsh-platform-resources/cordis.patch.yml +3 -0
  237. ksadk/plugins/providers/bundles/dsh-platform-resources/index.mjs +9 -0
  238. ksadk/plugins/providers/bundles/dsh-platform-resources/package.json +12 -0
  239. ksadk/plugins/providers/bundles/dsh-skill-center/cordis.patch.yml +3 -0
  240. ksadk/plugins/providers/bundles/dsh-skill-center/index.mjs +125 -0
  241. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +16 -0
  242. ksadk/plugins/providers/bundles/dsh-teams-client/client.js +29 -0
  243. ksadk/plugins/providers/bundles/dsh-teams-client/cordis.patch.yml +3 -0
  244. ksadk/plugins/providers/bundles/dsh-teams-client/index.mjs +11 -0
  245. ksadk/plugins/providers/bundles/dsh-teams-client/package.json +35 -0
  246. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/cordis.patch.yml +3 -0
  247. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/index.mjs +13 -0
  248. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/package.json +27 -0
  249. ksadk/plugins/providers/bundles/dsh-teams-profile/cordis.patch.yml +3 -0
  250. ksadk/plugins/providers/bundles/dsh-teams-profile/index.mjs +12 -0
  251. ksadk/plugins/providers/bundles/dsh-teams-profile/package.json +26 -0
  252. ksadk/plugins/providers/bundles/dsh-teams-router/cordis.patch.yml +3 -0
  253. ksadk/plugins/providers/bundles/dsh-teams-router/index.mjs +16 -0
  254. ksadk/plugins/providers/bundles/dsh-teams-router/package.json +27 -0
  255. ksadk/plugins/providers/bundles/dsh-teams-tasks/cordis.patch.yml +3 -0
  256. ksadk/plugins/providers/bundles/dsh-teams-tasks/index.mjs +16 -0
  257. ksadk/plugins/providers/bundles/dsh-teams-tasks/package.json +27 -0
  258. ksadk/plugins/providers/bundles/dsh-teams-tools/cordis.patch.yml +3 -0
  259. ksadk/plugins/providers/bundles/dsh-teams-tools/index.mjs +25 -0
  260. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +29 -0
  261. ksadk/plugins/providers/bundles/dsh-teams-tools/tools.json +235 -0
  262. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +1 -1
  263. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/cordis.patch.yml +3 -0
  264. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +920 -0
  265. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +27 -0
  266. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/client.mjs +133 -0
  267. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/index.mjs +14 -0
  268. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +115 -0
  269. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +19 -0
  270. ksadk/plugins/providers/bundles/ksadk-dsh-studio/package.json +7 -0
  271. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +1 -1
  272. ksadk/plugins/providers/codex.py +344 -70
  273. ksadk/plugins/providers/codex_native.py +368 -0
  274. ksadk/plugins/providers/codex_turn.py +301 -0
  275. ksadk/plugins/providers/dsh_capabilities.py +1450 -0
  276. ksadk/plugins/providers/dsh_mcp.py +467 -0
  277. ksadk/plugins/providers/harness.py +294 -141
  278. ksadk/plugins/providers/harness_delegation.py +593 -0
  279. ksadk/plugins/providers/harness_managed.py +456 -0
  280. ksadk/plugins/providers/harness_tools.py +326 -0
  281. ksadk/plugins/providers/mcp_projection.py +150 -0
  282. ksadk/plugins/providers/platform_resources.py +657 -0
  283. ksadk/plugins/providers/shipped_dsh.py +4 -1
  284. ksadk/plugins/resolver.py +8 -1
  285. ksadk/plugins/subagent_providers/codex.py +28 -6
  286. ksadk/plugins/teams/__init__.py +5 -0
  287. ksadk/plugins/teams/api.py +405 -0
  288. ksadk/plugins/teams/application.py +680 -0
  289. ksadk/plugins/teams/artifacts.py +60 -0
  290. ksadk/plugins/teams/context.py +96 -0
  291. ksadk/plugins/teams/contracts.py +136 -0
  292. ksadk/plugins/teams/domain.py +1427 -0
  293. ksadk/plugins/teams/domain_values.py +24 -0
  294. ksadk/plugins/teams/errors.py +13 -0
  295. ksadk/plugins/teams/migration.py +311 -0
  296. ksadk/plugins/teams/migration_cli.py +322 -0
  297. ksadk/plugins/teams/postgres_store.py +138 -0
  298. ksadk/plugins/teams/runtime.py +777 -0
  299. ksadk/plugins/teams/source_projection.py +84 -0
  300. ksadk/plugins/teams/store.py +311 -0
  301. ksadk/plugins/teams/task_decisions.py +423 -0
  302. ksadk/plugins/teams/transport.py +91 -0
  303. ksadk/plugins/teams/workspaces.py +255 -0
  304. ksadk/resource_runtime/__init__.py +4 -0
  305. ksadk/resource_runtime/broker.py +616 -0
  306. ksadk/resource_runtime/build_artifacts.py +165 -0
  307. ksadk/resource_runtime/contracts.py +138 -0
  308. ksadk/resource_runtime/discovery_receipts.py +100 -0
  309. ksadk/resource_runtime/discovery_skills.py +172 -0
  310. ksadk/resource_runtime/errors.py +6 -0
  311. ksadk/resource_runtime/ipc.py +142 -0
  312. ksadk/resource_runtime/kernel_approval.py +165 -0
  313. ksadk/resource_runtime/knowledge.py +114 -0
  314. ksadk/resource_runtime/langgraph.py +94 -0
  315. ksadk/resource_runtime/leases.py +191 -0
  316. ksadk/resource_runtime/managed_projection.py +186 -0
  317. ksadk/resource_runtime/mcp_server.py +138 -0
  318. ksadk/resource_runtime/memory_provider.py +318 -0
  319. ksadk/resource_runtime/memory_receipts.py +34 -0
  320. ksadk/resource_runtime/operation_ledger.py +211 -0
  321. ksadk/resource_runtime/plugin_config.py +48 -0
  322. ksadk/resource_runtime/policy_authorization.py +54 -0
  323. ksadk/resource_runtime/process.py +110 -0
  324. ksadk/resource_runtime/skill_artifacts.py +153 -0
  325. ksadk/resource_runtime/skill_runtime.py +42 -0
  326. ksadk/resource_runtime/skill_workspace.py +118 -0
  327. ksadk/resource_runtime/skills.py +215 -0
  328. ksadk/resource_runtime/snapshots.py +180 -0
  329. ksadk/resource_runtime/socket_server.py +103 -0
  330. ksadk/resource_runtime/supervisor.py +380 -0
  331. ksadk/resource_runtime/worker.py +504 -0
  332. ksadk/runners/_langgraph_runner_streams.py +182 -38
  333. ksadk/runners/_langgraph_state_reader.py +106 -0
  334. ksadk/runners/_session_identity.py +285 -0
  335. ksadk/runners/adk_runner.py +166 -63
  336. ksadk/runners/base_runner.py +29 -1
  337. ksadk/runners/langgraph_runner.py +542 -195
  338. ksadk/runners/patch_langchain.py +47 -0
  339. ksadk/runners/usage_accumulator.py +11 -3
  340. ksadk/runtime/_runner_adapter/stream_mapping.py +194 -20
  341. ksadk/runtime/adapter.py +2 -0
  342. ksadk/runtime/conversation_execution.py +117 -17
  343. ksadk/runtime/executor.py +87 -3
  344. ksadk/runtime/factory.py +65 -274
  345. ksadk/runtime/framework_adapters.py +23 -0
  346. ksadk/runtime/preprocessing.py +21 -5
  347. ksadk/runtime/runner_adapter.py +106 -18
  348. ksadk/runtime/skill_eval_result.py +36 -0
  349. ksadk/runtime/timing.py +46 -0
  350. ksadk/runtime/usage.py +49 -18
  351. ksadk/runtime_context.py +142 -2
  352. ksadk/sandbox/backends/e2b.py +288 -25
  353. ksadk/sandbox/backends/local_process.py +72 -39
  354. ksadk/sandbox/base.py +64 -1
  355. ksadk/sandbox/diagnostics.py +82 -0
  356. ksadk/sandbox/e2b_connection.py +66 -0
  357. ksadk/sandbox/local_controls.py +746 -0
  358. ksadk/sandbox/local_launcher.py +90 -0
  359. ksadk/scheduler/dispatcher.py +1 -1
  360. ksadk/scheduler/sqlite_store.py +18 -0
  361. ksadk/server/composition.py +2 -0
  362. ksadk/server/factory.py +5 -0
  363. ksadk/server/invocation_identity.py +118 -0
  364. ksadk/server/persistence_capability.py +516 -0
  365. ksadk/server/routes/common.py +32 -3
  366. ksadk/server/routes/control.py +271 -52
  367. ksadk/server/routes/dependencies.py +16 -0
  368. ksadk/server/routes/kernel_ingress.py +9 -1
  369. ksadk/server/routes/misc.py +233 -25
  370. ksadk/server/routes/models.py +47 -4
  371. ksadk/server/routes/openai_compat.py +76 -13
  372. ksadk/server/routes/projection.py +252 -12
  373. ksadk/server/routes/run.py +106 -35
  374. ksadk/server/routes/sessions.py +491 -138
  375. ksadk/server/routes/streaming.py +43 -9
  376. ksadk/server/routes/workspace.py +130 -21
  377. ksadk/server/static/assets/{ArtifactsPanel-10GPXIJ6.js → ArtifactsPanel-C1YoaKhx.js} +1 -1
  378. ksadk/server/static/assets/{CodeBlock-BXk1l-G1.js → CodeBlock-DHuAWfr5.js} +10 -7
  379. ksadk/server/static/assets/MathMessageMarkdown-cvdrBwYr.js +8 -0
  380. ksadk/server/static/assets/{MermaidBlock--OEYoXIJ.js → MermaidBlock-DeBkbJvI.js} +9 -9
  381. ksadk/server/static/assets/{NativeTerminalPanel-DrEe1syq.js → NativeTerminalPanel-oJj44_sV.js} +1 -1
  382. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-eeTFJLvo.js → abnfDiagram-VCTEODGH-Dhfv25o2.js} +1 -1
  383. ksadk/server/static/assets/{arc-S3ZNbIAd.js → arc-C35w-pn1.js} +1 -1
  384. ksadk/server/static/assets/architecture-7GRP2DOG-BCsa26zi.js +1 -0
  385. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-CRjgEJDX.js → architectureDiagram-5GKGNRK7-FoMY_u6D.js} +1 -1
  386. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-C7bsBoNH.js → blockDiagram-NRAW4CY4-zD4Rt7oE.js} +1 -1
  387. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BX3c33Ob.js → c4Diagram-UCG6FXSJ-BCtGGkhN.js} +1 -1
  388. ksadk/server/static/assets/channel-_KDifNys.js +1 -0
  389. ksadk/server/static/assets/chunk-2Q5K7J3B-HdVkJ9F0.js +1 -0
  390. ksadk/server/static/assets/{chunk-5VM5RSS4-bZ7ws-8m.js → chunk-5VM5RSS4-C2Ms13_k.js} +1 -1
  391. ksadk/server/static/assets/{chunk-F27PBJKO-D2r0pvhY.js → chunk-F27PBJKO-BoTj-qgx.js} +1 -1
  392. ksadk/server/static/assets/{chunk-G27WJ6UU-CZwF3oUP.js → chunk-G27WJ6UU-DOMyyjHH.js} +1 -1
  393. ksadk/server/static/assets/{chunk-JWPE2WC7-DigFYCML.js → chunk-JWPE2WC7-DbJJqDli.js} +1 -1
  394. ksadk/server/static/assets/{chunk-LCL6LL3I-CnorGV5q.js → chunk-LCL6LL3I-CLuRCt_W.js} +1 -1
  395. ksadk/server/static/assets/{chunk-POPQ4Y6H-CexntQA-.js → chunk-POPQ4Y6H-D0Dz847e.js} +1 -1
  396. ksadk/server/static/assets/{chunk-RHFEMEQ7-CHTC7UxA.js → chunk-RHFEMEQ7-BWSRzEcd.js} +1 -1
  397. ksadk/server/static/assets/{chunk-SVP7TREG-BC1EWt_-.js → chunk-SVP7TREG-CPoHqkCY.js} +1 -1
  398. ksadk/server/static/assets/{chunk-XXDRQBXY-BTG24xN0.js → chunk-XXDRQBXY-Bx1jS-X-.js} +1 -1
  399. ksadk/server/static/assets/classDiagram-DTDB5LWJ-BVCW3ZqZ.js +1 -0
  400. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-BVCW3ZqZ.js +1 -0
  401. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-CkonRdAS.js → cose-bilkent-JH36ORCC-LzyWm4m0.js} +1 -1
  402. ksadk/server/static/assets/cynefin-OW5HDTMX-CNXjFctL.js +1 -0
  403. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-DEOCBe15.js → cynefinDiagram-5FMLGOSQ-BlW_bHED.js} +1 -1
  404. ksadk/server/static/assets/{dagre-3AP2YEHR-DBThPuLa.js → dagre-3AP2YEHR-Bu_S86_i.js} +1 -1
  405. ksadk/server/static/assets/{dagre-ClTPrTht.js → dagre-B7nCawed.js} +1 -1
  406. ksadk/server/static/assets/{diagram-S7CK7UJ4-DsZHrnpJ.js → diagram-S7CK7UJ4-W_Zow2Km.js} +1 -1
  407. ksadk/server/static/assets/{diagram-UQ7AKVKN-BJR4nhVr.js → diagram-UQ7AKVKN-CLIKAHON.js} +1 -1
  408. ksadk/server/static/assets/{diagram-VSXAHHWV-xzcERX0a.js → diagram-VSXAHHWV-Dv6_QAlN.js} +1 -1
  409. ksadk/server/static/assets/{diagram-VX7I27RA-tn2xM1xu.js → diagram-VX7I27RA-BWAWRDtZ.js} +1 -1
  410. ksadk/server/static/assets/{diagram-Z3DM3KII-BZPGBkw5.js → diagram-Z3DM3KII-XA_rWMss.js} +1 -1
  411. ksadk/server/static/assets/dist-0X_j2Rcc.js +1 -0
  412. ksadk/server/static/assets/{dist-4zN1_tq5.js → dist-1nXCdsej.js} +1 -1
  413. ksadk/server/static/assets/{dist-M67Hwu0n.js → dist-2vL2sAdF.js} +1 -1
  414. ksadk/server/static/assets/{dist-BJLUwH6W.js → dist-B3bA05-e.js} +1 -1
  415. ksadk/server/static/assets/{dist-8VWI-2bZ.js → dist-BLpRy_Yx.js} +1 -1
  416. ksadk/server/static/assets/{dist-D1V3f1B4.js → dist-BO_UwatH.js} +1 -1
  417. ksadk/server/static/assets/{dist-Cq4OL6nO.js → dist-BdNFAney.js} +1 -1
  418. ksadk/server/static/assets/{dist-DfGFrb0v.js → dist-C0J5_3qM.js} +1 -1
  419. ksadk/server/static/assets/{dist-DyqV4fL4.js → dist-CGt_UGeO.js} +1 -1
  420. ksadk/server/static/assets/{dist-DjhwGUgZ.js → dist-CIRMvUM4.js} +1 -1
  421. ksadk/server/static/assets/{dist-B1oWRmrH.js → dist-CIpWk_5f.js} +1 -1
  422. ksadk/server/static/assets/{dist-CXpH_Rdd.js → dist-CPyieXEf.js} +1 -1
  423. ksadk/server/static/assets/{dist-Btyo4vX4.js → dist-D-92S-Fd.js} +1 -1
  424. ksadk/server/static/assets/{dist-u8tVH5Ak.js → dist-DNKuMzWc.js} +1 -1
  425. ksadk/server/static/assets/{dist-DQAB0qn_.js → dist-DWfdmz9s.js} +2 -2
  426. ksadk/server/static/assets/{dist-B-46q3Hk.js → dist-DppE_r-D.js} +1 -1
  427. ksadk/server/static/assets/{dist-C71CsujO.js → dist-DyG6Ya-z.js} +1 -1
  428. ksadk/server/static/assets/{dist-DJmCPRVB.js → dist-M-SrdhhZ.js} +1 -1
  429. ksadk/server/static/assets/{dist-Bbwqa8TG.js → dist-mqD5TZup.js} +1 -1
  430. ksadk/server/static/assets/{dist-BI1qQH4n.js → dist-n3n6t_FO.js} +1 -1
  431. ksadk/server/static/assets/{dist-DUwKa_l6.js → dist-qe8xjesy.js} +1 -1
  432. ksadk/server/static/assets/{dist-B0gdk4rl.js → dist-t6MzE0jU.js} +1 -1
  433. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-DVfMsLge.js → ebnfDiagram-PWID7BFC-BfCzF1Xi.js} +1 -1
  434. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CWEZSYaw.js → erDiagram-SSCWMZ5O-Dpz9_0zn.js} +1 -1
  435. ksadk/server/static/assets/eventmodeling-NTZA5JFV-B5-8RH9c.js +1 -0
  436. ksadk/server/static/assets/flowDiagram-A5DVABFB-BppFxEKw.js +1 -0
  437. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-TWIxoyYL.js → ganttDiagram-EL5Y4UJY-DDaG1f4_.js} +1 -1
  438. ksadk/server/static/assets/gitGraph-4MIJSDKK-B-AhYj4C.js +1 -0
  439. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DDh2hd2S.js → gitGraphDiagram-WWUBYQGX-DcxzRwYC.js} +1 -1
  440. ksadk/server/static/assets/index-BMd2mucF.css +2 -0
  441. ksadk/server/static/assets/index-D5qyyhTH.js +244 -0
  442. ksadk/server/static/assets/info-A6RAGUB7-0uiKrC35.js +1 -0
  443. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CgoyWiDR.js → infoDiagram-RXCK75RN-CYMdn6lQ.js} +1 -1
  444. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CyRIu_om.js → ishikawaDiagram-5VMMS53U-CLHFAD6c.js} +1 -1
  445. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DN5JXHzN.js → journeyDiagram-EYS64GPL-BHSKQGAl.js} +1 -1
  446. ksadk/server/static/assets/{kanban-definition-3QL26DDD-CNP3ui66.js → kanban-definition-3QL26DDD-D5W3tjTT.js} +1 -1
  447. ksadk/server/static/assets/{katex-DWEzQy1d.js → katex-mtjOi4KM.js} +1 -1
  448. ksadk/server/static/assets/{linear-C-qHp7d2.js → linear-BETqsxE_.js} +1 -1
  449. ksadk/server/static/assets/{mermaid-parser.core-Cl-K943T.js → mermaid-parser.core-DPWrvs90.js} +2 -2
  450. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-D5DB5mYm.js → mindmap-definition-FBJOCRG2-CJG2mfBP.js} +1 -1
  451. ksadk/server/static/assets/packet-AYTQ26CC-BVTmZ_cw.js +1 -0
  452. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-BQVc9ia_.js → pegDiagram-XKGWAZYB-GjAPNaqn.js} +1 -1
  453. ksadk/server/static/assets/pie-WAS4IAKB-DyfxBU7V.js +1 -0
  454. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-B6UCAvtY.js → pieDiagram-E7YTZNPT-ToIewrqr.js} +1 -1
  455. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-mIr2d3eb.js → quadrantDiagram-AXDQQJYC-4d78KiEY.js} +1 -1
  456. ksadk/server/static/assets/radar-RG4KPBEZ-FFontjL2.js +1 -0
  457. ksadk/server/static/assets/railroad-74A4TZTK-D0Uidzen.js +1 -0
  458. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BOo_9T2h.js +1 -0
  459. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-D6-BjW7Z.js +1 -0
  460. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CXx__yMm.js +1 -0
  461. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-Dt3FFDmK.js → railroadDiagram-O6MQD6OU-DKzx4xfv.js} +1 -1
  462. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-Cz_vQtgF.js → requirementDiagram-EFPCY7ZU-CJYljxQS.js} +1 -1
  463. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-wlO1TsH5.js → sankeyDiagram-P5KCCOFB-DLU2fV1w.js} +1 -1
  464. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CHRbElYq.js → sequenceDiagram-WJ2MYXX4-CVqysrA9.js} +1 -1
  465. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DXX54iyO.js → sizeCapture-X5ZJPWSS-BUxfmTHc.js} +1 -1
  466. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-Dp_lw9II.js → stateDiagram-HBIQ2CUA-CNFgYI9E.js} +1 -1
  467. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BXAFScz8.js +1 -0
  468. ksadk/server/static/assets/{swimlanes-XN3QIQJK-D8O5UlLG.js → swimlanes-XN3QIQJK-B6qCMe8N.js} +1 -1
  469. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uIQ2lJKH.js +8 -0
  470. ksadk/server/static/assets/{timeline-definition-24CTP7MA-8mfKcxvG.js → timeline-definition-24CTP7MA-CMD3x_U_.js} +1 -1
  471. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5GgucZ.js +1 -0
  472. ksadk/server/static/assets/treemap-WGGIJYW6-Bq1u1SpG.js +1 -0
  473. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-EnNl0DE7.js → vennDiagram-4TSXK5OY-BqtUqvXM.js} +1 -1
  474. ksadk/server/static/assets/wardley-WFR3VGLG-QAt06uEz.js +1 -0
  475. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DBu5fbYr.js → wardleyDiagram-VM6X3IG4-B5KfDjI-.js} +1 -1
  476. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BSVXs4IY.js → xychartDiagram-S5SC5T6Z-BaUlSZrn.js} +1 -1
  477. ksadk/server/static/index.html +2 -2
  478. ksadk/server/terminal_sessions.py +34 -2
  479. ksadk/session_context.py +66 -0
  480. ksadk/sessions/__init__.py +11 -21
  481. ksadk/sessions/_local_service_sync.py +263 -1
  482. ksadk/sessions/base.py +176 -0
  483. ksadk/sessions/errors.py +4 -0
  484. ksadk/sessions/in_memory.py +309 -19
  485. ksadk/sessions/invocation_identity.py +235 -0
  486. ksadk/sessions/local_service.py +83 -1
  487. ksadk/sessions/persistence.py +275 -0
  488. ksadk/sessions/postgres_service.py +358 -0
  489. ksadk/sessions/resilience.py +8 -0
  490. ksadk/sessions/resilient.py +362 -4
  491. ksadk/sessions/topology.py +135 -0
  492. ksadk/skills/__init__.py +26 -0
  493. ksadk/skills/events.py +464 -0
  494. ksadk/skills/manifest_cache.py +263 -0
  495. ksadk/skills/mcp_server/__init__.py +0 -0
  496. ksadk/skills/mcp_server/_registry.py +33 -0
  497. ksadk/skills/mcp_server/_routing.py +26 -0
  498. ksadk/skills/mcp_server/_workspace_files.py +160 -0
  499. ksadk/skills/mcp_server/register.py +415 -0
  500. ksadk/skills/mcp_server/server.py +218 -0
  501. ksadk/skills/models.py +37 -4
  502. ksadk/skills/observability.py +132 -0
  503. ksadk/skills/package_store.py +261 -40
  504. ksadk/skills/runtime/agent.py +67 -9
  505. ksadk/skills/runtime/artifact_delivery.py +139 -0
  506. ksadk/skills/runtime/artifacts.py +87 -0
  507. ksadk/skills/runtime/backends/e2b.py +460 -27
  508. ksadk/skills/runtime/backends/local.py +629 -62
  509. ksadk/skills/runtime/base.py +81 -7
  510. ksadk/skills/runtime/executor.py +268 -1
  511. ksadk/skills/runtime/loader.py +118 -5
  512. ksadk/skills/runtime/pinned.py +114 -0
  513. ksadk/skills/runtime/request.py +49 -0
  514. ksadk/skills/service_client.py +167 -28
  515. ksadk/skills/tool_defs.py +108 -3
  516. ksadk/studio/api.py +810 -93
  517. ksadk/studio/api_catalog_routes.py +18 -0
  518. ksadk/studio/api_contracts.py +8 -2
  519. ksadk/studio/api_plugin_routes.py +562 -104
  520. ksadk/studio/api_resource_connections.py +221 -0
  521. ksadk/studio/authoring.py +12 -6
  522. ksadk/studio/authoring_coordinator.py +23 -16
  523. ksadk/studio/builder.py +88 -0
  524. ksadk/studio/capabilities.py +23 -6
  525. ksadk/studio/channel_connections.py +333 -0
  526. ksadk/studio/cloud.py +370 -112
  527. ksadk/studio/cloud_shared_web.py +638 -0
  528. ksadk/studio/codex_agent_service.py +130 -28
  529. ksadk/studio/codex_builder.py +242 -3
  530. ksadk/studio/codex_credentials.py +90 -0
  531. ksadk/studio/codex_manifest.py +31 -4
  532. ksadk/studio/codex_plugin_store.py +746 -0
  533. ksadk/studio/codex_provider_build.py +231 -0
  534. ksadk/studio/codex_run.py +190 -26
  535. ksadk/studio/compatibility_report.py +12 -1
  536. ksadk/studio/compiler.py +88 -14
  537. ksadk/studio/configuration.py +182 -0
  538. ksadk/studio/contracts.py +165 -11
  539. ksadk/studio/dsh_application.py +247 -0
  540. ksadk/studio/dsh_capability_service.py +1374 -0
  541. ksadk/studio/dsh_lifecycle.py +58 -0
  542. ksadk/studio/dsh_models.py +59 -0
  543. ksadk/studio/dsh_provider_registration.py +367 -21
  544. ksadk/studio/entry.py +53 -0
  545. ksadk/studio/event_store.py +36 -5
  546. ksadk/studio/execution_host.py +525 -0
  547. ksadk/studio/framework_run.py +32 -10
  548. ksadk/studio/hosted_kernel.py +89 -14
  549. ksadk/studio/kernel_registry.py +418 -0
  550. ksadk/studio/kernel_sqlite_migration.py +181 -0
  551. ksadk/studio/mcp_runtime.py +11 -3
  552. ksadk/studio/model_client.py +1180 -66
  553. ksadk/studio/model_profile_service.py +26 -11
  554. ksadk/studio/native_documents.py +172 -0
  555. ksadk/studio/plugin_composition.py +202 -24
  556. ksadk/studio/plugin_kernel_adapter.py +21 -106
  557. ksadk/studio/plugin_lifecycle.py +80 -0
  558. ksadk/studio/plugin_runtime.py +448 -56
  559. ksadk/studio/provider_recovery.py +59 -0
  560. ksadk/studio/recovery_page.py +70 -0
  561. ksadk/studio/resource_authority.py +664 -0
  562. ksadk/studio/resource_binding_validation.py +77 -0
  563. ksadk/studio/resource_build_admission.py +196 -0
  564. ksadk/studio/resource_build_materializer.py +149 -0
  565. ksadk/studio/resource_catalog.py +149 -2
  566. ksadk/studio/resource_connections.py +220 -0
  567. ksadk/studio/run_activity.py +895 -0
  568. ksadk/studio/run_documents.py +127 -0
  569. ksadk/studio/run_service.py +789 -83
  570. ksadk/studio/runtime_catalog.py +53 -10
  571. ksadk/studio/runtime_source.py +16 -8
  572. ksadk/studio/scheduler_assistant.py +317 -0
  573. ksadk/studio/scheduler_runtime.py +32 -280
  574. ksadk/studio/scheduler_service.py +3 -0
  575. ksadk/studio/service.py +861 -120
  576. ksadk/studio/shared_web.py +579 -82
  577. ksadk/studio/static/assets/ChannelsPage-D_PGmKVq.js +8 -0
  578. ksadk/studio/static/assets/CodeBlock-DMIf4h33-UIqo-BPW.js +44 -0
  579. ksadk/studio/static/assets/ExecutionTree-v3HexvPo-Bk8wzGSy.js +1 -0
  580. ksadk/studio/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  581. ksadk/studio/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  582. ksadk/studio/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  583. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  584. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  585. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  586. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  587. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  588. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  589. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  590. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  591. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  592. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  593. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  594. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  595. ksadk/studio/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  596. ksadk/studio/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  597. ksadk/studio/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  598. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  599. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  600. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  601. ksadk/studio/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  602. ksadk/studio/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  603. ksadk/studio/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  604. ksadk/studio/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  605. ksadk/studio/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  606. ksadk/studio/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  607. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  608. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  609. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  610. ksadk/studio/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  611. ksadk/studio/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  612. ksadk/studio/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  613. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  614. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  615. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  616. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  617. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  618. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  619. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  620. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  621. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  622. ksadk/studio/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  623. ksadk/studio/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  624. ksadk/studio/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  625. ksadk/studio/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  626. ksadk/studio/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  627. ksadk/studio/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  628. ksadk/studio/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  629. ksadk/studio/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  630. ksadk/studio/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  631. ksadk/studio/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  632. ksadk/studio/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  633. ksadk/studio/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  634. ksadk/studio/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  635. ksadk/studio/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  636. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  637. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  638. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  639. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-BEOyPC3w.css +1 -0
  640. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-OhNwH4K9.js +8 -0
  641. ksadk/studio/static/assets/MermaidBlock-H_0qzQDf-BdXtxug_.js +11 -0
  642. ksadk/studio/static/assets/MessageMarkdown-CwMTvgFj-g0I-I4dD.js +59 -0
  643. ksadk/studio/static/assets/PrismRenderer-5pK6tUdb.js +3 -0
  644. ksadk/studio/static/assets/TeamsPage-DqX4HWKQ.js +3 -0
  645. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-Bnb1O3tA.js +1 -0
  646. ksadk/studio/static/assets/arc-Pry-7G1_.js +1 -0
  647. ksadk/studio/static/assets/architecture-7GRP2DOG-BMOPAkUC.js +1 -0
  648. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-5Zn1gqJv.js +36 -0
  649. ksadk/studio/static/assets/array-BifhSqXX.js +1 -0
  650. ksadk/studio/static/assets/blockDiagram-I7D4REHJ-CLB4L11u.js +129 -0
  651. ksadk/studio/static/assets/c4Diagram-7LVT6UL2-BOma_Z_F.js +38 -0
  652. ksadk/studio/static/assets/channel-r8itPEik.js +1 -0
  653. ksadk/studio/static/assets/chunk-2E4U76K2-BFf_huql.js +2 -0
  654. ksadk/studio/static/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  655. ksadk/studio/static/assets/chunk-2ZTRR5NV-C2qZJila.js +2 -0
  656. ksadk/studio/static/assets/chunk-3Z5EZCMW-DMniOlPd.js +1 -0
  657. ksadk/studio/static/assets/chunk-4HAMMTFA-DVtDP4rm.js +62 -0
  658. ksadk/studio/static/assets/chunk-5V3GS4D5-i-ZDOEnP.js +1 -0
  659. ksadk/studio/static/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  660. ksadk/studio/static/assets/chunk-6AZGARVD-BB6FqMl-.js +1 -0
  661. ksadk/studio/static/assets/chunk-6EIED4P4-DdUJkP0f.js +1 -0
  662. ksadk/studio/static/assets/chunk-6K3QC6MW-CqVsVn-y.js +1 -0
  663. ksadk/studio/static/assets/chunk-6TQVIW2G-DKlLbNIP.js +1 -0
  664. ksadk/studio/static/assets/chunk-747NJXEK-BFkZPlab.js +2 -0
  665. ksadk/studio/static/assets/chunk-75Z2AOVW-BZNhM4vB.js +2 -0
  666. ksadk/studio/static/assets/chunk-CLGD4ZFX-D-GTtyKs.js +1 -0
  667. ksadk/studio/static/assets/chunk-DU6HZSFF-CpEZCUgg.js +128 -0
  668. ksadk/studio/static/assets/chunk-F27PBJKO-D7pvKf0C.js +1 -0
  669. ksadk/studio/static/assets/chunk-FOHPRMQF-DHwB1DNv.js +161 -0
  670. ksadk/studio/static/assets/chunk-GMAD6QVW-DE_8H717.js +72 -0
  671. ksadk/studio/static/assets/chunk-GVQU2GXP-BfEB0lNv.js +1 -0
  672. ksadk/studio/static/assets/chunk-I5DQTOEV-Hm2LfiYI.js +1 -0
  673. ksadk/studio/static/assets/chunk-ICYGCRZG-749o-pGJ.js +1 -0
  674. ksadk/studio/static/assets/chunk-IH6LHLGP-CC6I9F3i.js +1 -0
  675. ksadk/studio/static/assets/chunk-IMKFNOWR-D38axYOR.js +231 -0
  676. ksadk/studio/static/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  677. ksadk/studio/static/assets/chunk-KI3K4JFJ-Rma-0k_M.js +1 -0
  678. ksadk/studio/static/assets/chunk-L3NEJ4N5-Dq5xn7aL.js +1 -0
  679. ksadk/studio/static/assets/chunk-LNGE3PJU-DWpGwHrW.js +34 -0
  680. ksadk/studio/static/assets/chunk-OSK3NFVY-DiCQjx9b.js +10 -0
  681. ksadk/studio/static/assets/chunk-OUJLGHUK-D0j2JRSg.js +2 -0
  682. ksadk/studio/static/assets/chunk-P2QGCYS3-VdhKmfYq.js +1 -0
  683. ksadk/studio/static/assets/chunk-POPQ4Y6H-C1_rzO5M.js +1 -0
  684. ksadk/studio/static/assets/chunk-PWAF6VOD-B45HvflI.js +1 -0
  685. ksadk/studio/static/assets/chunk-SHT3W25Y-DsCFnRVE.js +168 -0
  686. ksadk/studio/static/assets/chunk-SVP7TREG-DljApgRX.js +88 -0
  687. ksadk/studio/static/assets/chunk-TICWLB2K-DWqRtyqa.js +206 -0
  688. ksadk/studio/static/assets/chunk-TLUHSLCS-DUeGgnD5.js +2 -0
  689. ksadk/studio/static/assets/chunk-UY3FDG6J-CnmaAkG5.js +1 -0
  690. ksadk/studio/static/assets/chunk-XHIXRSVI-BFQ6B8BE.js +1 -0
  691. ksadk/studio/static/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
  692. ksadk/studio/static/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  693. ksadk/studio/static/assets/classDiagram-ZZMXUADV-DjeMNJmu.js +1 -0
  694. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-DjeMNJmu.js +1 -0
  695. ksadk/studio/static/assets/clsx-DB0hHKMi.js +1 -0
  696. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-om8AY0Mc.js +1 -0
  697. ksadk/studio/static/assets/createLucideIcon-DR0LGTP5.js +1 -0
  698. ksadk/studio/static/assets/cynefin-OW5HDTMX-7tP7QfM3.js +1 -0
  699. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-6BrmK52S.js +62 -0
  700. ksadk/studio/static/assets/cytoscape.esm-CGd-uY3x.js +321 -0
  701. ksadk/studio/static/assets/dagre-GXQ25YYZ-buZBRlwz.js +4 -0
  702. ksadk/studio/static/assets/dagre-PrKaheQc.js +1 -0
  703. ksadk/studio/static/assets/defaultLocale-BFoDCU3G.js +1 -0
  704. ksadk/studio/static/assets/diagram-S7CK7UJ4-C6aH78c4.js +30 -0
  705. ksadk/studio/static/assets/diagram-UQ7AKVKN-DY_tQ6C_.js +41 -0
  706. ksadk/studio/static/assets/diagram-VSXAHHWV-DX9p5cQT.js +3 -0
  707. ksadk/studio/static/assets/diagram-VX7I27RA-DB2WSH8X.js +24 -0
  708. ksadk/studio/static/assets/diagram-Z3DM3KII-Ce1BJwHE.js +24 -0
  709. ksadk/studio/static/assets/dist-v5Q1xZ2K.js +1 -0
  710. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-Daukxwqf.js +1 -0
  711. ksadk/studio/static/assets/erDiagram-RLTQ6QDP-CGthTMmJ.js +99 -0
  712. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-BR2FzK4R.js +1 -0
  713. ksadk/studio/static/assets/flowDiagram-HODETNUW-CZ1tEenp.js +1 -0
  714. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BfoAZW9X.js +292 -0
  715. ksadk/studio/static/assets/gitGraph-4MIJSDKK-DYlXv_yJ.js +1 -0
  716. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-S985OIJF.js +106 -0
  717. ksadk/studio/static/assets/graphlib-DS17s2tU.js +1 -0
  718. ksadk/studio/static/assets/iconfont-4HN3C9Pg.woff2 +0 -0
  719. ksadk/studio/static/assets/index-CfEnms6Y.css +2 -0
  720. ksadk/studio/static/assets/index-Dp61rOWZ.js +0 -0
  721. ksadk/studio/static/assets/index.dom-BQenBtFm.js +1 -0
  722. ksadk/studio/static/assets/info-A6RAGUB7-BlU-8_xu.js +1 -0
  723. ksadk/studio/static/assets/infoDiagram-27XIBGKW-CO3W8tFn.js +2 -0
  724. ksadk/studio/static/assets/init-C-OQMol4.js +1 -0
  725. ksadk/studio/static/assets/ishikawaDiagram-5VMMS53U-BUGEl8cO.js +70 -0
  726. ksadk/studio/static/assets/journeyDiagram-3NMN7TZE-Ch2ZYxvr.js +139 -0
  727. ksadk/studio/static/assets/kanban-definition-UXKFOSKX-Da-Fp4vC.js +89 -0
  728. ksadk/studio/static/assets/katex-DhON-x74.js +257 -0
  729. ksadk/studio/static/assets/kingsoft-cloud-BOcLiQ3e.ico +0 -0
  730. ksadk/studio/static/assets/line-BDaeq300.js +1 -0
  731. ksadk/studio/static/assets/linear-DmucvK78.js +1 -0
  732. ksadk/studio/static/assets/mermaid-parser.core-Cj5mYdBi.js +4 -0
  733. ksadk/studio/static/assets/mindmap-definition-YA3MSWOX-CvlsVQ38.js +96 -0
  734. ksadk/studio/static/assets/ordinal-BDEzSJ7C.js +1 -0
  735. ksadk/studio/static/assets/packet-AYTQ26CC-BSJEH9Lb.js +1 -0
  736. ksadk/studio/static/assets/path-fybaL0A-.js +1 -0
  737. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-BuHuNgT5.js +1 -0
  738. ksadk/studio/static/assets/pie-WAS4IAKB-qxv01Y8W.js +1 -0
  739. ksadk/studio/static/assets/pieDiagram-E7YTZNPT-DlrWiSOv.js +39 -0
  740. ksadk/studio/static/assets/preload-helper-CO68xz6u.js +1 -0
  741. ksadk/studio/static/assets/presentation-yYw7xK60-BmcZriri.js +1 -0
  742. ksadk/studio/static/assets/quadrantDiagram-AXDQQJYC-BA3hpUZM.js +7 -0
  743. ksadk/studio/static/assets/radar-RG4KPBEZ-B6h6pWOs.js +1 -0
  744. ksadk/studio/static/assets/railroad-74A4TZTK-CGtTWdGc.js +1 -0
  745. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-Cq7y22IA.js +1 -0
  746. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-V0aQVv9m.js +1 -0
  747. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-BQiIsX_p.js +1 -0
  748. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-BxpAazym.js +1 -0
  749. ksadk/studio/static/assets/requirementDiagram-BXWQKSXE-E-Ge0FcV.js +84 -0
  750. ksadk/studio/static/assets/rolldown-runtime-Dy4uBu1J-DK3Fl9T5.js +1 -0
  751. ksadk/studio/static/assets/rough.esm-Dy-Kn_BL.js +1 -0
  752. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-CA6YKhQ3.js +40 -0
  753. ksadk/studio/static/assets/sequenceDiagram-WJ2MYXX4-CcElXGg4.js +162 -0
  754. ksadk/studio/static/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  755. ksadk/studio/static/assets/src-B6xuSHsQ.js +1 -0
  756. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DdXZOFqY.js +1 -0
  757. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-CJbOM-QK.js +1 -0
  758. ksadk/studio/static/assets/swimlanes-42K2YHIH-NtgEEHLY.js +1 -0
  759. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-D-AVlW8B.js +8 -0
  760. ksadk/studio/static/assets/timeline-definition-24CTP7MA-CIuYhNy3.js +120 -0
  761. ksadk/studio/static/assets/treeView-Q6P3EWNA-BTTYcvrF.js +1 -0
  762. ksadk/studio/static/assets/treemap-WGGIJYW6-Cg7tyfH8.js +1 -0
  763. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-7HbApbrv.js +34 -0
  764. ksadk/studio/static/assets/wardley-WFR3VGLG-C6N1rULY.js +1 -0
  765. ksadk/studio/static/assets/wardleyDiagram-VM6X3IG4-CMJiaedy.js +78 -0
  766. ksadk/studio/static/assets/xychartDiagram-S5SC5T6Z-BdgtMvW2.js +7 -0
  767. ksadk/studio/static/index.html +8 -2
  768. ksadk/studio/teams_catalog.py +133 -0
  769. ksadk/studio/teams_installation.py +214 -0
  770. ksadk/studio/teams_node.py +545 -0
  771. ksadk/studio/teams_node_runner.py +69 -0
  772. ksadk/studio/teams_remote.py +274 -0
  773. ksadk/studio/templates.py +40 -19
  774. ksadk/studio/validator.py +13 -0
  775. ksadk/studio/workspace.py +19 -4
  776. ksadk/studio/workspace_plugins.py +136 -0
  777. ksadk/studio/workspace_registry.py +286 -0
  778. ksadk/toolsets/__init__.py +11 -0
  779. ksadk/toolsets/skills.py +446 -378
  780. ksadk/toolsets/workspace.py +3 -3
  781. ksadk/toolsets/workspace_identity.py +15 -0
  782. ksadk/version.py +1 -1
  783. ksadk_runtime_common/memory_backend/providers/lancedb.py +56 -2
  784. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -148
  785. ksadk_runtime_common/workspace_files/router.py +26 -13
  786. agentengine_sdk_python-0.8.3.dist-info/RECORD +0 -833
  787. ksadk/server/static/assets/MathMessageMarkdown-D9uB55Oh.js +0 -8
  788. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +0 -1
  789. ksadk/server/static/assets/channel-s354Yo6o.js +0 -1
  790. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +0 -1
  791. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +0 -1
  792. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +0 -1
  793. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +0 -1
  794. ksadk/server/static/assets/dist-DdRBIceA.js +0 -1
  795. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +0 -1
  796. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +0 -1
  797. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +0 -1
  798. ksadk/server/static/assets/index-B2k_urY8.js +0 -241
  799. ksadk/server/static/assets/index-ILPt6IWF.css +0 -2
  800. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +0 -1
  801. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +0 -1
  802. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +0 -1
  803. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +0 -1
  804. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +0 -1
  805. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +0 -1
  806. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +0 -1
  807. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +0 -1
  808. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +0 -1
  809. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +0 -8
  810. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +0 -1
  811. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +0 -1
  812. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +0 -1
  813. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +0 -3
  814. ksadk/studio/static/assets/index-DXs1Eq4M.css +0 -1
  815. ksadk/studio/static/assets/index-DeDqwTsD.js +0 -283
  816. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/WHEEL +0 -0
  817. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/entry_points.txt +0 -0
  818. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/licenses/LICENSE +0 -0
  819. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,895 @@
1
+ """Human-readable activity drilldown derived from durable execution evidence.
2
+
3
+ This projection never reads model reasoning or tool arguments/results. Old
4
+ records retain honest action counts; richer records may attach an explicitly
5
+ public action description. Neither path rewrites the canonical event log.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import ipaddress
11
+ import json
12
+ import re
13
+ import time
14
+ from collections import OrderedDict
15
+ from typing import Any
16
+ from urllib.parse import urlsplit, urlunsplit
17
+
18
+ _TERMINAL = {"completed", "failed", "cancelled", "interrupted", "timed_out"}
19
+ _STATUS = {
20
+ "accepted": "running",
21
+ "started": "running",
22
+ "running": "running",
23
+ "in_progress": "running",
24
+ "succeeded": "completed",
25
+ "completed": "completed",
26
+ "done": "completed",
27
+ "failed": "failed",
28
+ "error": "failed",
29
+ "canceled": "cancelled",
30
+ "cancelled": "cancelled",
31
+ "interrupted": "unknown",
32
+ }
33
+ _ACTIONS = {
34
+ "web_search": ("search", "搜索资料"),
35
+ "web_fetch": ("fetch", "查看资料"),
36
+ "read_workspace_file": ("read", "读取文件"),
37
+ "list_workspace_files": ("read", "查看工作区"),
38
+ "write_workspace_file": ("write", "编辑并保存文件"),
39
+ "execute_command": ("command", "运行命令"),
40
+ "run_command": ("command", "运行命令"),
41
+ "exec_command": ("command", "运行命令"),
42
+ "run_workspace_command": ("command", "运行命令"),
43
+ "edit_workspace_file": ("write", "编辑并保存文件"),
44
+ # Codex native item kinds share the same activity vocabulary.
45
+ "commandExecution": ("command", "运行命令"),
46
+ "mcpToolCall": ("tool", "调用工具"),
47
+ "dynamicToolCall": ("tool", "调用工具"),
48
+ "webSearch": ("search", "搜索资料"),
49
+ "fileChange": ("write", "编辑并保存文件"),
50
+ }
51
+ # Codex canonical items keep their native kind only in source metadata; the
52
+ # projection reads the kind and timestamps, never item content (no tool
53
+ # arguments, no results, no reasoning text).
54
+ _CODEX_TOOL_ITEMS = frozenset(
55
+ {"commandExecution", "mcpToolCall", "dynamicToolCall", "webSearch", "fileChange"}
56
+ )
57
+ _TOOL_GROUP_KEYS = frozenset({"search", "fetch", "read", "write", "command", "tool"})
58
+ _SECRET = re.compile(
59
+ r"(?i)\b(?:[\w-]*(?:api[_-]?key|token|secret|password|authorization|cookie)[\w-]*)"
60
+ r"\s*(?:[:=]\s*|\s+)(?:[\"'][^\"'\n]*[\"']|[^\s,;]+)"
61
+ )
62
+ _BEARER = re.compile(r"(?i)\bBearer\s+[^\s,;]+")
63
+ _KEY = re.compile(r"\b(?:sk-[A-Za-z0-9_-]{12,}|[A-Za-z0-9_-]{40,})\b")
64
+
65
+
66
+ def _retry_summary(detail: dict[str, Any]) -> str:
67
+ def number(key: str) -> int | None:
68
+ value = detail.get(key)
69
+ return (
70
+ value if isinstance(value, int) and not isinstance(value, bool) and value >= 0 else None
71
+ )
72
+
73
+ attempt = number("next_attempt")
74
+ previous_attempt = number("model_attempt")
75
+ if attempt is None and previous_attempt is not None:
76
+ attempt = previous_attempt + 1
77
+ maximum = number("max_attempts")
78
+ delay = number("delay_ms") or number("retry_delay_ms")
79
+ wait = f",{delay / 1000:g} 秒后" if delay else ",即将"
80
+ if attempt is not None and maximum is not None:
81
+ suffix = f"(第 {attempt}/{max(attempt, maximum)} 次)"
82
+ else:
83
+ suffix = f"(第 {attempt} 次)" if attempt is not None else ""
84
+ return f"模型服务繁忙{wait}自动重试{suffix}"
85
+
86
+
87
+ def safe_activity_url(value: Any) -> str | None:
88
+ """Keep public HTTP links, without credentials, fragments or query secrets."""
89
+ if not isinstance(value, str) or len(value) > 2048:
90
+ return None
91
+ try:
92
+ parsed = urlsplit(value)
93
+ host = (parsed.hostname or "").lower().rstrip(".")
94
+ if (
95
+ parsed.scheme not in {"http", "https"}
96
+ or not host
97
+ or "." not in host
98
+ or parsed.username
99
+ or parsed.password
100
+ or host.endswith((".localhost", ".local", ".internal", ".lan"))
101
+ or host == "localhost"
102
+ ):
103
+ return None
104
+ try:
105
+ if not ipaddress.ip_address(host).is_global:
106
+ return None
107
+ except ValueError:
108
+ pass
109
+ # Validate the port too; malformed netlocs must not survive rendering.
110
+ port = parsed.port
111
+ authority = host if port is None else f"{host}:{port}"
112
+ return urlunsplit((parsed.scheme, authority, parsed.path, "", ""))
113
+ except ValueError:
114
+ return None
115
+
116
+
117
+ def _safe_text(value: Any) -> str:
118
+ if not isinstance(value, str):
119
+ return ""
120
+ text = " ".join(value.split())
121
+ text = re.sub(
122
+ r"https?://[^\s<>]+",
123
+ lambda match: safe_activity_url(match.group()) or "[链接已隐藏]",
124
+ text,
125
+ )
126
+ text = _SECRET.sub("[敏感信息已隐藏]", text)
127
+ text = _BEARER.sub("Bearer [已隐藏]", text)
128
+ return _KEY.sub("[已隐藏]", text)[:280]
129
+
130
+
131
+ def _safe_commentary_text(value: Any) -> str:
132
+ """Sanitize public progress and drop empty streaming fragments.
133
+
134
+ Older persisted runs can contain a punctuation-only trailing chunk even
135
+ after the runtime-side filter is tightened. The activity projection is
136
+ intentionally defensive so both old and new sessions render cleanly.
137
+ """
138
+ text = _safe_text(value)
139
+ return text if re.search(r"[A-Za-z0-9\u3400-\u9fff]", text) else ""
140
+
141
+
142
+ def _records(events: list[Any]) -> list[dict[str, Any]]:
143
+ records = []
144
+ seen = set()
145
+ for event in events:
146
+ data = event.get("data", {}) if isinstance(event, dict) else event.data
147
+ if not isinstance(data, dict):
148
+ continue
149
+ native = data.get("runtimeEvent") or data.get("runtime_event") or {}
150
+ if not isinstance(native, dict):
151
+ continue
152
+ source = native.get("source") or {}
153
+ source = source if isinstance(source, dict) else {}
154
+ metadata = source.get("metadata") or {}
155
+ metadata = metadata if isinstance(metadata, dict) else {}
156
+ native_run = str(source.get("native_run_id") or native.get("run_id") or "")
157
+ # The same rich event can produce started/updated/completed canonical
158
+ # items. A retry must be shown once, not as three separate attempts.
159
+ identity = str(
160
+ source.get("native_event_id") or native.get("event_id") or f"row-{len(records)}"
161
+ )
162
+ seen_key = (native_run, identity)
163
+ if seen_key in seen:
164
+ continue
165
+ base = {
166
+ "run": native_run,
167
+ "scope": native.get("scope_id") or "",
168
+ "id": identity,
169
+ "session": metadata.get("session_id"),
170
+ "framework": str(source.get("framework") or ""),
171
+ "ts": native.get("timestamp")
172
+ if isinstance(native.get("timestamp"), (int, float))
173
+ else None,
174
+ }
175
+ parts = []
176
+ for field in ("snapshot", "initial"):
177
+ content = native.get(field)
178
+ if isinstance(content, dict) and isinstance(content.get("parts"), list):
179
+ parts.extend(content["parts"])
180
+ if isinstance(native.get("update"), dict):
181
+ parts.append(native["update"])
182
+ if native.get("item_kind") in {"message", "reasoning"}:
183
+ if (
184
+ native.get("item_kind") == "message"
185
+ and metadata.get("native_event_type") == "text.completed"
186
+ and metadata.get("phase") == "commentary"
187
+ ):
188
+ for part in parts:
189
+ text = _safe_commentary_text(
190
+ part.get("text") if isinstance(part, dict) else None
191
+ )
192
+ if text:
193
+ records.append(
194
+ {
195
+ **base,
196
+ "type": "public.commentary",
197
+ "details": {"text": text},
198
+ }
199
+ )
200
+ seen.add(seen_key)
201
+ break
202
+ continue
203
+ if metadata.get("native_event_type") not in {"model.call.failed", "run.progress"}:
204
+ continue
205
+ for part in parts:
206
+ text = part.get("text") if isinstance(part, dict) else None
207
+ # This is the fixed public retry summary, never provider
208
+ # reasoning, error bodies, payloads or arbitrary output text.
209
+ if isinstance(text, str) and re.fullmatch(
210
+ r"模型服务繁忙(?:([^\n]{0,120}))?(?:,[\d.]+ 秒后)?"
211
+ r"自动重试(第 \d+/\d+ 次)",
212
+ text,
213
+ ):
214
+ records.append(
215
+ {
216
+ **base,
217
+ "type": "provider.retry",
218
+ "details": {"text": _safe_text(text)},
219
+ }
220
+ )
221
+ seen.add(seen_key)
222
+ break
223
+ continue
224
+ if native.get("item_kind") in {"tool_call", "data"}:
225
+ # Non-harness runtimes (Codex) publish execution facts as canonical
226
+ # tool/data items; their native kind survives in source metadata.
227
+ # Translate them into the same record vocabulary as Harness so the
228
+ # projection below stays runtime-agnostic.
229
+ native_kind = str(metadata.get("native_item_kind") or "")
230
+ native_event = str(native.get("event_type") or "")
231
+ native_item = str(source.get("native_item_id") or identity)
232
+ if native_kind in _CODEX_TOOL_ITEMS:
233
+ if native_event == "item.started":
234
+ status = "running"
235
+ elif native_event == "item.completed":
236
+ status = "succeeded"
237
+ elif native_event in {"item.failed", "item.updated"}:
238
+ status = "failed" if native_event == "item.failed" else None
239
+ else:
240
+ status = None
241
+ if status is not None:
242
+ records.append(
243
+ {
244
+ **base,
245
+ "type": "tool.call.begin" if status == "running" else "tool.call.end",
246
+ "details": {
247
+ "name": native_kind,
248
+ "call_id": native_item,
249
+ "status": status,
250
+ },
251
+ }
252
+ )
253
+ seen.add(seen_key)
254
+ continue
255
+ if native_kind == "contextCompaction":
256
+ if native_event == "item.started":
257
+ records.append({**base, "type": "context.compaction.started", "details": {}})
258
+ seen.add(seen_key)
259
+ elif native_event == "item.completed":
260
+ records.append({**base, "type": "context.compaction.completed", "details": {}})
261
+ seen.add(seen_key)
262
+ continue
263
+ continue
264
+ if native.get("item_kind") != "status":
265
+ continue
266
+ for part in parts:
267
+ if not isinstance(part, dict) or not isinstance(part.get("text"), str):
268
+ continue
269
+ try:
270
+ payload = json.loads(part["text"])
271
+ except (ValueError, TypeError):
272
+ continue
273
+ if not isinstance(payload, dict) or not isinstance(payload.get("details"), dict):
274
+ continue
275
+ if payload.get("event") not in {
276
+ "tool.call.begin",
277
+ "tool.call.end",
278
+ "model.call.started",
279
+ "model.call.completed",
280
+ "model.call.failed",
281
+ "agent.started",
282
+ "agent.completed",
283
+ "context.compaction.started",
284
+ "context.compaction.completed",
285
+ "run.progress",
286
+ "text.completed",
287
+ }:
288
+ continue
289
+ event_type, detail = payload["event"], payload["details"]
290
+ if event_type == "text.completed":
291
+ text = _safe_commentary_text(detail.get("text"))
292
+ if metadata.get("phase") == "commentary" and text:
293
+ records.append(
294
+ {
295
+ **base,
296
+ "type": "public.commentary",
297
+ "details": {"text": text},
298
+ }
299
+ )
300
+ seen.add(seen_key)
301
+ break
302
+ if (event_type == "run.progress" and detail.get("kind") == "provider.retry") or (
303
+ event_type == "model.call.failed" and detail.get("action") == "retry_same_model"
304
+ ):
305
+ event_type, detail = "provider.retry", {"text": _retry_summary(detail)}
306
+ records.append(
307
+ {
308
+ **base,
309
+ "type": event_type,
310
+ "details": detail,
311
+ }
312
+ )
313
+ seen.add(seen_key)
314
+ break
315
+ return records
316
+
317
+
318
+ def project_run_activities(run: Any, events: list[Any]) -> dict[str, Any]:
319
+ status = str(getattr(run.status, "value", run.status)).lower()
320
+ observed_at = time.time()
321
+ result = {"runId": run.id, "status": status, "activities": []}
322
+ records = _records(events)
323
+ handle = getattr(run, "runtime_handle", {})
324
+ handle = handle if isinstance(handle, dict) else {}
325
+ own_runs = {
326
+ value for value in (run.id, handle.get("run_id")) if isinstance(value, str) and value
327
+ }
328
+ own_session = getattr(run, "session_id", None)
329
+ records = [
330
+ record
331
+ for record in records
332
+ if (
333
+ not record["run"]
334
+ # Provider-native run ids (e.g. Codex turn ids) are not Studio run
335
+ # identities; the per-run event fetch already scopes their events.
336
+ or record.get("framework") not in (None, "", "harness")
337
+ or any(
338
+ record["run"] == root or record["run"].startswith(f"{root}:sub:")
339
+ for root in own_runs
340
+ )
341
+ )
342
+ and (not own_session or not record["session"] or record["session"] == own_session)
343
+ ]
344
+ children: dict[str, dict[str, Any]] = {}
345
+ # Lifecycle notices can arrive after a child's tools. Resolve labels first.
346
+ for record in records:
347
+ detail = record["details"]
348
+ if record["type"] == "run.progress" and detail.get("kind") in {
349
+ "subagent.event",
350
+ "delegation.route",
351
+ }:
352
+ call_id = str(detail.get("call_id") or "")
353
+ if not call_id:
354
+ continue
355
+ child = children.setdefault(call_id, {})
356
+ label = _safe_text(detail.get("label"))
357
+ if label:
358
+ child["label"] = label
359
+ if record.get("ts") is not None:
360
+ if child.get("ts_begin") is None:
361
+ child["ts_begin"] = record["ts"]
362
+ child["ts_last"] = record["ts"]
363
+ provider_ref = str(detail.get("provider_ref") or "")
364
+ if provider_ref:
365
+ child["provider"] = "Codex" if "codex" in provider_ref else "Harness"
366
+ if detail.get("status"):
367
+ next_status = _STATUS.get(str(detail["status"]).lower(), "unknown")
368
+ if child.get("status") not in {"completed", "failed", "cancelled"}:
369
+ child["status"] = next_status
370
+ if next_status in {"completed", "failed", "cancelled"}:
371
+ child["ts_end"] = record.get("ts")
372
+ elif detail.get("kind") == "delegation.route":
373
+ child.setdefault("status", "running")
374
+ summary = _safe_text(detail.get("public_summary"))
375
+ if summary:
376
+ child["summary"] = summary
377
+ child["summary_ts"] = record.get("ts")
378
+ owners: OrderedDict[str, dict[str, Any]] = OrderedDict()
379
+ owners[""] = {"groups": OrderedDict()}
380
+
381
+ def owner_of(record: dict[str, Any]) -> str:
382
+ return owner_of_record_run(record)
383
+
384
+ for record in records:
385
+ detail, event_type = record["details"], record["type"]
386
+ owner_id = owner_of(record)
387
+ owner = owners.setdefault(owner_id, {"groups": OrderedDict()})
388
+ if record.get("ts") is not None:
389
+ owner["ts_last"] = max(record["ts"], owner.get("ts_last") or record["ts"])
390
+ if event_type == "agent.started":
391
+ owner["status"] = "running"
392
+ if event_type == "agent.completed":
393
+ owner["status"] = _STATUS.get(str(detail.get("status")), "unknown")
394
+ if event_type == "provider.retry":
395
+ group = owner["groups"].setdefault(
396
+ "retry", {"label": "自动重试", "calls": OrderedDict()}
397
+ )
398
+ group["calls"][record["id"]] = {
399
+ "status": "running",
400
+ "label": "自动重试",
401
+ "text": detail["text"],
402
+ "retry": True,
403
+ }
404
+ # The event proves the current model attempt failed; keep that
405
+ # evidence instead of leaving its started record running forever.
406
+ active_model = owner.setdefault("active_phases", {}).pop("model", None)
407
+ model_group = owner["groups"].get("model")
408
+ if active_model and model_group:
409
+ model_group["calls"][active_model]["status"] = "failed"
410
+ continue
411
+ if event_type == "public.commentary":
412
+ commentary = {
413
+ "id": f"{run.id}:commentary:{record['id']}",
414
+ "kind": "commentary",
415
+ "label": "公开进展",
416
+ "status": "completed",
417
+ "text": detail["text"],
418
+ "details": [],
419
+ "_sortTs": (
420
+ record["ts"]
421
+ if isinstance(record.get("ts"), (int, float))
422
+ else float("inf")
423
+ ),
424
+ }
425
+ if owner_id:
426
+ # Child progress belongs behind that child's Details affordance.
427
+ # Publishing every child checkpoint in the parent timeline turns
428
+ # a three-worker task into a wall of status text and makes it
429
+ # indistinguishable from the parent's own stage updates.
430
+ owner.setdefault("commentary", []).append(commentary)
431
+ else:
432
+ result["activities"].append(commentary)
433
+ continue
434
+ phase = {
435
+ "model.call.started": ("model", "running"),
436
+ "model.call.completed": ("model", "completed"),
437
+ "model.call.failed": ("model", "failed"),
438
+ "context.compaction.started": ("context", "running"),
439
+ "context.compaction.completed": ("context", "completed"),
440
+ }.get(event_type)
441
+ if phase:
442
+ base_key, phase_status = phase
443
+ # Deterministic phase titles derived from observed execution
444
+ # order: a model phase before any tool work is task analysis;
445
+ # after tool work it is result synthesis. The model never
446
+ # invents its own status labels.
447
+ if base_key == "model" and (
448
+ owner.get("tool_seen")
449
+ or any(group_key in owner["groups"] for group_key in _TOOL_GROUP_KEYS)
450
+ ):
451
+ key, label = "model:summary", "汇总结果"
452
+ else:
453
+ key = base_key
454
+ label = "分析任务" if base_key == "model" else "压缩上下文"
455
+ group = owner["groups"].setdefault(key, {"label": label, "calls": OrderedDict()})
456
+ active = owner.setdefault("active_phases", {})
457
+ if phase_status == "running" or key not in active:
458
+ active[key] = record["id"]
459
+ call = group["calls"].setdefault(active[key], {"label": label})
460
+ call["status"] = phase_status
461
+ # These are deterministic execution summaries, not model chain of
462
+ # thought. They give the expandable row a useful human-facing
463
+ # explanation without exposing prompts, parameters or outputs.
464
+ call["text"] = {
465
+ "model": "理解任务并确定执行步骤",
466
+ "model:summary": "整理已完成的执行结果",
467
+ "context": "整理并压缩较早的上下文,关键执行状态继续保留",
468
+ }[key]
469
+ if record.get("ts") is not None:
470
+ if phase_status == "running":
471
+ call["ts_begin"] = record["ts"]
472
+ else:
473
+ call["ts_end"] = record["ts"]
474
+ call.setdefault("ts_begin", record["ts"])
475
+ if phase_status != "running":
476
+ active.pop(key, None)
477
+ if base_key == "model" and phase_status in {"completed", "failed"}:
478
+ for retry in owner["groups"].get("retry", {}).get("calls", {}).values():
479
+ if retry["status"] == "running":
480
+ retry["status"] = phase_status
481
+ retry["outcome"] = (
482
+ "重试后已恢复" if phase_status == "completed" else "重试后仍未成功"
483
+ )
484
+ continue
485
+ if event_type not in {"tool.call.begin", "tool.call.end"}:
486
+ continue
487
+ name = str(detail.get("name") or "tool")
488
+ # Delegation is rendered as a sub-agent row instead of a generic tool
489
+ # row, but it still separates the analysis model turn from the later
490
+ # result-synthesis turn.
491
+ owner["tool_seen"] = True
492
+ if name == "delegate_task":
493
+ continue
494
+ key, label = _ACTIONS.get(name, ("tool", "使用工具处理任务"))
495
+ group = owner["groups"].setdefault(key, {"label": label, "calls": OrderedDict()})
496
+ call_id = f"{record['scope']}:{detail.get('call_id') or record['id']}"
497
+ call = group["calls"].setdefault(call_id, {"status": "unknown", "label": label})
498
+ call["status"] = _STATUS.get(str(detail.get("status")), "unknown")
499
+ if record.get("ts") is not None:
500
+ if record["type"] == "tool.call.begin":
501
+ call.setdefault("ts_begin", record["ts"])
502
+ else:
503
+ call["ts_end"] = record["ts"]
504
+ call.setdefault("ts_begin", record["ts"])
505
+ action = detail.get("public_action")
506
+ if isinstance(action, dict):
507
+ text = _safe_text(action.get("text"))
508
+ if text:
509
+ call["text"] = text
510
+ href = safe_activity_url(action.get("href"))
511
+ if href:
512
+ call["href"] = href
513
+
514
+ def render_groups(owner_id: str, owner: dict[str, Any]) -> list[dict[str, Any]]:
515
+ groups = []
516
+ for key, group in owner["groups"].items():
517
+ details = []
518
+ statuses = []
519
+ generic: OrderedDict[tuple[str, str], list[dict[str, str]]] = OrderedDict()
520
+ # A retried public action is often recorded as two independent
521
+ # tool calls. Keep the failed attempt in the drilldown, but do
522
+ # not let it poison the whole group once a later call for the
523
+ # exact same public target succeeds. Calls without a public
524
+ # target remain conservative: their failure cannot be inferred
525
+ # away from labels or private arguments/results.
526
+ recovered_failures: set[str] = set()
527
+ completed_targets: set[tuple[str, str]] = set()
528
+ for call_id, call in reversed(group["calls"].items()):
529
+ target = (
530
+ ("href", call["href"])
531
+ if call.get("href")
532
+ else (("text", call["text"]) if call.get("text") else None)
533
+ )
534
+ if key in _TOOL_GROUP_KEYS and call["status"] == "completed" and target:
535
+ completed_targets.add(target)
536
+ elif (
537
+ key in _TOOL_GROUP_KEYS
538
+ and call["status"] == "failed"
539
+ and target in completed_targets
540
+ ):
541
+ recovered_failures.add(call_id)
542
+ calls_in_order = list(group["calls"].items())
543
+ if (
544
+ key == "write"
545
+ and calls_in_order
546
+ and calls_in_order[-1][1]["status"] == "completed"
547
+ ):
548
+ # A malformed/truncated model tool call can fail before its
549
+ # arguments are safe enough to expose. If this same document
550
+ # delivery phase ends with an observed successful write, the
551
+ # earlier anonymous write failures are retry history, not the
552
+ # outcome of the phase. Keep them in the drilldown but do not
553
+ # paint the successfully delivered artifact red.
554
+ recovered_failures.update(
555
+ call_id
556
+ for call_id, call in calls_in_order[:-1]
557
+ if call["status"] == "failed" and not call.get("text")
558
+ )
559
+ for index, (call_id, call) in enumerate(group["calls"].items(), 1):
560
+ state = call["status"]
561
+ owner_status = children.get(owner_id, {}).get("status") or owner.get("status")
562
+ if state == "running" and (status in _TERMINAL or owner_status in _TERMINAL):
563
+ # The provider may omit a final model.call.completed after
564
+ # an approval resume. A canonical agent.completed event is
565
+ # positive evidence that the still-open model phase did
566
+ # finish; it is not enough to invent completion for tools.
567
+ if key.startswith("model") and owner_status == "completed":
568
+ state = "completed"
569
+ else:
570
+ state = (
571
+ "cancelled"
572
+ if status == "cancelled" or owner_status == "cancelled"
573
+ else "unknown"
574
+ )
575
+ effective_state = "completed" if call_id in recovered_failures else state
576
+ statuses.append(effective_state)
577
+ description = call.get("text") or f"第 {index} 次{call['label']}"
578
+ prefix = {
579
+ "running": "正在",
580
+ "completed": "已完成",
581
+ "failed": "未完成",
582
+ "cancelled": "已取消",
583
+ "unknown": "未确认完成",
584
+ }[state]
585
+ item = {"id": call_id, "text": f"{prefix}:{description}"}
586
+ if call_id in recovered_failures:
587
+ item["text"] = f"已重试:{description};后续已成功"
588
+ if call.get("retry"):
589
+ item["text"] = description
590
+ if call.get("outcome"):
591
+ item["text"] += f";{call['outcome']}"
592
+ elif state == "unknown":
593
+ item["text"] += ";未记录重试结果"
594
+ if call.get("href"):
595
+ item["href"] = call["href"]
596
+ details.append(item)
597
+ if not call.get("text"):
598
+ generic.setdefault((state, call["label"]), []).append(item)
599
+ # Older events have only action names. Forty-seven identical
600
+ # numbered rows add no evidence; summarize their real count while
601
+ # keeping failed/cancelled/unfinished calls separately visible.
602
+ for (state, label), items in generic.items():
603
+ if len(items) < 4:
604
+ continue
605
+ first = items[0]
606
+ prefix = {
607
+ "running": "正在执行",
608
+ "completed": "已完成",
609
+ "failed": "未完成",
610
+ "cancelled": "已取消",
611
+ "unknown": "未确认完成",
612
+ }[state]
613
+ first["text"] = f"{prefix} {len(items)} 次{label}(历史记录未保存更细的操作描述)"
614
+ other_ids = {item["id"] for item in items[1:]}
615
+ details = [item for item in details if item["id"] not in other_ids]
616
+ group_status = next(
617
+ (
618
+ value
619
+ for value in ("running", "failed", "unknown", "cancelled")
620
+ if value in statuses
621
+ ),
622
+ "completed",
623
+ )
624
+ owner_status = children.get(owner_id, {}).get("status") or owner.get("status")
625
+ if group_status == "failed" and owner_status in {"running", "completed"}:
626
+ # A failed search/fetch attempt is not the outcome of a child
627
+ # that is still working or has ultimately completed. Keep the
628
+ # failed attempts visible in drilldown, but present the group
629
+ # as partial evidence rather than declaring the whole
630
+ # sub-agent execution failed.
631
+ group_status = "partial"
632
+ if key == "model" and statuses and statuses[-1] == "completed":
633
+ # A recovered model phase may include an earlier failed
634
+ # attempt. Preserve that detail but don't label the entire
635
+ # phase failed after an observed successful retry.
636
+ if "running" not in statuses and "unknown" not in statuses:
637
+ group_status = "completed"
638
+ if key in {"model", "model:summary", "context"} and details:
639
+ # Internal model turns are implementation detail. A phase
640
+ # may contain many calls, but users need one truthful phase
641
+ # summary rather than seven identical rows and a "7 次"
642
+ # counter. Retry evidence remains separately visible in the
643
+ # dedicated retry activity.
644
+ description = next(
645
+ (
646
+ call.get("text")
647
+ for call in reversed(group["calls"].values())
648
+ if call.get("text")
649
+ ),
650
+ group["label"],
651
+ )
652
+ prefix = {
653
+ "running": "正在",
654
+ "completed": "已完成",
655
+ "failed": "未完成",
656
+ "cancelled": "已取消",
657
+ "unknown": "未确认完成",
658
+ }[group_status]
659
+ details = [
660
+ {
661
+ "id": f"{run.id}:{owner_id or 'parent'}:{key}:summary",
662
+ "text": f"{prefix}:{description}",
663
+ }
664
+ ]
665
+ begins = [
666
+ call["ts_begin"]
667
+ for call in group["calls"].values()
668
+ if isinstance(call.get("ts_begin"), (int, float))
669
+ ]
670
+ ends = [
671
+ call["ts_end"]
672
+ for call in group["calls"].values()
673
+ if isinstance(call.get("ts_end"), (int, float))
674
+ ]
675
+ duration_ms = None
676
+ if begins:
677
+ owner_status = children.get(owner_id, {}).get("status") or owner.get("status")
678
+ still_running = (
679
+ "running" in statuses
680
+ and status not in _TERMINAL
681
+ and owner_status not in _TERMINAL
682
+ )
683
+ latest_end = (
684
+ observed_at if still_running else (max(ends) if ends else owner.get("ts_last"))
685
+ )
686
+ if isinstance(latest_end, (int, float)) and latest_end >= min(begins):
687
+ duration_ms = int((latest_end - min(begins)) * 1000)
688
+ groups.append(
689
+ {
690
+ "id": f"{run.id}:{owner_id or 'parent'}:{key}",
691
+ "kind": "step",
692
+ "label": group["label"],
693
+ "status": group_status,
694
+ "details": details,
695
+ **(
696
+ {}
697
+ if key in {"model", "model:summary", "context"}
698
+ else {"count": len(group["calls"])}
699
+ ),
700
+ **({"durationMs": duration_ms} if duration_ms is not None else {}),
701
+ "_sortTs": min(begins) if begins else float("inf"),
702
+ }
703
+ )
704
+ return groups
705
+
706
+ result["activities"].extend(render_groups("", owners[""]))
707
+ # A lifecycle-only child must remain visible even without tool records.
708
+ for child_id in children:
709
+ owners.setdefault(child_id, {"groups": OrderedDict()})
710
+ for child_id, owner in owners.items():
711
+ if not child_id:
712
+ continue
713
+ metadata = children.get(child_id, {})
714
+ child_status = metadata.get("status") or owner.get("status") or "unknown"
715
+ if child_status == "running" and status in _TERMINAL:
716
+ child_status = "cancelled" if status == "cancelled" else "unknown"
717
+ groups = render_groups(child_id, owner)
718
+ summaries = (
719
+ [] if groups else [{"id": f"{child_id}:no-detail", "text": "暂未记录可展示的操作步骤"}]
720
+ )
721
+ duration_ms = None
722
+ ts_begin, ts_end = metadata.get("ts_begin"), metadata.get("ts_end")
723
+ if isinstance(ts_begin, (int, float)):
724
+ latest = (
725
+ observed_at
726
+ if child_status == "running" and status not in _TERMINAL
727
+ else ts_end
728
+ if isinstance(ts_end, (int, float))
729
+ else owner.get("ts_last")
730
+ )
731
+ if isinstance(latest, (int, float)) and latest >= ts_begin:
732
+ duration_ms = int((latest - ts_begin) * 1000)
733
+ entry: dict[str, Any] = {
734
+ "id": f"{run.id}:child:{child_id}",
735
+ "kind": "subagent",
736
+ "label": metadata.get("label") or "子智能体",
737
+ "status": child_status,
738
+ "details": summaries,
739
+ "children": groups,
740
+ "callId": child_id,
741
+ "_sortTs": (
742
+ ts_begin
743
+ if isinstance(ts_begin, (int, float))
744
+ else owner.get("ts_last", float("inf"))
745
+ ),
746
+ }
747
+ if duration_ms is not None:
748
+ entry["durationMs"] = duration_ms
749
+ if metadata.get("provider"):
750
+ entry["provider"] = metadata["provider"]
751
+ result["activities"].append(entry)
752
+ # Parent phases, tools and delegated work are projected in their observed
753
+ # execution order. This lets a live timeline naturally read as
754
+ # analysis → sub-agent/tool work → optional compaction → result synthesis,
755
+ # rather than putting every child after all parent phases.
756
+ result["activities"].sort(key=lambda activity: activity.get("_sortTs", float("inf")))
757
+ for activity in result["activities"]:
758
+ activity.pop("_sortTs", None)
759
+ return result
760
+
761
+
762
+ def _subagent_detail(run: Any, events: list[Any], call_id: str) -> dict[str, Any]:
763
+ """Curated sub-agent facts for the detail panel.
764
+
765
+ Same evidence rules as the parent projection: lifecycle metadata and
766
+ public action descriptions only — never tool arguments, results or
767
+ model reasoning.
768
+ """
769
+
770
+ projection = project_run_activities(run, events)
771
+ entry = next(
772
+ (
773
+ activity
774
+ for activity in projection["activities"]
775
+ if activity.get("kind") == "subagent" and activity.get("callId") == call_id
776
+ ),
777
+ None,
778
+ )
779
+ if entry is None:
780
+ return {}
781
+ models = []
782
+ own_session = getattr(run, "session_id", None)
783
+ child_sessions = []
784
+ for record in _records(events):
785
+ if owner_of_record_run(record) != call_id:
786
+ continue
787
+ model = record["details"].get("model") if record["type"].startswith("model.call") else None
788
+ if model:
789
+ model = _safe_text(model)
790
+ if model and model not in models:
791
+ models.append(model)
792
+ if (
793
+ record.get("session")
794
+ and own_session
795
+ and record["session"] != own_session
796
+ and record["session"] not in child_sessions
797
+ ):
798
+ child_sessions.append(record["session"])
799
+ child_progress = []
800
+ for record in _records(events):
801
+ if owner_of_record_run(record) != call_id or record["type"] != "public.commentary":
802
+ continue
803
+ child_progress.append(
804
+ {
805
+ "id": f"{run.id}:child:{call_id}:progress:{record['id']}",
806
+ "kind": "commentary",
807
+ "label": "阶段进展",
808
+ "status": "completed",
809
+ "text": record["details"]["text"],
810
+ "details": [],
811
+ }
812
+ )
813
+ # Keep the detail panel useful without replaying the child's entire chat.
814
+ # The first checkpoint explains the approach and the last two show the
815
+ # latest work; tool groups below retain the concrete execution evidence.
816
+ if len(child_progress) > 3:
817
+ child_progress = [child_progress[0], *child_progress[-2:]]
818
+ execution_facts = entry.get("children") or ([] if child_progress else entry["details"])
819
+ detail = {
820
+ "runId": run.id,
821
+ "callId": call_id,
822
+ "label": entry["label"],
823
+ "status": entry["status"],
824
+ "facts": [*child_progress, *execution_facts],
825
+ "parentStatus": projection["status"],
826
+ }
827
+ for key in ("durationMs", "provider"):
828
+ if entry.get(key) is not None:
829
+ detail[key] = entry[key]
830
+ if models:
831
+ detail["models"] = models
832
+ if child_sessions:
833
+ detail["sessionId"] = child_sessions[0]
834
+ return detail
835
+
836
+
837
+ def owner_of_record_run(record: dict[str, Any]) -> str:
838
+ # Scope hashes include the child's run ID, so parent_scope_id is not
839
+ # comparable to the parent's scope. The native child run suffix is the
840
+ # delegate call ID emitted by Harness and shared by lifecycle notices.
841
+ native_run = str(record["run"])
842
+ if ":sub:" not in native_run:
843
+ return ""
844
+ return native_run.rsplit(":", 1)[-1]
845
+
846
+
847
+ def register_activity_routes(app: Any, studio: Any, *, resolve_run_id: Any = None) -> None:
848
+ """Use the Studio app's existing session/CSRF security middleware."""
849
+
850
+ @app.get("/api/v1/runs/{run_id}/activities")
851
+ async def run_activities(run_id: str):
852
+ from fastapi.responses import JSONResponse
853
+
854
+ resolved_id = resolve_run_id(run_id) if resolve_run_id else run_id
855
+ resolve_owner = getattr(studio, "runtime_for_run", None)
856
+ owner = resolve_owner(resolved_id) if callable(resolve_owner) else studio
857
+ if owner is None:
858
+ from ksadk.studio.errors import not_found
859
+
860
+ raise not_found("run", resolved_id)
861
+ run = owner.event_store.get(resolved_id)
862
+ events = await owner.run_service.events(resolved_id)
863
+ return JSONResponse(
864
+ project_run_activities(run, events), headers={"Cache-Control": "no-store"}
865
+ )
866
+
867
+ @app.get("/api/v1/runs/{run_id}/subagents/{call_id}")
868
+ async def run_subagent(run_id: str, call_id: str):
869
+ from fastapi.responses import JSONResponse
870
+
871
+ from ksadk.studio.errors import not_found
872
+
873
+ resolved_id = resolve_run_id(run_id) if resolve_run_id else run_id
874
+ resolve_owner = getattr(studio, "runtime_for_run", None)
875
+ owner = resolve_owner(resolved_id) if callable(resolve_owner) else studio
876
+ if owner is None:
877
+ error = not_found("run", resolved_id)
878
+ else:
879
+ run = owner.event_store.get(resolved_id)
880
+ events = await owner.run_service.events(resolved_id)
881
+ detail = _subagent_detail(run, events, call_id)
882
+ if detail:
883
+ return JSONResponse(detail, headers={"Cache-Control": "no-store"})
884
+ error = not_found("subagent", call_id)
885
+ return JSONResponse(
886
+ {
887
+ "error": {
888
+ "code": error.code,
889
+ "message": error.message,
890
+ "details": error.details or {},
891
+ }
892
+ },
893
+ status_code=error.status_code,
894
+ headers={"Cache-Control": "no-store"},
895
+ )