agent-tower 0.5.4 → 0.6.0-beta.0
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.
- package/README.md +1 -1
- package/dist/core/event-bus.d.ts +4 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/executors/__tests__/codex.executor.test.js +27 -21
- package/dist/executors/__tests__/codex.executor.test.js.map +1 -1
- package/dist/executors/__tests__/providers-availability.test.js +23 -0
- package/dist/executors/__tests__/providers-availability.test.js.map +1 -1
- package/dist/executors/__tests__/providers.test.js +34 -1
- package/dist/executors/__tests__/providers.test.js.map +1 -1
- package/dist/executors/codex.executor.d.ts.map +1 -1
- package/dist/executors/codex.executor.js +4 -0
- package/dist/executors/codex.executor.js.map +1 -1
- package/dist/executors/default-providers.json +106 -0
- package/dist/executors/index.d.ts +1 -1
- package/dist/executors/index.d.ts.map +1 -1
- package/dist/executors/index.js +32 -13
- package/dist/executors/index.js.map +1 -1
- package/dist/executors/providers.d.ts +12 -3
- package/dist/executors/providers.d.ts.map +1 -1
- package/dist/executors/providers.js +45 -18
- package/dist/executors/providers.js.map +1 -1
- package/dist/output/types.d.ts +32 -2
- package/dist/output/types.d.ts.map +1 -1
- package/dist/output/types.js +10 -0
- package/dist/output/types.js.map +1 -1
- package/dist/routes/__tests__/providers.test.js +181 -1
- package/dist/routes/__tests__/providers.test.js.map +1 -1
- package/dist/routes/__tests__/sessions-runtime.test.d.ts +2 -0
- package/dist/routes/__tests__/sessions-runtime.test.d.ts.map +1 -0
- package/dist/routes/__tests__/sessions-runtime.test.js +107 -0
- package/dist/routes/__tests__/sessions-runtime.test.js.map +1 -0
- package/dist/routes/providers.d.ts.map +1 -1
- package/dist/routes/providers.js +3 -1
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +50 -3
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/system.d.ts.map +1 -1
- package/dist/routes/system.js +8 -0
- package/dist/routes/system.js.map +1 -1
- package/dist/runtime/__tests__/acp-agent-definitions.test.d.ts +2 -0
- package/dist/runtime/__tests__/acp-agent-definitions.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/acp-agent-definitions.test.js +360 -0
- package/dist/runtime/__tests__/acp-agent-definitions.test.js.map +1 -0
- package/dist/runtime/__tests__/acp-driver-cleanup.test.d.ts +2 -0
- package/dist/runtime/__tests__/acp-driver-cleanup.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/acp-driver-cleanup.test.js +39 -0
- package/dist/runtime/__tests__/acp-driver-cleanup.test.js.map +1 -0
- package/dist/runtime/__tests__/acp-driver.test.d.ts +2 -0
- package/dist/runtime/__tests__/acp-driver.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/acp-driver.test.js +122 -0
- package/dist/runtime/__tests__/acp-driver.test.js.map +1 -0
- package/dist/runtime/__tests__/acp-process-manager.test.d.ts +2 -0
- package/dist/runtime/__tests__/acp-process-manager.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/acp-process-manager.test.js +51 -0
- package/dist/runtime/__tests__/acp-process-manager.test.js.map +1 -0
- package/dist/runtime/__tests__/acp-projector.test.d.ts +2 -0
- package/dist/runtime/__tests__/acp-projector.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/acp-projector.test.js +195 -0
- package/dist/runtime/__tests__/acp-projector.test.js.map +1 -0
- package/dist/runtime/__tests__/runtime-coordinator.test.d.ts +2 -0
- package/dist/runtime/__tests__/runtime-coordinator.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/runtime-coordinator.test.js +134 -0
- package/dist/runtime/__tests__/runtime-coordinator.test.js.map +1 -0
- package/dist/runtime/acp/acp-driver.d.ts +7 -0
- package/dist/runtime/acp/acp-driver.d.ts.map +1 -0
- package/dist/runtime/acp/acp-driver.js +406 -0
- package/dist/runtime/acp/acp-driver.js.map +1 -0
- package/dist/runtime/acp/agents/claude-code.d.ts +3 -0
- package/dist/runtime/acp/agents/claude-code.d.ts.map +1 -0
- package/dist/runtime/acp/agents/claude-code.js +147 -0
- package/dist/runtime/acp/agents/claude-code.js.map +1 -0
- package/dist/runtime/acp/agents/codex.d.ts +3 -0
- package/dist/runtime/acp/agents/codex.d.ts.map +1 -0
- package/dist/runtime/acp/agents/codex.js +68 -0
- package/dist/runtime/acp/agents/codex.js.map +1 -0
- package/dist/runtime/acp/agents/cursor-agent.d.ts +2 -0
- package/dist/runtime/acp/agents/cursor-agent.d.ts.map +1 -0
- package/dist/runtime/acp/agents/cursor-agent.js +12 -0
- package/dist/runtime/acp/agents/cursor-agent.js.map +1 -0
- package/dist/runtime/acp/agents/executable-resolution.d.ts +6 -0
- package/dist/runtime/acp/agents/executable-resolution.d.ts.map +1 -0
- package/dist/runtime/acp/agents/executable-resolution.js +72 -0
- package/dist/runtime/acp/agents/executable-resolution.js.map +1 -0
- package/dist/runtime/acp/agents/gemini-cli.d.ts +2 -0
- package/dist/runtime/acp/agents/gemini-cli.d.ts.map +1 -0
- package/dist/runtime/acp/agents/gemini-cli.js +13 -0
- package/dist/runtime/acp/agents/gemini-cli.js.map +1 -0
- package/dist/runtime/acp/agents/grok-build.d.ts +2 -0
- package/dist/runtime/acp/agents/grok-build.d.ts.map +1 -0
- package/dist/runtime/acp/agents/grok-build.js +26 -0
- package/dist/runtime/acp/agents/grok-build.js.map +1 -0
- package/dist/runtime/acp/agents/kiro-cli.d.ts +2 -0
- package/dist/runtime/acp/agents/kiro-cli.d.ts.map +1 -0
- package/dist/runtime/acp/agents/kiro-cli.js +18 -0
- package/dist/runtime/acp/agents/kiro-cli.js.map +1 -0
- package/dist/runtime/acp/agents/managed-directory.d.ts +6 -0
- package/dist/runtime/acp/agents/managed-directory.d.ts.map +1 -0
- package/dist/runtime/acp/agents/managed-directory.js +31 -0
- package/dist/runtime/acp/agents/managed-directory.js.map +1 -0
- package/dist/runtime/acp/agents/minion-acp-sitecustomize.d.ts +2 -0
- package/dist/runtime/acp/agents/minion-acp-sitecustomize.d.ts.map +1 -0
- package/dist/runtime/acp/agents/minion-acp-sitecustomize.js +118 -0
- package/dist/runtime/acp/agents/minion-acp-sitecustomize.js.map +1 -0
- package/dist/runtime/acp/agents/minion-code.d.ts +2 -0
- package/dist/runtime/acp/agents/minion-code.d.ts.map +1 -0
- package/dist/runtime/acp/agents/minion-code.js +53 -0
- package/dist/runtime/acp/agents/minion-code.js.map +1 -0
- package/dist/runtime/acp/agents/native-agent.d.ts +23 -0
- package/dist/runtime/acp/agents/native-agent.d.ts.map +1 -0
- package/dist/runtime/acp/agents/native-agent.js +158 -0
- package/dist/runtime/acp/agents/native-agent.js.map +1 -0
- package/dist/runtime/acp/agents/opencode.d.ts +2 -0
- package/dist/runtime/acp/agents/opencode.d.ts.map +1 -0
- package/dist/runtime/acp/agents/opencode.js +35 -0
- package/dist/runtime/acp/agents/opencode.js.map +1 -0
- package/dist/runtime/acp/agents/pi-coding-agent.d.ts +3 -0
- package/dist/runtime/acp/agents/pi-coding-agent.d.ts.map +1 -0
- package/dist/runtime/acp/agents/pi-coding-agent.js +178 -0
- package/dist/runtime/acp/agents/pi-coding-agent.js.map +1 -0
- package/dist/runtime/acp/agents/qwen-code.d.ts +3 -0
- package/dist/runtime/acp/agents/qwen-code.d.ts.map +1 -0
- package/dist/runtime/acp/agents/qwen-code.js +67 -0
- package/dist/runtime/acp/agents/qwen-code.js.map +1 -0
- package/dist/runtime/acp/agents/registry.d.ts +5 -0
- package/dist/runtime/acp/agents/registry.d.ts.map +1 -0
- package/dist/runtime/acp/agents/registry.js +34 -0
- package/dist/runtime/acp/agents/registry.js.map +1 -0
- package/dist/runtime/acp/agents/types.d.ts +35 -0
- package/dist/runtime/acp/agents/types.d.ts.map +1 -0
- package/dist/runtime/acp/agents/types.js +2 -0
- package/dist/runtime/acp/agents/types.js.map +1 -0
- package/dist/runtime/acp/codex-provider-config.d.ts +9 -0
- package/dist/runtime/acp/codex-provider-config.d.ts.map +1 -0
- package/dist/runtime/acp/codex-provider-config.js +107 -0
- package/dist/runtime/acp/codex-provider-config.js.map +1 -0
- package/dist/runtime/acp/process-manager.d.ts +33 -0
- package/dist/runtime/acp/process-manager.d.ts.map +1 -0
- package/dist/runtime/acp/process-manager.js +204 -0
- package/dist/runtime/acp/process-manager.js.map +1 -0
- package/dist/runtime/acp/projector.d.ts +23 -0
- package/dist/runtime/acp/projector.d.ts.map +1 -0
- package/dist/runtime/acp/projector.js +354 -0
- package/dist/runtime/acp/projector.js.map +1 -0
- package/dist/runtime/cli-driver.d.ts +7 -0
- package/dist/runtime/cli-driver.d.ts.map +1 -0
- package/dist/runtime/cli-driver.js +282 -0
- package/dist/runtime/cli-driver.js.map +1 -0
- package/dist/runtime/cli-parser.d.ts +5 -0
- package/dist/runtime/cli-parser.d.ts.map +1 -0
- package/dist/runtime/cli-parser.js +15 -0
- package/dist/runtime/cli-parser.js.map +1 -0
- package/dist/runtime/contracts.d.ts +109 -0
- package/dist/runtime/contracts.d.ts.map +1 -0
- package/dist/runtime/contracts.js +2 -0
- package/dist/runtime/contracts.js.map +1 -0
- package/dist/runtime/errors.d.ts +9 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +29 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +9 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/runtime-coordinator.d.ts +32 -0
- package/dist/runtime/runtime-coordinator.d.ts.map +1 -0
- package/dist/runtime/runtime-coordinator.js +327 -0
- package/dist/runtime/runtime-coordinator.js.map +1 -0
- package/dist/runtime/runtime-registry.d.ts +8 -0
- package/dist/runtime/runtime-registry.d.ts.map +1 -0
- package/dist/runtime/runtime-registry.js +17 -0
- package/dist/runtime/runtime-registry.js.map +1 -0
- package/dist/runtime/runtime-state-view.d.ts +5 -0
- package/dist/runtime/runtime-state-view.d.ts.map +1 -0
- package/dist/runtime/runtime-state-view.js +15 -0
- package/dist/runtime/runtime-state-view.js.map +1 -0
- package/dist/services/__tests__/provider-config.service.test.js +31 -2
- package/dist/services/__tests__/provider-config.service.test.js.map +1 -1
- package/dist/services/__tests__/session-manager.lifecycle.test.js +105 -2
- package/dist/services/__tests__/session-manager.lifecycle.test.js.map +1 -1
- package/dist/services/__tests__/session-manager.team-run.test.js +16 -14
- package/dist/services/__tests__/session-manager.team-run.test.js.map +1 -1
- package/dist/services/conversation.service.d.ts.map +1 -1
- package/dist/services/conversation.service.js +3 -0
- package/dist/services/conversation.service.js.map +1 -1
- package/dist/services/provider-config.service.d.ts.map +1 -1
- package/dist/services/provider-config.service.js +34 -5
- package/dist/services/provider-config.service.js.map +1 -1
- package/dist/services/provider-effective-connection.service.d.ts +7 -1
- package/dist/services/provider-effective-connection.service.d.ts.map +1 -1
- package/dist/services/provider-effective-connection.service.js +56 -1
- package/dist/services/provider-effective-connection.service.js.map +1 -1
- package/dist/services/session-manager.d.ts +32 -24
- package/dist/services/session-manager.d.ts.map +1 -1
- package/dist/services/session-manager.js +265 -448
- package/dist/services/session-manager.js.map +1 -1
- package/dist/services/team-reconciler.service.d.ts +3 -0
- package/dist/services/team-reconciler.service.d.ts.map +1 -1
- package/dist/services/team-reconciler.service.js +14 -3
- package/dist/services/team-reconciler.service.js.map +1 -1
- package/dist/services/team-run.service.d.ts.map +1 -1
- package/dist/services/team-run.service.js +5 -1
- package/dist/services/team-run.service.js.map +1 -1
- package/dist/services/workspace.service.d.ts +2 -0
- package/dist/services/workspace.service.d.ts.map +1 -1
- package/dist/socket/__tests__/socket-gateway.test.js +42 -0
- package/dist/socket/__tests__/socket-gateway.test.js.map +1 -1
- package/dist/socket/events.d.ts +1 -1
- package/dist/socket/events.d.ts.map +1 -1
- package/dist/socket/events.js.map +1 -1
- package/dist/socket/index.js +1 -1
- package/dist/socket/index.js.map +1 -1
- package/dist/socket/socket-gateway.d.ts.map +1 -1
- package/dist/socket/socket-gateway.js +13 -1
- package/dist/socket/socket-gateway.js.map +1 -1
- package/dist/types/index.d.ts +7 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -1
- package/dist/utils/process-launch.d.ts.map +1 -1
- package/dist/utils/process-launch.js +3 -1
- package/dist/utils/process-launch.js.map +1 -1
- package/dist/utils/process-launch.test.js +17 -2
- package/dist/utils/process-launch.test.js.map +1 -1
- package/dist/web/assets/{AgentDemoPage-C3SHOCDR.js → AgentDemoPage-BpUO2gR6.js} +1 -1
- package/dist/web/assets/{AgentEnvironmentSettingsPage-D-BWLcC0.js → AgentEnvironmentSettingsPage-CSBMaAvL.js} +1 -1
- package/dist/web/assets/AgentLogo-C190Z6bw.js +1 -0
- package/dist/web/assets/ConversationPage-Cer_WtdC.js +3 -0
- package/dist/web/assets/CreateTaskInput-ByeWDjc8.js +1 -0
- package/dist/web/assets/{DemoPage-Cd1ggnZY.js → DemoPage-Dpb9aAKX.js} +1 -1
- package/dist/web/assets/{GeneralSettingsPage-B9D9wA_9.js → GeneralSettingsPage-TqbAsCZM.js} +1 -1
- package/dist/web/assets/{Icons-CM6Yg2lw.js → Icons-CyNNz4Z5.js} +1 -1
- package/dist/web/assets/{LoadingPreviewPage-BJ_Se_T_.js → LoadingPreviewPage-DmH1TGln.js} +1 -1
- package/dist/web/assets/{McpSettingsPage-B5GtqNme.js → McpSettingsPage-z1_NcsMR.js} +1 -1
- package/dist/web/assets/{MemberAvatar-yC8O30hv.js → MemberAvatar-BPoYS6Il.js} +1 -1
- package/dist/web/assets/{NotificationSettingsPage-BaJpYHLD.js → NotificationSettingsPage-CNsRJ6nN.js} +1 -1
- package/dist/web/assets/{ProfileSettingsPage-DYXew66J.js → ProfileSettingsPage-g1RKcEbo.js} +1 -1
- package/dist/web/assets/{ProjectKanbanPage-DbgIwiUC.js → ProjectKanbanPage-j2v5fLfg.js} +37 -36
- package/dist/web/assets/{ProjectSettingsPage-B2K8Kw_S.js → ProjectSettingsPage-Cp89NvwE.js} +1 -1
- package/dist/web/assets/ProviderSettingsPage-B-bBs2qN.js +93 -0
- package/dist/web/assets/{SettingsMasterDetail-ByKe_zcK.js → SettingsMasterDetail-BYB-1oyf.js} +1 -1
- package/dist/web/assets/{TeamSettingsPage-4sHo9Wpb.js → TeamSettingsPage-Y2zCVbVD.js} +1 -1
- package/dist/web/assets/agent-tower-lockup-DPAcheCt.png +0 -0
- package/dist/web/assets/{arc-g6Y4qqcK.js → arc-BmDnqN7Q.js} +1 -1
- package/dist/web/assets/{architectureDiagram-3BPJPVTR-ILRcqNPe.js → architectureDiagram-3BPJPVTR-BIG4K9gT.js} +1 -1
- package/dist/web/assets/{arrow-left-D0MkHwKU.js → arrow-left-CB4qTjQs.js} +1 -1
- package/dist/web/assets/{blockDiagram-GPEHLZMM-ZTMQ6CTT.js → blockDiagram-GPEHLZMM-CowveYw0.js} +1 -1
- package/dist/web/assets/{c4Diagram-AAUBKEIU-CAW8PcM8.js → c4Diagram-AAUBKEIU-CLjbYgNG.js} +1 -1
- package/dist/web/assets/channel-BsOpjSZw.js +1 -0
- package/dist/web/assets/check-BVOtZt28.js +1 -0
- package/dist/web/assets/{chevron-down-CmGXPki1.js → chevron-down-BXYCSpWd.js} +1 -1
- package/dist/web/assets/{chevron-right-jrkLz9qG.js → chevron-right-CkcSaX8x.js} +1 -1
- package/dist/web/assets/{chevron-up-UwBybVMK.js → chevron-up-Y8L6pbzc.js} +1 -1
- package/dist/web/assets/{chunk-2J33WTMH-BvuLBX1d.js → chunk-2J33WTMH-DRf_miP4.js} +1 -1
- package/dist/web/assets/{chunk-4BX2VUAB-DJO5Yx2A.js → chunk-4BX2VUAB-C6Ne_vwR.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-Dc117Qwf.js → chunk-55IACEB6-DejCglMr.js} +1 -1
- package/dist/web/assets/{chunk-727SXJPM-DsZmTw67.js → chunk-727SXJPM-B0MC9Ojc.js} +1 -1
- package/dist/web/assets/{chunk-AQP2D5EJ-DgmF7gD6.js → chunk-AQP2D5EJ-D9f4hbMX.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-vgh3Erl0.js → chunk-FMBD7UC4-k90hkOQq.js} +1 -1
- package/dist/web/assets/{chunk-ND2GUHAM-Ogtl4wwd.js → chunk-ND2GUHAM-CX2-qxPx.js} +1 -1
- package/dist/web/assets/{chunk-QZHKN3VN-Cif7bPpF.js → chunk-QZHKN3VN-CpFs7UD0.js} +1 -1
- package/dist/web/assets/{circle-alert-B6ZM3dSn.js → circle-alert-ClX4sQ2K.js} +1 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-KkLqUSdB.js +1 -0
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-KkLqUSdB.js +1 -0
- package/dist/web/assets/{code-block-OCS4YCEC-BQnKZly0.js → code-block-OCS4YCEC-_lkU1VUC.js} +1 -1
- package/dist/web/assets/{confirm-dialog-BZeaAl5j.js → confirm-dialog-BJwzwwOk.js} +1 -1
- package/dist/web/assets/{copy-DqNqPI8d.js → copy-jQAntc98.js} +1 -1
- package/dist/web/assets/{cose-bilkent-S5V4N54A-rxJB-TPw.js → cose-bilkent-S5V4N54A-CLWAfEVg.js} +1 -1
- package/dist/web/assets/cssMode-q0rL0Hjc.js +1 -0
- package/dist/web/assets/{dagre-BM42HDAG-BkB6VpXn.js → dagre-BM42HDAG-DKviWU-X.js} +1 -1
- package/dist/web/assets/{diagram-2AECGRRQ-BH2e-eqy.js → diagram-2AECGRRQ-L6emXRJ1.js} +1 -1
- package/dist/web/assets/{diagram-5GNKFQAL-B0I47Yhs.js → diagram-5GNKFQAL-CXGUerks.js} +1 -1
- package/dist/web/assets/{diagram-KO2AKTUF-BVXUYRvI.js → diagram-KO2AKTUF-C8FHXqeH.js} +1 -1
- package/dist/web/assets/{diagram-LMA3HP47-C1fEOLke.js → diagram-LMA3HP47-Cng_aa5j.js} +1 -1
- package/dist/web/assets/{diagram-OG6HWLK6-CVE8cOcO.js → diagram-OG6HWLK6-BEC6IDf4.js} +1 -1
- package/dist/web/assets/{erDiagram-TEJ5UH35-qCfnXmfp.js → erDiagram-TEJ5UH35-BWMCTdYK.js} +1 -1
- package/dist/web/assets/{flowDiagram-I6XJVG4X-KMhbF5QC.js → flowDiagram-I6XJVG4X-aAEYIyx2.js} +1 -1
- package/dist/web/assets/{folder-picker-C3BgqamQ.js → folder-picker-CioQjSzV.js} +1 -1
- package/dist/web/assets/{freemarker2-tYgVOcFl.js → freemarker2-DZgAIr6s.js} +2 -2
- package/dist/web/assets/{ganttDiagram-6RSMTGT7-CaX3qYV1.js → ganttDiagram-6RSMTGT7-DVqWnwcH.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PVQCEYII-CBAlZX7C.js → gitGraphDiagram-PVQCEYII-BVWrTXBv.js} +1 -1
- package/dist/web/assets/handlebars-9RRQrLUb.js +1 -0
- package/dist/web/assets/html-BVI4F9TT.js +1 -0
- package/dist/web/assets/htmlMode-t0djrjSv.js +1 -0
- package/dist/web/assets/index-CjAJoGg5.css +1 -0
- package/dist/web/assets/{index-BuQDZjol.js → index-Da9mzleR.js} +4 -4
- package/dist/web/assets/{index-DHKgc87I.js → index-RYlllU6n.js} +18 -18
- package/dist/web/assets/{infoDiagram-5YYISTIA-Bp_GeFtA.js → infoDiagram-5YYISTIA-DYG1ew4x.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-BfBNEV_D.js → ishikawaDiagram-YF4QCWOH-COBW1j3-.js} +1 -1
- package/dist/web/assets/javascript-DaUCpDvL.js +1 -0
- package/dist/web/assets/{journeyDiagram-JHISSGLW-DJkUQG4Z.js → journeyDiagram-JHISSGLW-BI_FlncW.js} +1 -1
- package/dist/web/assets/{jsonMode-D4_2geMa.js → jsonMode-A5wuW-PC.js} +2 -2
- package/dist/web/assets/{kanban-definition-UN3LZRKU-Bk7sA26p.js → kanban-definition-UN3LZRKU-BKrHEd7r.js} +1 -1
- package/dist/web/assets/{layers-BFkjcml2.js → layers-BZMh9pqm.js} +1 -1
- package/dist/web/assets/{linear-CmC68WUf.js → linear-DyoMQJGq.js} +1 -1
- package/dist/web/assets/liquid-HXqG_RIQ.js +1 -0
- package/dist/web/assets/{lspLanguageFeatures-vY541IS0.js → lspLanguageFeatures-s3xWnrXc.js} +1 -1
- package/dist/web/assets/mdx-k_7JTYp2.js +1 -0
- package/dist/web/assets/{mermaid-NOHMQCX5-C6wHDXti.js → mermaid-NOHMQCX5-orMHhlAj.js} +59 -61
- package/dist/web/assets/{message-square-Wwixl9YA.js → message-square-CStQg7sr.js} +1 -1
- package/dist/web/assets/{mindmap-definition-RKZ34NQL-Ck1je2Hf.js → mindmap-definition-RKZ34NQL-CKOIIjUJ.js} +1 -1
- package/dist/web/assets/{modal-kFSArLJi.js → modal-ZYdX5Krr.js} +1 -1
- package/dist/web/assets/{monaco-D3FVQqPj.js → monaco-DX9iObLO.js} +3 -3
- package/dist/web/assets/{pencil-5Kegi5_H.js → pencil-DoB4p30x.js} +1 -1
- package/dist/web/assets/{pieDiagram-4H26LBE5-6Ao8YaoY.js → pieDiagram-4H26LBE5-BW18kL8l.js} +1 -1
- package/dist/web/assets/python-abx8p9WS.js +1 -0
- package/dist/web/assets/{quadrantDiagram-W4KKPZXB-md1eBgjS.js → quadrantDiagram-W4KKPZXB-Df_F1INR.js} +1 -1
- package/dist/web/assets/razor-DGdDlX86.js +1 -0
- package/dist/web/assets/{requirementDiagram-4Y6WPE33-DJOb4wf-.js → requirementDiagram-4Y6WPE33-De6R8t8O.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-5OEKKPKP-B7srXhHb.js → sankeyDiagram-5OEKKPKP-ChlLeN5m.js} +1 -1
- package/dist/web/assets/{select-C2v0aFwN.js → select-B9kjO67b.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-3UESZ5HK-L0qwgf37.js → sequenceDiagram-3UESZ5HK-CPVnbcvz.js} +1 -1
- package/dist/web/assets/{stateDiagram-AJRCARHV-DGbH9dJ5.js → stateDiagram-AJRCARHV-BFS1G-aJ.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-DSxC8AfE.js +1 -0
- package/dist/web/assets/{switch-DjnF5A3R.js → switch-C2r5pofB.js} +1 -1
- package/dist/web/assets/{textarea-CbZnd5PO.js → textarea-BB3UoYxg.js} +1 -1
- package/dist/web/assets/{timeline-definition-PNZ67QCA-Dku_Yjmk.js → timeline-definition-PNZ67QCA-C1Rgs32y.js} +1 -1
- package/dist/web/assets/{trash-2-DA--Uikt.js → trash-2-BNiAEW-6.js} +1 -1
- package/dist/web/assets/{tsMode-CRNPFR24.js → tsMode-DHruHjGh.js} +2 -2
- package/dist/web/assets/typescript-SLYiKRhJ.js +1 -0
- package/dist/web/assets/{upload-hWnFHuhE.js → upload-BLLmywZY.js} +1 -1
- package/dist/web/assets/{use-profiles-roHXR8He.js → use-profiles-OJaV4lOv.js} +1 -1
- package/dist/web/assets/{use-projects-DiJMGduU.js → use-projects-D_Sq7ahS.js} +1 -1
- package/dist/web/assets/{use-providers-efX4HCcr.js → use-providers-SSHcslI-.js} +1 -1
- package/dist/web/assets/{useNormalizedLogs-xEobyuGF.js → useNormalizedLogs-DeA-fso_.js} +1 -1
- package/dist/web/assets/{vennDiagram-CIIHVFJN-_ufI1hxk.js → vennDiagram-CIIHVFJN-DLGPZTKg.js} +1 -1
- package/dist/web/assets/{wardley-L42UT6IY-Dve662aX.js → wardley-L42UT6IY-BVMPWfq9.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-YWT4CUSO-Dn2x3M_Q.js → wardleyDiagram-YWT4CUSO-_KXuEg6G.js} +1 -1
- package/dist/web/assets/xml-BmreQojr.js +1 -0
- package/dist/web/assets/{xychartDiagram-2RQKCTM6-BMe6JPre.js → xychartDiagram-2RQKCTM6-a-Do3v5G.js} +1 -1
- package/dist/web/assets/yaml-CJoLHuqv.js +1 -0
- package/dist/web/index.html +2 -2
- package/node_modules/@agent-tower/shared/dist/agent-runtime-support.d.ts +9 -0
- package/node_modules/@agent-tower/shared/dist/agent-runtime-support.d.ts.map +1 -0
- package/node_modules/@agent-tower/shared/dist/agent-runtime-support.js +21 -0
- package/node_modules/@agent-tower/shared/dist/agent-runtime-support.js.map +1 -0
- package/node_modules/@agent-tower/shared/dist/index.d.ts +1 -0
- package/node_modules/@agent-tower/shared/dist/index.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/index.js +1 -0
- package/node_modules/@agent-tower/shared/dist/index.js.map +1 -1
- package/node_modules/@agent-tower/shared/dist/log-adapter.d.ts +38 -3
- package/node_modules/@agent-tower/shared/dist/log-adapter.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/log-adapter.js +21 -2
- package/node_modules/@agent-tower/shared/dist/log-adapter.js.map +1 -1
- package/node_modules/@agent-tower/shared/dist/provider-capabilities.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/provider-capabilities.js +58 -0
- package/node_modules/@agent-tower/shared/dist/provider-capabilities.js.map +1 -1
- package/node_modules/@agent-tower/shared/dist/socket/events.d.ts +17 -0
- package/node_modules/@agent-tower/shared/dist/socket/events.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/socket/events.js +3 -0
- package/node_modules/@agent-tower/shared/dist/socket/events.js.map +1 -1
- package/node_modules/@agent-tower/shared/dist/types.d.ts +63 -2
- package/node_modules/@agent-tower/shared/dist/types.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/types.js +12 -0
- package/node_modules/@agent-tower/shared/dist/types.js.map +1 -1
- package/package.json +9 -3
- package/prisma/migrations/20260723000000_add_agent_runtime/migration.sql +2 -0
- package/prisma/schema.prisma +2 -0
- package/scripts/patch-claude-agent-acp.mjs +77 -0
- package/scripts/postinstall.js +5 -0
- package/dist/web/assets/AgentLogo-DOc8QQHe.js +0 -1
- package/dist/web/assets/ConversationPage-sknzMK-I.js +0 -3
- package/dist/web/assets/CreateTaskInput-Cn0k5D8K.js +0 -1
- package/dist/web/assets/ProviderSettingsPage-n2AFrtkZ.js +0 -93
- package/dist/web/assets/channel-DpisCjBV.js +0 -1
- package/dist/web/assets/check-VMcYyBr4.js +0 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-ByrAXg7x.js +0 -1
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-ByrAXg7x.js +0 -1
- package/dist/web/assets/cssMode-BvIKUSIl.js +0 -1
- package/dist/web/assets/handlebars-O23dzm6n.js +0 -1
- package/dist/web/assets/html-QaPgl834.js +0 -1
- package/dist/web/assets/htmlMode-CWyii3pY.js +0 -1
- package/dist/web/assets/index-BeEbDvc9.css +0 -1
- package/dist/web/assets/javascript-C_IpQDkn.js +0 -1
- package/dist/web/assets/liquid-C6FS7ekL.js +0 -1
- package/dist/web/assets/mdx-LQJToB8m.js +0 -1
- package/dist/web/assets/python-HMxhKAEt.js +0 -1
- package/dist/web/assets/razor-CfDc2DcT.js +0 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-Bq1LxgY_.js +0 -1
- package/dist/web/assets/typescript-CNopspEc.js +0 -1
- package/dist/web/assets/xml-dqhfYLW3.js +0 -1
- package/dist/web/assets/yaml-BOxNX83z.js +0 -1
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { prisma } from '../utils/index.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { SessionStatus, SessionPurpose, TaskStatus, SessionContext } from '../types/index.js';
|
|
3
|
+
import { getProviderById, ExecutionEnv, normalizeExecutorStartError, } from '../executors/index.js';
|
|
4
4
|
import { filterAgentSubprocessExternalEnv } from '../executors/execution-env.js';
|
|
5
|
-
import { sessionMsgStoreManager,
|
|
6
|
-
import { AgentPipeline } from '../pipeline/agent-pipeline.js';
|
|
5
|
+
import { sessionMsgStoreManager, createUserMessage, addNormalizedEntry, } from '../output/index.js';
|
|
7
6
|
import { execGit } from '../git/git-cli.js';
|
|
8
7
|
import { getCommitMessageService } from '../core/container.js';
|
|
9
8
|
import { TeamReconcilerService } from './team-reconciler.service.js';
|
|
10
|
-
import { NotFoundError } from '../errors.js';
|
|
9
|
+
import { NotFoundError, ValidationError } from '../errors.js';
|
|
11
10
|
import { ensureTaskNotDeleted } from './deleted-task-guard.js';
|
|
12
11
|
import { getWorkspaceWorkingDir, isMainDirectoryWorkspace, } from './workspace-kind.js';
|
|
13
12
|
import { writeErrorLog } from '../utils/error-log.js';
|
|
14
13
|
import { INTERNAL_API_TOKEN_ENV, readInternalApiTokenFromEnv } from '../utils/internal-api-token.js';
|
|
15
14
|
import { createHash } from 'node:crypto';
|
|
15
|
+
import { RuntimeType, supportsAgentRuntime } from '@agent-tower/shared';
|
|
16
|
+
import { getProviderRuntimeType } from '../executors/providers.js';
|
|
17
|
+
import { CliRuntimeDriver, AcpRuntimeDriver, RuntimeCoordinator, StaticRuntimeRegistry, setRuntimeStateSnapshot, } from '../runtime/index.js';
|
|
16
18
|
const DEBUG_SNAPSHOT = process.env.DEBUG_SNAPSHOT === 'true';
|
|
17
19
|
function hashForLog(value) {
|
|
18
20
|
return createHash('sha256').update(value).digest('hex').slice(0, 12);
|
|
@@ -46,12 +48,9 @@ function isAgentProgressPatch(patch) {
|
|
|
46
48
|
}
|
|
47
49
|
export class SessionManager {
|
|
48
50
|
eventBus;
|
|
49
|
-
pipelines = new Map();
|
|
50
|
-
pendingSpawns = new Map();
|
|
51
|
-
cancelTokens = new Map();
|
|
52
51
|
snapshotFlushTimers = new Map();
|
|
53
52
|
snapshotFlushChains = new Map();
|
|
54
|
-
|
|
53
|
+
sessionPersistenceWriterChain = Promise.resolve();
|
|
55
54
|
dirtySnapshots = new Set();
|
|
56
55
|
persistedSnapshotHashes = new Map();
|
|
57
56
|
pendingSnapshotStatus = new Map();
|
|
@@ -70,13 +69,15 @@ export class SessionManager {
|
|
|
70
69
|
followUpReservationReleases = new Set();
|
|
71
70
|
/** Incremented for every start/send cycle so late post-processing cannot affect a new turn. */
|
|
72
71
|
sessionGenerations = new Map();
|
|
73
|
-
logicalCompletionCleanupTimers = new Map();
|
|
74
72
|
// 每个 session 上次写入 TeamRun 心跳时间戳的时刻,用于节流 lastHeartbeatAt 落库。
|
|
75
73
|
heartbeatThrottle = new Map();
|
|
76
74
|
teamReconciler;
|
|
75
|
+
runtimeCoordinator;
|
|
76
|
+
runtimeProcessIds = new Map();
|
|
77
|
+
runtimePermissionStates = new Map();
|
|
78
|
+
externalSessionPersistence = new Map();
|
|
77
79
|
static SNAPSHOT_CHECKPOINT_MS = 15_000;
|
|
78
80
|
static HEARTBEAT_THROTTLE_MS = 30_000;
|
|
79
|
-
static CODEX_TURN_COMPLETION_GRACE_MS = 250;
|
|
80
81
|
constructor(eventBus, teamReconciler) {
|
|
81
82
|
this.eventBus = eventBus;
|
|
82
83
|
this.teamReconciler = teamReconciler ?? new TeamReconcilerService({
|
|
@@ -86,6 +87,14 @@ export class SessionManager {
|
|
|
86
87
|
// session 退出时的首次 reconcile(COMPLETED 判定 / 首次补催)仍即时执行,不依赖该定时器。
|
|
87
88
|
scheduleReminders: false,
|
|
88
89
|
});
|
|
90
|
+
this.runtimeCoordinator = new RuntimeCoordinator(new StaticRuntimeRegistry([
|
|
91
|
+
new CliRuntimeDriver(),
|
|
92
|
+
new AcpRuntimeDriver(),
|
|
93
|
+
]), {
|
|
94
|
+
onTurnEvent: (event) => this.handleRuntimeTurnEvent(event),
|
|
95
|
+
onRuntimeState: (state) => this.handleRuntimeState(state),
|
|
96
|
+
onProcessEvent: (event) => this.handleRuntimeProcessEvent(event),
|
|
97
|
+
});
|
|
89
98
|
// Patches only mark the snapshot dirty. A low-frequency checkpoint keeps the
|
|
90
99
|
// hot stream away from SQLite while terminal paths still force a final flush.
|
|
91
100
|
this.eventBus.on('session:patch', ({ sessionId, patch }) => {
|
|
@@ -105,7 +114,6 @@ export class SessionManager {
|
|
|
105
114
|
// The parser has already written raw stdout, the final assistant entry,
|
|
106
115
|
// usage and all other state from the turn.completed chunk at this point.
|
|
107
116
|
this.terminalSessions.set(sessionId, SessionStatus.COMPLETED);
|
|
108
|
-
this.scheduleLogicalCompletionCleanup(sessionId);
|
|
109
117
|
this.startSessionFinalization(sessionId, 0, { logicalCompletion: true });
|
|
110
118
|
});
|
|
111
119
|
this.eventBus.on('session:turn-failed', ({ sessionId }) => {
|
|
@@ -115,30 +123,8 @@ export class SessionManager {
|
|
|
115
123
|
// without an exit code. Use a synthetic non-zero code for the shared
|
|
116
124
|
// finalization path so success-only post-processing cannot run.
|
|
117
125
|
this.terminalSessions.set(sessionId, SessionStatus.FAILED);
|
|
118
|
-
this.scheduleLogicalCompletionCleanup(sessionId);
|
|
119
126
|
this.startSessionFinalization(sessionId, 1, { logicalCompletion: true });
|
|
120
127
|
});
|
|
121
|
-
this.eventBus.on('session:exit', ({ sessionId, exitCode }) => {
|
|
122
|
-
const terminalStatus = this.terminalSessions.get(sessionId);
|
|
123
|
-
this.clearLogicalCompletionCleanup(sessionId);
|
|
124
|
-
const pipeline = this.pipelines.get(sessionId);
|
|
125
|
-
if (DEBUG_SNAPSHOT) {
|
|
126
|
-
console.log(`[SessionManager:snapshot] session:exit sessionId=${sessionId} exitCode=${exitCode} hasPipeline=${Boolean(pipeline)}`);
|
|
127
|
-
}
|
|
128
|
-
if (pipeline) {
|
|
129
|
-
// Must call destroy() to remove MsgStore onPatch/onSessionId listeners.
|
|
130
|
-
// Without this, stale listeners accumulate across send/exit cycles and
|
|
131
|
-
// each subsequent pushPatch() forwards the same patch N times.
|
|
132
|
-
pipeline.destroy();
|
|
133
|
-
this.pipelines.delete(sessionId);
|
|
134
|
-
}
|
|
135
|
-
this.cancelTokens.delete(sessionId);
|
|
136
|
-
this.heartbeatThrottle.delete(sessionId);
|
|
137
|
-
if (terminalStatus)
|
|
138
|
-
return;
|
|
139
|
-
this.terminalSessions.set(sessionId, typeof exitCode === 'number' && exitCode !== 0 ? SessionStatus.FAILED : SessionStatus.COMPLETED);
|
|
140
|
-
this.startSessionFinalization(sessionId, exitCode);
|
|
141
|
-
});
|
|
142
128
|
// NOTE: checkTaskAutoRevert is called directly (awaited) inside start()
|
|
143
129
|
// and sendMessage() to guarantee the task status is updated before the
|
|
144
130
|
// HTTP response is sent. A fire-and-forget EventBus listener here caused
|
|
@@ -151,6 +137,12 @@ export class SessionManager {
|
|
|
151
137
|
include: { processes: true, workspace: true, conversation: true },
|
|
152
138
|
});
|
|
153
139
|
}
|
|
140
|
+
getRuntimeState(sessionId, runtimeType = RuntimeType.CLI) {
|
|
141
|
+
return this.runtimeCoordinator.getState(sessionId, runtimeType);
|
|
142
|
+
}
|
|
143
|
+
async resolveRuntimePermission(sessionId, requestId, optionId) {
|
|
144
|
+
await this.runtimeCoordinator.resolvePermission(sessionId, requestId, optionId);
|
|
145
|
+
}
|
|
154
146
|
async create(workspaceId, agentType, prompt, variant = 'DEFAULT', providerId) {
|
|
155
147
|
const workspace = await prisma.workspace.findUnique({
|
|
156
148
|
where: { id: workspaceId },
|
|
@@ -160,11 +152,23 @@ export class SessionManager {
|
|
|
160
152
|
throw new NotFoundError('Workspace', workspaceId);
|
|
161
153
|
}
|
|
162
154
|
ensureTaskNotDeleted(workspace.task);
|
|
155
|
+
const provider = providerId ? getProviderById(providerId) : null;
|
|
156
|
+
if (providerId && !provider) {
|
|
157
|
+
throw new ValidationError(`Provider not found: ${providerId}`);
|
|
158
|
+
}
|
|
159
|
+
if (provider && provider.agentType !== agentType) {
|
|
160
|
+
throw new ValidationError(`Provider '${provider.name}' belongs to agent '${provider.agentType}', not '${agentType}'`);
|
|
161
|
+
}
|
|
162
|
+
const runtimeType = provider ? getProviderRuntimeType(provider) : RuntimeType.CLI;
|
|
163
|
+
if (!supportsAgentRuntime(agentType, runtimeType)) {
|
|
164
|
+
throw new ValidationError(`Agent '${agentType}' does not support the '${runtimeType}' runtime`);
|
|
165
|
+
}
|
|
163
166
|
return prisma.session.create({
|
|
164
167
|
data: {
|
|
165
168
|
workspaceId,
|
|
166
169
|
context: SessionContext.WORKSPACE,
|
|
167
170
|
agentType,
|
|
171
|
+
runtimeType,
|
|
168
172
|
variant,
|
|
169
173
|
providerId: providerId ?? null,
|
|
170
174
|
prompt,
|
|
@@ -190,39 +194,7 @@ export class SessionManager {
|
|
|
190
194
|
prompt: summarizeTextForLog(session.prompt),
|
|
191
195
|
workingDir,
|
|
192
196
|
});
|
|
193
|
-
|
|
194
|
-
const executor = this.resolveExecutor(agentType, session.variant, session.providerId);
|
|
195
|
-
console.log('[SessionManager] ✅ Executor found, spawning process...');
|
|
196
|
-
const env = ExecutionEnv.default(workingDir);
|
|
197
|
-
// 如果有 provider,注入 provider 的环境变量
|
|
198
|
-
if (session.providerId) {
|
|
199
|
-
const provider = getProviderById(session.providerId);
|
|
200
|
-
if (provider && Object.keys(provider.env).length > 0) {
|
|
201
|
-
env.merge(filterAgentSubprocessExternalEnv(provider.env));
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
this.injectAgentTowerMcpServiceEnv(env);
|
|
205
|
-
if (!this.isConversationSession(session)) {
|
|
206
|
-
await this.injectTeamRunInvocationEnv(id, env);
|
|
207
|
-
}
|
|
208
|
-
let spawnResult;
|
|
209
|
-
try {
|
|
210
|
-
spawnResult = await executor.spawn({
|
|
211
|
-
workingDir,
|
|
212
|
-
prompt: session.prompt,
|
|
213
|
-
env,
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
this.logSessionError('session.spawn', error, {
|
|
218
|
-
sessionId: id,
|
|
219
|
-
agentType: session.agentType,
|
|
220
|
-
providerId: session.providerId,
|
|
221
|
-
workingDir,
|
|
222
|
-
});
|
|
223
|
-
throw normalizeExecutorStartError(error);
|
|
224
|
-
}
|
|
225
|
-
await this.activateSpawnedSession(id, agentType, workingDir, spawnResult);
|
|
197
|
+
await this.startRuntimeTurn(session, session.prompt, session.externalSessionId);
|
|
226
198
|
return session;
|
|
227
199
|
}
|
|
228
200
|
async startFollowUp(id, resumeFromSessionId) {
|
|
@@ -238,10 +210,11 @@ export class SessionManager {
|
|
|
238
210
|
this.ensureExecutionRecordIsLive(session);
|
|
239
211
|
const resumeFromSession = await prisma.session.findUnique({
|
|
240
212
|
where: { id: resumeFromSessionId },
|
|
241
|
-
select: { logSnapshot: true },
|
|
213
|
+
select: { logSnapshot: true, externalSessionId: true },
|
|
242
214
|
});
|
|
243
215
|
const agentSessionId = resumeFromSession
|
|
244
|
-
?
|
|
216
|
+
? resumeFromSession.externalSessionId
|
|
217
|
+
?? this.resolveAgentSessionId(resumeFromSessionId, resumeFromSession.logSnapshot)
|
|
245
218
|
: null;
|
|
246
219
|
console.log('[SessionManager] Follow-up session details:', {
|
|
247
220
|
id: session.id,
|
|
@@ -252,76 +225,7 @@ export class SessionManager {
|
|
|
252
225
|
prompt: summarizeTextForLog(session.prompt),
|
|
253
226
|
workingDir: this.getExecutionWorkingDir(session),
|
|
254
227
|
});
|
|
255
|
-
|
|
256
|
-
const executor = this.resolveExecutor(agentType, session.variant, session.providerId);
|
|
257
|
-
const workingDir = this.getExecutionWorkingDir(session);
|
|
258
|
-
const env = ExecutionEnv.default(workingDir);
|
|
259
|
-
if (session.providerId) {
|
|
260
|
-
const provider = getProviderById(session.providerId);
|
|
261
|
-
if (provider && Object.keys(provider.env).length > 0) {
|
|
262
|
-
env.merge(filterAgentSubprocessExternalEnv(provider.env));
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
this.injectAgentTowerMcpServiceEnv(env);
|
|
266
|
-
if (!this.isConversationSession(session)) {
|
|
267
|
-
await this.injectTeamRunInvocationEnv(id, env);
|
|
268
|
-
}
|
|
269
|
-
const spawnConfig = {
|
|
270
|
-
workingDir,
|
|
271
|
-
prompt: session.prompt,
|
|
272
|
-
env,
|
|
273
|
-
};
|
|
274
|
-
let spawnResult;
|
|
275
|
-
if (agentSessionId && executor.spawnFollowUp) {
|
|
276
|
-
try {
|
|
277
|
-
spawnResult = await executor.spawnFollowUp(spawnConfig, agentSessionId);
|
|
278
|
-
}
|
|
279
|
-
catch (error) {
|
|
280
|
-
console.warn(`[SessionManager] Follow-up spawn failed for ${id}, falling back to a new agent session:`, error instanceof Error ? error.message : error);
|
|
281
|
-
writeErrorLog({
|
|
282
|
-
level: 'warn',
|
|
283
|
-
source: 'session.spawnFollowUpResume',
|
|
284
|
-
message: `Follow-up spawn failed for session ${id}; falling back to a new agent session`,
|
|
285
|
-
error,
|
|
286
|
-
metadata: {
|
|
287
|
-
sessionId: id,
|
|
288
|
-
resumeFromSessionId,
|
|
289
|
-
agentType: session.agentType,
|
|
290
|
-
providerId: session.providerId,
|
|
291
|
-
workingDir,
|
|
292
|
-
},
|
|
293
|
-
});
|
|
294
|
-
try {
|
|
295
|
-
spawnResult = await executor.spawn(spawnConfig);
|
|
296
|
-
}
|
|
297
|
-
catch (fallbackError) {
|
|
298
|
-
this.logSessionError('session.spawnFollowUpFallback', fallbackError, {
|
|
299
|
-
sessionId: id,
|
|
300
|
-
resumeFromSessionId,
|
|
301
|
-
agentType: session.agentType,
|
|
302
|
-
providerId: session.providerId,
|
|
303
|
-
workingDir,
|
|
304
|
-
});
|
|
305
|
-
throw normalizeExecutorStartError(fallbackError);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
try {
|
|
311
|
-
spawnResult = await executor.spawn(spawnConfig);
|
|
312
|
-
}
|
|
313
|
-
catch (error) {
|
|
314
|
-
this.logSessionError('session.spawnFollowUp', error, {
|
|
315
|
-
sessionId: id,
|
|
316
|
-
resumeFromSessionId,
|
|
317
|
-
agentType: session.agentType,
|
|
318
|
-
providerId: session.providerId,
|
|
319
|
-
workingDir,
|
|
320
|
-
});
|
|
321
|
-
throw normalizeExecutorStartError(error);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
await this.activateSpawnedSession(id, agentType, workingDir, spawnResult);
|
|
228
|
+
await this.startRuntimeTurn(session, session.prompt, agentSessionId);
|
|
325
229
|
return session;
|
|
326
230
|
}
|
|
327
231
|
async sendMessage(id, message, providerId) {
|
|
@@ -353,6 +257,9 @@ export class SessionManager {
|
|
|
353
257
|
if (String(effectiveProvider.agentType) !== session.agentType) {
|
|
354
258
|
throw new Error(`Cannot switch provider: agentType mismatch. Session uses '${session.agentType}', but provider '${effectiveProvider.name}' is for '${effectiveProvider.agentType}'`);
|
|
355
259
|
}
|
|
260
|
+
if (getProviderRuntimeType(effectiveProvider) !== this.normalizeRuntimeType(session.runtimeType)) {
|
|
261
|
+
throw new Error(`Cannot switch provider: runtimeType mismatch. Session uses '${session.runtimeType}', but provider '${effectiveProvider.name}' uses '${getProviderRuntimeType(effectiveProvider)}'`);
|
|
262
|
+
}
|
|
356
263
|
}
|
|
357
264
|
if (providerId && providerId !== session.providerId) {
|
|
358
265
|
const switchedProvider = getProviderById(providerId);
|
|
@@ -368,18 +275,15 @@ export class SessionManager {
|
|
|
368
275
|
// the old execution with the new one.
|
|
369
276
|
this.invalidateSessionGeneration(id);
|
|
370
277
|
this.beginSessionExecution(id);
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
|
|
375
|
-
if (existing) {
|
|
278
|
+
// Stop the previous turn before waiting for its auto-commit boundary. The
|
|
279
|
+
// coordinator suppresses that superseded turn's terminal event so it cannot
|
|
280
|
+
// finalize the newly reserved generation.
|
|
281
|
+
if (this.runtimeCoordinator.hasActiveTurn(id)) {
|
|
376
282
|
if (DEBUG_SNAPSHOT) {
|
|
377
|
-
console.log(`[SessionManager:snapshot] sendMessage checkpoint before
|
|
283
|
+
console.log(`[SessionManager:snapshot] sendMessage checkpoint before runtime turn replace sessionId=${id}`);
|
|
378
284
|
}
|
|
379
285
|
await this.flushSnapshotPersist(id);
|
|
380
|
-
|
|
381
|
-
this.pipelines.delete(id);
|
|
382
|
-
this.cancelTokens.delete(id);
|
|
286
|
+
await this.runtimeCoordinator.abandonTurn(id);
|
|
383
287
|
}
|
|
384
288
|
await this.waitForPendingAutoCommit(id);
|
|
385
289
|
const isNewStore = !sessionMsgStoreManager.has(id);
|
|
@@ -416,74 +320,12 @@ export class SessionManager {
|
|
|
416
320
|
// MsgStore's patchListeners are empty at this point. Without this line
|
|
417
321
|
// the user-message patch would never reach WebSocket subscribers.
|
|
418
322
|
this.eventBus.emit('session:patch', { sessionId: id, patch: userPatch, seq: userPatchSeq });
|
|
419
|
-
const agentSessionId =
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const env = ExecutionEnv.default(workingDir);
|
|
424
|
-
// 如果有 provider,注入 provider 的环境变量
|
|
425
|
-
if (effectiveProviderId) {
|
|
426
|
-
const provider = getProviderById(effectiveProviderId);
|
|
427
|
-
if (provider && Object.keys(provider.env).length > 0) {
|
|
428
|
-
env.merge(filterAgentSubprocessExternalEnv(provider.env));
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
this.injectAgentTowerMcpServiceEnv(env);
|
|
432
|
-
if (!this.isConversationSession(session)) {
|
|
433
|
-
await this.injectTeamRunInvocationEnv(id, env);
|
|
434
|
-
}
|
|
435
|
-
const spawnConfig = {
|
|
436
|
-
workingDir,
|
|
437
|
-
prompt: message,
|
|
438
|
-
env,
|
|
439
|
-
};
|
|
440
|
-
let spawnResult;
|
|
441
|
-
if (agentSessionId && executor.spawnFollowUp) {
|
|
442
|
-
try {
|
|
443
|
-
spawnResult = await executor.spawnFollowUp(spawnConfig, agentSessionId);
|
|
444
|
-
}
|
|
445
|
-
catch (resumeError) {
|
|
446
|
-
writeErrorLog({
|
|
447
|
-
level: 'warn',
|
|
448
|
-
source: 'session.messageSpawnResume',
|
|
449
|
-
message: `Message follow-up spawn failed for session ${id}; falling back to a new agent session`,
|
|
450
|
-
error: resumeError,
|
|
451
|
-
metadata: {
|
|
452
|
-
sessionId: id,
|
|
453
|
-
agentType: session.agentType,
|
|
454
|
-
providerId: effectiveProviderId,
|
|
455
|
-
workingDir,
|
|
456
|
-
},
|
|
457
|
-
});
|
|
458
|
-
try {
|
|
459
|
-
spawnResult = await executor.spawn(spawnConfig);
|
|
460
|
-
}
|
|
461
|
-
catch (error) {
|
|
462
|
-
this.logSessionError('session.messageSpawnFallback', error, {
|
|
463
|
-
sessionId: id,
|
|
464
|
-
agentType: session.agentType,
|
|
465
|
-
providerId: effectiveProviderId,
|
|
466
|
-
workingDir,
|
|
467
|
-
});
|
|
468
|
-
throw normalizeExecutorStartError(error);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
try {
|
|
474
|
-
spawnResult = await executor.spawn(spawnConfig);
|
|
475
|
-
}
|
|
476
|
-
catch (error) {
|
|
477
|
-
this.logSessionError('session.messageSpawn', error, {
|
|
478
|
-
sessionId: id,
|
|
479
|
-
agentType: session.agentType,
|
|
480
|
-
providerId: effectiveProviderId,
|
|
481
|
-
workingDir,
|
|
482
|
-
});
|
|
483
|
-
throw normalizeExecutorStartError(error);
|
|
484
|
-
}
|
|
323
|
+
const agentSessionId = session.externalSessionId
|
|
324
|
+
?? this.resolveAgentSessionId(id, session.logSnapshot);
|
|
325
|
+
if (providerId && providerId !== session.providerId) {
|
|
326
|
+
await this.runtimeCoordinator.disposeSession(id);
|
|
485
327
|
}
|
|
486
|
-
await this.
|
|
328
|
+
await this.startRuntimeTurn(session, message, agentSessionId, effectiveProviderId);
|
|
487
329
|
return session;
|
|
488
330
|
}
|
|
489
331
|
finally {
|
|
@@ -495,19 +337,19 @@ export class SessionManager {
|
|
|
495
337
|
if (!session)
|
|
496
338
|
return null;
|
|
497
339
|
const terminalStatus = this.terminalSessions.get(id);
|
|
340
|
+
const hasActiveTurn = this.runtimeCoordinator.hasActiveTurn(id);
|
|
498
341
|
const persistedTerminal = [
|
|
499
342
|
SessionStatus.COMPLETED,
|
|
500
343
|
SessionStatus.FAILED,
|
|
501
344
|
SessionStatus.CANCELLED,
|
|
502
345
|
].includes(session.status);
|
|
503
|
-
if (terminalStatus || persistedTerminal) {
|
|
346
|
+
if (!hasActiveTurn && (terminalStatus || persistedTerminal)) {
|
|
504
347
|
const pendingFinalization = this.sessionFinalizations.get(id);
|
|
505
348
|
// A terminal transition already won the race. A late user stop may
|
|
506
349
|
// clean up the PTY, but it must not regress the persisted status. The
|
|
507
350
|
// backing TeamRun invocation may still be waiting for a room reply, so
|
|
508
351
|
// it must still pass through the cancellation reconciler.
|
|
509
|
-
this.
|
|
510
|
-
this.destroyActivePipeline(id);
|
|
352
|
+
await this.runtimeCoordinator.disposeSession(id);
|
|
511
353
|
this.maybeClearTerminalState(id);
|
|
512
354
|
await pendingFinalization;
|
|
513
355
|
if (!options.skipTeamRunReconcile && !this.isConversationSession(session)) {
|
|
@@ -515,35 +357,13 @@ export class SessionManager {
|
|
|
515
357
|
}
|
|
516
358
|
return session;
|
|
517
359
|
}
|
|
518
|
-
this.clearLogicalCompletionCleanup(id);
|
|
519
360
|
this.terminalSessions.set(id, SessionStatus.CANCELLED);
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
catch {
|
|
527
|
-
// ignore cancellation failures for pending spawns
|
|
528
|
-
}
|
|
529
|
-
try {
|
|
530
|
-
pendingSpawn.pty.kill();
|
|
531
|
-
}
|
|
532
|
-
catch {
|
|
533
|
-
// ignore kill errors for pending spawns
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
const pipeline = this.pipelines.get(id);
|
|
537
|
-
if (pipeline) {
|
|
538
|
-
// Try graceful shutdown via SIGINT first
|
|
539
|
-
const cancel = this.cancelTokens.get(id);
|
|
540
|
-
if (cancel) {
|
|
541
|
-
cancel.cancel();
|
|
542
|
-
}
|
|
543
|
-
pipeline.destroy();
|
|
544
|
-
this.pipelines.delete(id);
|
|
545
|
-
this.cancelTokens.delete(id);
|
|
546
|
-
}
|
|
361
|
+
await this.runtimeCoordinator.cancelTurn(id).catch((error) => {
|
|
362
|
+
this.logSessionError('session.runtimeCancel', error, { sessionId: id });
|
|
363
|
+
});
|
|
364
|
+
await this.runtimeCoordinator.disposeSession(id).catch((error) => {
|
|
365
|
+
this.logSessionError('session.runtimeDispose', error, { sessionId: id });
|
|
366
|
+
});
|
|
547
367
|
const msgStore = sessionMsgStoreManager.get(id);
|
|
548
368
|
if (msgStore) {
|
|
549
369
|
msgStore.pushFinished();
|
|
@@ -568,19 +388,21 @@ export class SessionManager {
|
|
|
568
388
|
await this.teamReconciler.handleSessionStopped(id);
|
|
569
389
|
}
|
|
570
390
|
this.eventBus.emit('session:stopped', { sessionId: id });
|
|
571
|
-
//
|
|
572
|
-
//
|
|
573
|
-
// 因此在这里释放 MsgStore。快照已在上方持久化(CANCELLED)。
|
|
391
|
+
// Cancellation does not run normal terminal finalization, so release the
|
|
392
|
+
// store after the CANCELLED snapshot has been persisted above.
|
|
574
393
|
sessionMsgStoreManager.delete(id);
|
|
575
394
|
this.releaseSnapshotPersistenceState(id);
|
|
576
395
|
return session;
|
|
577
396
|
}
|
|
578
|
-
/**
|
|
579
|
-
* 是否仍持有该 session 的活跃 PTY pipeline。
|
|
580
|
-
* 供 TeamRun 心跳 watchdog 判断 invocation 是真卡死(pipeline 存活)还是孤儿(进程已脱管)。
|
|
581
|
-
*/
|
|
397
|
+
/** @deprecated Use hasActiveTurn(). */
|
|
582
398
|
hasActivePipeline(sessionId) {
|
|
583
|
-
return this.
|
|
399
|
+
return this.runtimeCoordinator.hasActiveTurn(sessionId);
|
|
400
|
+
}
|
|
401
|
+
hasActiveTurn(sessionId) {
|
|
402
|
+
return this.runtimeCoordinator.hasActiveTurn(sessionId);
|
|
403
|
+
}
|
|
404
|
+
isAwaitingPermission(sessionId) {
|
|
405
|
+
return this.runtimeCoordinator.isAwaitingPermission(sessionId);
|
|
584
406
|
}
|
|
585
407
|
/**
|
|
586
408
|
* 节流写入 TeamRun invocation 的心跳时间戳。非 TeamRun session 无对应 invocation,updateMany 命中 0 行无副作用。
|
|
@@ -601,37 +423,16 @@ export class SessionManager {
|
|
|
601
423
|
});
|
|
602
424
|
}
|
|
603
425
|
writeInput(sessionId, data) {
|
|
604
|
-
|
|
605
|
-
if (!pipeline)
|
|
606
|
-
return;
|
|
607
|
-
pipeline.write(data);
|
|
426
|
+
this.runtimeCoordinator.writeInput(sessionId, data);
|
|
608
427
|
}
|
|
609
428
|
resize(sessionId, cols, rows) {
|
|
610
|
-
|
|
611
|
-
if (!pipeline)
|
|
612
|
-
return;
|
|
613
|
-
pipeline.resize(cols, rows);
|
|
429
|
+
this.runtimeCoordinator.resize(sessionId, cols, rows);
|
|
614
430
|
}
|
|
615
|
-
/**
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
console.log(`[SessionManager] Destroying all ${this.pipelines.size} active pipelines`);
|
|
621
|
-
}
|
|
622
|
-
for (const [sessionId, pipeline] of this.pipelines) {
|
|
623
|
-
const cancel = this.cancelTokens.get(sessionId);
|
|
624
|
-
if (cancel) {
|
|
625
|
-
cancel.cancel();
|
|
626
|
-
}
|
|
627
|
-
pipeline.destroy();
|
|
628
|
-
}
|
|
629
|
-
this.pipelines.clear();
|
|
630
|
-
this.cancelTokens.clear();
|
|
631
|
-
for (const timer of this.logicalCompletionCleanupTimers.values()) {
|
|
632
|
-
clearTimeout(timer);
|
|
633
|
-
}
|
|
634
|
-
this.logicalCompletionCleanupTimers.clear();
|
|
431
|
+
/** Close all runtime driver sessions during graceful server shutdown. */
|
|
432
|
+
async destroyAll() {
|
|
433
|
+
await this.runtimeCoordinator.destroyAll();
|
|
434
|
+
await Promise.allSettled(this.externalSessionPersistence.values());
|
|
435
|
+
this.externalSessionPersistence.clear();
|
|
635
436
|
this.terminalSessions.clear();
|
|
636
437
|
for (const resolve of this.pendingAutoCommitResolvers.values())
|
|
637
438
|
resolve();
|
|
@@ -661,163 +462,207 @@ export class SessionManager {
|
|
|
661
462
|
}
|
|
662
463
|
return null;
|
|
663
464
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
465
|
+
async startRuntimeTurn(session, prompt, resumeExternalSessionId, providerId = session.providerId) {
|
|
466
|
+
const workingDir = this.getExecutionWorkingDir(session);
|
|
467
|
+
const env = ExecutionEnv.default(workingDir);
|
|
468
|
+
if (providerId) {
|
|
469
|
+
const provider = getProviderById(providerId);
|
|
470
|
+
if (provider && Object.keys(provider.env).length > 0) {
|
|
471
|
+
env.merge(filterAgentSubprocessExternalEnv(provider.env));
|
|
472
|
+
}
|
|
670
473
|
}
|
|
671
|
-
|
|
672
|
-
|
|
474
|
+
this.injectAgentTowerMcpServiceEnv(env);
|
|
475
|
+
if (!this.isConversationSession(session)) {
|
|
476
|
+
await this.injectTeamRunInvocationEnv(session.id, env);
|
|
673
477
|
}
|
|
674
|
-
|
|
675
|
-
|
|
478
|
+
const isNewStore = !sessionMsgStoreManager.has(session.id);
|
|
479
|
+
const msgStore = sessionMsgStoreManager.getOrCreate(session.id);
|
|
480
|
+
if (isNewStore && session.logSnapshot) {
|
|
481
|
+
try {
|
|
482
|
+
msgStore.restoreFromSnapshot(JSON.parse(session.logSnapshot));
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
this.logSessionError('session.snapshotRestore', error, { sessionId: session.id });
|
|
486
|
+
}
|
|
676
487
|
}
|
|
677
|
-
return executor;
|
|
678
|
-
}
|
|
679
|
-
async activateSpawnedSession(sessionId, agentType, workingDir, spawnResult) {
|
|
680
488
|
try {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
489
|
+
// Session status follows the logical Runtime turn, not the lifetime of
|
|
490
|
+
// its backing OS process. ACP reuses one adapter process across turns,
|
|
491
|
+
// so a follow-up must become RUNNING even when no process starts.
|
|
492
|
+
await prisma.session.update({
|
|
493
|
+
where: { id: session.id },
|
|
494
|
+
data: { status: SessionStatus.RUNNING },
|
|
495
|
+
});
|
|
496
|
+
const handle = await this.runtimeCoordinator.startTurn({
|
|
497
|
+
towerSessionId: session.id,
|
|
498
|
+
agentType: session.agentType,
|
|
499
|
+
runtimeType: this.normalizeRuntimeType(session.runtimeType),
|
|
500
|
+
variant: session.variant ?? 'DEFAULT',
|
|
501
|
+
providerId,
|
|
502
|
+
workingDir,
|
|
503
|
+
env,
|
|
504
|
+
externalSessionId: session.externalSessionId,
|
|
505
|
+
msgStore,
|
|
506
|
+
prompt,
|
|
507
|
+
resumeExternalSessionId,
|
|
508
|
+
});
|
|
509
|
+
// Terminal persistence is driven by Runtime turn events. Attach a catch
|
|
510
|
+
// so the public start/message methods do not leave a rejected handle
|
|
511
|
+
// unobserved after they have returned to the HTTP caller.
|
|
512
|
+
void handle.completion.catch(() => undefined);
|
|
513
|
+
this.eventBus.emit('session:started', { sessionId: session.id });
|
|
514
|
+
await this.checkTaskAutoRevert(session.id);
|
|
686
515
|
}
|
|
687
516
|
catch (error) {
|
|
688
|
-
await this.
|
|
689
|
-
|
|
517
|
+
await this.runtimeCoordinator.disposeSession(session.id).catch(() => undefined);
|
|
518
|
+
await prisma.session.update({
|
|
519
|
+
where: { id: session.id },
|
|
520
|
+
data: { status: SessionStatus.CANCELLED },
|
|
521
|
+
}).catch(() => undefined);
|
|
522
|
+
sessionMsgStoreManager.delete(session.id);
|
|
523
|
+
this.releaseSnapshotPersistenceState(session.id);
|
|
524
|
+
this.logSessionError('session.runtimeStart', error, {
|
|
525
|
+
sessionId: session.id,
|
|
526
|
+
agentType: session.agentType,
|
|
527
|
+
runtimeType: session.runtimeType,
|
|
528
|
+
providerId,
|
|
529
|
+
workingDir,
|
|
530
|
+
});
|
|
531
|
+
throw normalizeExecutorStartError(error);
|
|
690
532
|
}
|
|
691
533
|
}
|
|
692
|
-
|
|
693
|
-
const
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
// 重放的 exit 会让 pipeline 在构造期间就自毁;已死的 pipeline 不能进 map,
|
|
699
|
-
// 否则 hasActivePipeline 会误报存活。
|
|
700
|
-
if (pipeline.isAlive) {
|
|
701
|
-
this.pipelines.set(sessionId, pipeline);
|
|
702
|
-
if (spawnResult.cancel) {
|
|
703
|
-
this.cancelTokens.set(sessionId, spawnResult.cancel);
|
|
704
|
-
}
|
|
534
|
+
handleRuntimeTurnEvent(envelope) {
|
|
535
|
+
const sessionId = envelope.towerSessionId;
|
|
536
|
+
const event = envelope.event;
|
|
537
|
+
if (event.type === 'stdout') {
|
|
538
|
+
this.eventBus.emit('session:stdout', { sessionId, data: event.data });
|
|
539
|
+
return;
|
|
705
540
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
541
|
+
if (event.type === 'conversation_patch') {
|
|
542
|
+
this.eventBus.emit('session:patch', { sessionId, patch: event.patch, seq: event.seq });
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (event.type === 'external_session_id') {
|
|
546
|
+
const previous = this.externalSessionPersistence.get(sessionId) ?? Promise.resolve();
|
|
547
|
+
const persistence = previous
|
|
548
|
+
.then(() => this.enqueueSessionPersistenceWrite(async () => {
|
|
549
|
+
await prisma.session.update({
|
|
712
550
|
where: { id: sessionId },
|
|
713
|
-
|
|
551
|
+
data: { externalSessionId: event.externalSessionId },
|
|
714
552
|
});
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
if (!session.workspace) {
|
|
725
|
-
throw new NotFoundError('Workspace', session.workspaceId ?? sessionId);
|
|
726
|
-
}
|
|
727
|
-
ensureTaskNotDeleted(session.workspace.task);
|
|
553
|
+
}))
|
|
554
|
+
.then(() => undefined)
|
|
555
|
+
.catch((error) => {
|
|
556
|
+
this.logSessionError('session.externalSessionId', error, { sessionId });
|
|
557
|
+
});
|
|
558
|
+
this.externalSessionPersistence.set(sessionId, persistence);
|
|
559
|
+
void persistence.finally(() => {
|
|
560
|
+
if (this.externalSessionPersistence.get(sessionId) === persistence) {
|
|
561
|
+
this.externalSessionPersistence.delete(sessionId);
|
|
728
562
|
}
|
|
729
|
-
await tx.session.update({
|
|
730
|
-
where: { id: sessionId },
|
|
731
|
-
data: { status: SessionStatus.RUNNING },
|
|
732
|
-
});
|
|
733
|
-
await tx.executionProcess.create({
|
|
734
|
-
data: {
|
|
735
|
-
sessionId,
|
|
736
|
-
pid: spawnResult.pid,
|
|
737
|
-
},
|
|
738
|
-
});
|
|
739
563
|
});
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
564
|
+
this.eventBus.emit('session:sessionId', {
|
|
565
|
+
sessionId,
|
|
566
|
+
agentSessionId: event.externalSessionId,
|
|
743
567
|
});
|
|
744
|
-
|
|
745
|
-
throw new NotFoundError('Session', sessionId);
|
|
746
|
-
}
|
|
747
|
-
if (this.isConversationSession(session)) {
|
|
748
|
-
if (!session.conversation || session.conversation.deletedAt) {
|
|
749
|
-
throw new NotFoundError('Conversation', session.conversationId ?? sessionId);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
else {
|
|
753
|
-
if (!session.workspace) {
|
|
754
|
-
throw new NotFoundError('Workspace', session.workspaceId ?? sessionId);
|
|
755
|
-
}
|
|
756
|
-
ensureTaskNotDeleted(session.workspace.task);
|
|
757
|
-
}
|
|
758
|
-
if (this.pendingSpawns.get(sessionId) !== spawnResult) {
|
|
759
|
-
throw new NotFoundError(this.isConversationSession(session) ? 'Conversation' : 'Task', this.isConversationSession(session)
|
|
760
|
-
? (session.conversationId ?? sessionId)
|
|
761
|
-
: (session.workspace?.task.id ?? sessionId));
|
|
762
|
-
}
|
|
568
|
+
return;
|
|
763
569
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
570
|
+
if (event.type === 'permission_requested') {
|
|
571
|
+
this.eventBus.emit('session:permission_requested', {
|
|
572
|
+
sessionId,
|
|
573
|
+
permission: event.request,
|
|
574
|
+
});
|
|
575
|
+
return;
|
|
767
576
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
577
|
+
if (event.type === 'permission_invalidated') {
|
|
578
|
+
this.eventBus.emit('session:permission_invalidated', {
|
|
579
|
+
sessionId,
|
|
580
|
+
turnId: envelope.turnId,
|
|
581
|
+
requestId: event.requestId,
|
|
582
|
+
});
|
|
583
|
+
return;
|
|
772
584
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
catch {
|
|
779
|
-
// Continue with explicit PTY cancellation even if pipeline teardown fails.
|
|
780
|
-
}
|
|
781
|
-
this.pipelines.delete(sessionId);
|
|
782
|
-
this.cancelTokens.delete(sessionId);
|
|
585
|
+
if (event.type === 'completed') {
|
|
586
|
+
this.eventBus.emit('session:turn-completed', { sessionId });
|
|
587
|
+
this.eventBus.emit('session:exit', { sessionId, exitCode: 0 });
|
|
588
|
+
return;
|
|
783
589
|
}
|
|
784
|
-
|
|
785
|
-
|
|
590
|
+
if (event.type === 'failed') {
|
|
591
|
+
this.eventBus.emit('session:turn-failed', { sessionId });
|
|
592
|
+
this.eventBus.emit('session:exit', { sessionId, exitCode: 1 });
|
|
786
593
|
}
|
|
787
|
-
|
|
788
|
-
|
|
594
|
+
}
|
|
595
|
+
handleRuntimeState(state) {
|
|
596
|
+
setRuntimeStateSnapshot(state);
|
|
597
|
+
this.eventBus.emit('session:runtime_state_changed', {
|
|
598
|
+
sessionId: state.sessionId,
|
|
599
|
+
state,
|
|
600
|
+
});
|
|
601
|
+
const awaitingPermission = state.turnState === 'AWAITING_PERMISSION';
|
|
602
|
+
const previous = this.runtimePermissionStates.get(state.sessionId) ?? false;
|
|
603
|
+
if (state.turnState === 'DISPOSED') {
|
|
604
|
+
this.runtimePermissionStates.delete(state.sessionId);
|
|
789
605
|
}
|
|
790
|
-
|
|
791
|
-
|
|
606
|
+
else {
|
|
607
|
+
this.runtimePermissionStates.set(state.sessionId, awaitingPermission);
|
|
792
608
|
}
|
|
793
|
-
|
|
794
|
-
|
|
609
|
+
if (previous !== awaitingPermission) {
|
|
610
|
+
void this.invalidateTeamRunRuntimeState(state.sessionId);
|
|
795
611
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
612
|
+
}
|
|
613
|
+
async invalidateTeamRunRuntimeState(sessionId) {
|
|
614
|
+
const invocation = await prisma.agentInvocation.findFirst({
|
|
615
|
+
where: { sessionId },
|
|
616
|
+
select: {
|
|
617
|
+
teamRunId: true,
|
|
618
|
+
teamRun: { select: { taskId: true, task: { select: { projectId: true } } } },
|
|
619
|
+
},
|
|
801
620
|
});
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
621
|
+
if (!invocation)
|
|
622
|
+
return;
|
|
623
|
+
this.eventBus.emit('team-run:invalidated', {
|
|
624
|
+
teamRunId: invocation.teamRunId,
|
|
625
|
+
taskId: invocation.teamRun.taskId,
|
|
626
|
+
projectId: invocation.teamRun.task.projectId,
|
|
627
|
+
scopes: ['team-members', 'agent-invocations', 'team-run'],
|
|
628
|
+
reason: 'agent-invocation-updated',
|
|
806
629
|
});
|
|
807
|
-
// 补偿路径同样释放 MsgStore(sendMessage 在 spawn 前已 getOrCreate)
|
|
808
|
-
sessionMsgStoreManager.delete(sessionId);
|
|
809
630
|
}
|
|
810
|
-
|
|
811
|
-
if (
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
631
|
+
async handleRuntimeProcessEvent(event) {
|
|
632
|
+
if (event.type === 'started') {
|
|
633
|
+
const processRecord = await prisma.$transaction(async (tx) => {
|
|
634
|
+
const session = await tx.session.findUnique({
|
|
635
|
+
where: { id: event.towerSessionId },
|
|
636
|
+
include: { workspace: { include: { task: true } }, conversation: true },
|
|
637
|
+
});
|
|
638
|
+
if (!session)
|
|
639
|
+
throw new NotFoundError('Session', event.towerSessionId);
|
|
640
|
+
this.ensureExecutionRecordIsLive(session);
|
|
641
|
+
return tx.executionProcess.create({
|
|
642
|
+
data: { sessionId: event.towerSessionId, pid: event.pid },
|
|
643
|
+
select: { id: true },
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
this.runtimeProcessIds.set(event.runtimeInstanceId, processRecord.id);
|
|
647
|
+
return;
|
|
819
648
|
}
|
|
820
|
-
|
|
649
|
+
const processId = this.runtimeProcessIds.get(event.runtimeInstanceId);
|
|
650
|
+
if (!processId)
|
|
651
|
+
return;
|
|
652
|
+
this.runtimeProcessIds.delete(event.runtimeInstanceId);
|
|
653
|
+
await prisma.executionProcess.update({
|
|
654
|
+
where: { id: processId },
|
|
655
|
+
data: { exitCode: event.exitCode },
|
|
656
|
+
}).catch((error) => {
|
|
657
|
+
this.logSessionError('session.processExit', error, {
|
|
658
|
+
sessionId: event.towerSessionId,
|
|
659
|
+
processId,
|
|
660
|
+
exitCode: event.exitCode,
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
normalizeRuntimeType(value) {
|
|
665
|
+
return value === RuntimeType.ACP ? RuntimeType.ACP : RuntimeType.CLI;
|
|
821
666
|
}
|
|
822
667
|
injectAgentTowerMcpServiceEnv(env) {
|
|
823
668
|
const serviceEnv = {};
|
|
@@ -954,7 +799,7 @@ export class SessionManager {
|
|
|
954
799
|
.catch(() => {
|
|
955
800
|
// Keep the chain alive even if previous flush failed.
|
|
956
801
|
})
|
|
957
|
-
.then(() => this.
|
|
802
|
+
.then(() => this.enqueueSessionPersistenceWrite(() => this.persistSnapshot(sessionId)));
|
|
958
803
|
this.snapshotFlushChains.set(sessionId, current);
|
|
959
804
|
try {
|
|
960
805
|
await current;
|
|
@@ -965,19 +810,19 @@ export class SessionManager {
|
|
|
965
810
|
}
|
|
966
811
|
}
|
|
967
812
|
}
|
|
968
|
-
async
|
|
969
|
-
const queued = this.
|
|
813
|
+
async enqueueSessionPersistenceWrite(write) {
|
|
814
|
+
const queued = this.sessionPersistenceWriterChain
|
|
970
815
|
.catch(() => {
|
|
971
816
|
// Keep the global writer alive after an isolated persistence failure.
|
|
972
817
|
})
|
|
973
818
|
.then(write);
|
|
974
|
-
this.
|
|
819
|
+
this.sessionPersistenceWriterChain = queued;
|
|
975
820
|
try {
|
|
976
821
|
await queued;
|
|
977
822
|
}
|
|
978
823
|
finally {
|
|
979
|
-
if (this.
|
|
980
|
-
this.
|
|
824
|
+
if (this.sessionPersistenceWriterChain === queued) {
|
|
825
|
+
this.sessionPersistenceWriterChain = Promise.resolve();
|
|
981
826
|
}
|
|
982
827
|
}
|
|
983
828
|
}
|
|
@@ -1201,6 +1046,7 @@ export class SessionManager {
|
|
|
1201
1046
|
*/
|
|
1202
1047
|
async handleSessionExit(sessionId, exitCode, options = {}) {
|
|
1203
1048
|
const generation = options.generation ?? this.sessionGenerations.get(sessionId);
|
|
1049
|
+
await this.externalSessionPersistence.get(sessionId);
|
|
1204
1050
|
const session = await prisma.session.findUnique({
|
|
1205
1051
|
where: { id: sessionId },
|
|
1206
1052
|
select: { purpose: true, context: true, conversationId: true },
|
|
@@ -1333,7 +1179,6 @@ export class SessionManager {
|
|
|
1333
1179
|
}
|
|
1334
1180
|
clearTerminalState(sessionId) {
|
|
1335
1181
|
this.terminalSessions.delete(sessionId);
|
|
1336
|
-
this.clearLogicalCompletionCleanup(sessionId);
|
|
1337
1182
|
}
|
|
1338
1183
|
startSessionFinalization(sessionId, exitCode, options = {}) {
|
|
1339
1184
|
if (options.logicalCompletion) {
|
|
@@ -1362,10 +1207,6 @@ export class SessionManager {
|
|
|
1362
1207
|
this.sessionFinalizations.set(sessionId, finalization);
|
|
1363
1208
|
}
|
|
1364
1209
|
maybeClearTerminalState(sessionId) {
|
|
1365
|
-
if (this.pipelines.has(sessionId))
|
|
1366
|
-
return;
|
|
1367
|
-
if (this.logicalCompletionCleanupTimers.has(sessionId))
|
|
1368
|
-
return;
|
|
1369
1210
|
if (this.sessionFinalizations.has(sessionId))
|
|
1370
1211
|
return;
|
|
1371
1212
|
this.terminalSessions.delete(sessionId);
|
|
@@ -1426,30 +1267,6 @@ export class SessionManager {
|
|
|
1426
1267
|
return;
|
|
1427
1268
|
}
|
|
1428
1269
|
}
|
|
1429
|
-
destroyActivePipeline(sessionId) {
|
|
1430
|
-
const pipeline = this.pipelines.get(sessionId);
|
|
1431
|
-
if (pipeline) {
|
|
1432
|
-
pipeline.destroy();
|
|
1433
|
-
this.pipelines.delete(sessionId);
|
|
1434
|
-
}
|
|
1435
|
-
this.cancelTokens.delete(sessionId);
|
|
1436
|
-
this.heartbeatThrottle.delete(sessionId);
|
|
1437
|
-
}
|
|
1438
|
-
clearLogicalCompletionCleanup(sessionId) {
|
|
1439
|
-
const timer = this.logicalCompletionCleanupTimers.get(sessionId);
|
|
1440
|
-
if (timer)
|
|
1441
|
-
clearTimeout(timer);
|
|
1442
|
-
this.logicalCompletionCleanupTimers.delete(sessionId);
|
|
1443
|
-
}
|
|
1444
|
-
scheduleLogicalCompletionCleanup(sessionId) {
|
|
1445
|
-
this.clearLogicalCompletionCleanup(sessionId);
|
|
1446
|
-
const timer = setTimeout(() => {
|
|
1447
|
-
this.logicalCompletionCleanupTimers.delete(sessionId);
|
|
1448
|
-
this.destroyActivePipeline(sessionId);
|
|
1449
|
-
this.maybeClearTerminalState(sessionId);
|
|
1450
|
-
}, SessionManager.CODEX_TURN_COMPLETION_GRACE_MS);
|
|
1451
|
-
this.logicalCompletionCleanupTimers.set(sessionId, timer);
|
|
1452
|
-
}
|
|
1453
1270
|
logSessionError(source, error, metadata) {
|
|
1454
1271
|
writeErrorLog({
|
|
1455
1272
|
level: 'error',
|