@maudecode/talaria-web 1.19.0 → 1.20.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 +8 -6
- package/dist/api/automation-router.js +7 -1
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +258 -33
- package/dist/api/chat-router.js +60 -25
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +4 -0
- package/dist/api/git-router.js +1 -1
- 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 +2 -2
- package/dist/api/session-visibility.js +2 -2
- package/dist/api/session-visibility.js.map +1 -1
- package/dist/api/sessions-router.d.ts +787 -107
- package/dist/api/sessions-router.js +16 -4
- 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 +41 -19
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-router.d.ts +314 -32
- package/dist/api/tools-router.js +135 -38
- 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 +14 -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.js +38 -14
- package/dist/redact.js.map +1 -1
- package/dist/release.js +5 -3
- package/dist/release.js.map +1 -1
- package/dist/runtime.js +85 -21
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +24 -21
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +2 -1
- package/dist/sessions/anchor.js +5 -1
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +23 -3
- package/dist/sessions/background-tasks.js +74 -4
- 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/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 +44 -4
- package/dist/sessions/gateway-sessions.js +626 -90
- 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 +11 -5
- package/dist/sessions/merge.js +59 -17
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +7 -4
- package/dist/sessions/prefix-index.js +21 -10
- package/dist/sessions/prefix-index.js.map +1 -1
- 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/service.d.ts +107 -37
- package/dist/sessions/service.js +490 -156
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +2 -0
- package/dist/sessions/session.js +4 -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 +70 -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 +5 -1
- package/dist/sessions/store.js +67 -27
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +8 -7
- package/dist/sessions/streams.js +49 -14
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +3 -1
- package/dist/sessions/tool-display.js +6 -0
- 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 +23 -5
- package/dist/sessions/turn.js +168 -78
- 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/mcp-health.js +74 -24
- package/dist/tools/mcp-health.js.map +1 -1
- package/dist/tools/mcp.js +19 -1
- package/dist/tools/mcp.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 +73 -7
- package/dist/tools/update-notifications.js +277 -43
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/updates.d.ts +8 -1
- package/dist/tools/updates.js +51 -17
- package/dist/tools/updates.js.map +1 -1
- 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 +17 -7
- 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 +17 -14
- 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 +159 -23
- package/sidecar/talaria_sidecar/agent_services.py +74 -11
- 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 +211 -27
- package/sidecar/talaria_sidecar/methods/kanban.py +2 -3
- package/sidecar/talaria_sidecar/methods/oauth.py +139 -11
- 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 +241 -213
- package/static/dist/THIRD_PARTY_LICENSES.md +6 -22
- package/static/dist/assets/AppShell-3isgvoro.js +8 -0
- package/static/dist/assets/Button-f4n6dapf.js +1 -0
- package/static/dist/assets/ChatPage-k7b6xfax.js +4 -0
- package/static/dist/assets/ConnectTargets-juqvt5lm.js +1 -0
- package/static/dist/assets/Dialog-hta5utr3.js +1 -0
- package/static/dist/assets/ExtensionRoute-zrhjn0wm.js +1 -0
- package/static/dist/assets/Field-b6ez48oz.js +1 -0
- package/static/dist/assets/HubRoute-iwvso2tz.js +2 -0
- package/static/dist/assets/LinkCheckContext-ix6zqqkk.js +1 -0
- package/static/dist/assets/Markdown-jdeth7zq.js +2 -0
- package/static/dist/assets/MarkdownRenderer-fbswsgld.js +302 -0
- package/static/dist/assets/MarkdownRenderer-i9o6nr38.css +1 -0
- package/static/dist/assets/OAuthSignIn-bpd8hom3.js +1 -0
- package/static/dist/assets/ResourceSwitch-odi6dy2o.js +1 -0
- package/static/dist/assets/RightPanel-eu6enlo6.js +1 -0
- package/static/dist/assets/Select-kr07928w.js +1 -0
- package/static/dist/assets/SessionListPanel-etb2i54l.js +1 -0
- package/static/dist/assets/SettingsLayout-eu3xxp23.js +1 -0
- package/static/dist/assets/States-icab19yg.js +1 -0
- package/static/dist/assets/TerminalPanel-hngmsr8b.js +16 -0
- package/static/dist/assets/Toaster-nb2uzjw1.js +1 -0
- package/static/dist/assets/_app-ga1moszl.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-na62087t.js +1 -0
- package/static/dist/assets/_app.index-jypgdqoi.js +1 -0
- package/static/dist/assets/_app.insights-kabejdtm.js +1 -0
- package/static/dist/assets/_app.kanban-m19kfcmx.js +1 -0
- package/static/dist/assets/_app.logs-iw4m96sz.js +1 -0
- package/static/dist/assets/_app.memory-jq5frwcg.js +1 -0
- package/static/dist/assets/_app.profiles-kwa3m7rp.js +1 -0
- package/static/dist/assets/_app.session._sessionId-o5lyeipj.js +1 -0
- package/static/dist/assets/_app.settings-ckl8hdll.js +1 -0
- package/static/dist/assets/_app.settings._section-dtdjk98a.js +3 -0
- package/static/dist/assets/_app.skills-n016rihd.js +1 -0
- package/static/dist/assets/_app.tasks-n8zuqsqe.js +1 -0
- package/static/dist/assets/_app.todos-btew5v2s.js +1 -0
- package/static/dist/assets/_app.workspaces-lnfk95ch.js +1 -0
- package/static/dist/assets/abnfDiagram-VCTEODGH-dttheegb.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-ic435919.js +1 -0
- package/static/dist/assets/architectureDiagram-5GKGNRK7-8r3glgiq.js +36 -0
- package/static/dist/assets/archive-il7c6053.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-jenyos6c.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-nzlx7yc4.js} +1 -1
- package/static/dist/assets/cancel-bsnfo36u.js +1 -0
- package/static/dist/assets/channel-dsbtk01y.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-koouqbut.js → chunk-4HAMMTFA-g0cru63b.js} +20 -20
- package/static/dist/assets/{chunk-75Z2AOVW-bl4bhdnt.js → chunk-75Z2AOVW-7rkswkjw.js} +1 -1
- package/static/dist/assets/chunk-DU6HZSFF-fn73jzdo.js +128 -0
- package/static/dist/assets/{chunk-F27PBJKO-d8xxi0zi.js → chunk-F27PBJKO-oey8e72m.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-l2a32wiy.js} +6 -6
- package/static/dist/assets/{chunk-GVQU2GXP-djn6gbyu.js → chunk-GVQU2GXP-o9dwzh8h.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-vw4p5p7o.js → chunk-IMKFNOWR-eblwj20b.js} +5 -5
- package/static/dist/assets/{chunk-L3NEJ4N5-n1hj77q8.js → chunk-L3NEJ4N5-o2mufspb.js} +1 -1
- package/static/dist/assets/chunk-OSK3NFVY-ijp9pw29.js +10 -0
- package/static/dist/assets/{chunk-P2QGCYS3-onf1hz6c.js → chunk-P2QGCYS3-hs9hqwl4.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-m8sqn7cs.js → chunk-POPQ4Y6H-bp9rsqez.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-ek4smc8x.js → chunk-PWAF6VOD-brkprov6.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-g9gfvefo.js → chunk-SHT3W25Y-gmpv0pxz.js} +13 -13
- package/static/dist/assets/{chunk-SVP7TREG-f9nfv2cu.js → chunk-SVP7TREG-oldm08fu.js} +4 -4
- package/static/dist/assets/{chunk-TICWLB2K-bnk3m1mq.js → chunk-TICWLB2K-ooqilfv7.js} +6 -6
- package/static/dist/assets/{chunk-XXDRQBXY-n40pf9vy.js → chunk-XXDRQBXY-jkmnqu65.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-fvgcv24g.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-fvgcv24g.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/copied-bz3gkazh.js +1 -0
- package/static/dist/assets/copy-jo006coq.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-d47op7qs.js +1 -0
- package/static/dist/assets/cynefinDiagram-5FMLGOSQ-doa7594y.js +62 -0
- package/static/dist/assets/cytoscape.esm-fjn2algp.js +321 -0
- package/static/dist/assets/dagre-GXQ25YYZ-os768dp4.js +4 -0
- package/static/dist/assets/dagre-o5jmjz46.js +1 -0
- package/static/dist/assets/{diagram-S7CK7UJ4-m6aeoe7c.js → diagram-S7CK7UJ4-fyi81nxd.js} +4 -4
- package/static/dist/assets/diagram-UQ7AKVKN-j3exggaq.js +41 -0
- package/static/dist/assets/{diagram-VSXAHHWV-hbawi7hn.js → diagram-VSXAHHWV-omo1en2l.js} +1 -1
- package/static/dist/assets/diagram-VX7I27RA-oro2cyu0.js +24 -0
- package/static/dist/assets/diagram-Z3DM3KII-byt9vdb7.js +24 -0
- package/static/dist/assets/dist-crc46di9.js +7 -0
- package/static/dist/assets/dist-etpoyscq.js +44 -0
- package/static/dist/assets/{dist-c4c2m3kv.js → dist-nb670eu6.js} +1 -1
- package/static/dist/assets/ebnfDiagram-PWID7BFC-ee3haugh.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-d1e93yff.js +99 -0
- package/static/dist/assets/{erb-idlyfheg.js → erb-flwsv146.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-i1ihb40c.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-jahfpiod.js +1 -0
- package/static/dist/assets/folder-plus-ivoglq98.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ma6jxj5i.js → ganttDiagram-EL5Y4UJY-m7g0jud4.js} +1 -1
- package/static/dist/assets/{git-rebase-d9lpfpbn.js → git-rebase-bli19aoq.js} +1 -1
- package/static/dist/assets/gitGraph-4MIJSDKK-hzdj07yy.js +1 -0
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-hzltvsod.js → gitGraphDiagram-WWUBYQGX-dm9agbna.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-mmgz2czu.js +1 -0
- package/static/dist/assets/host-fr6lni1p.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-73649w7o.js +10 -0
- package/static/dist/assets/index-lhf1fsdf.css +2 -0
- package/static/dist/assets/info-A6RAGUB7-lll1dqmm.js +1 -0
- package/static/dist/assets/infoDiagram-27XIBGKW-k7esc639.js +2 -0
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-e7bnwq7h.js → ishikawaDiagram-5VMMS53U-lgr6k9wo.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-ndmbxuqk.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-mjxym0jp.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-cwb6l7xh.js +1 -0
- package/static/dist/assets/{line-h0ojzsvs.js → line-mtr5k6il.js} +1 -1
- package/static/dist/assets/linear-jlwrvvy6.js +1 -0
- package/static/dist/assets/link-iadw4ghw.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-lkhtzfcl.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-jx0q5dm2.js +1 -0
- package/static/dist/assets/mermaid-parser.core-k91vdnvi.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-ehztfea4.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-f67z0a2r.js +1 -0
- package/static/dist/assets/packet-AYTQ26CC-ok2xrblz.js +1 -0
- package/static/dist/assets/pegDiagram-XKGWAZYB-ec3rpj0m.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-iwkir23u.js +1 -0
- package/static/dist/assets/pieDiagram-E7YTZNPT-fcpqpekh.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-lqsync43.js} +1 -1
- package/static/dist/assets/queryKeys-ed4n2egc.js +9 -0
- package/static/dist/assets/{r-o3r9c7ao.js → r-epfzuw6q.js} +1 -1
- package/static/dist/assets/radar-RG4KPBEZ-hje4jbk6.js +1 -0
- package/static/dist/assets/railroad-74A4TZTK-gll9n6qi.js +1 -0
- package/static/dist/assets/railroad-abnf-HS5TGJTU-o6h6lpn4.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-juaefj6o.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-cgfhvpah.js +1 -0
- package/static/dist/assets/railroadDiagram-O6MQD6OU-lp3w7awf.js +1 -0
- package/static/dist/assets/{razor-ilc585yr.js → razor-pea1u1d0.js} +1 -1
- package/static/dist/assets/refresh-cw-iccm7a4e.js +1 -0
- package/static/dist/assets/refresh-i9ya9dvl.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-ha8eibcf.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-oxf31pr9.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-jiq8lhyo.js} +11 -11
- package/static/dist/assets/settings_section_extensions_title-fadc7o65.js +1 -0
- package/static/dist/assets/share._token-o76ki0ly.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-ddcs88av.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-f3fslnon.js +1 -0
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hlt6yphw.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-k1hmk7jf.js +1 -0
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-hd5t9tnt.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-n3ncfy9r.js} +8 -8
- package/static/dist/assets/toast-liparz2j.js +56 -0
- package/static/dist/assets/treeView-Q6P3EWNA-l3y2pejt.js +1 -0
- package/static/dist/assets/treemap-WGGIJYW6-jown9axh.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-o4uu74mx.js +1 -0
- package/static/dist/assets/{useParams-gjc70qru.js → useParams-ftsveu84.js} +1 -1
- package/static/dist/assets/{useSearch-e6ae539u.js → useSearch-crqueqga.js} +1 -1
- package/static/dist/assets/vennDiagram-4TSXK5OY-dh59uq1c.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-e6d74b0j.js +1 -0
- package/static/dist/assets/wardleyDiagram-VM6X3IG4-hnofh78f.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-bpymjelb.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,34 +1,237 @@
|
|
|
1
|
-
|
|
1
|
+
import { unavailableContextDetail } from '@maudecode/talaria-web-contracts';
|
|
2
2
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
-
import { GatewaySessionResultSchema } from '@maudecode/talaria-web-contracts';
|
|
4
|
-
import { redactNestedMessageContainers, publicToolFrame } from '../redact.js';
|
|
3
|
+
import { OWNER_EXPORT_MAX_BYTES, SessionNoticeSchema, GatewayClarifyBatchSchema, GatewaySessionResultSchema } from '@maudecode/talaria-web-contracts';
|
|
4
|
+
import { redactNestedMessageContainers, publicToolFrame, redactString } from '../redact.js';
|
|
5
5
|
import { str } from '../util.js';
|
|
6
6
|
import { PendingPrompts } from './pending.js';
|
|
7
|
+
import { wrapExportHtml } from './export.js';
|
|
7
8
|
import { clarifyReply } from './pending.js';
|
|
8
9
|
import { HttpFailure } from './service.js';
|
|
10
|
+
import { SessionNotices } from './notices.js';
|
|
9
11
|
import { SessionEventBus } from './events.js';
|
|
10
12
|
import { messageWindowForDisplay, messagesForLimitedPayload } from './window.js';
|
|
11
13
|
import { pendingUserRow } from './merge.js';
|
|
12
|
-
import {
|
|
14
|
+
import { ReasoningTitleTracker, reasoningEventPayload } from './reasoning-titles.js';
|
|
15
|
+
import { CANONICAL_READ_ONLY_REASON, WEB_DIAGNOSTIC_REQUEST_PREFIX } from './state-db.js';
|
|
16
|
+
import { toolProgress } from './tool-display.js';
|
|
13
17
|
const ownerStreamPrefix = (home) => `owner-${createHash('sha256').update(home).digest('hex').slice(0, 16)}-`;
|
|
14
18
|
const ownerStateId = (identity) => `owner-${createHash('sha256').update(identity).digest('hex')}`;
|
|
15
19
|
/** The scope remains verifiable after a server restart, before a journal lookup or stream subscription. */
|
|
16
20
|
export const gatewayStreamVisible = (stream, home) => !stream.startsWith('owner-') || stream.startsWith(ownerStreamPrefix(home));
|
|
21
|
+
/** The server's one classification of why an owner cannot start a diagnostic chat; clients word the code. */
|
|
22
|
+
function unavailableReason(result) {
|
|
23
|
+
if (result.state === 'stopped')
|
|
24
|
+
return 'gateway_stopped';
|
|
25
|
+
if (result.reason === 'served_profile_sessions_unavailable')
|
|
26
|
+
return 'served_profile';
|
|
27
|
+
if (result.state === 'incompatible')
|
|
28
|
+
return 'agent_unsupported';
|
|
29
|
+
return 'gateway_unavailable';
|
|
30
|
+
}
|
|
17
31
|
/** A preview can be absent in a valid native receipt; only original nonblank text can become a retry draft. */
|
|
18
32
|
function retryText(admission) {
|
|
19
33
|
const text = admission.text;
|
|
20
34
|
return typeof text === 'string' && text.trim() ? text : null;
|
|
21
35
|
}
|
|
36
|
+
/** Steering belongs to the current turn; it must never replace that turn's transcript anchor. */
|
|
37
|
+
const runningAdmission = (snapshot) => snapshot.pending.find((p) => p.status === 'started' && !p.steering);
|
|
38
|
+
const sameExecution = (a, b) => a.authority_epoch === b.authority_epoch && a.replay_epoch === b.replay_epoch && a.execution_generation === b.execution_generation;
|
|
39
|
+
/** Native counters and the owner's compact turn-end usage share one existing Web usage shape. */
|
|
40
|
+
function ownerUsage(data) {
|
|
41
|
+
const fields = {
|
|
42
|
+
input_tokens: ['prompt_tokens', 'prompt', 'input_tokens', 'input'], output_tokens: ['completion_tokens', 'completion', 'output_tokens', 'output'],
|
|
43
|
+
cache_read_tokens: ['cache_read_tokens'], cache_write_tokens: ['cache_write_tokens'],
|
|
44
|
+
estimated_cost: ['estimated_cost_usd'], last_prompt_tokens: ['last_prompt_tokens', 'context_used'],
|
|
45
|
+
context_length: ['context_length', 'context_max'], cache_hit_percent: ['cache_hit_pct'], tps: ['tokens_per_s', 'avg_tps'],
|
|
46
|
+
};
|
|
47
|
+
const usage = {};
|
|
48
|
+
for (const [field, keys] of Object.entries(fields)) {
|
|
49
|
+
const value = keys.map((key) => data[key]).find((value) => typeof value === 'number' && Number.isFinite(value) && value >= 0);
|
|
50
|
+
if (value !== undefined)
|
|
51
|
+
usage[field] = value;
|
|
52
|
+
}
|
|
53
|
+
return usage;
|
|
54
|
+
}
|
|
55
|
+
/** Translate only owner-confirmed outcomes; an unknown receipt never means applied. */
|
|
56
|
+
function modelChange(receipt, selection = {}) {
|
|
57
|
+
const payload = receipt.payload && typeof receipt.payload === 'object' ? receipt.payload : selection;
|
|
58
|
+
const model = str(receipt.target_model) || str(payload.model) || str(receipt.model);
|
|
59
|
+
const provider = Object.hasOwn(receipt, 'target_provider') ? receipt.target_provider : payload.provider;
|
|
60
|
+
const target = { ...(model ? { model } : {}), ...(provider === null || typeof provider === 'string' ? { provider } : {}) };
|
|
61
|
+
if (receipt.operation !== 'model')
|
|
62
|
+
return { state: 'refused', message: 'The owner did not confirm the model change' };
|
|
63
|
+
if (receipt.status === 'deferred')
|
|
64
|
+
return { state: 'deferred', ...target };
|
|
65
|
+
if (receipt.status === 'confirmation_required' && typeof receipt.confirm === 'string' && receipt.confirm && model)
|
|
66
|
+
return { state: 'confirmation_required', message: str(receipt.confirm_message), confirm: receipt.confirm, ...target };
|
|
67
|
+
if (receipt.status === undefined && Number.isInteger(receipt.revision))
|
|
68
|
+
return { state: 'applied' };
|
|
69
|
+
return { state: 'refused', message: str(receipt.reason || receipt.message) || 'The owner did not confirm the model change' };
|
|
70
|
+
}
|
|
22
71
|
export class GatewaySessions {
|
|
23
72
|
deps;
|
|
24
73
|
watches = new Map();
|
|
74
|
+
runWorkers = new Set();
|
|
75
|
+
observations = new Map();
|
|
76
|
+
noticeEpochs = new Map();
|
|
77
|
+
notices;
|
|
78
|
+
modelMutations = new Map();
|
|
79
|
+
modelChanges = new Map();
|
|
80
|
+
rememberModelChange(target, snapshot, change) {
|
|
81
|
+
this.modelChanges.set(target.key, { epoch: snapshot.authority_epoch, replay: snapshot.replay_epoch, change });
|
|
82
|
+
}
|
|
83
|
+
currentModelChange(target, snapshot) {
|
|
84
|
+
const saved = this.modelChanges.get(target.key);
|
|
85
|
+
if (!saved || !snapshot)
|
|
86
|
+
return undefined;
|
|
87
|
+
if (saved.epoch === snapshot.authority_epoch && saved.replay === snapshot.replay_epoch)
|
|
88
|
+
return saved.change;
|
|
89
|
+
this.modelChanges.delete(target.key);
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
25
92
|
constructor(deps) {
|
|
26
93
|
this.deps = deps;
|
|
94
|
+
this.notices = new SessionNotices(deps.now);
|
|
95
|
+
}
|
|
96
|
+
addNativeNotice(target, key, frame) {
|
|
97
|
+
const text = typeof frame.text === 'string' ? frame.text.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, '') : '';
|
|
98
|
+
this.notices.add(target.key, { ...frame, key, text, lapses_with_agent: true });
|
|
99
|
+
}
|
|
100
|
+
noticeState(target, snapshot, reset = false) {
|
|
101
|
+
const identity = ownerStateId(JSON.stringify([target.key, snapshot.authority_epoch, snapshot.replay_epoch]));
|
|
102
|
+
let state = this.noticeEpochs.get(target.key);
|
|
103
|
+
if (state?.identity !== identity || reset) {
|
|
104
|
+
this.notices.reset(target.key);
|
|
105
|
+
state = { identity, sequence: reset ? snapshot.last_sequence : 0 };
|
|
106
|
+
this.noticeEpochs.set(target.key, state);
|
|
107
|
+
}
|
|
108
|
+
const warning = typeof snapshot.info.config_warning === 'string' ? snapshot.info.config_warning : '';
|
|
109
|
+
if (warning.trim())
|
|
110
|
+
this.addNativeNotice(target, `${identity}:config-warning`, { text: warning, level: 'warn' });
|
|
111
|
+
return state;
|
|
112
|
+
}
|
|
113
|
+
nativeNotices(target, snapshot) {
|
|
114
|
+
const observed = this.observations.get(target.key)?.snapshot;
|
|
115
|
+
this.noticeState(target, observed && observed.authority_epoch >= snapshot.authority_epoch ? observed : snapshot);
|
|
116
|
+
// A detail row may already contain our projection. Read the direct layer itself so
|
|
117
|
+
// retained transport bases cannot duplicate warnings or resurrect cleared notices.
|
|
118
|
+
const direct = SessionNoticeSchema.array().safeParse(this.deps.service.deps.runtime.sessionNotices?.(target.sid) ?? []);
|
|
119
|
+
return [...(direct.success ? direct.data : []), ...this.notices.list(target.key)];
|
|
120
|
+
}
|
|
121
|
+
changed(target) {
|
|
122
|
+
this.deps.channels.emit(target.sid, 'session-updated', { session_id: target.sid, source: 'native_owner' }, target.profile);
|
|
123
|
+
}
|
|
124
|
+
/** One shared connection, acquired by viewers and run projections, with no local Agent admission. */
|
|
125
|
+
transport(target, base, snapshot) {
|
|
126
|
+
const prior = this.observations.get(target.key);
|
|
127
|
+
if (prior && !prior.controller.signal.aborted)
|
|
128
|
+
return prior;
|
|
129
|
+
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 }) };
|
|
130
|
+
this.observations.set(target.key, observation);
|
|
131
|
+
this.noticeState(target, snapshot);
|
|
132
|
+
observation.ended = (async () => {
|
|
133
|
+
const showReasoning = await this.deps.showReasoning(target.home).catch(() => false);
|
|
134
|
+
const sidecar = this.deps.sidecar();
|
|
135
|
+
if (!sidecar || observation.controller.signal.aborted)
|
|
136
|
+
return { state: 'unavailable', reason: 'sidecar_unavailable', snapshot: null, receipt: null };
|
|
137
|
+
return sidecar.call('gateway.session', { profile_home: target.home, session_id: target.sid, action: 'watch', show_reasoning: showReasoning }, {
|
|
138
|
+
signal: observation.controller.signal, timeoutMs: 0,
|
|
139
|
+
onStream: (frame) => {
|
|
140
|
+
if (observation.controller.signal.aborted || this.observations.get(target.key) !== observation)
|
|
141
|
+
return;
|
|
142
|
+
if (frame.event === 'snapshot') {
|
|
143
|
+
const result = GatewaySessionResultSchema.parse(frame.data);
|
|
144
|
+
if (result.snapshot?.session_id !== target.sid)
|
|
145
|
+
return;
|
|
146
|
+
const completed = observation.completion?.data;
|
|
147
|
+
if (result.replay_gap || completed && (completed.authority_epoch !== result.snapshot.authority_epoch || completed.replay_epoch !== result.snapshot.replay_epoch))
|
|
148
|
+
observation.completion = null;
|
|
149
|
+
observation.snapshot = result.snapshot;
|
|
150
|
+
observation.replaying = frame.data.replaying === true;
|
|
151
|
+
this.noticeState(target, result.snapshot, result.replay_gap === true);
|
|
152
|
+
if ((result.snapshot.running || result.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')) && !this.watches.has(target.key))
|
|
153
|
+
this.watch(target, base, result.snapshot);
|
|
154
|
+
this.changed(target);
|
|
155
|
+
}
|
|
156
|
+
else if (frame.event === 'replay_complete') {
|
|
157
|
+
observation.replaying = false;
|
|
158
|
+
}
|
|
159
|
+
else if (frame.event === 'event') {
|
|
160
|
+
const event = frame.data;
|
|
161
|
+
const data = (event.payload ?? {});
|
|
162
|
+
if (event.type === 'notification.show' || event.type === 'notification.clear') {
|
|
163
|
+
const snap = observation.snapshot;
|
|
164
|
+
const state = this.noticeState(target, snap);
|
|
165
|
+
if (event.session_id !== target.sid || event.replay_epoch !== snap.replay_epoch
|
|
166
|
+
|| event.authority_epoch !== undefined && event.authority_epoch !== snap.authority_epoch
|
|
167
|
+
|| !Number.isSafeInteger(event.seq) || Number(event.seq) <= state.sequence)
|
|
168
|
+
return;
|
|
169
|
+
state.sequence = Number(event.seq);
|
|
170
|
+
const key = typeof data.key === 'string' ? data.key : typeof data.id === 'string' ? data.id : '';
|
|
171
|
+
if (!key)
|
|
172
|
+
return;
|
|
173
|
+
const scopedKey = `${state.identity}:plugin:${ownerStateId(key)}`;
|
|
174
|
+
if (event.type === 'notification.clear')
|
|
175
|
+
this.notices.clear(target.key, scopedKey);
|
|
176
|
+
else
|
|
177
|
+
this.addNativeNotice(target, scopedKey, data);
|
|
178
|
+
this.changed(target);
|
|
179
|
+
}
|
|
180
|
+
else if (event.type === 'session.info') {
|
|
181
|
+
if (data.authority_epoch !== observation.snapshot.authority_epoch || Number(data.execution_generation) < observation.snapshot.execution_generation)
|
|
182
|
+
return;
|
|
183
|
+
observation.snapshot = { ...observation.snapshot, ...data };
|
|
184
|
+
if ((observation.snapshot.running || observation.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')) && !this.watches.has(target.key))
|
|
185
|
+
this.watch(target, base, observation.snapshot);
|
|
186
|
+
this.changed(target);
|
|
187
|
+
}
|
|
188
|
+
else if (event.type === 'message.complete' && event.session_id === target.sid
|
|
189
|
+
&& event.authority_epoch === observation.snapshot.authority_epoch && event.replay_epoch === observation.snapshot.replay_epoch
|
|
190
|
+
&& Number.isSafeInteger(event.execution_generation) && Number(event.execution_generation) >= observation.snapshot.execution_generation) {
|
|
191
|
+
observation.completion = frame;
|
|
192
|
+
}
|
|
193
|
+
else if (event.type === 'session.updated')
|
|
194
|
+
this.changed(target);
|
|
195
|
+
}
|
|
196
|
+
for (const listener of observation.listeners)
|
|
197
|
+
listener(frame);
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
})().catch(() => ({ state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null })).finally(() => {
|
|
201
|
+
observation.controller.abort();
|
|
202
|
+
if (this.observations.get(target.key) === observation)
|
|
203
|
+
this.observations.delete(target.key);
|
|
204
|
+
this.changed(target);
|
|
205
|
+
});
|
|
206
|
+
return observation;
|
|
207
|
+
}
|
|
208
|
+
lease(observation) {
|
|
209
|
+
observation.leases++;
|
|
210
|
+
let held = true;
|
|
211
|
+
return () => { if (!held)
|
|
212
|
+
return; held = false; if (--observation.leases === 0)
|
|
213
|
+
observation.controller.abort(); };
|
|
214
|
+
}
|
|
215
|
+
/** Called only after the existing HTTP owner has authorized and claimed a viewer's stream slot. */
|
|
216
|
+
async observe(sid, profile, signal) {
|
|
217
|
+
const target = await this.target(sid, profile);
|
|
218
|
+
if (!target || signal.aborted)
|
|
219
|
+
return null;
|
|
220
|
+
const base = await this.deps.service.detail(sid, {});
|
|
221
|
+
const result = await this.call(target, { action: 'snapshot' }, signal);
|
|
222
|
+
if (signal.aborted)
|
|
223
|
+
return null;
|
|
224
|
+
if (!result.snapshot || result.state !== 'attached')
|
|
225
|
+
return { release: () => undefined, ended: Promise.resolve(result) };
|
|
226
|
+
const observation = this.transport(target, base, result.snapshot);
|
|
227
|
+
const release = this.lease(observation);
|
|
228
|
+
signal.addEventListener('abort', release, { once: true });
|
|
229
|
+
return { release: () => { signal.removeEventListener('abort', release); release(); }, ended: observation.ended };
|
|
27
230
|
}
|
|
28
|
-
target(sid, profile = this.deps.activeProfile()) {
|
|
231
|
+
async target(sid, profile = this.deps.activeProfile()) {
|
|
29
232
|
if (sid.length === 0 || sid !== sid.trim())
|
|
30
233
|
return null;
|
|
31
|
-
const owner = this.deps.service.stateDbSources([sid], profile)?.get(sid);
|
|
234
|
+
const owner = (await this.deps.service.stateDbSources([sid], profile))?.get(sid);
|
|
32
235
|
if (typeof owner !== 'object')
|
|
33
236
|
return null;
|
|
34
237
|
if (owner.reason)
|
|
@@ -36,40 +239,137 @@ export class GatewaySessions {
|
|
|
36
239
|
const home = this.deps.profileHome(profile);
|
|
37
240
|
return { sid, profile, home, key: JSON.stringify([home, sid]) };
|
|
38
241
|
}
|
|
39
|
-
|
|
40
|
-
|
|
242
|
+
async contextDetail(sid, expectedKey) {
|
|
243
|
+
const profile = this.deps.activeProfile();
|
|
244
|
+
const target = await this.target(sid, profile);
|
|
245
|
+
if (!target)
|
|
246
|
+
return unavailableContextDetail();
|
|
247
|
+
const result = await this.call(target, { action: 'context_detail' });
|
|
248
|
+
return profile === this.deps.activeProfile() && result.state === 'attached' && this.contextDetailKey(target, result.snapshot) === expectedKey ? result.context_detail ?? unavailableContextDetail('unsupported') : unavailableContextDetail('changed');
|
|
249
|
+
}
|
|
250
|
+
async isOwned(sid) { return (await this.target(sid)) !== null; }
|
|
251
|
+
async export(sid, format) {
|
|
252
|
+
const target = await this.target(sid);
|
|
253
|
+
if (!target)
|
|
254
|
+
return null;
|
|
255
|
+
const redact = this.deps.redactEnabled();
|
|
256
|
+
const result = await this.call(target, { action: 'export', format, redact });
|
|
257
|
+
const value = result.export;
|
|
258
|
+
if (result.reason === 'export_too_large')
|
|
259
|
+
throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
|
|
260
|
+
if (result.state !== 'attached' || value?.format !== format) {
|
|
261
|
+
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' });
|
|
262
|
+
}
|
|
263
|
+
if (Buffer.byteLength(value.content, 'utf8') > OWNER_EXPORT_MAX_BYTES)
|
|
264
|
+
throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
|
|
265
|
+
let content;
|
|
266
|
+
try {
|
|
267
|
+
// The owner redacts HTML's structured transcript before rendering. A shell/text redactor corrupts its markup.
|
|
268
|
+
content = format === 'html' ? wrapExportHtml(value.content) : format === 'json'
|
|
269
|
+
? JSON.stringify(redactNestedMessageContainers(JSON.parse(value.content), redact), null, 2)
|
|
270
|
+
: redactString(value.content, redact);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
throw new HttpFailure(409, 'The Agent owner returned an invalid transcript export', { code: 'owner_export_invalid' });
|
|
274
|
+
}
|
|
275
|
+
if (Buffer.byteLength(content, 'utf8') > OWNER_EXPORT_MAX_BYTES)
|
|
276
|
+
throw new HttpFailure(413, 'The owner transcript exceeds the export limit');
|
|
277
|
+
return { ...value, content };
|
|
278
|
+
}
|
|
279
|
+
async createCall(params) {
|
|
41
280
|
const sidecar = this.deps.sidecar();
|
|
42
281
|
if (!sidecar)
|
|
43
282
|
return { state: 'unavailable', reason: 'sidecar_unavailable', snapshot: null, receipt: null };
|
|
44
283
|
try {
|
|
45
|
-
return await sidecar.call('gateway.
|
|
284
|
+
return await sidecar.call('gateway.create', params, { timeoutMs: 35_000 });
|
|
46
285
|
}
|
|
47
286
|
catch {
|
|
48
287
|
return { state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null };
|
|
49
288
|
}
|
|
50
289
|
}
|
|
290
|
+
/** TAL-1040: normal always runs; the bypass modes need an owner that freezes them before any Agent import. */
|
|
291
|
+
async modes(profile) {
|
|
292
|
+
const result = await this.createCall({ profile_home: this.deps.profileHome(profile), probe: true });
|
|
293
|
+
const reason = result.state === 'attached' ? null : unavailableReason(result);
|
|
294
|
+
// Owner chats take no file attachments (`submit` refuses them), so a fresh chat in either bypass mode cannot attach.
|
|
295
|
+
return { modes: [{ mode: 'normal', available: true, reason: null, can_attach: true }, ...['ignore_config', 'safe'].map((mode) => ({ mode, available: reason === null, reason, can_attach: false }))] };
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* TAL-1040: the owner mints a diagnostic chat, freezes its bypass in the creation receipt and runs each turn in a fresh
|
|
299
|
+
* private worker. Talaria keeps no local Session and never falls back to an ordinary chat; no credential is sent.
|
|
300
|
+
*/
|
|
301
|
+
async create(profile, creationId, params) {
|
|
302
|
+
// The client's creation id survives a lost response, so a retry recovers the owner's committed session, never a second one.
|
|
303
|
+
const result = await this.createCall({ ...params, profile_home: this.deps.profileHome(profile), request_id: WEB_DIAGNOSTIC_REQUEST_PREFIX + (creationId ?? randomUUID()) });
|
|
304
|
+
if (result.state !== 'attached' || !result.snapshot) {
|
|
305
|
+
throw new HttpFailure(409, 'The Agent cannot start a chat in this mode', { code: 'execution_mode_unavailable', reason: unavailableReason(result) });
|
|
306
|
+
}
|
|
307
|
+
return result.snapshot.session_id;
|
|
308
|
+
}
|
|
309
|
+
async call(target, params, signal) {
|
|
310
|
+
const sidecar = this.deps.sidecar();
|
|
311
|
+
if (!sidecar)
|
|
312
|
+
return { state: 'unavailable', reason: 'sidecar_unavailable', snapshot: null, receipt: null };
|
|
313
|
+
const before = this.modelChanges.get(target.key);
|
|
314
|
+
const modelMutation = params.action === 'mutate' && params.operation === 'model';
|
|
315
|
+
if (modelMutation)
|
|
316
|
+
this.modelMutations.set(target.key, (this.modelMutations.get(target.key) ?? 0) + 1);
|
|
317
|
+
try {
|
|
318
|
+
const result = await sidecar.call('gateway.session', { ...params, profile_home: target.home, session_id: target.sid }, { timeoutMs: params.action === 'mutate' ? 675_000 : 35_000, ...(signal ? { signal } : {}) });
|
|
319
|
+
if (params.action === 'mutate' && params.operation === 'model' && result.snapshot) {
|
|
320
|
+
const change = modelChange(result.receipt ?? {}, params.payload);
|
|
321
|
+
// The stream can resolve a deferred pick before its HTTP ACK returns. Keep the later observation.
|
|
322
|
+
if (change.state !== 'deferred' || this.modelChanges.get(target.key) === before
|
|
323
|
+
|| !this.currentModelChange(target, result.snapshot))
|
|
324
|
+
this.rememberModelChange(target, result.snapshot, change);
|
|
325
|
+
}
|
|
326
|
+
const change = this.currentModelChange(target, result.snapshot);
|
|
327
|
+
return { ...result, ...(change ? { model_change: change } : {}) };
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
return { state: 'unavailable', reason: 'owner_connection_lost', snapshot: null, receipt: null };
|
|
331
|
+
}
|
|
332
|
+
finally {
|
|
333
|
+
if (modelMutation) {
|
|
334
|
+
const remaining = (this.modelMutations.get(target.key) ?? 1) - 1;
|
|
335
|
+
if (remaining)
|
|
336
|
+
this.modelMutations.set(target.key, remaining);
|
|
337
|
+
else {
|
|
338
|
+
this.modelMutations.delete(target.key);
|
|
339
|
+
this.watches.get(target.key)?.reconcile?.();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
51
344
|
attachment(result) {
|
|
52
345
|
const snapshot = result.snapshot;
|
|
53
346
|
const unknown = snapshot?.pending.some((p) => p.status === 'unknown') ?? false;
|
|
347
|
+
const restarting = result.restarting === true;
|
|
54
348
|
const value = {
|
|
55
|
-
state: result.state, reason: result.reason, can_submit: result.state === 'attached' && snapshot !== null && !unknown,
|
|
349
|
+
state: result.state, reason: result.reason, restarting, can_submit: result.state === 'attached' && snapshot !== null && !unknown && !restarting,
|
|
56
350
|
can_interrupt: result.state === 'attached' && snapshot?.running === true, can_attach: false,
|
|
57
351
|
revision: snapshot?.revision ?? null, execution_generation: snapshot?.execution_generation ?? null,
|
|
58
|
-
|
|
352
|
+
...(result.model_change ? { model_change: result.model_change } : {}),
|
|
353
|
+
active_admission: snapshot ? runningAdmission(snapshot) ?? null : null,
|
|
59
354
|
admissions: (snapshot?.pending ?? []).filter((p) => p.status === 'queued' || p.status === 'unknown').map((p) => ({ ...p,
|
|
60
|
-
actions: p.status === 'queued' ? ['cancel']
|
|
355
|
+
actions: p.status === 'queued' ? ['cancel', ...(p.controls?.includes('steer') ? ['steer'] : []), ...(p.controls?.includes('replace') ? ['edit'] : [])]
|
|
61
356
|
: p.execution_generation === null ? []
|
|
62
357
|
: retryText(p) === null ? ['discard'] : ['retry', 'discard'],
|
|
63
358
|
})),
|
|
64
359
|
};
|
|
65
360
|
return redactNestedMessageContainers(value, this.deps.redactEnabled());
|
|
66
361
|
}
|
|
362
|
+
contextDetailKey(target, snapshot) {
|
|
363
|
+
return snapshot ? ownerStateId(JSON.stringify([target.key, snapshot.authority_epoch, snapshot.replay_epoch, snapshot.revision, snapshot.execution_generation, snapshot.info, snapshot.last_sequence])) : null;
|
|
364
|
+
}
|
|
67
365
|
async view(base, result, stream, target, limit = 120, before = null, withMessages = true) {
|
|
68
366
|
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) };
|
|
367
|
+
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
368
|
if (snapshot) {
|
|
369
|
+
fields.notices = this.nativeNotices(target, snapshot);
|
|
370
|
+
const observed = this.watches.get(target.key)?.snapshot;
|
|
71
371
|
const nativeRows = [...snapshot.messages];
|
|
72
|
-
const active = stream ? snapshot
|
|
372
|
+
const active = stream ? runningAdmission(snapshot) : null;
|
|
73
373
|
let start = active ? nativeRows.findIndex((m) => m.role === 'user' && m.message_id === active.admission_id) : -1;
|
|
74
374
|
if (active && stream && start < 0) {
|
|
75
375
|
start = nativeRows.length;
|
|
@@ -86,6 +386,8 @@ export class GatewaySessions {
|
|
|
86
386
|
model_provider: provider, model_option_id: this.deps.service.deps.modelOptionFor?.(model, provider) ?? null,
|
|
87
387
|
workspace: str(snapshot.info.cwd) || base.workspace, active_stream_id: stream, is_streaming: Boolean(stream), agent_running: snapshot.running,
|
|
88
388
|
transcript_seq: stream ? { stream_id: stream, seq: 0 } : null,
|
|
389
|
+
tool_calls: withMessages && before === null && stream && snapshot.running && observed && sameExecution(snapshot, observed)
|
|
390
|
+
? this.deps.service.deps.runtime.liveToolProgress?.(stream) ?? [] : [],
|
|
89
391
|
});
|
|
90
392
|
fields.workspace_name = (await this.deps.service.workspaceNames([fields]))(fields);
|
|
91
393
|
}
|
|
@@ -95,7 +397,7 @@ export class GatewaySessions {
|
|
|
95
397
|
// The wire's existing owner lock already classified ordinary sessions, including cached pages.
|
|
96
398
|
if (base.read_only_reason !== CANONICAL_READ_ONLY_REASON)
|
|
97
399
|
return base;
|
|
98
|
-
const target = this.target(str(base.session_id), str(base.profile) || this.deps.activeProfile());
|
|
400
|
+
const target = await this.target(str(base.session_id), str(base.profile) || this.deps.activeProfile());
|
|
99
401
|
if (!target)
|
|
100
402
|
return base;
|
|
101
403
|
const result = await this.call(target, { action: 'snapshot' });
|
|
@@ -109,8 +411,8 @@ export class GatewaySessions {
|
|
|
109
411
|
return this.view(base, result, watch?.stream ?? null, target, limit, before, withMessages);
|
|
110
412
|
}
|
|
111
413
|
/** 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);
|
|
414
|
+
async submit(sid, body, timing) {
|
|
415
|
+
const target = await this.target(sid);
|
|
114
416
|
if (!target)
|
|
115
417
|
return null;
|
|
116
418
|
const text = str(body.message).trim();
|
|
@@ -118,7 +420,9 @@ export class GatewaySessions {
|
|
|
118
420
|
throw new HttpFailure(400, 'message is required');
|
|
119
421
|
// Native policy is frozen by its owner. Changing model/workspace travels through session.mutate,
|
|
120
422
|
// never through a hidden per-turn override or the local Agent setup path.
|
|
423
|
+
const closeSnapshot = timing?.begin('owner_snapshot');
|
|
121
424
|
const before = await this.call(target, { action: 'snapshot' });
|
|
425
|
+
closeSnapshot?.(before.state === 'unavailable' ? 'unknown' : before.state === 'attached' ? 'ok' : 'refused');
|
|
122
426
|
if (!this.attachment(before).can_submit)
|
|
123
427
|
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
428
|
if (typeof body.submission_id !== 'string' || !body.submission_id || body.submission_id.length > 128)
|
|
@@ -126,17 +430,27 @@ export class GatewaySessions {
|
|
|
126
430
|
if (Array.isArray(body.attachments) && body.attachments.length)
|
|
127
431
|
throw new HttpFailure(400, 'File attachments are unavailable through this owner connection', { code: 'owner_attachments_unavailable' });
|
|
128
432
|
// 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, {});
|
|
433
|
+
const base = await (timing ? timing.measure('owner_detail', () => this.deps.service.detail(sid, {})) : this.deps.service.detail(sid, {}));
|
|
434
|
+
const closeSubmit = timing?.begin('owner_submit');
|
|
130
435
|
const result = await this.call(target, { action: 'submit', request_id: body.submission_id, text });
|
|
131
|
-
|
|
436
|
+
closeSubmit?.(result.receipt ? 'ok' : result.state === 'unavailable' ? 'unknown' : 'refused');
|
|
437
|
+
if (result.state === 'attached' && result.snapshot && result.receipt?.voice_stopped === true) {
|
|
438
|
+
const watch = this.watches.get(target.key);
|
|
439
|
+
return { ok: true, status: 'suppressed', reason: 'voice_stopped', session_id: sid,
|
|
440
|
+
owner_attachment: this.attachment(result), session: await this.view(base, result, watch?.stream ?? null, target) };
|
|
441
|
+
}
|
|
442
|
+
if (!result.receipt || !('admission_id' in result.receipt))
|
|
132
443
|
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
444
|
const snapshot = result.snapshot;
|
|
134
|
-
|
|
445
|
+
// A fast refusal can settle before submit returns; its retained completion still belongs to this input.
|
|
446
|
+
const refused = result.receipt.status === 'terminal' && result.receipt.outcome === 'failed';
|
|
447
|
+
const watch = snapshot && (refused || snapshot.running || snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
448
|
+
? this.watches.get(target.key) ?? this.watch(target, base, snapshot, refused ? str(result.receipt.admission_id) : undefined) : null;
|
|
135
449
|
this.deps.events.publish('owner_admission', { profile: target.profile, sessionId: sid });
|
|
136
450
|
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
451
|
}
|
|
138
452
|
async action(sid, params) {
|
|
139
|
-
const target = this.target(sid);
|
|
453
|
+
const target = await this.target(sid);
|
|
140
454
|
if (!target)
|
|
141
455
|
throw new HttpFailure(403, 'This session has no canonical owner');
|
|
142
456
|
if (params.action === 'mutate' && params.operation === 'workspace') {
|
|
@@ -155,7 +469,7 @@ export class GatewaySessions {
|
|
|
155
469
|
}
|
|
156
470
|
/** The display preview is redacted; an explicit retry returns the original text for review, like direct-chat retry. */
|
|
157
471
|
async retry(sid, admissionId, generation) {
|
|
158
|
-
const target = this.target(sid);
|
|
472
|
+
const target = await this.target(sid);
|
|
159
473
|
if (!target)
|
|
160
474
|
throw new HttpFailure(403, 'This session has no canonical owner');
|
|
161
475
|
const current = await this.call(target, { action: 'snapshot' });
|
|
@@ -168,7 +482,7 @@ export class GatewaySessions {
|
|
|
168
482
|
await this.action(sid, { action: 'discard', admission_id: admissionId, execution_generation: generation });
|
|
169
483
|
return text;
|
|
170
484
|
}
|
|
171
|
-
prompts(snapshot, sid) {
|
|
485
|
+
prompts(snapshot, sid, batch) {
|
|
172
486
|
const pending = new PendingPrompts(new SessionEventBus(), this.deps.now);
|
|
173
487
|
for (const prompt of snapshot?.prompts ?? []) {
|
|
174
488
|
const data = { ...prompt, session_id: sid, request_id: prompt.prompt_id, timeout_seconds: 0, allowed_choices: prompt.choices, can_enable_yolo: false };
|
|
@@ -177,25 +491,56 @@ export class GatewaySessions {
|
|
|
177
491
|
else if (prompt.kind === 'clarify')
|
|
178
492
|
pending.submitClarify(sid, { ...data, clarify_id: prompt.prompt_id });
|
|
179
493
|
}
|
|
494
|
+
// A fully locked batch waits only for the owner's withdrawal; nothing is left to ask.
|
|
495
|
+
if (batch?.remaining.length) {
|
|
496
|
+
const entry = pending.submitClarify(sid, { session_id: sid, clarify_id: batch.request_id, request_id: batch.request_id, timeout_seconds: 0, questions: batch.questions });
|
|
497
|
+
for (const step of entry.steps)
|
|
498
|
+
step.answered = !batch.remaining.includes(step.qid);
|
|
499
|
+
}
|
|
180
500
|
return pending;
|
|
181
501
|
}
|
|
502
|
+
/** The batch the target's live watch received; the owner asks it once, of the viewers attached when it parks. */
|
|
503
|
+
batch(target) { return this.watches.get(target.key)?.batch ?? null; }
|
|
504
|
+
/** Locks each answer; the owner settles the batch on the lock that leaves nothing open. */
|
|
505
|
+
async lockBatch(target, batch, answers) {
|
|
506
|
+
for (const [qid, answer] of Object.entries(answers)) {
|
|
507
|
+
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 });
|
|
508
|
+
if (result.state === 'attached' && result.lock?.status === 'ok') {
|
|
509
|
+
batch.remaining = result.lock.remaining ?? [];
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
if (result.lock?.status === 'expired')
|
|
513
|
+
batch.remaining = [];
|
|
514
|
+
// An unconfirmed lock keeps the card and its answers for a retry; an ended batch or a refusal is stale.
|
|
515
|
+
throw new HttpFailure(result.state === 'unavailable' ? 503 : 409, 'The owning Agent did not accept this answer', { owner_attachment: this.attachment(result) });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
182
518
|
async pending(sid, kind) {
|
|
183
|
-
const target = this.target(sid);
|
|
519
|
+
const target = await this.target(sid);
|
|
184
520
|
if (!target)
|
|
185
521
|
throw new HttpFailure(404, 'Session not found');
|
|
186
522
|
const result = await this.call(target, { action: 'snapshot' });
|
|
187
|
-
const pending = this.prompts(result.snapshot, sid);
|
|
523
|
+
const pending = this.prompts(result.snapshot, sid, this.batch(target));
|
|
188
524
|
const envelope = kind === 'approval' ? pending.approvalPending(sid) : pending.clarifyPending(sid);
|
|
189
525
|
return { pending: envelope.pending ? redactNestedMessageContainers(envelope.pending, this.deps.redactEnabled()) : null, pending_count: envelope.pending_count };
|
|
190
526
|
}
|
|
191
527
|
async respond(sid, kind, id, value) {
|
|
192
|
-
const target = this.target(sid);
|
|
528
|
+
const target = await this.target(sid);
|
|
193
529
|
if (!target)
|
|
194
530
|
return false;
|
|
195
531
|
const current = await this.call(target, { action: 'snapshot' });
|
|
196
|
-
const
|
|
532
|
+
const batch = this.batch(target);
|
|
533
|
+
const pending = this.prompts(current.snapshot, sid, batch);
|
|
197
534
|
if (current.state !== 'attached')
|
|
198
535
|
throw new HttpFailure(403, 'This canonical session is read-only while its owner is unavailable');
|
|
536
|
+
if (kind === 'clarify' && batch?.remaining.length && batch.request_id === id) {
|
|
537
|
+
const entry = pending.peekClarify(sid, id);
|
|
538
|
+
const reply = entry && value !== null ? clarifyReply(entry, value) : null;
|
|
539
|
+
if (reply === null)
|
|
540
|
+
throw new HttpFailure(400, 'Answer every question in the pending clarification');
|
|
541
|
+
await this.lockBatch(target, batch, JSON.parse(reply).answers);
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
199
544
|
const prompt = current.snapshot?.prompts.find((p) => p.kind === kind && p.prompt_id === id);
|
|
200
545
|
if (!prompt)
|
|
201
546
|
throw new HttpFailure(409, 'The owner prompt is stale');
|
|
@@ -228,9 +573,30 @@ export class GatewaySessions {
|
|
|
228
573
|
await this.action(sid, { action: 'interrupt', execution_generation: watch.snapshot.execution_generation });
|
|
229
574
|
return true;
|
|
230
575
|
}
|
|
231
|
-
watch(target, base, snapshot) {
|
|
232
|
-
const watch = { stream: `${ownerStreamPrefix(target.home)}${randomUUID()}`, controller: new AbortController(), snapshot };
|
|
576
|
+
watch(target, base, snapshot, admissionId) {
|
|
577
|
+
const watch = { stream: `${ownerStreamPrefix(target.home)}${randomUUID()}`, controller: new AbortController(), snapshot, batch: null, restarting: false };
|
|
233
578
|
this.watches.set(target.key, watch);
|
|
579
|
+
const observation = this.transport(target, base, snapshot);
|
|
580
|
+
const release = this.lease(observation);
|
|
581
|
+
let activeAdmission = admissionId ?? runningAdmission(snapshot)?.admission_id ?? snapshot.pending.find((p) => !p.steering)?.admission_id;
|
|
582
|
+
let receive = null;
|
|
583
|
+
const buffered = [{ event: 'snapshot', seq: 0, data: { state: 'attached', reason: null, snapshot, receipt: null, replaying: true } }];
|
|
584
|
+
const completed = observation.completion?.data;
|
|
585
|
+
if (completed?.authority_epoch === snapshot.authority_epoch && completed.replay_epoch === snapshot.replay_epoch
|
|
586
|
+
&& completed.execution_generation === snapshot.execution_generation && (completed.payload ?? {}).admission_id === activeAdmission)
|
|
587
|
+
buffered.push(observation.completion);
|
|
588
|
+
if (!observation.replaying)
|
|
589
|
+
buffered.push({ event: 'replay_complete', seq: 0, data: {} });
|
|
590
|
+
const listener = (frame) => {
|
|
591
|
+
if (receive)
|
|
592
|
+
receive(frame);
|
|
593
|
+
else if (buffered.length < 4096)
|
|
594
|
+
buffered.push(frame);
|
|
595
|
+
else
|
|
596
|
+
watch.controller.abort();
|
|
597
|
+
};
|
|
598
|
+
observation.listeners.add(listener);
|
|
599
|
+
watch.controller.signal.addEventListener('abort', () => { observation.listeners.delete(listener); release(); }, { once: true });
|
|
234
600
|
const registry = this.deps.registry;
|
|
235
601
|
const channel = registry.create(watch.stream, target.sid);
|
|
236
602
|
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 +604,88 @@ export class GatewaySessions {
|
|
|
238
604
|
let terminal = false;
|
|
239
605
|
let streamError = null;
|
|
240
606
|
let closeWriter = null;
|
|
241
|
-
|
|
607
|
+
const enqueue = (work) => {
|
|
608
|
+
chain = chain.then(async () => { if (!terminal && !streamError)
|
|
609
|
+
await work(); })
|
|
610
|
+
.catch((error) => { streamError = error; watch.controller.abort(); });
|
|
611
|
+
};
|
|
242
612
|
const worker = async () => {
|
|
243
613
|
// Same persisted IDs can exist in separate homes. Native observation journals must not
|
|
244
614
|
// join the sid-only direct-chat journal; the owner retains the canonical transcript.
|
|
245
615
|
const journalSession = ownerStateId(target.key);
|
|
246
616
|
const writer = await this.deps.journal.writer(journalSession, watch.stream);
|
|
247
617
|
closeWriter = writer;
|
|
618
|
+
const showReasoning = await this.deps.showReasoning(target.home).catch(() => false);
|
|
619
|
+
let completion = null;
|
|
620
|
+
let replaying = true;
|
|
621
|
+
let usage = {};
|
|
622
|
+
let reasoning = '';
|
|
623
|
+
let titles = new ReasoningTitleTracker();
|
|
624
|
+
const calls = registry.liveToolCalls.get(watch.stream);
|
|
248
625
|
const put = async (event, data) => {
|
|
249
626
|
const safe = event === 'tool' || event === 'tool_complete' ? publicToolFrame(data, this.deps.redactEnabled()) : redactNestedMessageContainers(data, this.deps.redactEnabled());
|
|
627
|
+
// Progress is ephemeral, just like direct turns; a reload gets the channel's latest value after journal replay.
|
|
628
|
+
if (event === 'tool_progress') {
|
|
629
|
+
channel.put([event, safe, null, this.deps.redactEnabled()]);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
250
632
|
const record = await writer.appendSseEvent(event, safe);
|
|
251
633
|
channel.put([event, safe, record.event_id]);
|
|
252
634
|
};
|
|
635
|
+
const clearTools = async () => {
|
|
636
|
+
for (const call of calls)
|
|
637
|
+
if (call.progress)
|
|
638
|
+
await put('tool_progress', { id: call.tid, progress: null });
|
|
639
|
+
calls.length = 0;
|
|
640
|
+
};
|
|
641
|
+
const resetProjection = async () => { await clearTools(); reasoning = ''; usage = {}; completion = null; titles = new ReasoningTitleTracker(); };
|
|
642
|
+
const meter = async (data) => {
|
|
643
|
+
usage = { ...usage, ...ownerUsage(data) };
|
|
644
|
+
if (['input_tokens', 'output_tokens', 'cache_read_tokens', 'cache_write_tokens'].every((key) => typeof usage[key] === 'number'))
|
|
645
|
+
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 });
|
|
646
|
+
};
|
|
253
647
|
const finish = async () => {
|
|
254
|
-
|
|
648
|
+
// A model pick resolves at the owner's next claim boundary, after the turn becomes idle.
|
|
649
|
+
if (terminal || replaying || this.modelMutations.has(target.key) || this.currentModelChange(target, watch.snapshot)?.state === 'deferred')
|
|
255
650
|
return;
|
|
256
651
|
terminal = true;
|
|
652
|
+
// A new claim may arrive while this turn's receipt is being read. Give it its own projection immediately.
|
|
653
|
+
if (this.watches.get(target.key) === watch)
|
|
654
|
+
this.watches.delete(target.key);
|
|
655
|
+
registry.retire(watch.stream);
|
|
656
|
+
await clearTools();
|
|
257
657
|
const current = await this.call(target, { action: 'snapshot' });
|
|
258
|
-
const
|
|
658
|
+
const rawReceipt = activeAdmission ? (await this.call(target, { action: 'receipt', admission_id: activeAdmission })).receipt : null;
|
|
659
|
+
const receipt = rawReceipt && 'admission_id' in rawReceipt ? rawReceipt : null;
|
|
259
660
|
const cancelled = receipt?.outcome === 'interrupted' || receipt?.outcome === 'cancelled';
|
|
260
661
|
const failed = current.state !== 'attached' || receipt?.status !== 'terminal' || receipt.outcome !== 'completed' && !cancelled;
|
|
662
|
+
const refusal = current.state === 'attached' && current.snapshot && sameExecution(current.snapshot, watch.snapshot)
|
|
663
|
+
&& receipt?.status === 'terminal' && receipt.outcome === 'failed' && completion && completion.admission === activeAdmission
|
|
664
|
+
&& receipt.authority_epoch === watch.snapshot.authority_epoch && receipt.execution_generation === watch.snapshot.execution_generation
|
|
665
|
+
? { message: completion.message, type: completion.type, code: completion.code, retryable: completion.retryable } : null;
|
|
666
|
+
// A terminal frame for the previous generation must not overwrite the newer turn's state.
|
|
667
|
+
const session = current.snapshot && !sameExecution(current.snapshot, observation.snapshot)
|
|
668
|
+
? undefined : { ...await this.view(base, current, null, target), ...usage };
|
|
261
669
|
await put(cancelled ? 'cancel' : failed ? 'apperror' : 'done', { session_id: target.sid,
|
|
262
670
|
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
|
-
|
|
671
|
+
...(failed ? refusal ?? { message: 'The owning Agent could not complete this turn', type: current.reason ?? 'owner_turn_failed' } : {}),
|
|
672
|
+
...(Object.keys(usage).length ? { usage } : {}),
|
|
673
|
+
...(session ? { session } : {}) });
|
|
265
674
|
await put('stream_end', { session_id: target.sid });
|
|
266
675
|
watch.controller.abort();
|
|
267
676
|
};
|
|
268
|
-
|
|
677
|
+
// Reconcile after the last in-flight mutation releases its fence, in the same order as owner frames.
|
|
678
|
+
watch.reconcile = () => {
|
|
679
|
+
enqueue(async () => {
|
|
680
|
+
if (!watch.snapshot.running && !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
681
|
+
await finish();
|
|
682
|
+
});
|
|
683
|
+
};
|
|
684
|
+
let pending = this.prompts(snapshot, target.sid, watch.batch);
|
|
269
685
|
let ran = snapshot.running;
|
|
270
686
|
const prompts = async (snap) => {
|
|
271
687
|
watch.snapshot = snap;
|
|
272
|
-
pending = this.prompts(snap, target.sid);
|
|
688
|
+
pending = this.prompts(snap, target.sid, watch.batch);
|
|
273
689
|
const approval = pending.approvalPending(target.sid);
|
|
274
690
|
if (approval.pending)
|
|
275
691
|
await put('approval', { ...approval.pending, pending_count: approval.pending_count });
|
|
@@ -278,67 +694,177 @@ export class GatewaySessions {
|
|
|
278
694
|
await put('clarify', clarify);
|
|
279
695
|
};
|
|
280
696
|
await prompts(snapshot);
|
|
281
|
-
const sidecar = this.deps.sidecar();
|
|
282
|
-
if (!sidecar)
|
|
283
|
-
throw new Error('sidecar_unavailable');
|
|
284
697
|
if (watch.controller.signal.aborted)
|
|
285
698
|
return;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (
|
|
699
|
+
receive = (frame) => {
|
|
700
|
+
enqueue(async () => {
|
|
701
|
+
if (frame.event === 'replay_complete') {
|
|
702
|
+
replaying = false;
|
|
703
|
+
if (!watch.snapshot.running && !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
704
|
+
await finish();
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (frame.event === 'restarting') {
|
|
708
|
+
// The owner entered a restart's after-turn wait after this watch attached: clients stop sending.
|
|
709
|
+
watch.restarting = true;
|
|
710
|
+
await put('session_snapshot', { session: await this.view(base, { state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null, restarting: true }, watch.stream, target) });
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (frame.event === 'clarify_batch') {
|
|
714
|
+
const batch = GatewayClarifyBatchSchema.parse(frame.data);
|
|
715
|
+
watch.batch = { ...batch, remaining: batch.questions.map((q) => q.qid) };
|
|
716
|
+
await prompts(watch.snapshot);
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
if (frame.event === 'snapshot') {
|
|
720
|
+
const result = GatewaySessionResultSchema.parse(frame.data);
|
|
721
|
+
replaying = frame.data.replaying === true;
|
|
722
|
+
if (!result.snapshot)
|
|
291
723
|
return;
|
|
292
|
-
if (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
await
|
|
298
|
-
|
|
299
|
-
|
|
724
|
+
if (result.replay_gap || !sameExecution(result.snapshot, watch.snapshot))
|
|
725
|
+
await resetProjection();
|
|
726
|
+
await put('session_snapshot', { session: await this.view(base, result, watch.stream, target), replay_gap: result.replay_gap === true });
|
|
727
|
+
await prompts(result.snapshot);
|
|
728
|
+
if (!result.snapshot.running && !result.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
729
|
+
await finish();
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
const event = frame.data;
|
|
733
|
+
const data = (event.payload ?? {});
|
|
734
|
+
const kind = str(event.type);
|
|
735
|
+
if (kind === 'notification.show' || kind === 'notification.clear') {
|
|
736
|
+
await put('notices', { session_id: target.sid, notices: this.nativeNotices(target, observation.snapshot) });
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (kind === 'request.cancel') {
|
|
740
|
+
// The owner withdraws a settled, timed-out or interrupted batch from every viewer.
|
|
741
|
+
if (!watch.batch || watch.batch.request_id !== data.id)
|
|
742
|
+
return;
|
|
743
|
+
watch.batch = null;
|
|
744
|
+
await prompts(watch.snapshot);
|
|
745
|
+
if (!pending.clarifyHeadFrame(target.sid))
|
|
746
|
+
await put('clarify', { status: 'resolved', clarify_id: data.id });
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
if (kind === 'session.updated') {
|
|
750
|
+
// Idle owner mutations carry no execution stamp. The sidecar scopes their subscription and replay.
|
|
751
|
+
if (event.session_id !== target.sid
|
|
752
|
+
|| event.authority_epoch !== undefined && event.authority_epoch !== watch.snapshot.authority_epoch
|
|
753
|
+
|| event.execution_generation !== undefined && event.execution_generation !== watch.snapshot.execution_generation)
|
|
754
|
+
return;
|
|
755
|
+
if (data.operation !== 'model')
|
|
756
|
+
return;
|
|
757
|
+
this.rememberModelChange(target, watch.snapshot, modelChange(data));
|
|
758
|
+
const current = await this.call(target, { action: 'snapshot' });
|
|
759
|
+
if (current.snapshot)
|
|
760
|
+
watch.snapshot = current.snapshot;
|
|
761
|
+
await put('session_snapshot', { session: await this.view(base, current, watch.stream, target) });
|
|
762
|
+
if (!watch.snapshot.running && !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started'))
|
|
763
|
+
await finish();
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
if (kind === 'session.info') {
|
|
767
|
+
if (data.authority_epoch !== watch.snapshot.authority_epoch)
|
|
768
|
+
return;
|
|
769
|
+
if (Number(data.execution_generation) < watch.snapshot.execution_generation)
|
|
300
770
|
return;
|
|
771
|
+
const firstClaim = !ran && data.running === true;
|
|
772
|
+
if (Number(data.execution_generation) > watch.snapshot.execution_generation)
|
|
773
|
+
await resetProjection();
|
|
774
|
+
watch.snapshot = { ...watch.snapshot, ...data };
|
|
775
|
+
const claimed = runningAdmission(watch.snapshot);
|
|
776
|
+
if (firstClaim && claimed)
|
|
777
|
+
activeAdmission = claimed.admission_id;
|
|
778
|
+
ran ||= data.running === true;
|
|
779
|
+
if (firstClaim)
|
|
780
|
+
await put('session_snapshot', { session: await this.view(base, { state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null, restarting: watch.restarting }, watch.stream, target) });
|
|
781
|
+
if (data.running === false && (ran || !watch.snapshot.pending.some((p) => p.status === 'queued' || p.status === 'started')))
|
|
782
|
+
await finish();
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
if (event.authority_epoch !== watch.snapshot.authority_epoch || event.execution_generation !== watch.snapshot.execution_generation)
|
|
786
|
+
return;
|
|
787
|
+
if (kind === 'message.delta') {
|
|
788
|
+
const stable = titles.stableSnapshot(reasoning);
|
|
789
|
+
if (stable !== null)
|
|
790
|
+
await put('reasoning', { text: '', titles: stable });
|
|
791
|
+
await put('token', { text: str(data.text || data.delta || data.content) });
|
|
792
|
+
}
|
|
793
|
+
else if (kind === 'reasoning.delta' && showReasoning) {
|
|
794
|
+
reasoning += str(data.text);
|
|
795
|
+
await put('reasoning', titles.prepare(reasoningEventPayload(data.text, reasoning)));
|
|
796
|
+
}
|
|
797
|
+
else if (kind.startsWith('subagent.') && str(data.subagent_id)) {
|
|
798
|
+
// Reuse the delegate activity row; each child keeps one identity through progress and completion.
|
|
799
|
+
const complete = kind === 'subagent.complete';
|
|
800
|
+
const preview = kind === 'subagent.thinking' && !showReasoning ? '' : str(data.summary || data.tool_preview || data.text);
|
|
801
|
+
await put(complete ? 'tool_complete' : 'tool', { id: `owner-subagent-${str(data.subagent_id)}`, name: 'subagent_progress',
|
|
802
|
+
args: { task: str(data.goal) }, preview: preview || null,
|
|
803
|
+
...(complete ? { is_error: data.status !== 'completed', duration: data.duration_seconds } : {}) });
|
|
804
|
+
}
|
|
805
|
+
else if (kind === 'session.usage')
|
|
806
|
+
await meter(data);
|
|
807
|
+
else if (kind === 'message.complete') {
|
|
808
|
+
if (event.session_id !== target.sid || event.replay_epoch !== undefined && event.replay_epoch !== watch.snapshot.replay_epoch)
|
|
809
|
+
return;
|
|
810
|
+
// Only this owner-defined refusal is public; never forward provider diagnostics or private descriptor fields.
|
|
811
|
+
const surface = data.error_surface;
|
|
812
|
+
if (activeAdmission && data.admission_id === activeAdmission && data.outcome === 'failed' && data.status === 'error'
|
|
813
|
+
&& surface?.layer === 'gateway' && surface.code === 'cron_session_read_only' && surface.retryable === false
|
|
814
|
+
&& typeof data.text === 'string' && data.text.trim()) {
|
|
815
|
+
completion = { admission: activeAdmission, message: data.text, type: 'cron_session_read_only', code: 'cron_session_read_only', retryable: false };
|
|
301
816
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
817
|
+
if (data.usage && typeof data.usage === 'object')
|
|
818
|
+
await meter(data.usage);
|
|
819
|
+
}
|
|
820
|
+
else if (kind === 'tool.start' || kind === 'tool.progress' || kind === 'tool.complete') {
|
|
821
|
+
if (event.session_id !== target.sid || event.replay_epoch !== undefined && event.replay_epoch !== watch.snapshot.replay_epoch)
|
|
822
|
+
return;
|
|
823
|
+
const id = str(data.tool_id) || str(data.tool_call_id);
|
|
824
|
+
const call = calls.findLast((call) => call.tid === id);
|
|
825
|
+
if (kind === 'tool.start') {
|
|
826
|
+
if (id && call)
|
|
307
827
|
return;
|
|
308
|
-
|
|
828
|
+
calls.push({ tid: id, name: data.name || data.tool_name, args: data.args ?? {}, done: false });
|
|
829
|
+
await put('tool', { ...data, id, name: data.name || data.tool_name });
|
|
830
|
+
}
|
|
831
|
+
else if (kind === 'tool.progress') {
|
|
832
|
+
if (!id || !call || call.done || !watch.snapshot.running)
|
|
309
833
|
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;
|
|
834
|
+
call.progress = toolProgress({ ...data, message: typeof data.message === 'string' ? redactString(data.message, this.deps.redactEnabled()) : null });
|
|
835
|
+
await put('tool_progress', { id, progress: call.progress });
|
|
321
836
|
}
|
|
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 });
|
|
837
|
+
else {
|
|
838
|
+
if (call?.done)
|
|
839
|
+
return;
|
|
840
|
+
if (call)
|
|
841
|
+
Object.assign(call, { done: true, progress: null });
|
|
842
|
+
await put('tool_complete', { ...data, id, name: data.name || data.tool_name, progress: null });
|
|
338
843
|
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
844
|
+
}
|
|
845
|
+
else if (kind === 'approval.request' || kind === 'clarify.request')
|
|
846
|
+
await prompts({ ...watch.snapshot, prompts: [...watch.snapshot.prompts.filter((p) => p.prompt_id !== data.prompt_id), { ...data, kind: kind.split('.')[0] }] });
|
|
847
|
+
else if (kind === 'approval.settled' || kind === 'clarify.settled') {
|
|
848
|
+
await prompts({ ...watch.snapshot, prompts: watch.snapshot.prompts.filter((p) => p.prompt_id !== data.prompt_id) });
|
|
849
|
+
if (kind === 'approval.settled' && !pending.approvalPending(target.sid).pending)
|
|
850
|
+
await put('approval_cleared', { pending_count: 0 });
|
|
851
|
+
if (kind === 'clarify.settled' && !pending.clarifyHeadFrame(target.sid))
|
|
852
|
+
await put('clarify', { status: 'resolved', clarify_id: data.prompt_id });
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
};
|
|
856
|
+
for (const frame of buffered.splice(0))
|
|
857
|
+
receive(frame);
|
|
858
|
+
const result = await Promise.race([
|
|
859
|
+
observation.ended,
|
|
860
|
+
new Promise((resolve) => {
|
|
861
|
+
const stopped = () => { resolve({ state: 'attached', reason: null, snapshot: watch.snapshot, receipt: null }); };
|
|
862
|
+
if (watch.controller.signal.aborted)
|
|
863
|
+
stopped();
|
|
864
|
+
else
|
|
865
|
+
watch.controller.signal.addEventListener('abort', stopped, { once: true });
|
|
866
|
+
}),
|
|
867
|
+
]);
|
|
342
868
|
await chain;
|
|
343
869
|
if (streamError)
|
|
344
870
|
throw streamError instanceof Error ? streamError : new Error('Owner stream projection failed');
|
|
@@ -348,13 +874,15 @@ export class GatewaySessions {
|
|
|
348
874
|
watch.controller.abort();
|
|
349
875
|
}
|
|
350
876
|
};
|
|
351
|
-
|
|
877
|
+
const running = worker().catch((error) => {
|
|
352
878
|
// Closing the sidecar after a terminal snapshot is expected; every other exit is observable.
|
|
353
879
|
if (!terminal)
|
|
354
880
|
channel.put(['apperror', { message: 'The owning Agent connection ended', type: 'owner_unavailable', terminal_state: 'error' }, null]);
|
|
355
881
|
this.deps.log(`[webui] owner observation ended: ${error instanceof Error ? error.name : 'error'}`);
|
|
356
882
|
}).finally(async () => {
|
|
357
883
|
watch.controller.abort();
|
|
884
|
+
observation.listeners.delete(listener);
|
|
885
|
+
release();
|
|
358
886
|
try {
|
|
359
887
|
await closeWriter?.close();
|
|
360
888
|
}
|
|
@@ -364,15 +892,23 @@ export class GatewaySessions {
|
|
|
364
892
|
if (this.watches.get(target.key) === watch)
|
|
365
893
|
this.watches.delete(target.key);
|
|
366
894
|
registry.retire(watch.stream);
|
|
895
|
+
this.changed(target);
|
|
367
896
|
this.deps.events.publish('owner_changed', { profile: target.profile, sessionId: target.sid });
|
|
897
|
+
this.runWorkers.delete(running);
|
|
368
898
|
});
|
|
899
|
+
this.runWorkers.add(running);
|
|
369
900
|
return watch;
|
|
370
901
|
}
|
|
371
902
|
async close() {
|
|
903
|
+
const observations = [...this.observations.values()];
|
|
904
|
+
for (const observation of observations)
|
|
905
|
+
observation.controller.abort();
|
|
372
906
|
const watches = [...this.watches.values()];
|
|
373
907
|
for (const watch of watches)
|
|
374
908
|
watch.controller.abort();
|
|
375
|
-
await Promise.allSettled(
|
|
909
|
+
await Promise.allSettled([...this.runWorkers]);
|
|
910
|
+
await Promise.allSettled(observations.map((observation) => observation.ended));
|
|
911
|
+
this.modelChanges.clear();
|
|
376
912
|
}
|
|
377
913
|
}
|
|
378
914
|
//# sourceMappingURL=gateway-sessions.js.map
|