@maudecode/talaria-web 1.19.0 → 1.21.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/_release.json +8 -8
- package/dist/api/automation-raw.js +61 -6
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +309 -2
- package/dist/api/automation-router.js +28 -2
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +646 -24
- package/dist/api/chat-router.js +54 -167
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +54 -0
- package/dist/api/git-router.js +18 -5
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.js +13 -1
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +3 -3
- package/dist/api/session-visibility.js +2 -2
- package/dist/api/session-visibility.js.map +1 -1
- package/dist/api/sessions-router.d.ts +1868 -79
- package/dist/api/sessions-router.js +72 -43
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +34 -13
- package/dist/api/settings-router.js +54 -17
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.js +45 -21
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-router.d.ts +773 -39
- package/dist/api/tools-router.js +167 -45
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.js +15 -11
- package/dist/app.js.map +1 -1
- package/dist/auth/crypto.d.ts +3 -0
- package/dist/auth/crypto.js +18 -0
- package/dist/auth/crypto.js.map +1 -1
- package/dist/auth/gate.js +5 -1
- package/dist/auth/gate.js.map +1 -1
- package/dist/cli/ctl.js +6 -1
- package/dist/cli/ctl.js.map +1 -1
- package/dist/cli/main.js +23 -18
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/supervise.d.ts +22 -0
- package/dist/cli/supervise.js +80 -2
- package/dist/cli/supervise.js.map +1 -1
- package/dist/config/agent-config.d.ts +3 -0
- package/dist/config/agent-config.js +36 -9
- package/dist/config/agent-config.js.map +1 -1
- package/dist/fs/atomic.d.ts +3 -0
- package/dist/fs/atomic.js +19 -5
- package/dist/fs/atomic.js.map +1 -1
- package/dist/fs/stat.d.ts +6 -0
- package/dist/fs/stat.js +18 -2
- package/dist/fs/stat.js.map +1 -1
- package/dist/http/context.d.ts +16 -0
- package/dist/http/context.js +48 -5
- package/dist/http/context.js.map +1 -1
- package/dist/profiles/profiles.d.ts +2 -0
- package/dist/profiles/profiles.js +1 -0
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/providers/catalog.d.ts +11 -6
- package/dist/providers/catalog.js +76 -24
- package/dist/providers/catalog.js.map +1 -1
- package/dist/redact.d.ts +2 -0
- package/dist/redact.js +55 -16
- package/dist/redact.js.map +1 -1
- package/dist/release.js +5 -3
- package/dist/release.js.map +1 -1
- package/dist/runtime.js +118 -26
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +25 -21
- package/dist/server.js.map +1 -1
- package/dist/sessions/admission.d.ts +21 -0
- package/dist/sessions/admission.js +176 -0
- package/dist/sessions/admission.js.map +1 -0
- package/dist/sessions/anchor.d.ts +4 -1
- package/dist/sessions/anchor.js +9 -5
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +41 -3
- package/dist/sessions/background-tasks.js +110 -10
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/cli-sessions.d.ts +9 -2
- package/dist/sessions/cli-sessions.js +38 -57
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +8 -0
- package/dist/sessions/completions.js +55 -25
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/events.d.ts +3 -0
- package/dist/sessions/events.js +4 -0
- package/dist/sessions/events.js.map +1 -1
- package/dist/sessions/export.d.ts +2 -0
- package/dist/sessions/export.js +6 -2
- package/dist/sessions/export.js.map +1 -1
- package/dist/sessions/gateway-sessions.d.ts +92 -4
- package/dist/sessions/gateway-sessions.js +762 -93
- package/dist/sessions/gateway-sessions.js.map +1 -1
- package/dist/sessions/gateway-watcher.d.ts +10 -11
- package/dist/sessions/gateway-watcher.js +25 -21
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/list.d.ts +9 -2
- package/dist/sessions/list.js +38 -26
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +12 -5
- package/dist/sessions/merge.js +65 -18
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +15 -4
- package/dist/sessions/prefix-index.js +35 -13
- package/dist/sessions/prefix-index.js.map +1 -1
- package/dist/sessions/prompt-queues.d.ts +36 -0
- package/dist/sessions/prompt-queues.js +318 -0
- package/dist/sessions/prompt-queues.js.map +1 -0
- package/dist/sessions/recovery.d.ts +1 -1
- package/dist/sessions/recovery.js +4 -3
- package/dist/sessions/recovery.js.map +1 -1
- package/dist/sessions/relay.d.ts +12 -1
- package/dist/sessions/relay.js +75 -17
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +132 -37
- package/dist/sessions/service.js +688 -160
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +2 -0
- package/dist/sessions/session.js +5 -0
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/state-db-worker.js +22 -5
- package/dist/sessions/state-db-worker.js.map +1 -1
- package/dist/sessions/state-db.d.ts +106 -15
- package/dist/sessions/state-db.js +651 -236
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/state-saved.d.ts +1 -1
- package/dist/sessions/state-saved.js +35 -11
- package/dist/sessions/state-saved.js.map +1 -1
- package/dist/sessions/storage/backend.d.ts +10 -1
- package/dist/sessions/storage/backend.js.map +1 -1
- package/dist/sessions/storage/conformance.js +1 -1
- package/dist/sessions/storage/conformance.js.map +1 -1
- package/dist/sessions/storage/json-documents.d.ts +2 -0
- package/dist/sessions/storage/json-documents.js +71 -26
- package/dist/sessions/storage/json-documents.js.map +1 -1
- package/dist/sessions/storage/json-files.d.ts +13 -2
- package/dist/sessions/storage/json-files.js +126 -6
- package/dist/sessions/storage/json-files.js.map +1 -1
- package/dist/sessions/storage/json-journal.d.ts +6 -7
- package/dist/sessions/storage/json-journal.js +143 -73
- package/dist/sessions/storage/json-journal.js.map +1 -1
- package/dist/sessions/storage/json.d.ts +15 -1
- package/dist/sessions/storage/json.js +125 -33
- package/dist/sessions/storage/json.js.map +1 -1
- package/dist/sessions/store.d.ts +6 -1
- package/dist/sessions/store.js +68 -27
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +10 -7
- package/dist/sessions/streams.js +49 -14
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +11 -2
- package/dist/sessions/tool-display.js +45 -4
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn-context.js +6 -2
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +27 -6
- package/dist/sessions/turn.js +186 -89
- package/dist/sessions/turn.js.map +1 -1
- package/dist/sidecar/client.d.ts +24 -1
- package/dist/sidecar/client.js +118 -38
- package/dist/sidecar/client.js.map +1 -1
- package/dist/sidecar/fake.d.ts +6 -2
- package/dist/sidecar/fake.js +15 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/spa.d.ts +9 -4
- package/dist/spa.js +36 -12
- package/dist/spa.js.map +1 -1
- package/dist/startup-timing.d.ts +66 -0
- package/dist/startup-timing.js +129 -0
- package/dist/startup-timing.js.map +1 -0
- package/dist/test/fs-handles.d.ts +11 -0
- package/dist/test/fs-handles.js +31 -0
- package/dist/test/fs-handles.js.map +1 -0
- package/dist/tools/connectors.d.ts +1 -1
- package/dist/tools/connectors.js +2 -2
- package/dist/tools/connectors.js.map +1 -1
- package/dist/tools/crons.d.ts +8 -4
- package/dist/tools/crons.js +25 -18
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/dashboard-plugins.d.ts +29 -0
- package/dist/tools/dashboard-plugins.js +132 -0
- package/dist/tools/dashboard-plugins.js.map +1 -1
- package/dist/tools/gateway-restart.d.ts +25 -5
- package/dist/tools/gateway-restart.js +103 -23
- package/dist/tools/gateway-restart.js.map +1 -1
- package/dist/tools/health.d.ts +13 -1
- package/dist/tools/health.js +80 -22
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/insights.d.ts +1 -1
- package/dist/tools/insights.js +2 -2
- package/dist/tools/insights.js.map +1 -1
- package/dist/tools/kanban.d.ts +10 -1
- package/dist/tools/kanban.js +73 -1
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp-health.js +74 -24
- package/dist/tools/mcp-health.js.map +1 -1
- package/dist/tools/mcp.d.ts +3 -1
- package/dist/tools/mcp.js +92 -1
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/memory.d.ts +28 -0
- package/dist/tools/memory.js +120 -14
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/plugin-oauth.d.ts +14 -0
- package/dist/tools/plugin-oauth.js +53 -0
- package/dist/tools/plugin-oauth.js.map +1 -0
- package/dist/tools/prune-advice.d.ts +50 -0
- package/dist/tools/prune-advice.js +114 -0
- package/dist/tools/prune-advice.js.map +1 -0
- package/dist/tools/skills.d.ts +5 -2
- package/dist/tools/skills.js +9 -6
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/update-notifications.d.ts +77 -9
- package/dist/tools/update-notifications.js +390 -46
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/updates.d.ts +29 -3
- package/dist/tools/updates.js +166 -34
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/managed-buffers.d.ts +58 -0
- package/dist/workspace/managed-buffers.js +76 -0
- package/dist/workspace/managed-buffers.js.map +1 -0
- package/dist/workspace/media.js +69 -20
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/preview.js +4 -14
- package/dist/workspace/preview.js.map +1 -1
- package/dist/workspace/rollback.d.ts +6 -2
- package/dist/workspace/rollback.js +18 -8
- package/dist/workspace/rollback.js.map +1 -1
- package/package.json +3 -3
- package/sidecar/agent_dependency.json +4 -4
- package/sidecar/agent_support.json +30 -15
- package/sidecar/scripts/suite_runner.py +183 -27
- package/sidecar/scripts/test.sh +5 -7
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/__main__.py +10 -3
- package/sidecar/talaria_sidecar/agent_mutation.py +246 -32
- package/sidecar/talaria_sidecar/agent_services.py +157 -34
- package/sidecar/talaria_sidecar/context_detail.py +59 -0
- package/sidecar/talaria_sidecar/home.py +97 -20
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +80 -18
- package/sidecar/talaria_sidecar/methods/chat.py +571 -106
- package/sidecar/talaria_sidecar/methods/checkpoints.py +29 -4
- package/sidecar/talaria_sidecar/methods/commands.py +277 -16
- package/sidecar/talaria_sidecar/methods/config.py +73 -3
- package/sidecar/talaria_sidecar/methods/connectors.py +45 -13
- package/sidecar/talaria_sidecar/methods/cron.py +8 -2
- package/sidecar/talaria_sidecar/methods/dashboard_plugins.py +301 -0
- package/sidecar/talaria_sidecar/methods/gateway.py +24 -4
- package/sidecar/talaria_sidecar/methods/gateway_sessions.py +304 -30
- package/sidecar/talaria_sidecar/methods/kanban.py +50 -3
- package/sidecar/talaria_sidecar/methods/managed_buffers.py +110 -0
- package/sidecar/talaria_sidecar/methods/mcp.py +55 -0
- package/sidecar/talaria_sidecar/methods/oauth.py +139 -11
- package/sidecar/talaria_sidecar/methods/outbound_drafts.py +165 -0
- package/sidecar/talaria_sidecar/methods/plugin_catalog.py +198 -0
- package/sidecar/talaria_sidecar/methods/plugin_oauth.py +234 -0
- package/sidecar/talaria_sidecar/methods/process.py +70 -6
- package/sidecar/talaria_sidecar/methods/profiles.py +4 -3
- package/sidecar/talaria_sidecar/methods/runtime.py +2 -0
- package/sidecar/talaria_sidecar/methods/skills.py +22 -7
- package/sidecar/talaria_sidecar/methods/state_db.py +128 -42
- package/sidecar/talaria_sidecar/methods/toolsets.py +4 -2
- package/sidecar/talaria_sidecar/methods/worktree.py +121 -2
- package/sidecar/talaria_sidecar/rpc.py +25 -3
- package/sidecar/talaria_sidecar/runtime.py +42 -3
- package/sidecar/talaria_sidecar/speed.py +13 -1
- package/sidecar/talaria_sidecar/startup_timing.py +119 -0
- package/static/dist/FILES.txt +240 -213
- package/static/dist/THIRD_PARTY_LICENSES.md +6 -22
- package/static/dist/assets/AppShell-c5989995.js +8 -0
- package/static/dist/assets/Button-nuaikybd.js +1 -0
- package/static/dist/assets/ChatPage-bfg4khph.js +6 -0
- package/static/dist/assets/ConnectTargets-k5wo9yo8.js +1 -0
- package/static/dist/assets/Dialog-o8vo2aws.js +1 -0
- package/static/dist/assets/ExtensionRoute-l1yjrso4.js +1 -0
- package/static/dist/assets/Field-j7o8cfps.js +1 -0
- package/static/dist/assets/HubRoute-efnwe4xz.js +2 -0
- package/static/dist/assets/LinkCheckContext-ix6zqqkk.js +1 -0
- package/static/dist/assets/Markdown-clqf5m22.js +2 -0
- package/static/dist/assets/MarkdownRenderer-ccgqrza3.js +302 -0
- package/static/dist/assets/MarkdownRenderer-i9o6nr38.css +1 -0
- package/static/dist/assets/OAuthSignIn-h7bjaqp6.js +1 -0
- package/static/dist/assets/ResourceSwitch-oai2zqaj.js +1 -0
- package/static/dist/assets/RightPanel-ho161a45.js +1 -0
- package/static/dist/assets/Select-d1g5a8bm.js +1 -0
- package/static/dist/assets/SessionListPanel-i7kaokhi.js +1 -0
- package/static/dist/assets/SettingsLayout-lnecm87w.js +1 -0
- package/static/dist/assets/States-easntmry.js +1 -0
- package/static/dist/assets/TerminalPanel-lxhwd4jl.js +16 -0
- package/static/dist/assets/Toaster-l4sciy8t.js +1 -0
- package/static/dist/assets/_app-mqexqbg8.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-n797jp72.js +1 -0
- package/static/dist/assets/_app.index-ne43mdw2.js +1 -0
- package/static/dist/assets/_app.insights-fqonovb4.js +1 -0
- package/static/dist/assets/_app.kanban-kysliv19.js +1 -0
- package/static/dist/assets/_app.logs-febut82r.js +1 -0
- package/static/dist/assets/_app.memory-ha86oj1c.js +1 -0
- package/static/dist/assets/_app.profiles-cnu3gxxq.js +1 -0
- package/static/dist/assets/_app.session._sessionId-ifzjpcgn.js +1 -0
- package/static/dist/assets/_app.settings-nmakdiaf.js +1 -0
- package/static/dist/assets/_app.settings._section-djglnjmi.js +3 -0
- package/static/dist/assets/_app.skills-f3wad8yo.js +1 -0
- package/static/dist/assets/_app.tasks-l10py1c0.js +1 -0
- package/static/dist/assets/_app.todos-bml1m3r1.js +1 -0
- package/static/dist/assets/_app.workspaces-f3d066lx.js +1 -0
- package/static/dist/assets/abnfDiagram-VCTEODGH-i53jc4yp.js +1 -0
- package/static/dist/assets/{angular-html-nu6l31w3.js → angular-html-l28bd5fo.js} +1 -1
- package/static/dist/assets/{angular-ts-fbx4f8mm.js → angular-ts-ffzx1vj0.js} +1 -1
- package/static/dist/assets/{apl-bx2xr7dh.js → apl-b7h7mmy4.js} +1 -1
- package/static/dist/assets/{arc-7popfhbk.js → arc-fk1b21lm.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-e3bv5m6f.js +1 -0
- package/static/dist/assets/architectureDiagram-5GKGNRK7-pakekxu2.js +36 -0
- package/static/dist/assets/archive-ihqi7z2x.js +1 -0
- package/static/dist/assets/{astro-g77i97cb.js → astro-k117fy0t.js} +1 -1
- package/static/dist/assets/back-gu3nu279.js +1 -0
- package/static/dist/assets/{blade-boo0u92y.js → blade-npefsmn8.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-joedghi3.js → blockDiagram-I7D4REHJ-bc6bo1n6.js} +4 -4
- package/static/dist/assets/{c-cat0w3sc.js → c-2umg6kbn.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-hyrjrohe.js → c4Diagram-7LVT6UL2-btvwk2qx.js} +1 -1
- package/static/dist/assets/channel-jn4f8443.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-koouqbut.js → chunk-4HAMMTFA-dlwab11c.js} +20 -20
- package/static/dist/assets/{chunk-75Z2AOVW-bl4bhdnt.js → chunk-75Z2AOVW-dp5gh7i8.js} +1 -1
- package/static/dist/assets/chunk-DU6HZSFF-bi06zl1c.js +128 -0
- package/static/dist/assets/{chunk-F27PBJKO-d8xxi0zi.js → chunk-F27PBJKO-kvv1rnlh.js} +1 -1
- package/static/dist/assets/{chunk-FOHPRMQF-opuflp73.js → chunk-FOHPRMQF-ipewusgj.js} +8 -8
- package/static/dist/assets/{chunk-GMAD6QVW-jro0hl73.js → chunk-GMAD6QVW-ji0rx9by.js} +6 -6
- package/static/dist/assets/{chunk-GVQU2GXP-djn6gbyu.js → chunk-GVQU2GXP-nmz0j82p.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-vw4p5p7o.js → chunk-IMKFNOWR-kmi1qx88.js} +5 -5
- package/static/dist/assets/{chunk-L3NEJ4N5-n1hj77q8.js → chunk-L3NEJ4N5-xhb7mebj.js} +1 -1
- package/static/dist/assets/chunk-OSK3NFVY-5a9sgscq.js +10 -0
- package/static/dist/assets/{chunk-P2QGCYS3-onf1hz6c.js → chunk-P2QGCYS3-dfezp4vu.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-m8sqn7cs.js → chunk-POPQ4Y6H-gd2vq3c0.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-ek4smc8x.js → chunk-PWAF6VOD-wvw2nksf.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-g9gfvefo.js → chunk-SHT3W25Y-f58q97px.js} +13 -13
- package/static/dist/assets/{chunk-SVP7TREG-f9nfv2cu.js → chunk-SVP7TREG-abgwpyz9.js} +4 -4
- package/static/dist/assets/{chunk-TICWLB2K-bnk3m1mq.js → chunk-TICWLB2K-h4sbs8ds.js} +6 -6
- package/static/dist/assets/{chunk-XXDRQBXY-n40pf9vy.js → chunk-XXDRQBXY-jkmnqu65.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-dzrw66se.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-dzrw66se.js +1 -0
- package/static/dist/assets/{cobol-go622aep.js → cobol-ssf9hkh7.js} +1 -1
- package/static/dist/assets/{coffee-jwo1xjhq.js → coffee-lsi9fwae.js} +1 -1
- package/static/dist/assets/completionAudio-ce86msbu.js +1 -0
- package/static/dist/assets/copied-bz3gkazh.js +1 -0
- package/static/dist/assets/copy-m9h56qa8.js +1 -0
- package/static/dist/assets/cose-bilkent-JH36ORCC-layy2r27.js +1 -0
- package/static/dist/assets/{cpp-nre7j0kq.js → cpp-lfrh4y55.js} +1 -1
- package/static/dist/assets/{crystal-lviso2je.js → crystal-efh4pte7.js} +1 -1
- package/static/dist/assets/{css-ywz9j4hb.js → css-i82qdo89.js} +1 -1
- package/static/dist/assets/cynefin-OW5HDTMX-g081vffs.js +1 -0
- package/static/dist/assets/cynefinDiagram-5FMLGOSQ-odxvjesk.js +62 -0
- package/static/dist/assets/cytoscape.esm-fjn2algp.js +321 -0
- package/static/dist/assets/dagre-GXQ25YYZ-cpdwzjs4.js +4 -0
- package/static/dist/assets/dagre-o5jmjz46.js +1 -0
- package/static/dist/assets/{diagram-S7CK7UJ4-m6aeoe7c.js → diagram-S7CK7UJ4-clv5mxvu.js} +4 -4
- package/static/dist/assets/diagram-UQ7AKVKN-m2ia1mbf.js +41 -0
- package/static/dist/assets/{diagram-VSXAHHWV-hbawi7hn.js → diagram-VSXAHHWV-ea6zv636.js} +1 -1
- package/static/dist/assets/diagram-VX7I27RA-oqlef685.js +24 -0
- package/static/dist/assets/diagram-Z3DM3KII-kjubcbwu.js +24 -0
- package/static/dist/assets/dist-carq1azj.js +44 -0
- package/static/dist/assets/dist-crc46di9.js +7 -0
- package/static/dist/assets/{dist-c4c2m3kv.js → dist-nb670eu6.js} +1 -1
- package/static/dist/assets/ebnfDiagram-PWID7BFC-fg0zri3e.js +1 -0
- package/static/dist/assets/{edge-dvv35byi.js → edge-lrob635n.js} +1 -1
- package/static/dist/assets/{elixir-i2f1ki1g.js → elixir-kdpxeq93.js} +1 -1
- package/static/dist/assets/{elm-cpepyjm4.js → elm-c8irj9uh.js} +1 -1
- package/static/dist/assets/erDiagram-RLTQ6QDP-eb7pmk3x.js +99 -0
- package/static/dist/assets/{erb-idlyfheg.js → erb-flwsv146.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-gvi1fxhn.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-abekab15.js +1 -0
- package/static/dist/assets/folder-plus-ksaons88.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ma6jxj5i.js → ganttDiagram-EL5Y4UJY-jmisowrc.js} +1 -1
- package/static/dist/assets/{git-rebase-d9lpfpbn.js → git-rebase-bli19aoq.js} +1 -1
- package/static/dist/assets/gitGraph-4MIJSDKK-m7kt3u6e.js +1 -0
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-hzltvsod.js → gitGraphDiagram-WWUBYQGX-nq7vfzh2.js} +1 -1
- package/static/dist/assets/{glimmer-js-39i0urfb.js → glimmer-js-d4icg38p.js} +1 -1
- package/static/dist/assets/{glimmer-ts-gdtd6n73.js → glimmer-ts-bk75772u.js} +1 -1
- package/static/dist/assets/{glsl-o1djm5pp.js → glsl-lqormp2b.js} +1 -1
- package/static/dist/assets/{graphql-kj6rz55t.js → graphql-hw6s5qzd.js} +1 -1
- package/static/dist/assets/{hack-pe1qqr2i.js → hack-ozrv6l4d.js} +1 -1
- package/static/dist/assets/{haml-cknnbcqs.js → haml-gytfosdt.js} +1 -1
- package/static/dist/assets/{handlebars-hwq64orh.js → handlebars-b6g7jffd.js} +1 -1
- package/static/dist/assets/highlighted-body-KPVGNVTW-gcu017ay.js +1 -0
- package/static/dist/assets/host-ipp4e84c.js +1 -0
- package/static/dist/assets/{html-derivative-h2i2pyjc.js → html-derivative-f1tqcroo.js} +1 -1
- package/static/dist/assets/{html-ha05xtvt.js → html-on6oj6yj.js} +1 -1
- package/static/dist/assets/{http-cf94zu27.js → http-odhufsl7.js} +1 -1
- package/static/dist/assets/{hurl-lslax568.js → hurl-mu680336.js} +1 -1
- package/static/dist/assets/index-d6vbxlra.js +13 -0
- package/static/dist/assets/index-ey6qo0zx.css +2 -0
- package/static/dist/assets/info-A6RAGUB7-idazwfqe.js +1 -0
- package/static/dist/assets/infoDiagram-27XIBGKW-bb9jh8gl.js +2 -0
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-e7bnwq7h.js → ishikawaDiagram-5VMMS53U-nqc132rv.js} +6 -6
- package/static/dist/assets/{java-ndjf2o89.js → java-nxbe8uju.js} +1 -1
- package/static/dist/assets/{javascript-coftlwy3.js → javascript-lz3kxcyz.js} +1 -1
- package/static/dist/assets/{jinja-etei9wy7.js → jinja-l5pk84gt.js} +1 -1
- package/static/dist/assets/{jison-hyekgft1.js → jison-jdutdwyy.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-etd1bi6p.js → journeyDiagram-3NMN7TZE-fpvnhy44.js} +1 -1
- package/static/dist/assets/{json-lok0yaho.js → json-dnge4ssf.js} +1 -1
- package/static/dist/assets/{jsx-b64w0nbx.js → jsx-c3lwhkep.js} +1 -1
- package/static/dist/assets/{jsx-runtime-eu92a5pu.js → jsx-runtime-o40ukmjl.js} +1 -1
- package/static/dist/assets/{julia-jxxzz2yn.js → julia-hwd4rrcb.js} +1 -1
- package/static/dist/assets/{just-mc29iw9t.js → just-nka3oxdx.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-emb1g9dz.js → kanban-definition-UXKFOSKX-ndzqm6fu.js} +28 -28
- package/static/dist/assets/katex-cbdd1ohw.css +1 -0
- package/static/dist/assets/katex-pbij2oo6.js +257 -0
- package/static/dist/assets/{latex-pafa03ft.js → latex-iqmr7e40.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-javud235.js +1 -0
- package/static/dist/assets/{line-h0ojzsvs.js → line-g625e7cj.js} +1 -1
- package/static/dist/assets/linear-jlwrvvy6.js +1 -0
- package/static/dist/assets/link-gfdaho08.js +2 -0
- package/static/dist/assets/{liquid-hz5c2pov.js → liquid-okmk9tbp.js} +1 -1
- package/static/dist/assets/locale-cs-n41hptse.js +5 -0
- package/static/dist/assets/locale-de-k7ht47ew.js +5 -0
- package/static/dist/assets/locale-es-ih078lco.js +5 -0
- package/static/dist/assets/locale-fr-ojabnf41.js +5 -0
- package/static/dist/assets/locale-it-kb96jufy.js +5 -0
- package/static/dist/assets/locale-ja-jpsp3xs1.js +7 -0
- package/static/dist/assets/locale-ko-cpzuy0n7.js +5 -0
- package/static/dist/assets/locale-pl-dbap4leu.js +5 -0
- package/static/dist/assets/locale-pt-nci7w72x.js +5 -0
- package/static/dist/assets/locale-ru-soghe4cs.js +7 -0
- package/static/dist/assets/locale-tr-ks00mu68.js +5 -0
- package/static/dist/assets/locale-vi-ij7twfm6.js +5 -0
- package/static/dist/assets/locale-zh-Hant-feakwr7a.js +5 -0
- package/static/dist/assets/locale-zh-ren0vjyv.js +7 -0
- package/static/dist/assets/login-iv6yq4xf.js +1 -0
- package/static/dist/assets/{lua-leyf8mlb.js → lua-krx4xj5h.js} +1 -1
- package/static/dist/assets/{marko-cn1fzpdv.js → marko-gbvpfehz.js} +1 -1
- package/static/dist/assets/{mdc-huhy88df.js → mdc-c21zlyi5.js} +1 -1
- package/static/dist/assets/mermaid-HWGCJPDP-cwj5cl6k.js +1 -0
- package/static/dist/assets/mermaid-parser.core-plzkuzov.js +7 -0
- package/static/dist/assets/micromark-factory-space-fnmnpi6s.js +1 -0
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-o1vathns.js → mindmap-definition-YA3MSWOX-ojrgs569.js} +28 -28
- package/static/dist/assets/{nginx-e7lvhsmn.js → nginx-f3d68ed4.js} +1 -1
- package/static/dist/assets/{nim-dun5d8mk.js → nim-dw0jcy70.js} +1 -1
- package/static/dist/assets/onboarding-ff4emacu.js +1 -0
- package/static/dist/assets/packet-AYTQ26CC-gyaf9s8h.js +1 -0
- package/static/dist/assets/pegDiagram-XKGWAZYB-bf6xj8mq.js +1 -0
- package/static/dist/assets/{perl-bj3oqtet.js → perl-3c0r45c8.js} +1 -1
- package/static/dist/assets/{php-buzp12r0.js → php-rznhidvp.js} +1 -1
- package/static/dist/assets/pie-WAS4IAKB-f5ymzelo.js +1 -0
- package/static/dist/assets/pieDiagram-E7YTZNPT-d0qjl3zi.js +39 -0
- package/static/dist/assets/{pug-mjad7he9.js → pug-f2le4f3y.js} +1 -1
- package/static/dist/assets/{qml-d1gdp10s.js → qml-e2wbq9cr.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-owqc4uqn.js → quadrantDiagram-AXDQQJYC-oqy1mras.js} +1 -1
- package/static/dist/assets/queryKeys-x8fjxhut.js +9 -0
- package/static/dist/assets/{r-o3r9c7ao.js → r-epfzuw6q.js} +1 -1
- package/static/dist/assets/radar-RG4KPBEZ-b6jcjvda.js +1 -0
- package/static/dist/assets/railroad-74A4TZTK-e3a6lk5k.js +1 -0
- package/static/dist/assets/railroad-abnf-HS5TGJTU-ff5hocrx.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-exkhyw4n.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-jefk9b7c.js +1 -0
- package/static/dist/assets/railroadDiagram-O6MQD6OU-e4amks1i.js +1 -0
- package/static/dist/assets/{razor-ilc585yr.js → razor-pea1u1d0.js} +1 -1
- package/static/dist/assets/refresh-cw-lfp4u1oh.js +1 -0
- package/static/dist/assets/{regexp-mpjtcvwm.js → regexp-hzte0a5x.js} +1 -1
- package/static/dist/assets/registry-g7w3353u.js +1 -0
- package/static/dist/assets/requirementDiagram-BXWQKSXE-c77k1e2y.js +84 -0
- package/static/dist/assets/rolldown-runtime-bnnw9q4a.js +1 -0
- package/static/dist/assets/{rst-jrkwjdyi.js → rst-m6tugj5o.js} +1 -1
- package/static/dist/assets/{ruby-n4tjcbpz.js → ruby-l19vq3w1.js} +1 -1
- package/static/dist/assets/runtime-nlxpnegr.js +1 -0
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-iqc02emv.js → sankeyDiagram-P5KCCOFB-oa1cc52s.js} +1 -1
- package/static/dist/assets/{sas-hjo6y93k.js → sas-ktdxo397.js} +1 -1
- package/static/dist/assets/{scss-ncidjv48.js → scss-kn3oxfwf.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-i0v116q0.js → sequenceDiagram-WJ2MYXX4-j20gqt22.js} +11 -11
- package/static/dist/assets/settings_section_extensions_title-fadc7o65.js +1 -0
- package/static/dist/assets/share._token-kmfoflw6.js +2 -0
- package/static/dist/assets/{shellscript-m8whjpqd.js → shellscript-l100jtrg.js} +1 -1
- package/static/dist/assets/{shellsession-i5bj6syz.js → shellsession-m5qukwow.js} +1 -1
- package/static/dist/assets/sizeCapture-INFHLROL-dk1io13w.js +1 -0
- package/static/dist/assets/sliders-horizontal-g5jkzd9k.js +1 -0
- package/static/dist/assets/{soy-hhh36ysq.js → soy-mexlscur.js} +1 -1
- package/static/dist/assets/{sql-j21bzcl6.js → sql-o0ho5suh.js} +1 -1
- package/static/dist/assets/src-h89s0hs4.js +1 -0
- package/static/dist/assets/{stata-bbu2onh1.js → stata-be9ck1q3.js} +1 -1
- package/static/dist/assets/stateDiagram-D77RDMKH-co2ghkdp.js +1 -0
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-faw1opgh.js +1 -0
- package/static/dist/assets/{surrealql-l5vczuco.js → surrealql-gk1xkkyy.js} +1 -1
- package/static/dist/assets/{svelte-idn422g6.js → svelte-k6ecjilf.js} +1 -1
- package/static/dist/assets/swimlanes-42K2YHIH-m30cktqe.js +1 -0
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-hfil433g.js +8 -0
- package/static/dist/assets/{templ-e22qou3c.js → templ-gf3bftk6.js} +1 -1
- package/static/dist/assets/{tex-deqpc5ee.js → tex-d21fqv1z.js} +1 -1
- package/static/dist/assets/{timeline-definition-24CTP7MA-ol2hnvma.js → timeline-definition-24CTP7MA-liuep6fl.js} +8 -8
- package/static/dist/assets/toast-zmb35u3r.js +56 -0
- package/static/dist/assets/treeView-Q6P3EWNA-np5d2jv2.js +1 -0
- package/static/dist/assets/treemap-WGGIJYW6-cmpltxh1.js +1 -0
- package/static/dist/assets/{ts-tags-ctnibc27.js → ts-tags-n0g61gr6.js} +1 -1
- package/static/dist/assets/{tsx-i163n32g.js → tsx-cvv7wv6q.js} +1 -1
- package/static/dist/assets/{twig-x0fi7wm8.js → twig-n1f67204.js} +1 -1
- package/static/dist/assets/{typescript-g18c34xz.js → typescript-og7o55cx.js} +1 -1
- package/static/dist/assets/untitled-mj86r4gz.js +1 -0
- package/static/dist/assets/useDebounced-g8r0ggve.js +1 -0
- package/static/dist/assets/useForm-f1udzsjf.js +1 -0
- package/static/dist/assets/{useParams-gjc70qru.js → useParams-ierevvts.js} +1 -1
- package/static/dist/assets/{useSearch-e6ae539u.js → useSearch-i7nr9ypl.js} +1 -1
- package/static/dist/assets/vennDiagram-4TSXK5OY-b2g42qrg.js +34 -0
- package/static/dist/assets/{vue-mwu5l1bb.js → vue-ej4xpwqw.js} +1 -1
- package/static/dist/assets/{vue-html-nskj3du0.js → vue-html-d48xsjuo.js} +1 -1
- package/static/dist/assets/{vue-vine-cqe77smq.js → vue-vine-pev88ip6.js} +1 -1
- package/static/dist/assets/wardley-WFR3VGLG-lb0eqbff.js +1 -0
- package/static/dist/assets/wardleyDiagram-VM6X3IG4-ermwaqha.js +78 -0
- package/static/dist/assets/with-selector-nu1b5z0v.js +1 -0
- package/static/dist/assets/{xml-gau7gvrv.js → xml-ifxp6gqb.js} +1 -1
- package/static/dist/assets/{xsl-ew09zq8b.js → xsl-fug2cckc.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-aqbgvujg.js → xychartDiagram-S5SC5T6Z-dll0jldk.js} +6 -6
- package/static/dist/assets/{yaml-ofnrxtvf.js → yaml-fjmafnlo.js} +1 -1
- package/static/dist/extension-sdk.js +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +180 -136
- package/static/dist/assets/AppShell-cey33v9s.js +0 -8
- package/static/dist/assets/ChatPage-i8wnugr7.js +0 -18
- package/static/dist/assets/ConnectTargets-hg19553x.js +0 -1
- package/static/dist/assets/ExtensionRoute-cly4apm5.js +0 -1
- package/static/dist/assets/Field-j8uqoigz.js +0 -9
- package/static/dist/assets/HubRoute-e4bgz41j.js +0 -2
- package/static/dist/assets/Markdown-lahuichm.js +0 -598
- package/static/dist/assets/Markdown-lwviulmg.css +0 -1
- package/static/dist/assets/RightPanel-lbo4i0fn.js +0 -1
- package/static/dist/assets/Select-gqatm2e0.js +0 -1
- package/static/dist/assets/SessionListPanel-mfqayfjh.js +0 -1
- package/static/dist/assets/SettingsLayout-b8980u7k.js +0 -1
- package/static/dist/assets/States-e7dkgtxf.js +0 -1
- package/static/dist/assets/Toaster-bfqqy786.js +0 -1
- package/static/dist/assets/_app-n1n6pfx1.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-buxjxav3.js +0 -1
- package/static/dist/assets/_app.index-jt8zwiu2.js +0 -1
- package/static/dist/assets/_app.insights-cv76ml71.js +0 -1
- package/static/dist/assets/_app.kanban-h6ts53j7.js +0 -1
- package/static/dist/assets/_app.logs-dm873z90.js +0 -1
- package/static/dist/assets/_app.memory-glk5y6m8.js +0 -1
- package/static/dist/assets/_app.profiles-ka6zpstq.js +0 -1
- package/static/dist/assets/_app.session._sessionId-g2vzghvc.js +0 -1
- package/static/dist/assets/_app.settings-hgjdhzcd.js +0 -1
- package/static/dist/assets/_app.settings._section-jf2kmhae.js +0 -3
- package/static/dist/assets/_app.skills-cii852yq.js +0 -1
- package/static/dist/assets/_app.tasks-fp9q7atm.js +0 -1
- package/static/dist/assets/_app.todos-dw94qzue.js +0 -1
- package/static/dist/assets/_app.workspaces-inyygzze.js +0 -1
- package/static/dist/assets/abnfDiagram-VCTEODGH-gjayq3ra.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +0 -1
- package/static/dist/assets/architectureDiagram-5GKGNRK7-nwb3xovn.js +0 -36
- package/static/dist/assets/archive-b1j004vn.js +0 -1
- package/static/dist/assets/back-g74gkozu.js +0 -1
- package/static/dist/assets/channel-es95o4y8.js +0 -1
- package/static/dist/assets/chunk-DU6HZSFF-gpedttsp.js +0 -128
- package/static/dist/assets/chunk-OSK3NFVY-oy0gwn2n.js +0 -10
- package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +0 -1
- package/static/dist/assets/copied-bli9tbcx.js +0 -1
- package/static/dist/assets/copy-jamtd1pf.js +0 -1
- package/static/dist/assets/cose-bilkent-JH36ORCC-eclcy6ja.js +0 -1
- package/static/dist/assets/cynefin-OW5HDTMX-f8xfdd3f.js +0 -1
- package/static/dist/assets/cynefinDiagram-5FMLGOSQ-n9lb99h9.js +0 -62
- package/static/dist/assets/cytoscape.esm-bqu53u12.js +0 -321
- package/static/dist/assets/dagre-GXQ25YYZ-dgailddi.js +0 -4
- package/static/dist/assets/dagre-lkoknbjn.js +0 -1
- package/static/dist/assets/diagram-UQ7AKVKN-jall3j0x.js +0 -41
- package/static/dist/assets/diagram-VX7I27RA-hendl2tt.js +0 -24
- package/static/dist/assets/diagram-Z3DM3KII-igwc35p3.js +0 -24
- package/static/dist/assets/ebnfDiagram-PWID7BFC-c64knz08.js +0 -1
- package/static/dist/assets/erDiagram-RLTQ6QDP-brdu9lcm.js +0 -99
- package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +0 -1
- package/static/dist/assets/folder-plus-lvt9kudb.js +0 -1
- package/static/dist/assets/gitGraph-4MIJSDKK-naa9w6xa.js +0 -1
- package/static/dist/assets/highlighted-body-KPVGNVTW-ghoavj8d.js +0 -1
- package/static/dist/assets/host-hzm8n85n.js +0 -1
- package/static/dist/assets/index-drdcaqeq.css +0 -2
- package/static/dist/assets/index-jzm844he.js +0 -11
- package/static/dist/assets/info-A6RAGUB7-mn2ut5ko.js +0 -1
- package/static/dist/assets/infoDiagram-27XIBGKW-h6kuqvsb.js +0 -2
- package/static/dist/assets/lazyRouteComponent-o816ytzl.js +0 -1
- package/static/dist/assets/linear-becwlnhk.js +0 -1
- package/static/dist/assets/link-k01ryaf9.js +0 -1
- package/static/dist/assets/login-bsae49ew.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +0 -1
- package/static/dist/assets/mermaid-parser.core-bnre27u8.js +0 -7
- package/static/dist/assets/not-found-ccnnac39.js +0 -1
- package/static/dist/assets/onboarding-c65tysya.js +0 -1
- package/static/dist/assets/onboarding_model_label-gpn28uix.js +0 -1
- package/static/dist/assets/packet-AYTQ26CC-hatq7m2e.js +0 -1
- package/static/dist/assets/pegDiagram-XKGWAZYB-gwisz8jv.js +0 -1
- package/static/dist/assets/pie-WAS4IAKB-fpftf0mk.js +0 -1
- package/static/dist/assets/pieDiagram-E7YTZNPT-khm1o9a6.js +0 -39
- package/static/dist/assets/radar-RG4KPBEZ-cntfwjpq.js +0 -1
- package/static/dist/assets/railroad-74A4TZTK-a7t5eibp.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +0 -1
- package/static/dist/assets/railroadDiagram-O6MQD6OU-etuh0qa0.js +0 -1
- package/static/dist/assets/refresh-cw-mqbkv2a3.js +0 -1
- package/static/dist/assets/refresh-l29ljp76.js +0 -1
- package/static/dist/assets/requirementDiagram-BXWQKSXE-oq2ulk22.js +0 -84
- package/static/dist/assets/rolldown-runtime-b9miacsj.js +0 -1
- package/static/dist/assets/root-mbklpuv4.js +0 -1
- package/static/dist/assets/saved-ndd4t2xb.js +0 -1
- package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +0 -1
- package/static/dist/assets/share._token-c1ri0hy1.js +0 -2
- package/static/dist/assets/sizeCapture-INFHLROL-g612l48j.js +0 -1
- package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +0 -1
- package/static/dist/assets/src-hjyib4mu.js +0 -1
- package/static/dist/assets/stateDiagram-D77RDMKH-dnpt1ato.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +0 -1
- package/static/dist/assets/swimlanes-42K2YHIH-loqbdazb.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +0 -8
- package/static/dist/assets/toast-i3h34v6o.js +0 -64
- package/static/dist/assets/treeView-Q6P3EWNA-idrj6iox.js +0 -1
- package/static/dist/assets/treemap-WGGIJYW6-lzr49vv5.js +0 -1
- package/static/dist/assets/untitled-oaoya4qj.js +0 -1
- package/static/dist/assets/useForm-nfaxgmsk.js +0 -1
- package/static/dist/assets/vennDiagram-4TSXK5OY-bvwr9o2z.js +0 -34
- package/static/dist/assets/wardley-WFR3VGLG-31ui8tma.js +0 -1
- package/static/dist/assets/wardleyDiagram-VM6X3IG4-k5wqtx4b.js +0 -78
- /package/static/dist/assets/{ChatPage-gmu5c7lf.css → TerminalPanel-gmu5c7lf.css} +0 -0
|
@@ -1,75 +1,479 @@
|
|
|
1
|
-
|
|
1
|
+
import { CHECKPOINT_DIFF_MAX_BYTES, ReactionEmojiSchema, unavailableContextDetail } from '@maudecode/talaria-web-contracts';
|
|
2
|
+
import { checkpointDiffFiles } from '../workspace/rollback.js';
|
|
2
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
-
import { GatewaySessionResultSchema } from '@maudecode/talaria-web-contracts';
|
|
4
|
-
import { redactNestedMessageContainers, publicToolFrame } from '../redact.js';
|
|
4
|
+
import { OWNER_EXPORT_MAX_BYTES, SessionNoticeSchema, GatewayClarifyBatchSchema, GatewaySessionResultSchema } from '@maudecode/talaria-web-contracts';
|
|
5
|
+
import { redactNestedMessageContainers, publicToolFrame, redactString } from '../redact.js';
|
|
5
6
|
import { str } from '../util.js';
|
|
6
7
|
import { PendingPrompts } from './pending.js';
|
|
8
|
+
import { wrapExportHtml } from './export.js';
|
|
7
9
|
import { clarifyReply } from './pending.js';
|
|
8
10
|
import { HttpFailure } from './service.js';
|
|
11
|
+
import { SessionNotices } from './notices.js';
|
|
9
12
|
import { SessionEventBus } from './events.js';
|
|
10
13
|
import { messageWindowForDisplay, messagesForLimitedPayload } from './window.js';
|
|
11
14
|
import { pendingUserRow } from './merge.js';
|
|
12
|
-
import {
|
|
15
|
+
import { ReasoningTitleTracker, reasoningEventPayload } from './reasoning-titles.js';
|
|
16
|
+
import { CANONICAL_READ_ONLY_REASON, WEB_DIAGNOSTIC_REQUEST_PREFIX } from './state-db.js';
|
|
17
|
+
import { toolProgress } from './tool-display.js';
|
|
13
18
|
const ownerStreamPrefix = (home) => `owner-${createHash('sha256').update(home).digest('hex').slice(0, 16)}-`;
|
|
14
19
|
const ownerStateId = (identity) => `owner-${createHash('sha256').update(identity).digest('hex')}`;
|
|
15
20
|
/** The scope remains verifiable after a server restart, before a journal lookup or stream subscription. */
|
|
16
21
|
export const gatewayStreamVisible = (stream, home) => !stream.startsWith('owner-') || stream.startsWith(ownerStreamPrefix(home));
|
|
22
|
+
/** The server's one classification of why an owner cannot start a diagnostic chat; clients word the code. */
|
|
23
|
+
function unavailableReason(result) {
|
|
24
|
+
if (result.state === 'stopped')
|
|
25
|
+
return 'gateway_stopped';
|
|
26
|
+
if (result.reason === 'served_profile_sessions_unavailable')
|
|
27
|
+
return 'served_profile';
|
|
28
|
+
if (result.state === 'incompatible')
|
|
29
|
+
return 'agent_unsupported';
|
|
30
|
+
return 'gateway_unavailable';
|
|
31
|
+
}
|
|
17
32
|
/** A preview can be absent in a valid native receipt; only original nonblank text can become a retry draft. */
|
|
18
33
|
function retryText(admission) {
|
|
19
34
|
const text = admission.text;
|
|
20
35
|
return typeof text === 'string' && text.trim() ? text : null;
|
|
21
36
|
}
|
|
37
|
+
/** Steering belongs to the current turn; it must never replace that turn's transcript anchor. */
|
|
38
|
+
const runningAdmission = (snapshot) => snapshot.pending.find((p) => p.status === 'started' && !p.steering);
|
|
39
|
+
const sameExecution = (a, b) => a.authority_epoch === b.authority_epoch && a.replay_epoch === b.replay_epoch && a.execution_generation === b.execution_generation;
|
|
40
|
+
/** Native counters and the owner's compact turn-end usage share one existing Web usage shape. */
|
|
41
|
+
function ownerUsage(data) {
|
|
42
|
+
const fields = {
|
|
43
|
+
input_tokens: ['prompt_tokens', 'prompt', 'input_tokens', 'input'], output_tokens: ['completion_tokens', 'completion', 'output_tokens', 'output'],
|
|
44
|
+
cache_read_tokens: ['cache_read_tokens'], cache_write_tokens: ['cache_write_tokens'],
|
|
45
|
+
estimated_cost: ['estimated_cost_usd'], last_prompt_tokens: ['last_prompt_tokens', 'context_used'],
|
|
46
|
+
context_length: ['context_length', 'context_max'], cache_hit_percent: ['cache_hit_pct'], tps: ['tokens_per_s', 'avg_tps'],
|
|
47
|
+
};
|
|
48
|
+
const usage = {};
|
|
49
|
+
for (const [field, keys] of Object.entries(fields)) {
|
|
50
|
+
const value = keys.map((key) => data[key]).find((value) => typeof value === 'number' && Number.isFinite(value) && value >= 0);
|
|
51
|
+
if (value !== undefined)
|
|
52
|
+
usage[field] = value;
|
|
53
|
+
}
|
|
54
|
+
return usage;
|
|
55
|
+
}
|
|
56
|
+
/** Translate only owner-confirmed outcomes; an unknown receipt never means applied. */
|
|
57
|
+
function modelChange(receipt, selection = {}) {
|
|
58
|
+
const payload = receipt.payload && typeof receipt.payload === 'object' ? receipt.payload : selection;
|
|
59
|
+
const model = str(receipt.target_model) || str(payload.model) || str(receipt.model);
|
|
60
|
+
const provider = Object.hasOwn(receipt, 'target_provider') ? receipt.target_provider : payload.provider;
|
|
61
|
+
const target = { ...(model ? { model } : {}), ...(provider === null || typeof provider === 'string' ? { provider } : {}) };
|
|
62
|
+
if (receipt.operation !== 'model')
|
|
63
|
+
return { state: 'refused', message: 'The owner did not confirm the model change' };
|
|
64
|
+
if (receipt.status === 'deferred')
|
|
65
|
+
return { state: 'deferred', ...target };
|
|
66
|
+
if (receipt.status === 'confirmation_required' && typeof receipt.confirm === 'string' && receipt.confirm && model)
|
|
67
|
+
return { state: 'confirmation_required', message: str(receipt.confirm_message), confirm: receipt.confirm, ...target };
|
|
68
|
+
if (receipt.status === undefined && Number.isInteger(receipt.revision))
|
|
69
|
+
return { state: 'applied' };
|
|
70
|
+
return { state: 'refused', message: str(receipt.reason || receipt.message) || 'The owner did not confirm the model change' };
|
|
71
|
+
}
|
|
22
72
|
export class GatewaySessions {
|
|
23
73
|
deps;
|
|
24
74
|
watches = new Map();
|
|
75
|
+
runWorkers = new Set();
|
|
76
|
+
observations = new Map();
|
|
77
|
+
noticeEpochs = new Map();
|
|
78
|
+
notices;
|
|
79
|
+
modelMutations = new Map();
|
|
80
|
+
modelChanges = new Map();
|
|
81
|
+
rememberModelChange(target, snapshot, change) {
|
|
82
|
+
this.modelChanges.set(target.key, { epoch: snapshot.authority_epoch, replay: snapshot.replay_epoch, change });
|
|
83
|
+
}
|
|
84
|
+
currentModelChange(target, snapshot) {
|
|
85
|
+
const saved = this.modelChanges.get(target.key);
|
|
86
|
+
if (!saved || !snapshot)
|
|
87
|
+
return undefined;
|
|
88
|
+
if (saved.epoch === snapshot.authority_epoch && saved.replay === snapshot.replay_epoch)
|
|
89
|
+
return saved.change;
|
|
90
|
+
this.modelChanges.delete(target.key);
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
25
93
|
constructor(deps) {
|
|
26
94
|
this.deps = deps;
|
|
95
|
+
this.notices = new SessionNotices(deps.now);
|
|
96
|
+
}
|
|
97
|
+
addNativeNotice(target, key, frame) {
|
|
98
|
+
const text = typeof frame.text === 'string' ? frame.text.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, '') : '';
|
|
99
|
+
this.notices.add(target.key, { ...frame, key, text, lapses_with_agent: true });
|
|
100
|
+
}
|
|
101
|
+
noticeState(target, snapshot, reset = false) {
|
|
102
|
+
const identity = ownerStateId(JSON.stringify([target.key, snapshot.authority_epoch, snapshot.replay_epoch]));
|
|
103
|
+
let state = this.noticeEpochs.get(target.key);
|
|
104
|
+
if (state?.identity !== identity || reset) {
|
|
105
|
+
this.notices.reset(target.key);
|
|
106
|
+
state = { identity, sequence: reset ? snapshot.last_sequence : 0 };
|
|
107
|
+
this.noticeEpochs.set(target.key, state);
|
|
108
|
+
}
|
|
109
|
+
const warning = typeof snapshot.info.config_warning === 'string' ? snapshot.info.config_warning : '';
|
|
110
|
+
if (warning.trim())
|
|
111
|
+
this.addNativeNotice(target, `${identity}:config-warning`, { text: warning, level: 'warn' });
|
|
112
|
+
return state;
|
|
113
|
+
}
|
|
114
|
+
nativeNotices(target, snapshot) {
|
|
115
|
+
const observed = this.observations.get(target.key)?.snapshot;
|
|
116
|
+
this.noticeState(target, observed && observed.authority_epoch >= snapshot.authority_epoch ? observed : snapshot);
|
|
117
|
+
// A detail row may already contain our projection. Read the direct layer itself so
|
|
118
|
+
// retained transport bases cannot duplicate warnings or resurrect cleared notices.
|
|
119
|
+
const direct = SessionNoticeSchema.array().safeParse(this.deps.service.deps.runtime.sessionNotices?.(target.sid) ?? []);
|
|
120
|
+
return [...(direct.success ? direct.data : []), ...this.notices.list(target.key)];
|
|
121
|
+
}
|
|
122
|
+
changed(target) {
|
|
123
|
+
this.deps.channels.emit(target.sid, 'session-updated', { session_id: target.sid, source: 'native_owner' }, target.profile);
|
|
124
|
+
}
|
|
125
|
+
/** One shared connection, acquired by viewers and run projections, with no local Agent admission. */
|
|
126
|
+
transport(target, base, snapshot) {
|
|
127
|
+
const prior = this.observations.get(target.key);
|
|
128
|
+
if (prior && !prior.controller.signal.aborted)
|
|
129
|
+
return prior;
|
|
130
|
+
const observation = { controller: new AbortController(), snapshot, replaying: true, completion: null, listeners: new Set(), leases: 0, ended: Promise.resolve({ state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null }) };
|
|
131
|
+
this.observations.set(target.key, observation);
|
|
132
|
+
this.noticeState(target, snapshot);
|
|
133
|
+
observation.ended = (async () => {
|
|
134
|
+
const showReasoning = await this.deps.showReasoning(target.home).catch(() => false);
|
|
135
|
+
const sidecar = this.deps.sidecar();
|
|
136
|
+
if (!sidecar || observation.controller.signal.aborted)
|
|
137
|
+
return { state: 'unavailable', reason: 'sidecar_unavailable', snapshot: null, receipt: null };
|
|
138
|
+
return sidecar.call('gateway.session', { profile_home: target.home, session_id: target.sid, action: 'watch', show_reasoning: showReasoning }, {
|
|
139
|
+
signal: observation.controller.signal, timeoutMs: 0,
|
|
140
|
+
onStream: (frame) => {
|
|
141
|
+
if (observation.controller.signal.aborted || this.observations.get(target.key) !== observation)
|
|
142
|
+
return;
|
|
143
|
+
if (frame.event === 'snapshot') {
|
|
144
|
+
const result = GatewaySessionResultSchema.parse(frame.data);
|
|
145
|
+
if (result.snapshot?.session_id !== target.sid)
|
|
146
|
+
return;
|
|
147
|
+
// Reaction readback invalidates display data only. Queued native turn events still own settlement.
|
|
148
|
+
if (frame.data.reaction_only === true) {
|
|
149
|
+
this.changed(target);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const completed = observation.completion?.data;
|
|
153
|
+
if (result.replay_gap || completed && (completed.authority_epoch !== result.snapshot.authority_epoch || completed.replay_epoch !== result.snapshot.replay_epoch))
|
|
154
|
+
observation.completion = null;
|
|
155
|
+
observation.snapshot = result.snapshot;
|
|
156
|
+
observation.replaying = frame.data.replaying === true;
|
|
157
|
+
this.noticeState(target, result.snapshot, result.replay_gap === true);
|
|
158
|
+
if ((result.snapshot.running || result.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')) && !this.watches.has(target.key))
|
|
159
|
+
this.watch(target, base, result.snapshot);
|
|
160
|
+
this.changed(target);
|
|
161
|
+
}
|
|
162
|
+
else if (frame.event === 'replay_complete') {
|
|
163
|
+
observation.replaying = false;
|
|
164
|
+
}
|
|
165
|
+
else if (frame.event === 'event') {
|
|
166
|
+
const event = frame.data;
|
|
167
|
+
const data = (event.payload ?? {});
|
|
168
|
+
if (event.type === 'notification.show' || event.type === 'notification.clear') {
|
|
169
|
+
const snap = observation.snapshot;
|
|
170
|
+
const state = this.noticeState(target, snap);
|
|
171
|
+
if (event.session_id !== target.sid || event.replay_epoch !== snap.replay_epoch
|
|
172
|
+
|| event.authority_epoch !== undefined && event.authority_epoch !== snap.authority_epoch
|
|
173
|
+
|| !Number.isSafeInteger(event.seq) || Number(event.seq) <= state.sequence)
|
|
174
|
+
return;
|
|
175
|
+
state.sequence = Number(event.seq);
|
|
176
|
+
const key = typeof data.key === 'string' ? data.key : typeof data.id === 'string' ? data.id : '';
|
|
177
|
+
if (!key)
|
|
178
|
+
return;
|
|
179
|
+
const scopedKey = `${state.identity}:plugin:${ownerStateId(key)}`;
|
|
180
|
+
if (event.type === 'notification.clear')
|
|
181
|
+
this.notices.clear(target.key, scopedKey);
|
|
182
|
+
else
|
|
183
|
+
this.addNativeNotice(target, scopedKey, data);
|
|
184
|
+
this.changed(target);
|
|
185
|
+
}
|
|
186
|
+
else if (event.type === 'session.info') {
|
|
187
|
+
if (data.authority_epoch !== observation.snapshot.authority_epoch || Number(data.execution_generation) < observation.snapshot.execution_generation)
|
|
188
|
+
return;
|
|
189
|
+
observation.snapshot = { ...observation.snapshot, ...data };
|
|
190
|
+
if ((observation.snapshot.running || observation.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')) && !this.watches.has(target.key))
|
|
191
|
+
this.watch(target, base, observation.snapshot);
|
|
192
|
+
this.changed(target);
|
|
193
|
+
}
|
|
194
|
+
else if (event.type === 'message.complete' && event.session_id === target.sid
|
|
195
|
+
&& event.authority_epoch === observation.snapshot.authority_epoch && event.replay_epoch === observation.snapshot.replay_epoch
|
|
196
|
+
&& Number.isSafeInteger(event.execution_generation) && Number(event.execution_generation) >= observation.snapshot.execution_generation) {
|
|
197
|
+
observation.completion = frame;
|
|
198
|
+
}
|
|
199
|
+
else if (event.type === 'session.updated')
|
|
200
|
+
this.changed(target);
|
|
201
|
+
}
|
|
202
|
+
for (const listener of observation.listeners)
|
|
203
|
+
listener(frame);
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
})().catch(() => ({ state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null })).finally(() => {
|
|
207
|
+
observation.controller.abort();
|
|
208
|
+
if (this.observations.get(target.key) === observation)
|
|
209
|
+
this.observations.delete(target.key);
|
|
210
|
+
this.changed(target);
|
|
211
|
+
});
|
|
212
|
+
return observation;
|
|
213
|
+
}
|
|
214
|
+
lease(observation) {
|
|
215
|
+
observation.leases++;
|
|
216
|
+
let held = true;
|
|
217
|
+
return () => { if (!held)
|
|
218
|
+
return; held = false; if (--observation.leases === 0)
|
|
219
|
+
observation.controller.abort(); };
|
|
27
220
|
}
|
|
28
|
-
|
|
221
|
+
/** Called only after the existing HTTP owner has authorized and claimed a viewer's stream slot. */
|
|
222
|
+
async observe(sid, profile, signal) {
|
|
223
|
+
const target = await this.target(sid, profile);
|
|
224
|
+
if (!target || signal.aborted)
|
|
225
|
+
return null;
|
|
226
|
+
const base = await this.deps.service.detail(sid, {});
|
|
227
|
+
const result = await this.call(target, { action: 'snapshot' }, signal);
|
|
228
|
+
if (signal.aborted)
|
|
229
|
+
return null;
|
|
230
|
+
if (!result.snapshot || result.state !== 'attached')
|
|
231
|
+
return { release: () => undefined, ended: Promise.resolve(result) };
|
|
232
|
+
const observation = this.transport(target, base, result.snapshot);
|
|
233
|
+
const release = this.lease(observation);
|
|
234
|
+
signal.addEventListener('abort', release, { once: true });
|
|
235
|
+
return { release: () => { signal.removeEventListener('abort', release); release(); }, ended: observation.ended };
|
|
236
|
+
}
|
|
237
|
+
async target(sid, profile = this.deps.activeProfile(), requireKnownOwnership = false) {
|
|
29
238
|
if (sid.length === 0 || sid !== sid.trim())
|
|
30
239
|
return null;
|
|
31
|
-
const
|
|
240
|
+
const sources = await this.deps.service.stateDbSources([sid], profile);
|
|
241
|
+
if (requireKnownOwnership && !sources)
|
|
242
|
+
throw new HttpFailure(503, 'Agent session ownership could not be verified');
|
|
243
|
+
const owner = sources?.get(sid);
|
|
32
244
|
if (typeof owner !== 'object')
|
|
33
245
|
return null;
|
|
34
|
-
if (owner.reason)
|
|
246
|
+
if (owner.reason) {
|
|
247
|
+
if (requireKnownOwnership)
|
|
248
|
+
throw new HttpFailure(403, owner.reason);
|
|
35
249
|
return null;
|
|
250
|
+
}
|
|
36
251
|
const home = this.deps.profileHome(profile);
|
|
37
252
|
return { sid, profile, home, key: JSON.stringify([home, sid]) };
|
|
38
253
|
}
|
|
39
|
-
|
|
40
|
-
|
|
254
|
+
async contextDetail(sid, expectedKey) {
|
|
255
|
+
const profile = this.deps.activeProfile();
|
|
256
|
+
const target = await this.target(sid, profile);
|
|
257
|
+
if (!target)
|
|
258
|
+
return unavailableContextDetail();
|
|
259
|
+
const result = await this.call(target, { action: 'context_detail' });
|
|
260
|
+
return profile === this.deps.activeProfile() && result.state === 'attached' && this.contextDetailKey(target, result.snapshot) === expectedKey ? result.context_detail ?? unavailableContextDetail('unsupported') : unavailableContextDetail('changed');
|
|
261
|
+
}
|
|
262
|
+
activityPhaseFor(result, target) {
|
|
263
|
+
if (result.state !== 'attached' || !result.snapshot)
|
|
264
|
+
return 'stale';
|
|
265
|
+
const pending = this.prompts(result.snapshot, target.sid, this.batch(target));
|
|
266
|
+
if (pending.approvalPending(target.sid).pending)
|
|
267
|
+
return 'waiting_for_approval';
|
|
268
|
+
if (pending.clarifyPending(target.sid).pending)
|
|
269
|
+
return 'waiting_for_input';
|
|
270
|
+
if (result.snapshot.running || result.snapshot.pending.some((entry) => entry.status === 'queued' || entry.status === 'started'))
|
|
271
|
+
return 'running';
|
|
272
|
+
return result.snapshot.pending.some((entry) => entry.status === 'unknown') ? 'stale' : null;
|
|
273
|
+
}
|
|
274
|
+
async activityPhase(sid, profile) {
|
|
275
|
+
const target = await this.target(sid, profile);
|
|
276
|
+
return target ? this.activityPhaseFor(await this.call(target, { action: 'snapshot' }), target) : undefined;
|
|
277
|
+
}
|
|
278
|
+
async isOwned(sid) { return (await this.target(sid)) !== null; }
|
|
279
|
+
/** Exact native receipt lookup for a durable queue step, never another submit. */
|
|
280
|
+
async queueReceipt(sid, admissionId) {
|
|
281
|
+
const target = await this.target(sid);
|
|
282
|
+
return target ? this.call(target, admissionId ? { action: 'receipt', admission_id: admissionId } : { action: 'snapshot' }) : null;
|
|
283
|
+
}
|
|
284
|
+
async checkpointDiff(sid) {
|
|
285
|
+
const profile = this.deps.activeProfile();
|
|
286
|
+
const target = await this.target(sid, profile);
|
|
287
|
+
if (!target)
|
|
288
|
+
return null;
|
|
289
|
+
const result = await this.call(target, { action: 'checkpoint_diff' });
|
|
290
|
+
const read = profile === this.deps.activeProfile() && result.state === 'attached' ? result.checkpoint_diff : undefined;
|
|
291
|
+
const comparison = read ? { ...read.comparison } : { provenance: 'native_owner', baseline: 'earliest_retained_project_checkpoint', available: false, reason: 'owner_unavailable', truncated: false };
|
|
292
|
+
if (read && (Buffer.byteLength(JSON.stringify(read.diff), 'utf8') + Buffer.byteLength(JSON.stringify(read.stat), 'utf8') - 4 > CHECKPOINT_DIFF_MAX_BYTES)) {
|
|
293
|
+
comparison.available = false;
|
|
294
|
+
comparison.reason = 'payload_too_large';
|
|
295
|
+
}
|
|
296
|
+
const diff = comparison.available ? read?.diff ?? '' : '';
|
|
297
|
+
const files = checkpointDiffFiles(diff);
|
|
298
|
+
return { checkpoint: 'earliest-retained', workspace: '', diff: diff.trimEnd(), files_changed: files, total_changes: files.length, comparison };
|
|
299
|
+
}
|
|
300
|
+
terminalKey(target, snap) {
|
|
301
|
+
return ownerStateId(JSON.stringify([target.key, snap.session_id, snap.authority_epoch, snap.replay_epoch, snap.info.cwd]));
|
|
302
|
+
}
|
|
303
|
+
async terminal(sid) {
|
|
304
|
+
const target = await this.target(sid, this.deps.activeProfile(), true);
|
|
305
|
+
if (!target)
|
|
306
|
+
return null;
|
|
307
|
+
const result = await this.call(target, { action: 'terminal_info' });
|
|
308
|
+
const snap = result.snapshot;
|
|
309
|
+
if (target.profile !== this.deps.activeProfile() || result.state !== 'attached' || snap?.session_id !== sid)
|
|
310
|
+
throw new HttpFailure(409, 'The native owner cannot run captured commands. Reopen the terminal after checking the gateway.', { code: 'owner_shell_unavailable' });
|
|
311
|
+
return { target, snap, key: this.terminalKey(target, snap) };
|
|
312
|
+
}
|
|
313
|
+
async capturedCommand(sid, key, command) {
|
|
314
|
+
const selected = await this.terminal(sid);
|
|
315
|
+
if (key !== selected?.key)
|
|
316
|
+
throw new HttpFailure(409, 'The native owner changed. Reopen the terminal before running a command.');
|
|
317
|
+
const { target, snap } = selected;
|
|
318
|
+
const result = await this.call(target, { action: 'shell_exec', command, authority_epoch: snap.authority_epoch, replay_epoch: snap.replay_epoch });
|
|
319
|
+
if (result.state !== 'attached' || !result.shell) {
|
|
320
|
+
// Only allowlisted native policy refusals are safe to show. A transport failure may have executed.
|
|
321
|
+
const messages = {
|
|
322
|
+
unsupported_terminal_backend: 'Captured commands require the native owner’s local terminal backend.',
|
|
323
|
+
cwd_unavailable: 'The native workspace no longer exists.', dangerous_command: 'The native owner refused this command.',
|
|
324
|
+
permission_denied: 'The native owner denied this command.', command_timeout: 'The command timed out on the native owner.',
|
|
325
|
+
owner_changed: 'The native owner changed. Reopen the terminal.',
|
|
326
|
+
};
|
|
327
|
+
throw new HttpFailure(409, messages[result.reason ?? ''] ?? 'The command outcome is unknown. Check the native workspace before running it again.', { code: 'owner_shell_failed' });
|
|
328
|
+
}
|
|
329
|
+
return { stdout: redactString(result.shell.stdout, true), stderr: redactString(result.shell.stderr, true), code: result.shell.code };
|
|
330
|
+
}
|
|
331
|
+
async export(sid, format) {
|
|
332
|
+
const target = await this.target(sid);
|
|
333
|
+
if (!target)
|
|
334
|
+
return null;
|
|
335
|
+
const redact = this.deps.redactEnabled();
|
|
336
|
+
const result = await this.call(target, { action: 'export', format, redact });
|
|
337
|
+
const value = result.export;
|
|
338
|
+
if (result.reason === 'export_too_large')
|
|
339
|
+
throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
|
|
340
|
+
if (result.state !== 'attached' || value?.format !== format) {
|
|
341
|
+
throw new HttpFailure(409, 'The Agent owner cannot export this chat. Check that its gateway is running and supports transcript export.', { code: 'owner_export_unavailable' });
|
|
342
|
+
}
|
|
343
|
+
if (Buffer.byteLength(value.content, 'utf8') > OWNER_EXPORT_MAX_BYTES)
|
|
344
|
+
throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
|
|
345
|
+
let content;
|
|
346
|
+
try {
|
|
347
|
+
// The owner redacts HTML's structured transcript before rendering. A shell/text redactor corrupts its markup.
|
|
348
|
+
content = format === 'html' ? wrapExportHtml(value.content) : format === 'json'
|
|
349
|
+
? JSON.stringify(redactNestedMessageContainers(JSON.parse(value.content), redact), null, 2)
|
|
350
|
+
: redactString(value.content, redact);
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
throw new HttpFailure(409, 'The Agent owner returned an invalid transcript export', { code: 'owner_export_invalid' });
|
|
354
|
+
}
|
|
355
|
+
if (Buffer.byteLength(content, 'utf8') > OWNER_EXPORT_MAX_BYTES)
|
|
356
|
+
throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
|
|
357
|
+
return { ...value, content };
|
|
358
|
+
}
|
|
359
|
+
async createCall(params) {
|
|
41
360
|
const sidecar = this.deps.sidecar();
|
|
42
361
|
if (!sidecar)
|
|
43
362
|
return { state: 'unavailable', reason: 'sidecar_unavailable', snapshot: null, receipt: null };
|
|
44
363
|
try {
|
|
45
|
-
return await sidecar.call('gateway.
|
|
364
|
+
return await sidecar.call('gateway.create', params, { timeoutMs: 35_000 });
|
|
46
365
|
}
|
|
47
366
|
catch {
|
|
48
367
|
return { state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null };
|
|
49
368
|
}
|
|
50
369
|
}
|
|
370
|
+
/** TAL-1040: normal always runs; the bypass modes need an owner that freezes them before any Agent import. */
|
|
371
|
+
async modes(profile) {
|
|
372
|
+
const result = await this.createCall({ profile_home: this.deps.profileHome(profile), probe: true });
|
|
373
|
+
const reason = result.state === 'attached' ? null : unavailableReason(result);
|
|
374
|
+
// Owner chats take no file attachments (`submit` refuses them), so a fresh chat in either bypass mode cannot attach.
|
|
375
|
+
return { modes: [{ mode: 'normal', available: true, reason: null, can_attach: true, can_reference: true }, ...['ignore_config', 'safe'].map((mode) => ({ mode, available: reason === null, reason, can_attach: false, can_reference: false }))] };
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* TAL-1040: the owner mints a diagnostic chat, freezes its bypass in the creation receipt and runs each turn in a fresh
|
|
379
|
+
* private worker. Talaria keeps no local Session and never falls back to an ordinary chat; no credential is sent.
|
|
380
|
+
*/
|
|
381
|
+
async create(profile, creationId, params) {
|
|
382
|
+
// The client's creation id survives a lost response, so a retry recovers the owner's committed session, never a second one.
|
|
383
|
+
const result = await this.createCall({ ...params, profile_home: this.deps.profileHome(profile), request_id: WEB_DIAGNOSTIC_REQUEST_PREFIX + (creationId ?? randomUUID()) });
|
|
384
|
+
if (result.state !== 'attached' || !result.snapshot) {
|
|
385
|
+
throw new HttpFailure(409, 'The Agent cannot start a chat in this mode', { code: 'execution_mode_unavailable', reason: unavailableReason(result) });
|
|
386
|
+
}
|
|
387
|
+
return result.snapshot.session_id;
|
|
388
|
+
}
|
|
389
|
+
async call(target, params, signal) {
|
|
390
|
+
const sidecar = this.deps.sidecar();
|
|
391
|
+
if (!sidecar)
|
|
392
|
+
return { state: 'unavailable', reason: 'sidecar_unavailable', snapshot: null, receipt: null };
|
|
393
|
+
const before = this.modelChanges.get(target.key);
|
|
394
|
+
const modelMutation = params.action === 'mutate' && params.operation === 'model';
|
|
395
|
+
if (modelMutation)
|
|
396
|
+
this.modelMutations.set(target.key, (this.modelMutations.get(target.key) ?? 0) + 1);
|
|
397
|
+
try {
|
|
398
|
+
const result = await sidecar.call('gateway.session', { ...params, profile_home: target.home, session_id: target.sid }, { timeoutMs: params.action === 'mutate' ? 675_000 : params.action === 'shell_exec' ? 40_000 : 35_000, ...(signal ? { signal } : {}) });
|
|
399
|
+
if (params.action === 'mutate' && params.operation === 'model' && result.snapshot) {
|
|
400
|
+
const change = modelChange(result.receipt ?? {}, params.payload);
|
|
401
|
+
// The stream can resolve a deferred pick before its HTTP ACK returns. Keep the later observation.
|
|
402
|
+
if (change.state !== 'deferred' || this.modelChanges.get(target.key) === before
|
|
403
|
+
|| !this.currentModelChange(target, result.snapshot))
|
|
404
|
+
this.rememberModelChange(target, result.snapshot, change);
|
|
405
|
+
}
|
|
406
|
+
const change = this.currentModelChange(target, result.snapshot);
|
|
407
|
+
return { ...result, ...(change ? { model_change: change } : {}) };
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
return { state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null };
|
|
411
|
+
}
|
|
412
|
+
finally {
|
|
413
|
+
if (modelMutation) {
|
|
414
|
+
const remaining = (this.modelMutations.get(target.key) ?? 1) - 1;
|
|
415
|
+
if (remaining)
|
|
416
|
+
this.modelMutations.set(target.key, remaining);
|
|
417
|
+
else {
|
|
418
|
+
this.modelMutations.delete(target.key);
|
|
419
|
+
this.watches.get(target.key)?.reconcile?.();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
51
424
|
attachment(result) {
|
|
52
425
|
const snapshot = result.snapshot;
|
|
53
426
|
const unknown = snapshot?.pending.some((p) => p.status === 'unknown') ?? false;
|
|
427
|
+
const restarting = result.restarting === true;
|
|
54
428
|
const value = {
|
|
55
|
-
state: result.state, reason: result.reason, can_submit: result.state === 'attached' && snapshot !== null && !unknown,
|
|
429
|
+
state: result.state, reason: result.reason, restarting, can_submit: result.state === 'attached' && snapshot !== null && !unknown && !restarting,
|
|
56
430
|
can_interrupt: result.state === 'attached' && snapshot?.running === true, can_attach: false,
|
|
57
431
|
revision: snapshot?.revision ?? null, execution_generation: snapshot?.execution_generation ?? null,
|
|
58
|
-
|
|
432
|
+
...(result.model_change ? { model_change: result.model_change } : {}),
|
|
433
|
+
active_admission: snapshot ? runningAdmission(snapshot) ?? null : null,
|
|
59
434
|
admissions: (snapshot?.pending ?? []).filter((p) => p.status === 'queued' || p.status === 'unknown').map((p) => ({ ...p,
|
|
60
|
-
actions: p.status === 'queued' ? ['cancel']
|
|
435
|
+
actions: p.status === 'queued' ? ['cancel', ...(p.controls?.includes('steer') ? ['steer'] : []), ...(p.controls?.includes('replace') ? ['edit'] : [])]
|
|
61
436
|
: p.execution_generation === null ? []
|
|
62
437
|
: retryText(p) === null ? ['discard'] : ['retry', 'discard'],
|
|
63
438
|
})),
|
|
64
439
|
};
|
|
65
440
|
return redactNestedMessageContainers(value, this.deps.redactEnabled());
|
|
66
441
|
}
|
|
442
|
+
contextDetailKey(target, snapshot) {
|
|
443
|
+
return snapshot ? ownerStateId(JSON.stringify([target.key, snapshot.authority_epoch, snapshot.replay_epoch, snapshot.revision, snapshot.execution_generation, snapshot.info, snapshot.last_sequence])) : null;
|
|
444
|
+
}
|
|
445
|
+
reactionView(row, allowed) {
|
|
446
|
+
if (!Number.isSafeInteger(row.row_id) || Number(row.row_id) <= 0 || !['user', 'assistant'].includes(str(row.role)))
|
|
447
|
+
return undefined;
|
|
448
|
+
const authors = new Map();
|
|
449
|
+
for (const raw of Array.isArray(row.reactions) ? row.reactions : []) {
|
|
450
|
+
const reaction = raw;
|
|
451
|
+
const emoji = ReactionEmojiSchema.safeParse(reaction?.emoji);
|
|
452
|
+
if (emoji.success && (reaction.author === 'user' || reaction.author === 'agent'))
|
|
453
|
+
authors.set(reaction.author, emoji.data);
|
|
454
|
+
}
|
|
455
|
+
const state = (selected) => {
|
|
456
|
+
const values = [authors.get('agent'), selected].filter((emoji) => emoji !== undefined && emoji !== null);
|
|
457
|
+
return { selected, items: ReactionEmojiSchema.options.flatMap((emoji) => {
|
|
458
|
+
const count = values.filter((value) => value === emoji).length;
|
|
459
|
+
return count ? [{ emoji, count, mine: selected === emoji }] : [];
|
|
460
|
+
}) };
|
|
461
|
+
};
|
|
462
|
+
const selected = authors.get('user') ?? null;
|
|
463
|
+
return { row_id: Number(row.row_id), state: state(selected), actions: allowed
|
|
464
|
+
? [...ReactionEmojiSchema.options, ...(selected ? [null] : [])].map((emoji) => ({ emoji, result: state(emoji === selected ? null : emoji) })) : [] };
|
|
465
|
+
}
|
|
67
466
|
async view(base, result, stream, target, limit = 120, before = null, withMessages = true) {
|
|
68
467
|
const snapshot = result.snapshot;
|
|
69
|
-
const fields = { ...base, owner_attachment: this.attachment(result), composer_state_key: ownerStateId(target.key), active_stream_id: stream, is_streaming: Boolean(stream) };
|
|
468
|
+
const fields = { ...base, owner_attachment: this.attachment({ ...result, model_change: this.currentModelChange(target, snapshot) }), composer_state_key: ownerStateId(target.key), context_detail_key: this.contextDetailKey(target, snapshot), active_stream_id: stream, is_streaming: Boolean(stream) };
|
|
70
469
|
if (snapshot) {
|
|
71
|
-
|
|
72
|
-
const
|
|
470
|
+
fields.notices = this.nativeNotices(target, snapshot);
|
|
471
|
+
const observed = this.watches.get(target.key)?.snapshot;
|
|
472
|
+
const canReact = snapshot.reactions_supported === true && this.attachment(result).can_submit;
|
|
473
|
+
const nativeRows = snapshot.messages.map(({ reactions, ...row }) => ({ ...row,
|
|
474
|
+
reaction_view: this.reactionView({ ...row, reactions }, canReact),
|
|
475
|
+
}));
|
|
476
|
+
const active = stream ? runningAdmission(snapshot) : null;
|
|
73
477
|
let start = active ? nativeRows.findIndex((m) => m.role === 'user' && m.message_id === active.admission_id) : -1;
|
|
74
478
|
if (active && stream && start < 0) {
|
|
75
479
|
start = nativeRows.length;
|
|
@@ -86,6 +490,8 @@ export class GatewaySessions {
|
|
|
86
490
|
model_provider: provider, model_option_id: this.deps.service.deps.modelOptionFor?.(model, provider) ?? null,
|
|
87
491
|
workspace: str(snapshot.info.cwd) || base.workspace, active_stream_id: stream, is_streaming: Boolean(stream), agent_running: snapshot.running,
|
|
88
492
|
transcript_seq: stream ? { stream_id: stream, seq: 0 } : null,
|
|
493
|
+
tool_calls: withMessages && before === null && stream && snapshot.running && observed && sameExecution(snapshot, observed)
|
|
494
|
+
? this.deps.service.deps.runtime.liveToolProgress?.(stream) ?? [] : [],
|
|
89
495
|
});
|
|
90
496
|
fields.workspace_name = (await this.deps.service.workspaceNames([fields]))(fields);
|
|
91
497
|
}
|
|
@@ -95,7 +501,7 @@ export class GatewaySessions {
|
|
|
95
501
|
// The wire's existing owner lock already classified ordinary sessions, including cached pages.
|
|
96
502
|
if (base.read_only_reason !== CANONICAL_READ_ONLY_REASON)
|
|
97
503
|
return base;
|
|
98
|
-
const target = this.target(str(base.session_id), str(base.profile) || this.deps.activeProfile());
|
|
504
|
+
const target = await this.target(str(base.session_id), str(base.profile) || this.deps.activeProfile());
|
|
99
505
|
if (!target)
|
|
100
506
|
return base;
|
|
101
507
|
const result = await this.call(target, { action: 'snapshot' });
|
|
@@ -109,8 +515,8 @@ export class GatewaySessions {
|
|
|
109
515
|
return this.view(base, result, watch?.stream ?? null, target, limit, before, withMessages);
|
|
110
516
|
}
|
|
111
517
|
/** Called before the direct-chat admission path, including for an already materialized foreign session. */
|
|
112
|
-
async submit(sid, body) {
|
|
113
|
-
const target = this.target(sid);
|
|
518
|
+
async submit(sid, body, timing, fence) {
|
|
519
|
+
const target = await this.target(sid);
|
|
114
520
|
if (!target)
|
|
115
521
|
return null;
|
|
116
522
|
const text = str(body.message).trim();
|
|
@@ -118,7 +524,9 @@ export class GatewaySessions {
|
|
|
118
524
|
throw new HttpFailure(400, 'message is required');
|
|
119
525
|
// Native policy is frozen by its owner. Changing model/workspace travels through session.mutate,
|
|
120
526
|
// never through a hidden per-turn override or the local Agent setup path.
|
|
527
|
+
const closeSnapshot = timing?.begin('owner_snapshot');
|
|
121
528
|
const before = await this.call(target, { action: 'snapshot' });
|
|
529
|
+
closeSnapshot?.(before.state === 'unavailable' ? 'unknown' : before.state === 'attached' ? 'ok' : 'refused');
|
|
122
530
|
if (!this.attachment(before).can_submit)
|
|
123
531
|
throw new HttpFailure(before.state === 'attached' ? 409 : 403, 'The owning Agent is unavailable or needs an explicit recovery decision', { owner_attachment: this.attachment(before) });
|
|
124
532
|
if (typeof body.submission_id !== 'string' || !body.submission_id || body.submission_id.length > 128)
|
|
@@ -126,17 +534,29 @@ export class GatewaySessions {
|
|
|
126
534
|
if (Array.isArray(body.attachments) && body.attachments.length)
|
|
127
535
|
throw new HttpFailure(400, 'File attachments are unavailable through this owner connection', { code: 'owner_attachments_unavailable' });
|
|
128
536
|
// Resolve display state before admission; a failed post-ACK read must never turn accepted work into a refusal.
|
|
129
|
-
const base = await this.deps.service.detail(sid, {});
|
|
537
|
+
const base = await (timing ? timing.measure('owner_detail', () => this.deps.service.detail(sid, {})) : this.deps.service.detail(sid, {}));
|
|
538
|
+
if (fence && (!this.deps.service.deps.profilesMatch(str(base.profile) || null, fence.profile) || (str(base.project_id) || null) !== fence.project_id || before.snapshot?.authority_epoch !== fence.authority_epoch || before.snapshot.running || before.snapshot.pending.some((p) => p.status !== 'terminal')))
|
|
539
|
+
throw new HttpFailure(409, 'Queue target changed or is busy');
|
|
540
|
+
const closeSubmit = timing?.begin('owner_submit');
|
|
130
541
|
const result = await this.call(target, { action: 'submit', request_id: body.submission_id, text });
|
|
131
|
-
|
|
542
|
+
closeSubmit?.(result.receipt ? 'ok' : result.state === 'unavailable' ? 'unknown' : 'refused');
|
|
543
|
+
if (result.state === 'attached' && result.snapshot && result.receipt?.voice_stopped === true) {
|
|
544
|
+
const watch = this.watches.get(target.key);
|
|
545
|
+
return { ok: true, status: 'suppressed', reason: 'voice_stopped', session_id: sid,
|
|
546
|
+
owner_attachment: this.attachment(result), session: await this.view(base, result, watch?.stream ?? null, target) };
|
|
547
|
+
}
|
|
548
|
+
if (!result.receipt || !('admission_id' in result.receipt))
|
|
132
549
|
throw new HttpFailure(409, 'The owner did not confirm this admission. Reconcile it before resending.', { owner_attachment: this.attachment(result), outcome_unknown: result.state === 'unavailable' });
|
|
133
550
|
const snapshot = result.snapshot;
|
|
134
|
-
|
|
551
|
+
// A fast refusal can settle before submit returns; its retained completion still belongs to this input.
|
|
552
|
+
const refused = result.receipt.status === 'terminal' && result.receipt.outcome === 'failed';
|
|
553
|
+
const watch = snapshot && (refused || snapshot.running || snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
554
|
+
? this.watches.get(target.key) ?? this.watch(target, base, snapshot, refused ? str(result.receipt.admission_id) : undefined) : null;
|
|
135
555
|
this.deps.events.publish('owner_admission', { profile: target.profile, sessionId: sid });
|
|
136
556
|
return { session_id: sid, ...(watch ? { stream_id: watch.stream, turn_id: watch.stream } : {}), owner_attachment: this.attachment(result), admission_id: result.receipt.admission_id, session: await this.view(base, result, watch?.stream ?? null, target) };
|
|
137
557
|
}
|
|
138
558
|
async action(sid, params) {
|
|
139
|
-
const target = this.target(sid);
|
|
559
|
+
const target = await this.target(sid);
|
|
140
560
|
if (!target)
|
|
141
561
|
throw new HttpFailure(403, 'This session has no canonical owner');
|
|
142
562
|
if (params.action === 'mutate' && params.operation === 'workspace') {
|
|
@@ -147,15 +567,30 @@ export class GatewaySessions {
|
|
|
147
567
|
throw new HttpFailure(400, 'The workspace must be trusted before selecting it');
|
|
148
568
|
}
|
|
149
569
|
}
|
|
150
|
-
|
|
570
|
+
if (params.action === 'react') {
|
|
571
|
+
const current = await this.call(target, { action: 'snapshot' });
|
|
572
|
+
const row = current.snapshot?.messages.find((row) => row.row_id === params.row_id);
|
|
573
|
+
if (!row || current.snapshot?.reactions_supported !== true || !this.attachment(current).can_submit
|
|
574
|
+
|| !['user', 'assistant'].includes(str(row.role)))
|
|
575
|
+
throw new HttpFailure(409, 'Reactions are unavailable for this message');
|
|
576
|
+
}
|
|
577
|
+
let result = await this.call(target, params);
|
|
578
|
+
if (params.action === 'react' && result.state === 'unavailable') {
|
|
579
|
+
// A toggle has no idempotency key. Read the owner after a lost ACK; never replay the write.
|
|
580
|
+
result = await this.call(target, { action: 'snapshot' });
|
|
581
|
+
if (result.state !== 'attached' || !result.snapshot)
|
|
582
|
+
throw new HttpFailure(503, 'Could not confirm the reaction. Reconnect to read its current value.', { outcome_unknown: true });
|
|
583
|
+
}
|
|
151
584
|
if (result.state !== 'attached' || !result.snapshot)
|
|
152
585
|
throw new HttpFailure(409, 'The owning Agent refused the action', { owner_attachment: this.attachment(result) });
|
|
586
|
+
if (params.action === 'react')
|
|
587
|
+
this.changed(target);
|
|
153
588
|
this.deps.events.publish('owner_changed', { profile: target.profile, sessionId: sid });
|
|
154
589
|
return result;
|
|
155
590
|
}
|
|
156
591
|
/** The display preview is redacted; an explicit retry returns the original text for review, like direct-chat retry. */
|
|
157
592
|
async retry(sid, admissionId, generation) {
|
|
158
|
-
const target = this.target(sid);
|
|
593
|
+
const target = await this.target(sid);
|
|
159
594
|
if (!target)
|
|
160
595
|
throw new HttpFailure(403, 'This session has no canonical owner');
|
|
161
596
|
const current = await this.call(target, { action: 'snapshot' });
|
|
@@ -168,7 +603,7 @@ export class GatewaySessions {
|
|
|
168
603
|
await this.action(sid, { action: 'discard', admission_id: admissionId, execution_generation: generation });
|
|
169
604
|
return text;
|
|
170
605
|
}
|
|
171
|
-
prompts(snapshot, sid) {
|
|
606
|
+
prompts(snapshot, sid, batch) {
|
|
172
607
|
const pending = new PendingPrompts(new SessionEventBus(), this.deps.now);
|
|
173
608
|
for (const prompt of snapshot?.prompts ?? []) {
|
|
174
609
|
const data = { ...prompt, session_id: sid, request_id: prompt.prompt_id, timeout_seconds: 0, allowed_choices: prompt.choices, can_enable_yolo: false };
|
|
@@ -177,25 +612,56 @@ export class GatewaySessions {
|
|
|
177
612
|
else if (prompt.kind === 'clarify')
|
|
178
613
|
pending.submitClarify(sid, { ...data, clarify_id: prompt.prompt_id });
|
|
179
614
|
}
|
|
615
|
+
// A fully locked batch waits only for the owner's withdrawal; nothing is left to ask.
|
|
616
|
+
if (batch?.remaining.length) {
|
|
617
|
+
const entry = pending.submitClarify(sid, { session_id: sid, clarify_id: batch.request_id, request_id: batch.request_id, timeout_seconds: 0, questions: batch.questions });
|
|
618
|
+
for (const step of entry.steps)
|
|
619
|
+
step.answered = !batch.remaining.includes(step.qid);
|
|
620
|
+
}
|
|
180
621
|
return pending;
|
|
181
622
|
}
|
|
623
|
+
/** The batch the target's live watch received; the owner asks it once, of the viewers attached when it parks. */
|
|
624
|
+
batch(target) { return this.watches.get(target.key)?.batch ?? null; }
|
|
625
|
+
/** Locks each answer; the owner settles the batch on the lock that leaves nothing open. */
|
|
626
|
+
async lockBatch(target, batch, answers) {
|
|
627
|
+
for (const [qid, answer] of Object.entries(answers)) {
|
|
628
|
+
const result = await this.call(target, { action: 'clarify_lock', request_id: batch.request_id, question_id: qid, answer: Array.isArray(answer) ? JSON.stringify(answer) : answer });
|
|
629
|
+
if (result.state === 'attached' && result.lock?.status === 'ok') {
|
|
630
|
+
batch.remaining = result.lock.remaining ?? [];
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (result.lock?.status === 'expired')
|
|
634
|
+
batch.remaining = [];
|
|
635
|
+
// An unconfirmed lock keeps the card and its answers for a retry; an ended batch or a refusal is stale.
|
|
636
|
+
throw new HttpFailure(result.state === 'unavailable' ? 503 : 409, 'The owning Agent did not accept this answer', { owner_attachment: this.attachment(result) });
|
|
637
|
+
}
|
|
638
|
+
}
|
|
182
639
|
async pending(sid, kind) {
|
|
183
|
-
const target = this.target(sid);
|
|
640
|
+
const target = await this.target(sid);
|
|
184
641
|
if (!target)
|
|
185
642
|
throw new HttpFailure(404, 'Session not found');
|
|
186
643
|
const result = await this.call(target, { action: 'snapshot' });
|
|
187
|
-
const pending = this.prompts(result.snapshot, sid);
|
|
644
|
+
const pending = this.prompts(result.snapshot, sid, this.batch(target));
|
|
188
645
|
const envelope = kind === 'approval' ? pending.approvalPending(sid) : pending.clarifyPending(sid);
|
|
189
646
|
return { pending: envelope.pending ? redactNestedMessageContainers(envelope.pending, this.deps.redactEnabled()) : null, pending_count: envelope.pending_count };
|
|
190
647
|
}
|
|
191
648
|
async respond(sid, kind, id, value) {
|
|
192
|
-
const target = this.target(sid);
|
|
649
|
+
const target = await this.target(sid);
|
|
193
650
|
if (!target)
|
|
194
651
|
return false;
|
|
195
652
|
const current = await this.call(target, { action: 'snapshot' });
|
|
196
|
-
const
|
|
653
|
+
const batch = this.batch(target);
|
|
654
|
+
const pending = this.prompts(current.snapshot, sid, batch);
|
|
197
655
|
if (current.state !== 'attached')
|
|
198
656
|
throw new HttpFailure(403, 'This canonical session is read-only while its owner is unavailable');
|
|
657
|
+
if (kind === 'clarify' && batch?.remaining.length && batch.request_id === id) {
|
|
658
|
+
const entry = pending.peekClarify(sid, id);
|
|
659
|
+
const reply = entry && value !== null ? clarifyReply(entry, value) : null;
|
|
660
|
+
if (reply === null)
|
|
661
|
+
throw new HttpFailure(400, 'Answer every question in the pending clarification');
|
|
662
|
+
await this.lockBatch(target, batch, JSON.parse(reply).answers);
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
199
665
|
const prompt = current.snapshot?.prompts.find((p) => p.kind === kind && p.prompt_id === id);
|
|
200
666
|
if (!prompt)
|
|
201
667
|
throw new HttpFailure(409, 'The owner prompt is stale');
|
|
@@ -228,9 +694,30 @@ export class GatewaySessions {
|
|
|
228
694
|
await this.action(sid, { action: 'interrupt', execution_generation: watch.snapshot.execution_generation });
|
|
229
695
|
return true;
|
|
230
696
|
}
|
|
231
|
-
watch(target, base, snapshot) {
|
|
232
|
-
const watch = { stream: `${ownerStreamPrefix(target.home)}${randomUUID()}`, controller: new AbortController(), snapshot };
|
|
697
|
+
watch(target, base, snapshot, admissionId) {
|
|
698
|
+
const watch = { stream: `${ownerStreamPrefix(target.home)}${randomUUID()}`, controller: new AbortController(), snapshot, batch: null, restarting: false };
|
|
233
699
|
this.watches.set(target.key, watch);
|
|
700
|
+
const observation = this.transport(target, base, snapshot);
|
|
701
|
+
const release = this.lease(observation);
|
|
702
|
+
let activeAdmission = admissionId ?? runningAdmission(snapshot)?.admission_id ?? snapshot.pending.find((p) => !p.steering)?.admission_id;
|
|
703
|
+
let receive = null;
|
|
704
|
+
const buffered = [{ event: 'snapshot', seq: 0, data: { state: 'attached', reason: null, snapshot, receipt: null, replaying: true } }];
|
|
705
|
+
const completed = observation.completion?.data;
|
|
706
|
+
if (completed?.authority_epoch === snapshot.authority_epoch && completed.replay_epoch === snapshot.replay_epoch
|
|
707
|
+
&& completed.execution_generation === snapshot.execution_generation && (completed.payload ?? {}).admission_id === activeAdmission)
|
|
708
|
+
buffered.push(observation.completion);
|
|
709
|
+
if (!observation.replaying)
|
|
710
|
+
buffered.push({ event: 'replay_complete', seq: 0, data: {} });
|
|
711
|
+
const listener = (frame) => {
|
|
712
|
+
if (receive)
|
|
713
|
+
receive(frame);
|
|
714
|
+
else if (buffered.length < 4096)
|
|
715
|
+
buffered.push(frame);
|
|
716
|
+
else
|
|
717
|
+
watch.controller.abort();
|
|
718
|
+
};
|
|
719
|
+
observation.listeners.add(listener);
|
|
720
|
+
watch.controller.signal.addEventListener('abort', () => { observation.listeners.delete(listener); release(); }, { once: true });
|
|
234
721
|
const registry = this.deps.registry;
|
|
235
722
|
const channel = registry.create(watch.stream, target.sid);
|
|
236
723
|
registry.registerActiveRun({ stream_id: watch.stream, session_id: target.sid, phase: 'running', started_at: this.deps.now(), workspace: str(base.workspace), model: str(base.model) || null, provider: null, ephemeral: false, origin: 'user' });
|
|
@@ -238,38 +725,95 @@ export class GatewaySessions {
|
|
|
238
725
|
let terminal = false;
|
|
239
726
|
let streamError = null;
|
|
240
727
|
let closeWriter = null;
|
|
241
|
-
|
|
728
|
+
const enqueue = (work) => {
|
|
729
|
+
chain = chain.then(async () => { if (!terminal && !streamError)
|
|
730
|
+
await work(); })
|
|
731
|
+
.catch((error) => { streamError = error; watch.controller.abort(); });
|
|
732
|
+
};
|
|
242
733
|
const worker = async () => {
|
|
243
734
|
// Same persisted IDs can exist in separate homes. Native observation journals must not
|
|
244
735
|
// join the sid-only direct-chat journal; the owner retains the canonical transcript.
|
|
245
736
|
const journalSession = ownerStateId(target.key);
|
|
246
737
|
const writer = await this.deps.journal.writer(journalSession, watch.stream);
|
|
247
738
|
closeWriter = writer;
|
|
739
|
+
const showReasoning = await this.deps.showReasoning(target.home).catch(() => false);
|
|
740
|
+
let completion = null;
|
|
741
|
+
let replaying = true;
|
|
742
|
+
let liveRunning = false;
|
|
743
|
+
let usage = {};
|
|
744
|
+
let reasoning = '';
|
|
745
|
+
let titles = new ReasoningTitleTracker();
|
|
746
|
+
const calls = registry.liveToolCalls.get(watch.stream);
|
|
248
747
|
const put = async (event, data) => {
|
|
249
748
|
const safe = event === 'tool' || event === 'tool_complete' ? publicToolFrame(data, this.deps.redactEnabled()) : redactNestedMessageContainers(data, this.deps.redactEnabled());
|
|
749
|
+
// Progress is ephemeral, just like direct turns; a reload gets the channel's latest value after journal replay.
|
|
750
|
+
if (event === 'tool_progress') {
|
|
751
|
+
channel.put([event, safe, null, this.deps.redactEnabled()]);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
250
754
|
const record = await writer.appendSseEvent(event, safe);
|
|
251
755
|
channel.put([event, safe, record.event_id]);
|
|
252
756
|
};
|
|
757
|
+
const clearTools = async () => {
|
|
758
|
+
for (const call of calls)
|
|
759
|
+
if (call.progress)
|
|
760
|
+
await put('tool_progress', { id: call.tid, progress: null });
|
|
761
|
+
calls.length = 0;
|
|
762
|
+
};
|
|
763
|
+
const resetProjection = async () => { await clearTools(); liveRunning = false; reasoning = ''; usage = {}; completion = null; titles = new ReasoningTitleTracker(); };
|
|
764
|
+
const meter = async (data) => {
|
|
765
|
+
usage = { ...usage, ...ownerUsage(data) };
|
|
766
|
+
if (['input_tokens', 'output_tokens', 'cache_read_tokens', 'cache_write_tokens'].every((key) => typeof usage[key] === 'number'))
|
|
767
|
+
await put('metering', { session_id: target.sid, usage: { ...usage, estimated_cost: usage.estimated_cost ?? null }, tps: usage.tps ?? null, tps_available: usage.tps !== undefined, estimated: false });
|
|
768
|
+
};
|
|
253
769
|
const finish = async () => {
|
|
254
|
-
|
|
770
|
+
// A model pick resolves at the owner's next claim boundary, after the turn becomes idle.
|
|
771
|
+
if (terminal || replaying || this.modelMutations.has(target.key) || this.currentModelChange(target, watch.snapshot)?.state === 'deferred')
|
|
255
772
|
return;
|
|
256
773
|
terminal = true;
|
|
774
|
+
// A new claim may arrive while this turn's receipt is being read. Give it its own projection immediately.
|
|
775
|
+
if (this.watches.get(target.key) === watch)
|
|
776
|
+
this.watches.delete(target.key);
|
|
777
|
+
registry.activeRuns.delete(watch.stream);
|
|
778
|
+
await clearTools();
|
|
257
779
|
const current = await this.call(target, { action: 'snapshot' });
|
|
258
|
-
const
|
|
780
|
+
const rawReceipt = activeAdmission ? (await this.call(target, { action: 'receipt', admission_id: activeAdmission })).receipt : null;
|
|
781
|
+
const receipt = rawReceipt && 'admission_id' in rawReceipt ? rawReceipt : null;
|
|
259
782
|
const cancelled = receipt?.outcome === 'interrupted' || receipt?.outcome === 'cancelled';
|
|
260
783
|
const failed = current.state !== 'attached' || receipt?.status !== 'terminal' || receipt.outcome !== 'completed' && !cancelled;
|
|
784
|
+
const refusal = current.state === 'attached' && current.snapshot && sameExecution(current.snapshot, watch.snapshot)
|
|
785
|
+
&& receipt?.status === 'terminal' && receipt.outcome === 'failed' && completion && completion.admission === activeAdmission
|
|
786
|
+
&& receipt.authority_epoch === watch.snapshot.authority_epoch && receipt.execution_generation === watch.snapshot.execution_generation
|
|
787
|
+
? { message: completion.message, type: completion.type, code: completion.code, retryable: completion.retryable } : null;
|
|
788
|
+
// A terminal frame for the previous generation must not overwrite the newer turn's state.
|
|
789
|
+
const session = current.snapshot && !sameExecution(current.snapshot, observation.snapshot)
|
|
790
|
+
? undefined : { ...await this.view(base, current, null, target), ...usage };
|
|
791
|
+
if (session)
|
|
792
|
+
session.activity_phase = await this.deps.service.deps.sessionActivity?.(target.sid, target.profile, { terminalPhase: cancelled ? 'cancelled' : failed ? 'failed' : 'completed' });
|
|
261
793
|
await put(cancelled ? 'cancel' : failed ? 'apperror' : 'done', { session_id: target.sid,
|
|
262
794
|
terminal_state: cancelled ? 'cancelled' : failed ? 'error' : 'completed',
|
|
263
|
-
...(failed ? { message: 'The owning Agent could not complete this turn', type: current.reason ?? 'owner_turn_failed' } : {}),
|
|
264
|
-
|
|
795
|
+
...(failed ? refusal ?? { message: 'The owning Agent could not complete this turn', type: current.reason ?? 'owner_turn_failed' } : {}),
|
|
796
|
+
...(Object.keys(usage).length ? { usage } : {}),
|
|
797
|
+
...(session ? { session } : {}) });
|
|
798
|
+
if (liveRunning && !cancelled && !failed && receipt?.admission_id === activeAdmission && receipt?.authority_epoch === watch.snapshot.authority_epoch
|
|
799
|
+
&& receipt.execution_generation === watch.snapshot.execution_generation) {
|
|
800
|
+
this.deps.onWebCompletion?.(target.profile, target.sid, JSON.stringify(['owner', target.sid, watch.snapshot.authority_epoch, watch.snapshot.replay_epoch, watch.snapshot.execution_generation, receipt.admission_id]));
|
|
801
|
+
}
|
|
265
802
|
await put('stream_end', { session_id: target.sid });
|
|
266
803
|
watch.controller.abort();
|
|
267
804
|
};
|
|
268
|
-
|
|
805
|
+
// Reconcile after the last in-flight mutation releases its fence, in the same order as owner frames.
|
|
806
|
+
watch.reconcile = () => {
|
|
807
|
+
enqueue(async () => {
|
|
808
|
+
if (!watch.snapshot.running && !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
809
|
+
await finish();
|
|
810
|
+
});
|
|
811
|
+
};
|
|
812
|
+
let pending = this.prompts(snapshot, target.sid, watch.batch);
|
|
269
813
|
let ran = snapshot.running;
|
|
270
814
|
const prompts = async (snap) => {
|
|
271
815
|
watch.snapshot = snap;
|
|
272
|
-
pending = this.prompts(snap, target.sid);
|
|
816
|
+
pending = this.prompts(snap, target.sid, watch.batch);
|
|
273
817
|
const approval = pending.approvalPending(target.sid);
|
|
274
818
|
if (approval.pending)
|
|
275
819
|
await put('approval', { ...approval.pending, pending_count: approval.pending_count });
|
|
@@ -278,67 +822,182 @@ export class GatewaySessions {
|
|
|
278
822
|
await put('clarify', clarify);
|
|
279
823
|
};
|
|
280
824
|
await prompts(snapshot);
|
|
281
|
-
const sidecar = this.deps.sidecar();
|
|
282
|
-
if (!sidecar)
|
|
283
|
-
throw new Error('sidecar_unavailable');
|
|
284
825
|
if (watch.controller.signal.aborted)
|
|
285
826
|
return;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
827
|
+
receive = (frame) => {
|
|
828
|
+
enqueue(async () => {
|
|
829
|
+
if (frame.event === 'replay_complete') {
|
|
830
|
+
replaying = false;
|
|
831
|
+
liveRunning ||= watch.snapshot.running;
|
|
832
|
+
if (!watch.snapshot.running && !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
833
|
+
await finish();
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
if (frame.event === 'restarting') {
|
|
837
|
+
// The owner entered a restart's after-turn wait after this watch attached: clients stop sending.
|
|
838
|
+
watch.restarting = true;
|
|
839
|
+
await put('session_snapshot', { session: await this.view(base, { state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null, restarting: true }, watch.stream, target) });
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
if (frame.event === 'clarify_batch') {
|
|
843
|
+
const batch = GatewayClarifyBatchSchema.parse(frame.data);
|
|
844
|
+
watch.batch = { ...batch, remaining: batch.questions.map((q) => q.qid) };
|
|
845
|
+
await prompts(watch.snapshot);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
if (frame.event === 'snapshot') {
|
|
849
|
+
const result = GatewaySessionResultSchema.parse(frame.data);
|
|
850
|
+
replaying = frame.data.replaying === true;
|
|
851
|
+
if (replaying)
|
|
852
|
+
liveRunning = false;
|
|
853
|
+
if (!result.snapshot)
|
|
291
854
|
return;
|
|
292
|
-
if (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
855
|
+
if (result.replay_gap || !sameExecution(result.snapshot, watch.snapshot))
|
|
856
|
+
await resetProjection();
|
|
857
|
+
await put('session_snapshot', { session: await this.view(base, result, watch.stream, target), replay_gap: result.replay_gap === true });
|
|
858
|
+
await prompts(result.snapshot);
|
|
859
|
+
liveRunning ||= !replaying && result.snapshot.running;
|
|
860
|
+
if (!result.snapshot.running && !result.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
861
|
+
await finish();
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const event = frame.data;
|
|
865
|
+
const data = (event.payload ?? {});
|
|
866
|
+
const kind = str(event.type);
|
|
867
|
+
if (kind === 'notification.show' || kind === 'notification.clear') {
|
|
868
|
+
await put('notices', { session_id: target.sid, notices: this.nativeNotices(target, observation.snapshot) });
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
if (kind === 'request.cancel') {
|
|
872
|
+
// The owner withdraws a settled, timed-out or interrupted batch from every viewer.
|
|
873
|
+
if (!watch.batch || watch.batch.request_id !== data.id)
|
|
874
|
+
return;
|
|
875
|
+
watch.batch = null;
|
|
876
|
+
await prompts(watch.snapshot);
|
|
877
|
+
if (!pending.clarifyHeadFrame(target.sid))
|
|
878
|
+
await put('clarify', { status: 'resolved', clarify_id: data.id });
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (kind === 'session.updated') {
|
|
882
|
+
// Idle owner mutations carry no execution stamp. The sidecar scopes their subscription and replay.
|
|
883
|
+
if (event.session_id !== target.sid
|
|
884
|
+
|| event.authority_epoch !== undefined && event.authority_epoch !== watch.snapshot.authority_epoch
|
|
885
|
+
|| event.execution_generation !== undefined && event.execution_generation !== watch.snapshot.execution_generation)
|
|
300
886
|
return;
|
|
887
|
+
if (data.operation !== 'model')
|
|
888
|
+
return;
|
|
889
|
+
this.rememberModelChange(target, watch.snapshot, modelChange(data));
|
|
890
|
+
const current = await this.call(target, { action: 'snapshot' });
|
|
891
|
+
if (current.snapshot)
|
|
892
|
+
watch.snapshot = current.snapshot;
|
|
893
|
+
await put('session_snapshot', { session: await this.view(base, current, watch.stream, target) });
|
|
894
|
+
if (!watch.snapshot.running && !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
895
|
+
await finish();
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
if (kind === 'session.info') {
|
|
899
|
+
if (data.authority_epoch !== watch.snapshot.authority_epoch)
|
|
900
|
+
return;
|
|
901
|
+
if (Number(data.execution_generation) < watch.snapshot.execution_generation)
|
|
902
|
+
return;
|
|
903
|
+
const firstClaim = !ran && data.running === true;
|
|
904
|
+
if (Number(data.execution_generation) > watch.snapshot.execution_generation)
|
|
905
|
+
await resetProjection();
|
|
906
|
+
watch.snapshot = { ...watch.snapshot, ...data };
|
|
907
|
+
const claimed = runningAdmission(watch.snapshot);
|
|
908
|
+
if (firstClaim && claimed)
|
|
909
|
+
activeAdmission = claimed.admission_id;
|
|
910
|
+
ran ||= data.running === true;
|
|
911
|
+
liveRunning ||= !replaying && data.running === true;
|
|
912
|
+
if (firstClaim)
|
|
913
|
+
await put('session_snapshot', { session: await this.view(base, { state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null, restarting: watch.restarting }, watch.stream, target) });
|
|
914
|
+
if (data.running === false && (ran || !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')))
|
|
915
|
+
await finish();
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
if (event.authority_epoch !== watch.snapshot.authority_epoch || event.execution_generation !== watch.snapshot.execution_generation)
|
|
919
|
+
return;
|
|
920
|
+
if (kind === 'message.delta') {
|
|
921
|
+
const stable = titles.stableSnapshot(reasoning);
|
|
922
|
+
if (stable !== null)
|
|
923
|
+
await put('reasoning', { text: '', titles: stable });
|
|
924
|
+
await put('token', { text: str(data.text || data.delta || data.content) });
|
|
925
|
+
}
|
|
926
|
+
else if (kind === 'reasoning.delta' && showReasoning) {
|
|
927
|
+
reasoning += str(data.text);
|
|
928
|
+
await put('reasoning', titles.prepare(reasoningEventPayload(data.text, reasoning)));
|
|
929
|
+
}
|
|
930
|
+
else if (kind.startsWith('subagent.') && str(data.subagent_id)) {
|
|
931
|
+
// Reuse the delegate activity row; each child keeps one identity through progress and completion.
|
|
932
|
+
const complete = kind === 'subagent.complete';
|
|
933
|
+
const preview = kind === 'subagent.thinking' && !showReasoning ? '' : str(data.summary || data.tool_preview || data.text);
|
|
934
|
+
await put(complete ? 'tool_complete' : 'tool', { id: `owner-subagent-${str(data.subagent_id)}`, name: 'subagent_progress',
|
|
935
|
+
args: { task: str(data.goal) }, preview: preview || null,
|
|
936
|
+
...(complete ? { is_error: data.status !== 'completed', duration: data.duration_seconds } : {}) });
|
|
937
|
+
}
|
|
938
|
+
else if (kind === 'session.usage')
|
|
939
|
+
await meter(data);
|
|
940
|
+
else if (kind === 'message.complete') {
|
|
941
|
+
if (event.session_id !== target.sid || event.replay_epoch !== undefined && event.replay_epoch !== watch.snapshot.replay_epoch)
|
|
942
|
+
return;
|
|
943
|
+
// Only this owner-defined refusal is public; never forward provider diagnostics or private descriptor fields.
|
|
944
|
+
const surface = data.error_surface;
|
|
945
|
+
if (activeAdmission && data.admission_id === activeAdmission && data.outcome === 'failed' && data.status === 'error'
|
|
946
|
+
&& surface?.layer === 'gateway' && surface.code === 'cron_session_read_only' && surface.retryable === false
|
|
947
|
+
&& typeof data.text === 'string' && data.text.trim()) {
|
|
948
|
+
completion = { admission: activeAdmission, message: data.text, type: 'cron_session_read_only', code: 'cron_session_read_only', retryable: false };
|
|
301
949
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
950
|
+
if (data.usage && typeof data.usage === 'object')
|
|
951
|
+
await meter(data.usage);
|
|
952
|
+
}
|
|
953
|
+
else if (kind === 'tool.start' || kind === 'tool.progress' || kind === 'tool.complete') {
|
|
954
|
+
if (event.session_id !== target.sid || event.replay_epoch !== undefined && event.replay_epoch !== watch.snapshot.replay_epoch)
|
|
955
|
+
return;
|
|
956
|
+
const id = str(data.tool_id) || str(data.tool_call_id);
|
|
957
|
+
const call = calls.findLast((call) => call.tid === id);
|
|
958
|
+
if (kind === 'tool.start') {
|
|
959
|
+
if (id && call)
|
|
307
960
|
return;
|
|
308
|
-
|
|
961
|
+
calls.push({ tid: id, name: data.name || data.tool_name, args: data.args ?? {}, done: false });
|
|
962
|
+
await put('tool', { ...data, id, name: data.name || data.tool_name });
|
|
963
|
+
}
|
|
964
|
+
else if (kind === 'tool.progress') {
|
|
965
|
+
if (!id || !call || call.done || !watch.snapshot.running)
|
|
309
966
|
return;
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const claimed = watch.snapshot.pending.find((p) => p.status === 'started');
|
|
313
|
-
if (firstClaim && claimed)
|
|
314
|
-
activeAdmission = claimed.admission_id;
|
|
315
|
-
ran ||= data.running === true;
|
|
316
|
-
if (firstClaim)
|
|
317
|
-
await put('session_snapshot', { session: await this.view(base, { state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null }, watch.stream, target) });
|
|
318
|
-
if (data.running === false && (ran || !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')))
|
|
319
|
-
await finish();
|
|
320
|
-
return;
|
|
967
|
+
call.progress = toolProgress({ ...data, message: typeof data.message === 'string' ? redactString(data.message, this.deps.redactEnabled()) : null });
|
|
968
|
+
await put('tool_progress', { id, progress: call.progress });
|
|
321
969
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
await put('
|
|
328
|
-
else if (kind === 'tool.complete')
|
|
329
|
-
await put('tool_complete', { ...data, id: data.tool_id || data.tool_call_id, name: data.name || data.tool_name });
|
|
330
|
-
else if (kind === 'approval.request' || kind === 'clarify.request')
|
|
331
|
-
await prompts({ ...watch.snapshot, prompts: [...watch.snapshot.prompts.filter((p) => p.prompt_id !== data.prompt_id), { ...data, kind: kind.split('.')[0] }] });
|
|
332
|
-
else if (kind === 'approval.settled' || kind === 'clarify.settled') {
|
|
333
|
-
await prompts({ ...watch.snapshot, prompts: watch.snapshot.prompts.filter((p) => p.prompt_id !== data.prompt_id) });
|
|
334
|
-
if (kind === 'approval.settled' && !pending.approvalPending(target.sid).pending)
|
|
335
|
-
await put('approval_cleared', { pending_count: 0 });
|
|
336
|
-
if (kind === 'clarify.settled' && !pending.clarifyHeadFrame(target.sid))
|
|
337
|
-
await put('clarify', { status: 'resolved', clarify_id: data.prompt_id });
|
|
970
|
+
else {
|
|
971
|
+
if (call?.done)
|
|
972
|
+
return;
|
|
973
|
+
if (call)
|
|
974
|
+
Object.assign(call, { done: true, progress: null });
|
|
975
|
+
await put('tool_complete', { ...data, id, name: data.name || data.tool_name, progress: null });
|
|
338
976
|
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
977
|
+
}
|
|
978
|
+
else if (kind === 'approval.request' || kind === 'clarify.request')
|
|
979
|
+
await prompts({ ...watch.snapshot, prompts: [...watch.snapshot.prompts.filter((p) => p.prompt_id !== data.prompt_id), { ...data, kind: kind.split('.')[0] }] });
|
|
980
|
+
else if (kind === 'approval.settled' || kind === 'clarify.settled') {
|
|
981
|
+
await prompts({ ...watch.snapshot, prompts: watch.snapshot.prompts.filter((p) => p.prompt_id !== data.prompt_id) });
|
|
982
|
+
if (kind === 'approval.settled' && !pending.approvalPending(target.sid).pending)
|
|
983
|
+
await put('approval_cleared', { pending_count: 0 });
|
|
984
|
+
if (kind === 'clarify.settled' && !pending.clarifyHeadFrame(target.sid))
|
|
985
|
+
await put('clarify', { status: 'resolved', clarify_id: data.prompt_id });
|
|
986
|
+
}
|
|
987
|
+
});
|
|
988
|
+
};
|
|
989
|
+
for (const frame of buffered.splice(0))
|
|
990
|
+
receive(frame);
|
|
991
|
+
const result = await Promise.race([
|
|
992
|
+
observation.ended,
|
|
993
|
+
new Promise((resolve) => {
|
|
994
|
+
const stopped = () => { resolve({ state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null }); };
|
|
995
|
+
if (watch.controller.signal.aborted)
|
|
996
|
+
stopped();
|
|
997
|
+
else
|
|
998
|
+
watch.controller.signal.addEventListener('abort', stopped, { once: true });
|
|
999
|
+
}),
|
|
1000
|
+
]);
|
|
342
1001
|
await chain;
|
|
343
1002
|
if (streamError)
|
|
344
1003
|
throw streamError instanceof Error ? streamError : new Error('Owner stream projection failed');
|
|
@@ -348,13 +1007,15 @@ export class GatewaySessions {
|
|
|
348
1007
|
watch.controller.abort();
|
|
349
1008
|
}
|
|
350
1009
|
};
|
|
351
|
-
|
|
1010
|
+
const running = worker().catch((error) => {
|
|
352
1011
|
// Closing the sidecar after a terminal snapshot is expected; every other exit is observable.
|
|
353
1012
|
if (!terminal)
|
|
354
1013
|
channel.put(['apperror', { message: 'The owning Agent connection ended', type: 'owner_unavailable', terminal_state: 'error' }, null]);
|
|
355
1014
|
this.deps.log(`[webui] owner observation ended: ${error instanceof Error ? error.name : 'error'}`);
|
|
356
1015
|
}).finally(async () => {
|
|
357
1016
|
watch.controller.abort();
|
|
1017
|
+
observation.listeners.delete(listener);
|
|
1018
|
+
release();
|
|
358
1019
|
try {
|
|
359
1020
|
await closeWriter?.close();
|
|
360
1021
|
}
|
|
@@ -364,15 +1025,23 @@ export class GatewaySessions {
|
|
|
364
1025
|
if (this.watches.get(target.key) === watch)
|
|
365
1026
|
this.watches.delete(target.key);
|
|
366
1027
|
registry.retire(watch.stream);
|
|
1028
|
+
this.changed(target);
|
|
367
1029
|
this.deps.events.publish('owner_changed', { profile: target.profile, sessionId: target.sid });
|
|
1030
|
+
this.runWorkers.delete(running);
|
|
368
1031
|
});
|
|
1032
|
+
this.runWorkers.add(running);
|
|
369
1033
|
return watch;
|
|
370
1034
|
}
|
|
371
1035
|
async close() {
|
|
1036
|
+
const observations = [...this.observations.values()];
|
|
1037
|
+
for (const observation of observations)
|
|
1038
|
+
observation.controller.abort();
|
|
372
1039
|
const watches = [...this.watches.values()];
|
|
373
1040
|
for (const watch of watches)
|
|
374
1041
|
watch.controller.abort();
|
|
375
|
-
await Promise.allSettled(
|
|
1042
|
+
await Promise.allSettled([...this.runWorkers]);
|
|
1043
|
+
await Promise.allSettled(observations.map((observation) => observation.ended));
|
|
1044
|
+
this.modelChanges.clear();
|
|
376
1045
|
}
|
|
377
1046
|
}
|
|
378
1047
|
//# sourceMappingURL=gateway-sessions.js.map
|