@maudecode/talaria-web 1.16.1 → 1.18.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/auth-raw.d.ts +1 -1
- package/dist/api/auth-raw.js +4 -4
- package/dist/api/auth-raw.js.map +1 -1
- package/dist/api/automation-raw.d.ts +6 -0
- package/dist/api/automation-raw.js +59 -9
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +163 -10
- package/dist/api/automation-router.js +25 -8
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +700 -15
- package/dist/api/chat-router.js +74 -55
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +47 -2
- package/dist/api/git-router.js +31 -22
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +14 -0
- package/dist/api/raw-routes.js +277 -36
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +10 -0
- package/dist/api/router.js +10 -8
- package/dist/api/router.js.map +1 -1
- package/dist/api/sessions-router.d.ts +1710 -73
- package/dist/api/sessions-router.js +164 -10
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +132 -2
- package/dist/api/settings-router.js +15 -5
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +16 -3
- package/dist/api/sse-routes.js +194 -67
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.js +12 -25
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +425 -19
- package/dist/api/tools-router.js +157 -26
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.d.ts +0 -9377
- package/dist/app.js +42 -17
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +8 -2
- package/dist/auth/gate.js.map +1 -1
- package/dist/auth/oidc.d.ts +5 -2
- package/dist/auth/oidc.js +8 -7
- package/dist/auth/oidc.js.map +1 -1
- package/dist/bin/talaria-web.js +1 -1
- package/dist/bin/talaria-web.js.map +1 -1
- package/dist/cli/dotenv.js +1 -0
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/config/agent-config.d.ts +2 -0
- package/dist/config/agent-config.js +12 -2
- package/dist/config/agent-config.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/http/context.d.ts +20 -3
- package/dist/http/context.js +41 -8
- package/dist/http/context.js.map +1 -1
- package/dist/http/csp.d.ts +2 -1
- package/dist/http/csp.js +3 -2
- package/dist/http/csp.js.map +1 -1
- package/dist/onboarding.js +4 -0
- package/dist/onboarding.js.map +1 -1
- package/dist/profiles/profiles.d.ts +10 -0
- package/dist/profiles/profiles.js +40 -2
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/providers/catalog.d.ts +101 -8
- package/dist/providers/catalog.js +463 -123
- package/dist/providers/catalog.js.map +1 -1
- package/dist/raster-image.d.ts +7 -0
- package/dist/raster-image.js +267 -0
- package/dist/raster-image.js.map +1 -0
- package/dist/redact.d.ts +1 -0
- package/dist/redact.js +354 -44
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +111 -27
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +5 -0
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +2 -0
- package/dist/sessions/anchor.js +8 -3
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +2 -9
- package/dist/sessions/background-tasks.js +2 -12
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/claude-code.d.ts +19 -0
- package/dist/sessions/claude-code.js +250 -0
- package/dist/sessions/claude-code.js.map +1 -0
- package/dist/sessions/cli-sessions.d.ts +15 -4
- package/dist/sessions/cli-sessions.js +120 -29
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +61 -9
- package/dist/sessions/completions.js +282 -34
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +14 -1
- package/dist/sessions/compress.js +52 -11
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/export.d.ts +5 -0
- package/dist/sessions/export.js +30 -0
- package/dist/sessions/export.js.map +1 -1
- package/dist/sessions/gateway-watcher.d.ts +7 -3
- package/dist/sessions/gateway-watcher.js +31 -19
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/handoff.d.ts +32 -0
- package/dist/sessions/handoff.js +114 -0
- package/dist/sessions/handoff.js.map +1 -0
- package/dist/sessions/journal.d.ts +8 -0
- package/dist/sessions/journal.js +44 -10
- package/dist/sessions/journal.js.map +1 -1
- package/dist/sessions/list.d.ts +13 -3
- package/dist/sessions/list.js +46 -15
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +53 -5
- package/dist/sessions/merge.js +219 -23
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/recovery.d.ts +22 -0
- package/dist/sessions/recovery.js +506 -0
- package/dist/sessions/recovery.js.map +1 -0
- package/dist/sessions/relay.d.ts +21 -2
- package/dist/sessions/relay.js +156 -11
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +152 -8
- package/dist/sessions/service.js +640 -72
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +17 -1
- package/dist/sessions/session.js +63 -4
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/state-db-worker.d.ts +1 -0
- package/dist/sessions/state-db-worker.js +33 -0
- package/dist/sessions/state-db-worker.js.map +1 -0
- package/dist/sessions/state-db.d.ts +87 -4
- package/dist/sessions/state-db.js +417 -8
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/store.d.ts +7 -0
- package/dist/sessions/store.js +36 -22
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +10 -0
- package/dist/sessions/streams.js +14 -3
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/titles.d.ts +2 -0
- package/dist/sessions/titles.js +4 -0
- package/dist/sessions/titles.js.map +1 -1
- package/dist/sessions/todo.d.ts +6 -1
- package/dist/sessions/todo.js +11 -4
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +12 -1
- package/dist/sessions/tool-display.js +50 -1
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn-context.d.ts +1 -1
- package/dist/sessions/turn-context.js +11 -7
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +67 -11
- package/dist/sessions/turn.js +413 -111
- package/dist/sessions/turn.js.map +1 -1
- package/dist/sessions/wakeup-pause.d.ts +59 -0
- package/dist/sessions/wakeup-pause.js +181 -0
- package/dist/sessions/wakeup-pause.js.map +1 -0
- package/dist/settings.d.ts +20 -2
- package/dist/settings.js +45 -9
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/fake.d.ts +4 -4
- package/dist/sidecar/fake.js +5 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/spa.js +2 -1
- package/dist/spa.js.map +1 -1
- package/dist/startup.d.ts +13 -5
- package/dist/startup.js +48 -0
- package/dist/startup.js.map +1 -1
- package/dist/test/harness.js +2 -0
- package/dist/test/harness.js.map +1 -1
- package/dist/test/ts-worker-hooks.d.ts +1 -0
- package/dist/test/ts-worker-hooks.js +24 -0
- package/dist/test/ts-worker-hooks.js.map +1 -0
- package/dist/text/diff.d.ts +9 -14
- package/dist/text/diff.js +74 -108
- package/dist/text/diff.js.map +1 -1
- package/dist/tools/crons.js +45 -8
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/dashboard-plugins.d.ts +53 -0
- package/dist/tools/dashboard-plugins.js +188 -0
- package/dist/tools/dashboard-plugins.js.map +1 -0
- package/dist/tools/extensions.d.ts +13 -1
- package/dist/tools/extensions.js +132 -60
- package/dist/tools/extensions.js.map +1 -1
- package/dist/tools/health.d.ts +32 -0
- package/dist/tools/health.js +111 -19
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/insights.d.ts +8 -2
- package/dist/tools/insights.js +18 -2
- package/dist/tools/insights.js.map +1 -1
- package/dist/tools/kanban.d.ts +41 -1
- package/dist/tools/kanban.js +113 -2
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp.d.ts +15 -1
- package/dist/tools/mcp.js +99 -5
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/project-os.d.ts +11 -0
- package/dist/tools/project-os.js +267 -0
- package/dist/tools/project-os.js.map +1 -0
- package/dist/tools/skills.d.ts +5 -1
- package/dist/tools/skills.js +5 -3
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/terminal.d.ts +1 -0
- package/dist/tools/terminal.js +1 -1
- package/dist/tools/terminal.js.map +1 -1
- package/dist/tools/updates.d.ts +33 -8
- package/dist/tools/updates.js +236 -57
- package/dist/tools/updates.js.map +1 -1
- package/dist/tools/wiki.d.ts +68 -0
- package/dist/tools/wiki.js +413 -0
- package/dist/tools/wiki.js.map +1 -0
- package/dist/workspace/escape.d.ts +61 -0
- package/dist/workspace/escape.js +149 -0
- package/dist/workspace/escape.js.map +1 -0
- package/dist/workspace/extract.d.ts +22 -0
- package/dist/workspace/extract.js +308 -0
- package/dist/workspace/extract.js.map +1 -0
- package/dist/workspace/fs.d.ts +19 -3
- package/dist/workspace/fs.js +96 -23
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/git.d.ts +18 -0
- package/dist/workspace/git.js +38 -25
- package/dist/workspace/git.js.map +1 -1
- package/dist/workspace/media.d.ts +4 -4
- package/dist/workspace/media.js +18 -45
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/preview.d.ts +28 -0
- package/dist/workspace/preview.js +110 -0
- package/dist/workspace/preview.js.map +1 -0
- package/dist/workspace/rollback.d.ts +36 -21
- package/dist/workspace/rollback.js +179 -270
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/unzip.js +4 -1
- package/dist/workspace/unzip.js.map +1 -1
- package/dist/workspace/upload.d.ts +9 -4
- package/dist/workspace/upload.js +9 -3
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/worktrees.d.ts +2 -1
- package/dist/workspace/worktrees.js +14 -15
- package/dist/workspace/worktrees.js.map +1 -1
- package/package.json +4 -2
- package/sidecar/agent_dependency.json +4 -4
- package/sidecar/scripts/replay_sidecar.py +25 -1
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/__main__.py +7 -1
- package/sidecar/talaria_sidecar/home.py +52 -2
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +39 -5
- package/sidecar/talaria_sidecar/methods/chat.py +431 -43
- package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
- package/sidecar/talaria_sidecar/methods/commands.py +96 -2
- package/sidecar/talaria_sidecar/methods/cron.py +39 -8
- package/sidecar/talaria_sidecar/methods/gateway.py +32 -15
- package/sidecar/talaria_sidecar/methods/kanban.py +140 -19
- package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
- package/sidecar/talaria_sidecar/methods/process.py +115 -2
- package/sidecar/talaria_sidecar/methods/profiles.py +84 -8
- package/sidecar/talaria_sidecar/methods/providers.py +27 -8
- package/sidecar/talaria_sidecar/methods/runtime.py +3 -0
- package/sidecar/talaria_sidecar/methods/state_db.py +39 -5
- package/sidecar/talaria_sidecar/methods/text.py +17 -1
- package/sidecar/talaria_sidecar/methods/usage.py +257 -4
- package/sidecar/talaria_sidecar/runtime.py +17 -1
- package/static/dist/FILES.txt +127 -125
- package/static/dist/assets/AppShell-g3bkgnvt.js +1 -0
- package/static/dist/assets/ChatPage-oo7bdan6.js +25 -0
- package/static/dist/assets/Dialog-g355qxhp.js +1 -0
- package/static/dist/assets/ExtensionRoute-i2y9fvjm.js +1 -0
- package/static/dist/assets/HubRoute-lmkrbw47.js +2 -0
- package/static/dist/assets/{Markdown-jqrx5es0.js → Markdown-j4kut4j2.js} +125 -125
- package/static/dist/assets/RightPanel-ohlsdzfl.js +1 -0
- package/static/dist/assets/Select-kddq75qc.js +1 -0
- package/static/dist/assets/SessionListPanel-lu3oy0hw.js +1 -0
- package/static/dist/assets/SettingsLayout-o9bv4mgb.js +1 -0
- package/static/dist/assets/States-eq6fe29m.js +1 -0
- package/static/dist/assets/Toaster-pc247u9f.js +1 -0
- package/static/dist/assets/_app-f8n1i0m1.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-gfbzpoou.js +1 -0
- package/static/dist/assets/_app.index-bzzv80hk.js +1 -0
- package/static/dist/assets/_app.insights-dzixbryi.js +1 -0
- package/static/dist/assets/_app.kanban-c6hep2us.js +1 -0
- package/static/dist/assets/_app.logs-i69qds98.js +1 -0
- package/static/dist/assets/_app.memory-kl4vf0gd.js +1 -0
- package/static/dist/assets/_app.profiles-b8zinmyp.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-hh27wwu2.js → _app.session._sessionId-fn1bhde6.js} +1 -1
- package/static/dist/assets/_app.settings-cg8plwmf.js +1 -0
- package/static/dist/assets/_app.settings._section-bkwbi9zn.js +3 -0
- package/static/dist/assets/_app.skills-cs47sbvs.js +1 -0
- package/static/dist/assets/_app.tasks-dwvk64tc.js +1 -0
- package/static/dist/assets/_app.todos-c8xjm8p3.js +1 -0
- package/static/dist/assets/_app.workspaces-ehvd1gds.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-oity9y4o.js → abnfDiagram-VCTEODGH-c8kdixke.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-6crvnylg.js +1 -0
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-ceaepnyr.js → architectureDiagram-5GKGNRK7-cku06x1p.js} +1 -1
- package/static/dist/assets/{back-eu64w89w.js → back-h7aun7ew.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-n79st4pj.js → blockDiagram-I7D4REHJ-jzthp1wa.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-mi73akzk.js → c4Diagram-7LVT6UL2-mwr67mt8.js} +1 -1
- package/static/dist/assets/{cancel-mzvkdjg8.js → cancel-fhi0vcnu.js} +1 -1
- package/static/dist/assets/channel-b2zo73z1.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-laat0g1q.js → chunk-4HAMMTFA-gpq1y228.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-0psy1tr2.js → chunk-75Z2AOVW-ktje58c4.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-lw8uox8x.js → chunk-DU6HZSFF-ofajdixh.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-erassib3.js → chunk-F27PBJKO-cmev85ti.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-fz7rx619.js → chunk-GMAD6QVW-htjgt22y.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-gdb0epb2.js → chunk-GVQU2GXP-qndvoxl7.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-ea8t26qw.js → chunk-IMKFNOWR-e5bkd5q6.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-mb1gu9kz.js → chunk-L3NEJ4N5-mj1155r6.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-eovmccvy.js → chunk-OSK3NFVY-e7gkikcw.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-bo55zjo5.js → chunk-P2QGCYS3-f7t54xfm.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-ja7ohe4h.js → chunk-POPQ4Y6H-i927v9oa.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-e30g9nus.js → chunk-PWAF6VOD-m84lmnyt.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-gbb798f7.js → chunk-SHT3W25Y-mi0tlcu9.js} +1 -1
- package/static/dist/assets/{chunk-SVP7TREG-h2iw8urm.js → chunk-SVP7TREG-dnau702j.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-fd2cottz.js → chunk-TICWLB2K-edem1gkg.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-oe99st8x.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-oe99st8x.js +1 -0
- package/static/dist/assets/{copied-h65fc3cx.js → copied-hcplv46p.js} +1 -1
- package/static/dist/assets/copy-magtofyp.js +1 -0
- package/static/dist/assets/{cynefin-OW5HDTMX-lbltyl5j.js → cynefin-OW5HDTMX-siqlulkl.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-lxhsqq4a.js → cynefinDiagram-5FMLGOSQ-i648tah9.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-gn4nnaln.js → dagre-GXQ25YYZ-mwn6uc17.js} +1 -1
- package/static/dist/assets/{diagram-S7CK7UJ4-pa3ij6q7.js → diagram-S7CK7UJ4-l8abxaes.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-zbipyz57.js → diagram-UQ7AKVKN-mekq7zgq.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-d1kbpzgf.js → diagram-VSXAHHWV-fnky6lvc.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-i3ty14xl.js → diagram-VX7I27RA-xe6r5qfw.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-m8xefqa7.js → diagram-Z3DM3KII-nq07dg7k.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-nz7wj05l.js → ebnfDiagram-PWID7BFC-c62ipm3g.js} +1 -1
- package/static/dist/assets/endpoints-klbxod4t.js +64 -0
- package/static/dist/assets/{erDiagram-RLTQ6QDP-fa41ib83.js → erDiagram-RLTQ6QDP-h39kmnzy.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-obfede4u.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-kdpsp1je.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-n7zq01qu.js → ganttDiagram-EL5Y4UJY-ngbsyp37.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-c89emb07.js → gitGraph-4MIJSDKK-fr2i7caa.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-cz7cgr6w.js → gitGraphDiagram-WWUBYQGX-eravdti4.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-d9bapmni.js → highlighted-body-KPVGNVTW-jwpop9p8.js} +1 -1
- package/static/dist/assets/host-i828xuo7.js +1 -0
- package/static/dist/assets/index-eh8zilnv.css +2 -0
- package/static/dist/assets/index-r648f4o1.js +11 -0
- package/static/dist/assets/{info-A6RAGUB7-ndddhhhh.js → info-A6RAGUB7-h11x0dxo.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-ccxigcpf.js → infoDiagram-27XIBGKW-dfh47dw9.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-le0z9vtc.js → ishikawaDiagram-5VMMS53U-i6ypq351.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-ivsmb26o.js → journeyDiagram-3NMN7TZE-lduf1z95.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-h6n2awt0.js → kanban-definition-UXKFOSKX-e18bu4pg.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-e1y4t2i9.js +1 -0
- package/static/dist/assets/{line-dmzlfe0u.js → line-meizqsvn.js} +1 -1
- package/static/dist/assets/link-oot2yn73.js +1 -0
- package/static/dist/assets/login-gu28l9ou.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-mtwrj8fn.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-gwyd5bnq.js → mermaid-parser.core-ntne45i9.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-l68gg5h7.js → mindmap-definition-YA3MSWOX-27b26eok.js} +1 -1
- package/static/dist/assets/onboarding-lkphzu1s.js +1 -0
- package/static/dist/assets/onboarding_model_label-ftpjdwqk.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-gpv06065.js → packet-AYTQ26CC-l6jdka8p.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-e52vs23u.js → pegDiagram-XKGWAZYB-g1er3bxj.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-l6m7nz5s.js → pie-WAS4IAKB-i0ylcrt9.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-b4is36bq.js → pieDiagram-E7YTZNPT-fbz1e55z.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-m8vt2788.js → quadrantDiagram-AXDQQJYC-hhue7d8o.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-nxbrhiov.js → radar-RG4KPBEZ-f9b70aa4.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-222mu9hi.js → railroad-74A4TZTK-lgsuoeda.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nf9d6pdx.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-f7ummkt5.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-oczq5tqs.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-o8lldfzv.js → railroadDiagram-O6MQD6OU-eqpy9fnz.js} +1 -1
- package/static/dist/assets/refresh-abtu93ke.js +1 -0
- package/static/dist/assets/refresh-cw-hlwb02qv.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-ovyq38kv.js → requirementDiagram-BXWQKSXE-ogf6puhi.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-ou7lznor.js → sankeyDiagram-P5KCCOFB-fqb8xcjf.js} +1 -1
- package/static/dist/assets/{saved-bazmcup9.js → saved-girnabkf.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-ovckdzf2.js → sequenceDiagram-WJ2MYXX4-dlcz6qjz.js} +1 -1
- package/static/dist/assets/{settings_section_extensions_title-ertwwhlx.js → settings_section_extensions_title-h14cwk6f.js} +1 -1
- package/static/dist/assets/share._token-kl0r7ido.js +2 -0
- package/static/dist/assets/sliders-horizontal-n1zm34qq.js +1 -0
- package/static/dist/assets/sse-iwku0sjo.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-fcrexkkv.js → stateDiagram-D77RDMKH-fyoznpcs.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-ixhx8r46.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-f7usu8fw.js → swimlanes-42K2YHIH-oefldhfy.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-h9ersk2e.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-gp1hvz9f.js → timeline-definition-24CTP7MA-b1vl2zil.js} +1 -1
- package/static/dist/assets/todoStore-jjr5yr78.js +1 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-gb9gf11u.js → treeView-Q6P3EWNA-f7hcci5o.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-nuvfnvvi.js → treemap-WGGIJYW6-nl85071a.js} +1 -1
- package/static/dist/assets/units-kgxzxfhi.js +1 -0
- package/static/dist/assets/{untitled-htelhc68.js → untitled-cikfjntn.js} +1 -1
- package/static/dist/assets/{useForm-h2t0u14e.js → useForm-kqoqg0k9.js} +1 -1
- package/static/dist/assets/useLocale-o59tbiea.js +1 -0
- package/static/dist/assets/{useParams-dqd64jv7.js → useParams-b4dq6n4q.js} +1 -1
- package/static/dist/assets/{useSearch-j30pvsy7.js → useSearch-ipfmv3he.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-fzchbzaj.js → vennDiagram-4TSXK5OY-h5hzbk0n.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-m47mhfbh.js → wardley-WFR3VGLG-jftvpm3e.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-odg6ct1z.js → wardleyDiagram-VM6X3IG4-hedh85ge.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mrhms5um.js → xychartDiagram-S5SC5T6Z-e49523ab.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +2 -2
- package/static/dist/assets/AppShell-ef3bhu32.js +0 -1
- package/static/dist/assets/Button-nx37f4u1.js +0 -1
- package/static/dist/assets/ChatPage-cdcpykcg.js +0 -25
- package/static/dist/assets/Dialog-mec42hvb.js +0 -1
- package/static/dist/assets/HubRoute-ecb65zpr.js +0 -2
- package/static/dist/assets/RightPanel-d1lgvk4s.js +0 -1
- package/static/dist/assets/Select-h4ivl9qf.js +0 -1
- package/static/dist/assets/SessionListPanel-ewib046b.js +0 -1
- package/static/dist/assets/SettingsLayout-lx654cup.js +0 -1
- package/static/dist/assets/States-ehsb6lzo.js +0 -1
- package/static/dist/assets/Toaster-mch1pa3t.js +0 -1
- package/static/dist/assets/_app-m8d961ef.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +0 -1
- package/static/dist/assets/_app.index-dk6zp7e0.js +0 -1
- package/static/dist/assets/_app.insights-jt2fk4i1.js +0 -1
- package/static/dist/assets/_app.kanban-if4pubeu.js +0 -1
- package/static/dist/assets/_app.logs-mfaw9m6g.js +0 -1
- package/static/dist/assets/_app.memory-h3eaarb6.js +0 -1
- package/static/dist/assets/_app.profiles-ienktovs.js +0 -1
- package/static/dist/assets/_app.settings-dpoe0bzf.js +0 -1
- package/static/dist/assets/_app.settings._section-l468ynag.js +0 -3
- package/static/dist/assets/_app.skills-kcbncc8i.js +0 -1
- package/static/dist/assets/_app.tasks-occdrqhw.js +0 -2
- package/static/dist/assets/_app.todos-nnke2rcc.js +0 -1
- package/static/dist/assets/_app.workspaces-cdlatvwj.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +0 -1
- package/static/dist/assets/channel-mbvmf2vv.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +0 -1
- package/static/dist/assets/copy-e6977uwq.js +0 -1
- package/static/dist/assets/endpoints-k7yf25m0.js +0 -64
- package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +0 -1
- package/static/dist/assets/index-h00usru2.js +0 -11
- package/static/dist/assets/index-n73ijkv2.css +0 -2
- package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +0 -1
- package/static/dist/assets/link-budeg5t9.js +0 -1
- package/static/dist/assets/login-kjhasvp8.js +0 -1
- package/static/dist/assets/matchContext-f8oy3lo7.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +0 -1
- package/static/dist/assets/onboarding-cdfrk0pj.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +0 -1
- package/static/dist/assets/refresh-cw-kbcje1uy.js +0 -1
- package/static/dist/assets/search-jen74z4u.js +0 -1
- package/static/dist/assets/share._token-dan9hgvj.js +0 -2
- package/static/dist/assets/sliders-horizontal-f9cb3lh3.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +0 -8
- package/static/dist/assets/todoStore-eqtid4r4.js +0 -1
- package/static/dist/assets/useLocale-hcsb84pj.js +0 -1
- package/static/dist/assets/useNavigate-nwy70ztj.js +0 -1
|
@@ -1,31 +1,43 @@
|
|
|
1
1
|
import type { SidecarLike } from '../sidecar/client.js';
|
|
2
2
|
import type { SessionChannels, StreamRegistry } from './streams.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type SessionStore } from './store.js';
|
|
4
4
|
import type { Session } from './session.js';
|
|
5
5
|
import type { BackgroundActivity } from './background-tasks.js';
|
|
6
6
|
type Dict = Record<string, unknown>;
|
|
7
7
|
export declare const COMPLETION_POLL_MS = 1000;
|
|
8
|
+
interface StartedTurn {
|
|
9
|
+
_status?: number;
|
|
10
|
+
error?: string;
|
|
11
|
+
stream_id?: string;
|
|
12
|
+
retryable?: boolean;
|
|
13
|
+
}
|
|
8
14
|
export interface CompletionDrainDeps {
|
|
9
15
|
sidecar: () => SidecarLike | null;
|
|
16
|
+
/** The base Hermes home: every profile under it has its background processes recovered in a new sidecar (TAL-533). */
|
|
17
|
+
baseHome: string;
|
|
10
18
|
profileHome: (profile: string | null) => string;
|
|
11
19
|
activeProfile: () => string;
|
|
12
20
|
store: SessionStore;
|
|
13
21
|
channels: SessionChannels;
|
|
14
22
|
registry: StreamRegistry;
|
|
15
|
-
/** Start a server-side turn; `_status` 409 means a turn is already active. */
|
|
16
|
-
startTurn: (session: Session, prompt: string) =>
|
|
17
|
-
_status?: number;
|
|
18
|
-
error?: string;
|
|
19
|
-
stream_id?: string;
|
|
20
|
-
};
|
|
23
|
+
/** Start a server-side turn; `_status` 409 means a turn is already active, or with `retryable` that the Agent runtime is stale. */
|
|
24
|
+
startTurn: (session: Session, prompt: string) => StartedTurn | Promise<StartedTurn>;
|
|
21
25
|
now: () => number;
|
|
22
26
|
log: (line: string) => void;
|
|
23
27
|
pollMs?: number;
|
|
28
|
+
/** TAL-576: the profile's authoritative config file (`AgentConfig.path`); `<home>/config.yaml` when absent. */
|
|
29
|
+
configPath?: (profileHome: string) => string;
|
|
24
30
|
/** TAL-372: each routed completion settles its background record. */
|
|
25
31
|
background?: Pick<BackgroundActivity, 'recordEvent'>;
|
|
26
32
|
}
|
|
27
33
|
/** Python `format_wakeup_prompt` for plain completion events; async delegations use the sidecar formatter. */
|
|
28
34
|
export declare function formatWakeupPrompt(evt: Dict): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* TAL-724: an event's delivery identity, the `process_id` of its wakeup entry. A completion (an event with no type is one) or
|
|
37
|
+
* an async delegation is its process: one exit can be enqueued twice when a kill races the reader thread. The Agent enqueues
|
|
38
|
+
* each watch event once, and one process raises several, so each is its own delivery; its event keeps the process id.
|
|
39
|
+
*/
|
|
40
|
+
export declare function deliveryKey(evt: Dict, processId: string): string;
|
|
29
41
|
export declare class CompletionDrain {
|
|
30
42
|
private readonly deps;
|
|
31
43
|
private timer;
|
|
@@ -37,6 +49,16 @@ export declare class CompletionDrain {
|
|
|
37
49
|
private readonly retryTimers;
|
|
38
50
|
private readonly lastEmitAt;
|
|
39
51
|
private readonly pendingEmit;
|
|
52
|
+
/** The handshake of the sidecar whose process registry already recovered every profile's checkpoint. */
|
|
53
|
+
private recoveredFor;
|
|
54
|
+
private recoveryWarnedFor;
|
|
55
|
+
private lastDrainError;
|
|
56
|
+
private heldResumed;
|
|
57
|
+
private readonly drains;
|
|
58
|
+
/** Admitted wakeups whose release could not be written: never delivered again, and the release is retried. */
|
|
59
|
+
private readonly unreleased;
|
|
60
|
+
/** TAL-576: wakeups held while their session is paused. */
|
|
61
|
+
private readonly heldWakeups;
|
|
40
62
|
constructor(deps: CompletionDrainDeps);
|
|
41
63
|
start(): void;
|
|
42
64
|
stop(): void;
|
|
@@ -52,7 +74,10 @@ export declare class CompletionDrain {
|
|
|
52
74
|
/** Python `_emit_bg_task_complete_events_coalesced`: first emit immediately, bursts flush the latest payload after 1 s of quiet. */
|
|
53
75
|
private emitCoalesced;
|
|
54
76
|
recordDeferred(sid: string, processId: string, prompt: string, event?: Dict): void;
|
|
77
|
+
/** Re-deferring keeps an entry's delivery identity, so its held copy and this one stay one wakeup. */
|
|
78
|
+
private defer;
|
|
55
79
|
deferredCount(sid: string): number;
|
|
80
|
+
/** Delivering a process's exit consumes it; a watch event leaves the exit to be delivered (TAL-724). */
|
|
56
81
|
private markConsumed;
|
|
57
82
|
/**
|
|
58
83
|
* TAL-459: claim each async delegation in the Agent's durable ledger right before delivering it. A refused claim means
|
|
@@ -66,12 +91,39 @@ export declare class CompletionDrain {
|
|
|
66
91
|
* lease bounds a lost hand-back.
|
|
67
92
|
*/
|
|
68
93
|
private settleClaims;
|
|
69
|
-
private profileHome;
|
|
70
94
|
private scheduleRetry;
|
|
95
|
+
private scheduleDrain;
|
|
96
|
+
/** TAL-576: `usage.pool` for the provider whose pool ran dry, through `poolRecovery`; null when the sidecar cannot say. */
|
|
97
|
+
private poolRecovery;
|
|
98
|
+
/** A restarted server resumes every session it left holding wakeups (`startWakeup` drops a deleted session's). */
|
|
99
|
+
private resumeHeld;
|
|
100
|
+
private held;
|
|
101
|
+
/** A session whose file is gone was deleted; any other load failure keeps its wakeups. */
|
|
102
|
+
private deleted;
|
|
103
|
+
/** Admitted or settled wakeups (every one, with none given) leave the held file. */
|
|
104
|
+
private release;
|
|
105
|
+
private saveSession;
|
|
106
|
+
/**
|
|
107
|
+
* TAL-576: while the provider has no usable credentials no wakeup turn starts. The entries are held until a turn
|
|
108
|
+
* admits them, and a timer rechecks the pause at the pool's earliest retry deadline, at least every five minutes.
|
|
109
|
+
* Returns whether the wakeup is handled here (held, or dropped with its deleted session).
|
|
110
|
+
*/
|
|
111
|
+
private holdWhilePaused;
|
|
71
112
|
/** Python `_start_server_side_wakeup_turn`: one batched turn; 409 re-defers, other failures re-defer with a timed retry. */
|
|
72
113
|
private startWakeup;
|
|
73
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* TAL-532: the deferred process completions the agent already holds from its own turn (wait/log or poll). Checked at
|
|
116
|
+
* delivery, not drain: the completion is usually drained seconds before the agent's wait returns. Only completions:
|
|
117
|
+
* consuming the exit says nothing about a watch match or notice, and async delegations settle in their delivery ledger.
|
|
118
|
+
* A failed check delivers everything rather than lose a result.
|
|
119
|
+
*/
|
|
120
|
+
private alreadyConsumed;
|
|
121
|
+
/**
|
|
122
|
+
* Python `drain_deferred_wakeups_for_session`: turn-teardown idle hook; only the last active stream's teardown fires.
|
|
123
|
+
* TAL-576: one drain per session at a time, so two never copy the same held wakeups before either admits them.
|
|
124
|
+
*/
|
|
74
125
|
drainDeferred(sid: string): Promise<number>;
|
|
126
|
+
private drainDeferredNow;
|
|
75
127
|
/** Reaper sweep: forget dedupe sets for sessions with nothing pending. */
|
|
76
128
|
sweep(): void;
|
|
77
129
|
}
|
|
@@ -7,13 +7,20 @@
|
|
|
7
7
|
* redelivered at turn teardown with a bounded retry budget).
|
|
8
8
|
*/
|
|
9
9
|
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { SessionNotFound } from './store.js';
|
|
10
13
|
import { str } from '../util.js';
|
|
14
|
+
import { isDict } from './merge.js';
|
|
11
15
|
import { batchUpdate, recordBackgroundUpdate } from './background-updates.js';
|
|
16
|
+
import { HeldWakeups, deliveredPerProcess, heldKey, mergeWakeups, poolRecovery, wakeupPaused } from './wakeup-pause.js';
|
|
12
17
|
export const COMPLETION_POLL_MS = 1000;
|
|
13
18
|
const EMIT_COALESCE_WINDOW_S = 1;
|
|
14
19
|
const WAKEUP_RETRY_SECONDS = 30;
|
|
15
20
|
const WAKEUP_RETRY_MAX_ATTEMPTS = 5;
|
|
16
21
|
const WAKEUP_BATCH_MAX_CHARS = 24_000;
|
|
22
|
+
/** A session with held wakeups rechecks its pause at least this often (a credential edit has no deadline). */
|
|
23
|
+
const HELD_RECHECK_SECONDS = 300;
|
|
17
24
|
const DELIVERY_CONSUMER = 'webui';
|
|
18
25
|
/** Python `format_wakeup_prompt` for plain completion events; async delegations use the sidecar formatter. */
|
|
19
26
|
export function formatWakeupPrompt(evt) {
|
|
@@ -37,6 +44,16 @@ export function formatWakeupPrompt(evt) {
|
|
|
37
44
|
return null;
|
|
38
45
|
return `[IMPORTANT: Background process ${sid} completed (exit_code=${str(evt.exit_code ?? '?')}).\nCommand: ${cmd}\nOutput:\n${truncate(evt.output, 4000)}]`;
|
|
39
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* TAL-724: an event's delivery identity, the `process_id` of its wakeup entry. A completion (an event with no type is one) or
|
|
49
|
+
* an async delegation is its process: one exit can be enqueued twice when a kill races the reader thread. The Agent enqueues
|
|
50
|
+
* each watch event once, and one process raises several, so each is its own delivery; its event keeps the process id.
|
|
51
|
+
*/
|
|
52
|
+
export function deliveryKey(evt, processId) {
|
|
53
|
+
return !processId || deliveredPerProcess(evt) ? processId : `${processId}:${str(evt.type)}:${randomUUID()}`;
|
|
54
|
+
}
|
|
55
|
+
/** Only a process's exit is consumed by the agent's own wait or poll (TAL-532); its watch events and delegations are not. */
|
|
56
|
+
const isCompletion = (e) => Boolean(e.process_id) && str(e.event?.type ?? 'completion') === 'completion';
|
|
40
57
|
export class CompletionDrain {
|
|
41
58
|
deps;
|
|
42
59
|
timer = null;
|
|
@@ -48,8 +65,19 @@ export class CompletionDrain {
|
|
|
48
65
|
retryTimers = new Map();
|
|
49
66
|
lastEmitAt = new Map();
|
|
50
67
|
pendingEmit = new Map();
|
|
68
|
+
/** The handshake of the sidecar whose process registry already recovered every profile's checkpoint. */
|
|
69
|
+
recoveredFor = null;
|
|
70
|
+
recoveryWarnedFor = null;
|
|
71
|
+
lastDrainError = null;
|
|
72
|
+
heldResumed = false;
|
|
73
|
+
drains = new Map();
|
|
74
|
+
/** Admitted wakeups whose release could not be written: never delivered again, and the release is retried. */
|
|
75
|
+
unreleased = new Map();
|
|
76
|
+
/** TAL-576: wakeups held while their session is paused. */
|
|
77
|
+
heldWakeups;
|
|
51
78
|
constructor(deps) {
|
|
52
79
|
this.deps = deps;
|
|
80
|
+
this.heldWakeups = new HeldWakeups(join(deps.store.sessionDir, '_wakeup_held.json'));
|
|
53
81
|
}
|
|
54
82
|
start() {
|
|
55
83
|
if (this.timer || this.stopped)
|
|
@@ -57,7 +85,13 @@ export class CompletionDrain {
|
|
|
57
85
|
const tick = () => {
|
|
58
86
|
if (this.stopped)
|
|
59
87
|
return;
|
|
60
|
-
|
|
88
|
+
// A lasting failure (an unrecoverable checkpoint fails every call in its home, TAL-533) is logged once, not every poll.
|
|
89
|
+
void this.drainOnce().then(() => { this.lastDrainError = null; }, (error) => {
|
|
90
|
+
const message = error.message;
|
|
91
|
+
if (message !== this.lastDrainError)
|
|
92
|
+
this.deps.log(`[webui] WARNING: bg_task_complete drain failed: ${message}`);
|
|
93
|
+
this.lastDrainError = message;
|
|
94
|
+
}).finally(() => {
|
|
61
95
|
if (this.stopped)
|
|
62
96
|
return;
|
|
63
97
|
this.timer = setTimeout(tick, this.deps.pollMs ?? COMPLETION_POLL_MS);
|
|
@@ -82,7 +116,34 @@ export class CompletionDrain {
|
|
|
82
116
|
const sidecar = this.deps.sidecar();
|
|
83
117
|
if (!sidecar)
|
|
84
118
|
return 0;
|
|
85
|
-
|
|
119
|
+
// Each sidecar handshake is a fresh process registry: re-adopt every profile's checkpointed processes before the first
|
|
120
|
+
// drain, so one that exits in a profile nobody has used since the restart still reports its completion.
|
|
121
|
+
const describe = sidecar.describe;
|
|
122
|
+
if (describe && describe !== this.recoveredFor) {
|
|
123
|
+
try {
|
|
124
|
+
await sidecar.call('process.recover', { base_home: this.deps.baseHome });
|
|
125
|
+
this.recoveredFor = describe;
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
// Retried on every pass; reported once per sidecar so a lasting failure does not flood the log.
|
|
129
|
+
if (this.recoveryWarnedFor !== describe)
|
|
130
|
+
this.deps.log(`[webui] WARNING: background process recovery failed; retrying: ${error.message}`);
|
|
131
|
+
this.recoveryWarnedFor = describe;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// TAL-576: whether or not every profile recovered, the sessions left holding wakeups resume once a sidecar answers.
|
|
135
|
+
if (!this.heldResumed)
|
|
136
|
+
this.resumeHeld();
|
|
137
|
+
// The drain is sidecar-wide; an active profile whose home escapes the profiles root (`profileHome` throws) scopes it
|
|
138
|
+
// to the base home instead of stalling every other profile's completions.
|
|
139
|
+
let scope;
|
|
140
|
+
try {
|
|
141
|
+
scope = this.deps.profileHome(this.deps.activeProfile());
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
scope = this.deps.baseHome;
|
|
145
|
+
}
|
|
146
|
+
const { events } = await sidecar.call('process.drain', { profile_home: scope, max_events: 256 });
|
|
86
147
|
let routed = 0;
|
|
87
148
|
const unrouted = [];
|
|
88
149
|
for (const evt of events) {
|
|
@@ -154,20 +215,23 @@ export class CompletionDrain {
|
|
|
154
215
|
return true;
|
|
155
216
|
const seen = this.seen.get(sid) ?? new Set();
|
|
156
217
|
this.seen.set(sid, seen);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
218
|
+
// Only a per-process delivery can repeat: a watch event's key is unique, so remembering it would only grow `seen`.
|
|
219
|
+
if (processId && deliveredPerProcess(evt)) {
|
|
220
|
+
if (seen.has(processId))
|
|
221
|
+
return true;
|
|
160
222
|
seen.add(processId);
|
|
223
|
+
}
|
|
161
224
|
this.pendingSessions.add(sid);
|
|
162
225
|
const prompt = await this.wakeupPrompt(evt);
|
|
163
226
|
this.deps.background?.recordEvent(sid, evt, prompt);
|
|
164
227
|
this.emitCoalesced(sid, this.buildPayload(evt, sid, prompt));
|
|
165
228
|
if (!prompt)
|
|
166
229
|
return true;
|
|
230
|
+
const entry = { process_id: deliveryKey(evt, processId), wakeup_prompt: prompt, event: evt };
|
|
167
231
|
if (this.hasActiveTurn(sid))
|
|
168
|
-
this.
|
|
232
|
+
this.defer(sid, entry);
|
|
169
233
|
else
|
|
170
|
-
await this.startWakeup(sid, [
|
|
234
|
+
await this.startWakeup(sid, [entry]);
|
|
171
235
|
return true;
|
|
172
236
|
}
|
|
173
237
|
buildPayload(evt, sid, prompt) {
|
|
@@ -218,21 +282,26 @@ export class CompletionDrain {
|
|
|
218
282
|
this.pendingEmit.set(sid, { payload, timer });
|
|
219
283
|
}
|
|
220
284
|
recordDeferred(sid, processId, prompt, event) {
|
|
221
|
-
|
|
285
|
+
this.defer(sid, { process_id: deliveryKey(event ?? {}, processId), wakeup_prompt: prompt, ...(event ? { event } : {}) });
|
|
286
|
+
}
|
|
287
|
+
/** Re-deferring keeps an entry's delivery identity, so its held copy and this one stay one wakeup. */
|
|
288
|
+
defer(sid, entry) {
|
|
289
|
+
if (!sid || !entry.wakeup_prompt)
|
|
222
290
|
return;
|
|
223
291
|
const entries = this.deferred.get(sid) ?? [];
|
|
224
|
-
if (
|
|
292
|
+
if (entries.some((e) => heldKey(e) === heldKey(entry)))
|
|
225
293
|
return;
|
|
226
|
-
entries.push(
|
|
294
|
+
entries.push(entry);
|
|
227
295
|
this.deferred.set(sid, entries);
|
|
228
296
|
this.pendingSessions.add(sid);
|
|
229
297
|
}
|
|
230
298
|
deferredCount(sid) { return this.deferred.get(sid)?.length ?? 0; }
|
|
231
|
-
|
|
299
|
+
/** Delivering a process's exit consumes it; a watch event leaves the exit to be delivered (TAL-724). */
|
|
300
|
+
async markConsumed(entries) {
|
|
232
301
|
const sidecar = this.deps.sidecar();
|
|
233
302
|
if (!sidecar)
|
|
234
303
|
return;
|
|
235
|
-
for (const pid of
|
|
304
|
+
for (const pid of new Set(entries.filter(isCompletion).map((e) => e.process_id))) {
|
|
236
305
|
try {
|
|
237
306
|
await sidecar.call('process.mark_consumed', { process_id: pid });
|
|
238
307
|
}
|
|
@@ -244,7 +313,7 @@ export class CompletionDrain {
|
|
|
244
313
|
* another consumer delivered (or holds) it, so it leaves the batch; a sidecar failure returns null so the caller keeps
|
|
245
314
|
* every entry pending. Claims are taken at delivery, never while deferred, so a long turn cannot outlive the lease.
|
|
246
315
|
*/
|
|
247
|
-
async claimBatch(batched) {
|
|
316
|
+
async claimBatch(home, batched) {
|
|
248
317
|
const deliver = [];
|
|
249
318
|
const held = [];
|
|
250
319
|
for (const entry of batched) {
|
|
@@ -257,10 +326,10 @@ export class CompletionDrain {
|
|
|
257
326
|
try {
|
|
258
327
|
if (!sidecar)
|
|
259
328
|
throw new Error('sidecar unavailable');
|
|
260
|
-
claimId = (await sidecar.call('process.claim_delivery', { profile_home:
|
|
329
|
+
claimId = (await sidecar.call('process.claim_delivery', { profile_home: home, event: entry.event, consumer: DELIVERY_CONSUMER })).claim_id;
|
|
261
330
|
}
|
|
262
331
|
catch (error) {
|
|
263
|
-
await this.settleClaims('process.release_delivery', held);
|
|
332
|
+
await this.settleClaims(home, 'process.release_delivery', held);
|
|
264
333
|
this.deps.log(`[webui] WARNING: async delegation delivery claim failed for ${entry.process_id}: ${error.message}; kept pending`);
|
|
265
334
|
return null;
|
|
266
335
|
}
|
|
@@ -277,20 +346,19 @@ export class CompletionDrain {
|
|
|
277
346
|
* attempt spent), `release` when it failed (spends one; the Agent drops a row past its budget). Best effort: the Agent's
|
|
278
347
|
* lease bounds a lost hand-back.
|
|
279
348
|
*/
|
|
280
|
-
async settleClaims(method, held) {
|
|
349
|
+
async settleClaims(home, method, held) {
|
|
281
350
|
const sidecar = this.deps.sidecar();
|
|
282
351
|
if (!sidecar)
|
|
283
352
|
return;
|
|
284
353
|
for (const claim of held) {
|
|
285
354
|
try {
|
|
286
|
-
await sidecar.call(method, { profile_home:
|
|
355
|
+
await sidecar.call(method, { profile_home: home, event: claim.event, claim_id: claim.claim_id });
|
|
287
356
|
}
|
|
288
357
|
catch (error) {
|
|
289
358
|
this.deps.log(`[webui] WARNING: ${method} failed for ${str(claim.event.delegation_id)}: ${error.message}`);
|
|
290
359
|
}
|
|
291
360
|
}
|
|
292
361
|
}
|
|
293
|
-
profileHome() { return this.deps.profileHome(this.deps.activeProfile()); }
|
|
294
362
|
scheduleRetry(sid) {
|
|
295
363
|
const attempts = (this.retryAttempts.get(sid) ?? 0) + 1;
|
|
296
364
|
this.retryAttempts.set(sid, attempts);
|
|
@@ -298,24 +366,150 @@ export class CompletionDrain {
|
|
|
298
366
|
this.deps.log(`[webui] WARNING: server-side wakeup retry budget exhausted for session ${sid}; deferred entries wait for the next turn teardown`);
|
|
299
367
|
return;
|
|
300
368
|
}
|
|
369
|
+
this.scheduleDrain(sid, WAKEUP_RETRY_SECONDS);
|
|
370
|
+
}
|
|
371
|
+
scheduleDrain(sid, delaySeconds) {
|
|
301
372
|
const existing = this.retryTimers.get(sid);
|
|
302
373
|
if (existing)
|
|
303
374
|
clearTimeout(existing);
|
|
304
|
-
const timer = setTimeout(() => { this.retryTimers.delete(sid); void this.drainDeferred(sid); },
|
|
375
|
+
const timer = setTimeout(() => { this.retryTimers.delete(sid); void this.drainDeferred(sid); }, Math.max(0, delaySeconds) * 1000);
|
|
305
376
|
timer.unref();
|
|
306
377
|
this.retryTimers.set(sid, timer);
|
|
307
378
|
}
|
|
379
|
+
/** TAL-576: `usage.pool` for the provider whose pool ran dry, through `poolRecovery`; null when the sidecar cannot say. */
|
|
380
|
+
async poolRecovery(home, session) {
|
|
381
|
+
const sidecar = this.deps.sidecar();
|
|
382
|
+
const pause = session.process_wakeup_pause;
|
|
383
|
+
const provider = str(isDict(pause) ? pause.pool_provider : '').trim() || str(session.model_provider).trim();
|
|
384
|
+
if (!sidecar || !provider)
|
|
385
|
+
return null;
|
|
386
|
+
try {
|
|
387
|
+
return poolRecovery((await sidecar.call('usage.pool', { profile_home: home, provider })).entries, this.deps.now());
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/** A restarted server resumes every session it left holding wakeups (`startWakeup` drops a deleted session's). */
|
|
394
|
+
resumeHeld() {
|
|
395
|
+
let sids;
|
|
396
|
+
try {
|
|
397
|
+
sids = this.heldWakeups.sessions();
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
this.deps.log(`[webui] WARNING: held wakeups unreadable; retrying: ${error.message}`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
this.heldResumed = true;
|
|
404
|
+
for (const sid of sids)
|
|
405
|
+
void this.drainDeferred(sid);
|
|
406
|
+
}
|
|
407
|
+
held(sid) {
|
|
408
|
+
if (this.unreleased.has(sid))
|
|
409
|
+
this.release(sid, []);
|
|
410
|
+
const done = new Set((this.unreleased.get(sid) ?? []).map(heldKey));
|
|
411
|
+
try {
|
|
412
|
+
return this.heldWakeups.get(sid).filter((e) => !done.has(heldKey(e)));
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
// An unreadable store is unknown, not empty: recheck later rather than leave the session dormant.
|
|
416
|
+
this.scheduleDrain(sid, HELD_RECHECK_SECONDS);
|
|
417
|
+
this.deps.log(`[webui] WARNING: held wakeups unreadable for session ${sid}; retrying: ${error.message}`);
|
|
418
|
+
return [];
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/** A session whose file is gone was deleted; any other load failure keeps its wakeups. */
|
|
422
|
+
deleted(sid, error) {
|
|
423
|
+
return error instanceof SessionNotFound && !existsSync(this.deps.store.pathFor(sid));
|
|
424
|
+
}
|
|
425
|
+
/** Admitted or settled wakeups (every one, with none given) leave the held file. */
|
|
426
|
+
release(sid, entries) {
|
|
427
|
+
// Earlier releases that could not be written go with this one.
|
|
428
|
+
const batch = entries ? mergeWakeups([...(this.unreleased.get(sid) ?? [])], entries) : undefined;
|
|
429
|
+
try {
|
|
430
|
+
this.heldWakeups.release(sid, batch);
|
|
431
|
+
this.unreleased.delete(sid);
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
if (batch)
|
|
435
|
+
this.unreleased.set(sid, batch);
|
|
436
|
+
this.deps.log(`[webui] WARNING: failed to release held wakeups for session ${sid}; they are not delivered again: ${error.message}`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
saveSession(sid, session) {
|
|
440
|
+
try {
|
|
441
|
+
this.deps.store.save(session, { touchUpdatedAt: false });
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
this.deps.log(`[webui] WARNING: failed to save wakeup pause for session ${sid}: ${error.message}`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* TAL-576: while the provider has no usable credentials no wakeup turn starts. The entries are held until a turn
|
|
449
|
+
* admits them, and a timer rechecks the pause at the pool's earliest retry deadline, at least every five minutes.
|
|
450
|
+
* Returns whether the wakeup is handled here (held, or dropped with its deleted session).
|
|
451
|
+
*/
|
|
452
|
+
async holdWhilePaused(sid, session, home, batched) {
|
|
453
|
+
const pause = session.process_wakeup_pause;
|
|
454
|
+
if (!wakeupPaused(session, home, this.deps.configPath?.(home))) {
|
|
455
|
+
if (pause !== session.process_wakeup_pause)
|
|
456
|
+
this.saveSession(sid, session);
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
const recovery = await this.poolRecovery(home, session);
|
|
460
|
+
// A turn that succeeded or a provider switched during the lookup lifted the pause already.
|
|
461
|
+
// A deleted session owns no turn; a transient load failure holds the wakeups for the next recheck.
|
|
462
|
+
let current = null;
|
|
463
|
+
try {
|
|
464
|
+
current = this.deps.store.get(sid);
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
if (this.deleted(sid, error)) {
|
|
468
|
+
this.release(sid);
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (current) {
|
|
473
|
+
const before = current.process_wakeup_pause;
|
|
474
|
+
if (recovery === true)
|
|
475
|
+
current.process_wakeup_pause = null;
|
|
476
|
+
if (recovery === true || !wakeupPaused(current, home, this.deps.configPath?.(home))) {
|
|
477
|
+
if (before !== current.process_wakeup_pause)
|
|
478
|
+
this.saveSession(sid, current);
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
try {
|
|
483
|
+
this.heldWakeups.hold(sid, batched);
|
|
484
|
+
}
|
|
485
|
+
catch (error) {
|
|
486
|
+
for (const e of batched)
|
|
487
|
+
this.defer(sid, e);
|
|
488
|
+
this.deps.log(`[webui] WARNING: failed to persist held wakeups for session ${sid}; kept in memory: ${error.message}`);
|
|
489
|
+
}
|
|
490
|
+
this.retryAttempts.delete(sid);
|
|
491
|
+
this.scheduleDrain(sid, typeof recovery === 'number' ? Math.min(recovery - this.deps.now(), HELD_RECHECK_SECONDS) : HELD_RECHECK_SECONDS);
|
|
492
|
+
this.deps.log(`[webui] server-side wakeup paused for session ${sid}: provider credential pool is empty`);
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
308
495
|
/** Python `_start_server_side_wakeup_turn`: one batched turn; 409 re-defers, other failures re-defer with a timed retry. */
|
|
309
496
|
async startWakeup(sid, batched) {
|
|
310
497
|
const redefer = (entries) => { for (const e of entries)
|
|
311
|
-
this.
|
|
498
|
+
this.defer(sid, e); };
|
|
312
499
|
let session;
|
|
313
500
|
try {
|
|
314
501
|
session = this.deps.store.get(sid);
|
|
315
502
|
}
|
|
316
|
-
catch {
|
|
503
|
+
catch (error) {
|
|
504
|
+
// A deleted session owns no turn: its wakeups, held ones included, go with it.
|
|
505
|
+
if (this.deleted(sid, error)) {
|
|
506
|
+
this.release(sid);
|
|
507
|
+
this.deps.log(`[webui] server-side wakeup dropped for deleted session ${sid}`);
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
317
510
|
redefer(batched);
|
|
318
|
-
this.
|
|
511
|
+
this.scheduleRetry(sid);
|
|
512
|
+
this.deps.log(`[webui] WARNING: server-side wakeup retained for session ${sid}: session unavailable; retrying`);
|
|
319
513
|
return false;
|
|
320
514
|
}
|
|
321
515
|
if (session.pre_compression_snapshot) {
|
|
@@ -323,7 +517,19 @@ export class CompletionDrain {
|
|
|
323
517
|
this.deps.log(`[webui] WARNING: automatic wakeup retained: sealed snapshot ${sid} cannot own a turn`);
|
|
324
518
|
return false;
|
|
325
519
|
}
|
|
326
|
-
|
|
520
|
+
// TAL-534: the delegation's ledger row lives in the session's own profile, whichever profile is active now.
|
|
521
|
+
let home;
|
|
522
|
+
try {
|
|
523
|
+
home = this.deps.profileHome(session.profile ?? this.deps.activeProfile());
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
redefer(batched);
|
|
527
|
+
this.deps.log(`[webui] WARNING: server-side wakeup retained for session ${sid}: ${error.message}`);
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
if (await this.holdWhilePaused(sid, session, home, batched))
|
|
531
|
+
return false;
|
|
532
|
+
const claimed = await this.claimBatch(home, batched);
|
|
327
533
|
if (!claimed) {
|
|
328
534
|
redefer(batched);
|
|
329
535
|
this.scheduleRetry(sid);
|
|
@@ -332,15 +538,16 @@ export class CompletionDrain {
|
|
|
332
538
|
const { deliver, held } = claimed;
|
|
333
539
|
// Entries another consumer already delivered are done here too.
|
|
334
540
|
if (!deliver.length) {
|
|
335
|
-
|
|
541
|
+
this.release(sid, batched);
|
|
542
|
+
await this.markConsumed(batched);
|
|
336
543
|
return true;
|
|
337
544
|
}
|
|
338
545
|
// A wakeup that does not start hands its claims back, so those rows stay pending for the retry or the next restart.
|
|
339
|
-
const giveBack = async (method = 'process.release_delivery') => { await this.settleClaims(method, held); redefer(deliver); };
|
|
546
|
+
const giveBack = async (method = 'process.release_delivery') => { await this.settleClaims(home, method, held); redefer(deliver); };
|
|
340
547
|
const prompt = deliver.length === 1 ? deliver[0].wakeup_prompt : deliver.map((e) => e.wakeup_prompt).join('\n\n');
|
|
341
548
|
let resp;
|
|
342
549
|
try {
|
|
343
|
-
resp = this.deps.startTurn(session, prompt);
|
|
550
|
+
resp = await this.deps.startTurn(session, prompt);
|
|
344
551
|
}
|
|
345
552
|
catch (error) {
|
|
346
553
|
await giveBack();
|
|
@@ -349,8 +556,11 @@ export class CompletionDrain {
|
|
|
349
556
|
return false;
|
|
350
557
|
}
|
|
351
558
|
const status = resp._status ?? (resp.stream_id ? 200 : 500);
|
|
559
|
+
// A busy session redelivers at its turn teardown; a stale runtime admits no turn, so it is retried on a timer (TAL-577).
|
|
352
560
|
if (status === 409) {
|
|
353
561
|
await giveBack('process.defer_delivery');
|
|
562
|
+
if (resp.retryable)
|
|
563
|
+
this.scheduleRetry(sid);
|
|
354
564
|
return false;
|
|
355
565
|
}
|
|
356
566
|
if (status >= 400) {
|
|
@@ -360,22 +570,60 @@ export class CompletionDrain {
|
|
|
360
570
|
return false;
|
|
361
571
|
}
|
|
362
572
|
this.retryAttempts.delete(sid);
|
|
573
|
+
this.release(sid, batched);
|
|
363
574
|
recordBackgroundUpdate(session, str(resp.stream_id), batchUpdate(deliver.map((e) => ({ event: e.event ?? {}, prompt: e.wakeup_prompt }))));
|
|
364
|
-
await this.settleClaims('process.complete_delivery', held);
|
|
365
|
-
await this.markConsumed(batched
|
|
575
|
+
await this.settleClaims(home, 'process.complete_delivery', held);
|
|
576
|
+
await this.markConsumed(batched);
|
|
366
577
|
this.deps.log(`[webui] server-side wakeup turn started for session ${sid} (stream_id=${str(resp.stream_id)})`);
|
|
367
578
|
return true;
|
|
368
579
|
}
|
|
369
|
-
/**
|
|
370
|
-
|
|
580
|
+
/**
|
|
581
|
+
* TAL-532: the deferred process completions the agent already holds from its own turn (wait/log or poll). Checked at
|
|
582
|
+
* delivery, not drain: the completion is usually drained seconds before the agent's wait returns. Only completions:
|
|
583
|
+
* consuming the exit says nothing about a watch match or notice, and async delegations settle in their delivery ledger.
|
|
584
|
+
* A failed check delivers everything rather than lose a result.
|
|
585
|
+
*/
|
|
586
|
+
async alreadyConsumed(entries) {
|
|
587
|
+
const completions = entries.filter(isCompletion);
|
|
588
|
+
const sidecar = this.deps.sidecar();
|
|
589
|
+
if (!completions.length || !sidecar)
|
|
590
|
+
return new Set();
|
|
591
|
+
try {
|
|
592
|
+
const { consumed } = await sidecar.call('process.consumed', { process_ids: completions.map((e) => e.process_id) });
|
|
593
|
+
return new Set(completions.filter((e) => consumed.includes(e.process_id)));
|
|
594
|
+
}
|
|
595
|
+
catch {
|
|
596
|
+
return new Set();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Python `drain_deferred_wakeups_for_session`: turn-teardown idle hook; only the last active stream's teardown fires.
|
|
601
|
+
* TAL-576: one drain per session at a time, so two never copy the same held wakeups before either admits them.
|
|
602
|
+
*/
|
|
603
|
+
drainDeferred(sid) {
|
|
604
|
+
const run = (this.drains.get(sid) ?? Promise.resolve(0)).catch(() => 0).then(() => this.drainDeferredNow(sid));
|
|
605
|
+
this.drains.set(sid, run);
|
|
606
|
+
void run.finally(() => { if (this.drains.get(sid) === run)
|
|
607
|
+
this.drains.delete(sid); }).catch(() => undefined);
|
|
608
|
+
return run;
|
|
609
|
+
}
|
|
610
|
+
async drainDeferredNow(sid) {
|
|
371
611
|
if (!sid || this.hasActiveTurn(sid))
|
|
372
612
|
return 0;
|
|
373
|
-
const entries = this.deferred.get(sid);
|
|
374
|
-
if (!entries
|
|
613
|
+
const entries = mergeWakeups([...(this.deferred.get(sid) ?? [])], this.held(sid));
|
|
614
|
+
if (!entries.length)
|
|
375
615
|
return 0;
|
|
376
616
|
this.deferred.delete(sid);
|
|
377
617
|
this.pendingSessions.delete(sid);
|
|
378
|
-
const
|
|
618
|
+
const prompted = entries.filter((e) => e.wakeup_prompt.trim());
|
|
619
|
+
const held = await this.alreadyConsumed(prompted);
|
|
620
|
+
if (held.size) {
|
|
621
|
+
this.release(sid, [...held]);
|
|
622
|
+
const ids = [...held].map((e) => e.process_id);
|
|
623
|
+
await this.markConsumed([...held]);
|
|
624
|
+
this.deps.log(`[webui] dropped ${String(held.size)} deferred wakeup(s) already consumed by the agent's own turn for session ${sid}: ${ids.join(', ')}`);
|
|
625
|
+
}
|
|
626
|
+
const pending = prompted.filter((e) => !held.has(e));
|
|
379
627
|
if (!pending.length) {
|
|
380
628
|
this.retryAttempts.delete(sid);
|
|
381
629
|
return 0;
|
|
@@ -385,7 +633,7 @@ export class CompletionDrain {
|
|
|
385
633
|
for (const entry of pending) {
|
|
386
634
|
const size = entry.wakeup_prompt.length;
|
|
387
635
|
if (batch.length && total + size > WAKEUP_BATCH_MAX_CHARS) {
|
|
388
|
-
this.
|
|
636
|
+
this.defer(sid, entry);
|
|
389
637
|
continue;
|
|
390
638
|
}
|
|
391
639
|
batch.push(entry);
|