@maudecode/talaria-web 1.16.1 → 1.17.2
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 +4 -4
- package/dist/api/automation-raw.js +6 -3
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +137 -9
- package/dist/api/automation-router.js +9 -6
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +51 -0
- package/dist/api/chat-router.js +29 -12
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +12 -1
- package/dist/api/git-router.js +17 -7
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +6 -0
- package/dist/api/raw-routes.js +30 -0
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/sessions-router.d.ts +260 -0
- package/dist/api/sessions-router.js +30 -2
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +101 -2
- package/dist/api/settings-router.js +7 -2
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +11 -3
- package/dist/api/sse-routes.js +144 -64
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.js +6 -2
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +73 -8
- package/dist/api/tools-router.js +9 -7
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.d.ts +0 -9377
- package/dist/app.js +7 -2
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +3 -0
- package/dist/auth/gate.js.map +1 -1
- package/dist/config/agent-config.d.ts +2 -0
- package/dist/config/agent-config.js +9 -0
- package/dist/config/agent-config.js.map +1 -1
- package/dist/http/context.d.ts +3 -0
- package/dist/http/context.js +10 -4
- package/dist/http/context.js.map +1 -1
- package/dist/onboarding.js +4 -0
- package/dist/onboarding.js.map +1 -1
- package/dist/providers/catalog.d.ts +96 -7
- package/dist/providers/catalog.js +434 -113
- package/dist/providers/catalog.js.map +1 -1
- package/dist/redact.d.ts +1 -0
- package/dist/redact.js +27 -4
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +27 -9
- package/dist/runtime.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/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/completions.d.ts +13 -1
- package/dist/sessions/completions.js +63 -11
- 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/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 +6 -2
- package/dist/sessions/list.js +33 -10
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +52 -2
- package/dist/sessions/merge.js +213 -10
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/service.d.ts +44 -2
- package/dist/sessions/service.js +251 -57
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +11 -1
- package/dist/sessions/session.js +23 -2
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/state-db.d.ts +26 -4
- package/dist/sessions/state-db.js +126 -8
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/store.js +5 -0
- 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/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 +76 -1
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn.d.ts +30 -9
- package/dist/sessions/turn.js +247 -78
- package/dist/sessions/turn.js.map +1 -1
- package/dist/settings.d.ts +20 -2
- package/dist/settings.js +40 -2
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/fake.d.ts +2 -2
- 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/test/harness.js +2 -0
- package/dist/test/harness.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 +2 -1
- package/dist/tools/mcp.js +11 -5
- package/dist/tools/mcp.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 +7 -0
- package/dist/tools/updates.js +74 -7
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/fs.d.ts +7 -3
- package/dist/workspace/fs.js +5 -1
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/media.js +2 -0
- 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 +5 -4
- package/dist/workspace/rollback.js +12 -9
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/upload.d.ts +2 -0
- package/dist/workspace/upload.js +4 -1
- package/dist/workspace/upload.js.map +1 -1
- package/package.json +2 -2
- package/sidecar/scripts/replay_sidecar.py +1 -1
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/__main__.py +7 -1
- package/sidecar/talaria_sidecar/home.py +39 -0
- package/sidecar/talaria_sidecar/methods/chat.py +422 -38
- package/sidecar/talaria_sidecar/methods/commands.py +15 -2
- package/sidecar/talaria_sidecar/methods/cron.py +10 -6
- package/sidecar/talaria_sidecar/methods/kanban.py +115 -15
- package/sidecar/talaria_sidecar/methods/process.py +60 -1
- package/sidecar/talaria_sidecar/methods/profiles.py +7 -1
- package/sidecar/talaria_sidecar/methods/runtime.py +3 -0
- package/sidecar/talaria_sidecar/methods/text.py +17 -1
- package/sidecar/talaria_sidecar/methods/usage.py +257 -4
- package/static/dist/FILES.txt +126 -125
- package/static/dist/assets/AppShell-fb2td9zi.js +1 -0
- package/static/dist/assets/ChatPage-cj96kiy9.js +25 -0
- package/static/dist/assets/Dialog-kxcg7ard.js +1 -0
- package/static/dist/assets/ExtensionRoute-jf7h0754.js +1 -0
- package/static/dist/assets/HubRoute-gmanpd5y.js +2 -0
- package/static/dist/assets/{Markdown-jqrx5es0.js → Markdown-mdwlvj3w.js} +29 -29
- package/static/dist/assets/RightPanel-ftvrjlcp.js +1 -0
- package/static/dist/assets/Select-bilaypej.js +1 -0
- package/static/dist/assets/SessionListPanel-og8n36qs.js +1 -0
- package/static/dist/assets/SettingsLayout-jonjefmj.js +1 -0
- package/static/dist/assets/States-nmejrwrm.js +1 -0
- package/static/dist/assets/Toaster-nnl8zkt9.js +1 -0
- package/static/dist/assets/_app-gdidzd94.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-opyh9y0v.js +1 -0
- package/static/dist/assets/_app.index-hbarzbjx.js +1 -0
- package/static/dist/assets/_app.insights-luywlarz.js +1 -0
- package/static/dist/assets/_app.kanban-kincnbr8.js +1 -0
- package/static/dist/assets/_app.logs-oi2gr3gs.js +1 -0
- package/static/dist/assets/_app.memory-b6jfivt6.js +1 -0
- package/static/dist/assets/_app.profiles-lpvixmqp.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-hh27wwu2.js → _app.session._sessionId-bfd4h3id.js} +1 -1
- package/static/dist/assets/_app.settings-vowx3iq0.js +1 -0
- package/static/dist/assets/_app.settings._section-cnntg1tu.js +3 -0
- package/static/dist/assets/_app.skills-fb57lpau.js +1 -0
- package/static/dist/assets/_app.tasks-eszpx1q7.js +2 -0
- package/static/dist/assets/_app.todos-nr05ac6w.js +1 -0
- package/static/dist/assets/_app.workspaces-d2luomu6.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-oity9y4o.js → abnfDiagram-VCTEODGH-b2x1lqot.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +1 -0
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-ceaepnyr.js → architectureDiagram-5GKGNRK7-h38o5l7b.js} +1 -1
- package/static/dist/assets/{back-eu64w89w.js → back-bemaer09.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-n79st4pj.js → blockDiagram-I7D4REHJ-bqquxv2u.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-mi73akzk.js → c4Diagram-7LVT6UL2-f3fb8w6z.js} +1 -1
- package/static/dist/assets/{cancel-mzvkdjg8.js → cancel-drd0g6d9.js} +1 -1
- package/static/dist/assets/channel-cpdgf867.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-laat0g1q.js → chunk-4HAMMTFA-bzfyyzp3.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-0psy1tr2.js → chunk-75Z2AOVW-ly99rfx5.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-lw8uox8x.js → chunk-DU6HZSFF-bg6ecfqf.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-erassib3.js → chunk-F27PBJKO-e8k7mmqw.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-fz7rx619.js → chunk-GMAD6QVW-cmalnoaj.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-gdb0epb2.js → chunk-GVQU2GXP-gmif5o01.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-ea8t26qw.js → chunk-IMKFNOWR-f1nwwh6u.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-mb1gu9kz.js → chunk-L3NEJ4N5-oktfh5v7.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-eovmccvy.js → chunk-OSK3NFVY-b1sdx96z.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-bo55zjo5.js → chunk-P2QGCYS3-fhu4nzxt.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-ja7ohe4h.js → chunk-POPQ4Y6H-em31rnef.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-e30g9nus.js → chunk-PWAF6VOD-bxhhyftw.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-gbb798f7.js → chunk-SHT3W25Y-fmrvwcav.js} +1 -1
- package/static/dist/assets/{chunk-SVP7TREG-h2iw8urm.js → chunk-SVP7TREG-lymukl2j.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-fd2cottz.js → chunk-TICWLB2K-lmza6k23.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +1 -0
- package/static/dist/assets/{copied-h65fc3cx.js → copied-ima3pysb.js} +1 -1
- package/static/dist/assets/copy-fw5b1pc6.js +1 -0
- package/static/dist/assets/{cynefin-OW5HDTMX-lbltyl5j.js → cynefin-OW5HDTMX-czlhbyhs.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-lxhsqq4a.js → cynefinDiagram-5FMLGOSQ-gq7mvswb.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-gn4nnaln.js → dagre-GXQ25YYZ-cqdbf7dr.js} +1 -1
- package/static/dist/assets/{diagram-S7CK7UJ4-pa3ij6q7.js → diagram-S7CK7UJ4-o6arxa58.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-zbipyz57.js → diagram-UQ7AKVKN-nhnd68tz.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-d1kbpzgf.js → diagram-VSXAHHWV-dk2sclzn.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-i3ty14xl.js → diagram-VX7I27RA-n3k5nyx3.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-m8xefqa7.js → diagram-Z3DM3KII-m6q9cwdh.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-nz7wj05l.js → ebnfDiagram-PWID7BFC-lsa5641p.js} +1 -1
- package/static/dist/assets/endpoints-d33siokx.js +64 -0
- package/static/dist/assets/{erDiagram-RLTQ6QDP-fa41ib83.js → erDiagram-RLTQ6QDP-fo2ckbe6.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-n7zq01qu.js → ganttDiagram-EL5Y4UJY-nzqz6x9g.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-c89emb07.js → gitGraph-4MIJSDKK-gukvcxe6.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-cz7cgr6w.js → gitGraphDiagram-WWUBYQGX-lqhdp8f0.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-d9bapmni.js → highlighted-body-KPVGNVTW-igw6cp39.js} +1 -1
- package/static/dist/assets/index-cxq58xb1.js +11 -0
- package/static/dist/assets/index-hgtx08n5.css +2 -0
- package/static/dist/assets/{info-A6RAGUB7-ndddhhhh.js → info-A6RAGUB7-gvu7a93l.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-ccxigcpf.js → infoDiagram-27XIBGKW-m8t8g6w1.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-le0z9vtc.js → ishikawaDiagram-5VMMS53U-l07vkbgj.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-ivsmb26o.js → journeyDiagram-3NMN7TZE-hybkgj8l.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-h6n2awt0.js → kanban-definition-UXKFOSKX-by13uvtn.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +1 -0
- package/static/dist/assets/{line-dmzlfe0u.js → line-osxq6fq7.js} +1 -1
- package/static/dist/assets/link-jyxicdhg.js +1 -0
- package/static/dist/assets/{login-kjhasvp8.js → login-ec21t39x.js} +1 -1
- package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-gwyd5bnq.js → mermaid-parser.core-i91oxmou.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-l68gg5h7.js → mindmap-definition-YA3MSWOX-m82mx8ww.js} +1 -1
- package/static/dist/assets/onboarding-btnltvyz.js +1 -0
- package/static/dist/assets/onboarding_model_label-dp7xffoh.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-gpv06065.js → packet-AYTQ26CC-nbtgge2o.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-e52vs23u.js → pegDiagram-XKGWAZYB-f1zxzga1.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-l6m7nz5s.js → pie-WAS4IAKB-of8vuhxs.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-b4is36bq.js → pieDiagram-E7YTZNPT-o7y8ftio.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-m8vt2788.js → quadrantDiagram-AXDQQJYC-iqiwia1t.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-nxbrhiov.js → radar-RG4KPBEZ-delnsy2v.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-222mu9hi.js → railroad-74A4TZTK-nspnyq9u.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-o8lldfzv.js → railroadDiagram-O6MQD6OU-z41tqx5z.js} +1 -1
- package/static/dist/assets/refresh-b4uams1i.js +1 -0
- package/static/dist/assets/refresh-cw-nt1dtsx4.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-ovyq38kv.js → requirementDiagram-BXWQKSXE-bdvif194.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-ou7lznor.js → sankeyDiagram-P5KCCOFB-h73e0rol.js} +1 -1
- package/static/dist/assets/{saved-bazmcup9.js → saved-kg52csy7.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-ovckdzf2.js → sequenceDiagram-WJ2MYXX4-iv95mb1z.js} +1 -1
- package/static/dist/assets/{settings_section_extensions_title-ertwwhlx.js → settings_section_extensions_title-ej0iapxe.js} +1 -1
- package/static/dist/assets/share._token-f97e94r0.js +2 -0
- package/static/dist/assets/sliders-horizontal-fj18it47.js +1 -0
- package/static/dist/assets/sse-fwpqtzbg.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-fcrexkkv.js → stateDiagram-D77RDMKH-k417ixmf.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-f7usu8fw.js → swimlanes-42K2YHIH-esola70w.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-gp1hvz9f.js → timeline-definition-24CTP7MA-getrz2y8.js} +1 -1
- package/static/dist/assets/todoStore-eginf9h4.js +1 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-gb9gf11u.js → treeView-Q6P3EWNA-hc7ap1q7.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-nuvfnvvi.js → treemap-WGGIJYW6-b7k1syy5.js} +1 -1
- package/static/dist/assets/tts-lxdxnmjd.js +1 -0
- package/static/dist/assets/{untitled-htelhc68.js → untitled-ovpfthg4.js} +1 -1
- package/static/dist/assets/{useForm-h2t0u14e.js → useForm-bcblv1rx.js} +1 -1
- package/static/dist/assets/useLocale-fi5jb8ma.js +1 -0
- package/static/dist/assets/{useParams-dqd64jv7.js → useParams-lhg566ew.js} +1 -1
- package/static/dist/assets/{useSearch-j30pvsy7.js → useSearch-lbrh6ejn.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-fzchbzaj.js → vennDiagram-4TSXK5OY-n6pcy5qb.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-m47mhfbh.js → wardley-WFR3VGLG-lpa18vz1.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-odg6ct1z.js → wardleyDiagram-VM6X3IG4-kpclwwg7.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mrhms5um.js → xychartDiagram-S5SC5T6Z-paa2n8y0.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/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
package/dist/sessions/service.js
CHANGED
|
@@ -3,15 +3,16 @@ import { randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { rmSync } from 'node:fs';
|
|
4
4
|
import { buildActiveTurnToken, copyJson, redactSessionData, redactValue, stripPublicInternalFields, withSceneToolDisplay } from '../redact.js';
|
|
5
5
|
import { DraftVersionConflict, normalizeDraftVersion } from './drafts.js';
|
|
6
|
-
import { allSessions, buildSessionListPayload, CLI_IDENTITY_FIELDS, isClaimableCliSource, isMessagingSessionRecord, withOwnerLocks, withSessionWireFlags, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMessageText, sessionSearchPreview } from './list.js';
|
|
6
|
+
import { allSessions, buildSessionListPayload, CLI_IDENTITY_FIELDS, isClaimableCliSource, isMessagingSessionRecord, withOwnerLocks, withSessionWireFlags, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMatches, sessionSearchMessageText, sessionSearchPreview, sessionSearchTerms } from './list.js';
|
|
7
7
|
import { anchorSceneIntOrNull, fullToolResult, hydrateAnchorActivityScenes, normalizeAnchorSceneMessageRef, readAnchorSceneRows, storeAnchorScene, withTurnIds } from './anchor.js';
|
|
8
|
-
import { isSafeSessionId, lastMessageTimestamp, Session, stripAttachedFilesMarker, titleFrom } from './session.js';
|
|
8
|
+
import { isSafeSessionId, lastMessageTimestamp, Session, sharePath, stripAttachedFilesMarker, titleFrom } from './session.js';
|
|
9
9
|
import { SessionBusy, SessionNotFound, statSignature } from './store.js';
|
|
10
|
-
import { attachTodoState } from './todo.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { UNSETTLED_TODO_KEY, attachTodoState } from './todo.js';
|
|
11
|
+
import { isClaudeCodeSessionId } from './claude-code.js';
|
|
12
|
+
import { stateDbCompressionLineage, stateDbSessionMessages, stateDbSessionRead, stateDbSessionRow, stateDbSessionSources } from './state-db.js';
|
|
13
|
+
import { anchorMessageKey, anchorSummary, CompressionJobs, compressionReference, visibleMessagesForAnchor } from './compress.js';
|
|
13
14
|
import { SidecarError } from '../sidecar/client.js';
|
|
14
|
-
import { attachmentObjects, isContextCompressionMarker, mergeSessionMessagesAppendOnly, pendingUserRow, sanitizeMessagesForApi, stripWorkspacePrefix, withAttachmentObjects, withBodyExcerpts, withDisplayMedia, withMarkerKinds, withSceneRowMedia, withPendingUserTurn, withToolCallOutcomes, withoutRunningTurnOutput } from './merge.js';
|
|
15
|
+
import { agentSteerText, attachedFilesPrompt, attachmentObjects, dedupeContext, isContextCompressionMarker, journalOutputRows, looksLikeCurrentUserTurn, stoppedTurnContext, workspaceContextPrefix, mergeSessionMessagesAppendOnly, messageIdentity, pendingUserRow, reasoningFieldsText, sanitizeMessagesForApi, stateDbSeenId, stripWorkspacePrefix, withAttachmentObjects, withBodyExcerpts, withDisplayMedia, withMarkerKinds, withSceneRowMedia, withPendingUserTurn, withToolCallOutcomes, withoutRunningTurnOutput } from './merge.js';
|
|
15
16
|
import { withBackgroundUpdates } from './background-updates.js';
|
|
16
17
|
import { withBackgroundLinks } from './background-tasks.js';
|
|
17
18
|
import { messagesForLimitedPayload, messageWindowForDisplay, MAX_MSG_LIMIT, parseMsgLimit, toolCallsForMessageWindow } from './window.js';
|
|
@@ -50,6 +51,9 @@ export async function ensureAgentRuntimeCurrent(sidecar) {
|
|
|
50
51
|
function staleRuntimeFailure(error) {
|
|
51
52
|
return new HttpFailure(409, error.message, { type: 'agent_runtime_stale', retryable: true, restart_scheduled: false, ...(error.data.agent_update_state !== undefined ? { agent_update_state: error.data.agent_update_state } : {}) });
|
|
52
53
|
}
|
|
54
|
+
/** TAL-536: the most of a dead run's journal stale-stream cleanup reads (Python's recovery window). */
|
|
55
|
+
const RECOVERY_JOURNAL_MAX_BYTES = 8 * 1024 * 1024;
|
|
56
|
+
const RECOVERY_JOURNAL_MAX_ROWS = 65536;
|
|
53
57
|
const isDict = (v) => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
|
|
54
58
|
export class SessionService {
|
|
55
59
|
deps;
|
|
@@ -185,9 +189,18 @@ export class SessionService {
|
|
|
185
189
|
}
|
|
186
190
|
/** The Agent's state.db rows for this session (empty for subagent views, which never merge). */
|
|
187
191
|
stateDbRows(s) {
|
|
192
|
+
return this.stateDbRead(s).rows;
|
|
193
|
+
}
|
|
194
|
+
/** `stateDbRows` and whether the read succeeded on a state.db whose messages carry ids (TAL-493). */
|
|
195
|
+
stateDbRead(s) {
|
|
188
196
|
if (str(s.source_tag || s.raw_source || s.session_source).trim().toLowerCase() === 'subagent')
|
|
189
|
-
return [];
|
|
190
|
-
|
|
197
|
+
return { rows: [], idCapable: false, ok: false };
|
|
198
|
+
// TAL-529: after a compression rotation the Agent writes to the continuation, so the read follows the recorded lineage.
|
|
199
|
+
const lineage = s.state_db_lineage?.[0] === s.session_id ? s.state_db_lineage : null;
|
|
200
|
+
return stateDbSessionRead(this.stateDbPath(s.profile), s.session_id, { stitch: false, lineage });
|
|
201
|
+
}
|
|
202
|
+
stateDbPath(profile) {
|
|
203
|
+
return join(this.deps.profileHome(profile ?? this.deps.activeProfile()), 'state.db');
|
|
191
204
|
}
|
|
192
205
|
/**
|
|
193
206
|
* Python `_merged_session_messages_for_display`: the sidecar transcript merged append-only with the Agent's state.db
|
|
@@ -197,7 +210,91 @@ export class SessionService {
|
|
|
197
210
|
mergedTranscript(s, local = s.messages, stateRows = this.stateDbRows(s)) {
|
|
198
211
|
if (!stateRows.length)
|
|
199
212
|
return local;
|
|
200
|
-
return mergeSessionMessagesAppendOnly(local, stateRows, { truncationWatermark: s.truncation_watermark, compressedWatermark: s.truncation_watermark_compressed });
|
|
213
|
+
return mergeSessionMessagesAppendOnly(local, stateRows, { truncationWatermark: s.truncation_watermark, compressedWatermark: s.truncation_watermark_compressed, stateDbSeenId: currentStateDbSeenId(s, stateRows) });
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* TAL-493: record the highest state.db id this boundary or settled turn read, under the session lock in the same save,
|
|
217
|
+
* so the merge never replays a covered row and appends every row committed after the read. Call it after the boundary
|
|
218
|
+
* fields are set: the marker holds only while they and the row it names stay as recorded.
|
|
219
|
+
*/
|
|
220
|
+
markStateDbSeen(s, read = this.stateDbRead(s), opts = {}) {
|
|
221
|
+
// A failed read says nothing. A settlement keeps the marker; a boundary drops it (fail closed): it may cut rows the
|
|
222
|
+
// marker still admits without moving a field, and the timestamp rules honour its watermark.
|
|
223
|
+
if (!read.ok) {
|
|
224
|
+
if (opts.boundary) {
|
|
225
|
+
s.state_db_seen_id = null;
|
|
226
|
+
s.state_db_seen_boundary = null;
|
|
227
|
+
s.state_db_seen_stamp = null;
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
// A successful read with no rows yet is a baseline: every row the session gets later is new.
|
|
232
|
+
s.state_db_seen_id = stateDbSeenId(read.rows) ?? (read.idCapable ? 0 : null);
|
|
233
|
+
s.state_db_seen_boundary = stateDbMarkKey(s, read.rows, s.state_db_seen_id);
|
|
234
|
+
s.state_db_seen_stamp = s.updated_at;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* TAL-493: a turn's settlement. Each state.db row the merge shows now is matched to what the turn holds: a row already
|
|
238
|
+
* in the context it started from (by id), or one row the Agent added this turn (`agentRows` past that context, matched
|
|
239
|
+
* one to one by full text). An unmatched row is a CLI or gateway row committed while the turn ran: it joins the
|
|
240
|
+
* transcript and the model context before the marker passes it. Without the Agent's rows (`agentRows` empty), rows past
|
|
241
|
+
* `startId` (the highest id the turn read when it started) are its own unreported work: covered, never shown. Rows the
|
|
242
|
+
* turn started from but the transcript lacks (a CLI continuation read into its context) are kept before the turn.
|
|
243
|
+
*/
|
|
244
|
+
settleStateDb(s, turn) {
|
|
245
|
+
const read = this.stateDbRead(s);
|
|
246
|
+
const startedWith = new Set(turn.previousContext.flatMap((m) => (typeof m._state_db_row_id === 'number' ? [m._state_db_row_id] : [])));
|
|
247
|
+
const earlier = mergeSessionMessagesAppendOnly(s.messages, read.rows.filter((m) => typeof m._state_db_row_id === 'number' && startedWith.has(m._state_db_row_id)), { stateDbSeenId: -1 }).slice(s.messages.length);
|
|
248
|
+
const added = new Map();
|
|
249
|
+
for (const m of withoutRows(turn.agentRows ?? [], turn.previousContext))
|
|
250
|
+
added.set(settledIdentity(m), (added.get(settledIdentity(m)) ?? 0) + 1);
|
|
251
|
+
const ownWorkAfter = turn.agentRows?.length ? null : turn.startId ?? null;
|
|
252
|
+
// Without a current marker, the turn's own starting read is the baseline: rows committed after it are judged here.
|
|
253
|
+
const seenId = currentStateDbSeenId(s, read.rows) ?? turn.startId ?? null;
|
|
254
|
+
const shown = read.rows.length ? mergeSessionMessagesAppendOnly(s.messages, read.rows, { truncationWatermark: s.truncation_watermark, compressedWatermark: s.truncation_watermark_compressed, stateDbSeenId: seenId }) : s.messages;
|
|
255
|
+
const fresh = new Set(shown.slice(s.messages.length));
|
|
256
|
+
// The turn's own rows the merge already matched to their local copies use up their share before any shown row can.
|
|
257
|
+
if (seenId !== null) {
|
|
258
|
+
for (const m of read.rows) {
|
|
259
|
+
const id = m._state_db_row_id;
|
|
260
|
+
if (typeof id !== 'number' || id <= seenId || startedWith.has(id) || fresh.has(m))
|
|
261
|
+
continue;
|
|
262
|
+
const left = added.get(settledIdentity(m)) ?? 0;
|
|
263
|
+
if (left > 0)
|
|
264
|
+
added.set(settledIdentity(m), left - 1);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const missed = [...fresh].filter((m) => {
|
|
268
|
+
const id = m._state_db_row_id;
|
|
269
|
+
if (typeof id === 'number' && startedWith.has(id))
|
|
270
|
+
return false;
|
|
271
|
+
const key = settledIdentity(m);
|
|
272
|
+
const left = added.get(key) ?? 0;
|
|
273
|
+
if (left > 0) {
|
|
274
|
+
added.set(key, left - 1);
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return !(ownWorkAfter !== null && typeof id === 'number' && id > ownWorkAfter);
|
|
278
|
+
});
|
|
279
|
+
if (earlier.length) {
|
|
280
|
+
const at = s.messages.findIndex((m) => m._turn_id === turn.turnId);
|
|
281
|
+
s.messages.splice(at < 0 ? s.messages.length : at, 0, ...copyJson(earlier));
|
|
282
|
+
}
|
|
283
|
+
if (missed.length) {
|
|
284
|
+
s.messages.push(...copyJson(missed));
|
|
285
|
+
if (s.context_messages.length)
|
|
286
|
+
s.context_messages.push(...copyJson(missed));
|
|
287
|
+
}
|
|
288
|
+
this.markStateDbSeen(s, read);
|
|
289
|
+
// TAL-529: a compression rotation moved the Agent to a continuation, whose first rows restate the compressed context.
|
|
290
|
+
// The read follows the new lineage from here, and everything it holds now is covered.
|
|
291
|
+
// ponytail: a CLI row committed to the continuation before this settlement is covered with them; telling them apart
|
|
292
|
+
// needs the Agent to mark the rows it writes at rotation.
|
|
293
|
+
const lineage = stateDbCompressionLineage(this.stateDbPath(s.profile), s.session_id);
|
|
294
|
+
if (JSON.stringify(lineage) !== JSON.stringify(s.state_db_lineage ?? [s.session_id])) {
|
|
295
|
+
s.state_db_lineage = lineage.length > 1 ? lineage : null;
|
|
296
|
+
this.markStateDbSeen(s);
|
|
297
|
+
}
|
|
201
298
|
}
|
|
202
299
|
/**
|
|
203
300
|
* Python `reconciled_state_db_messages_for_session(prefer_context=True)`: the model history is the owner context
|
|
@@ -220,12 +317,17 @@ export class SessionService {
|
|
|
220
317
|
/** Python `_lookup_cli_session_metadata`: the sidebar row for a state.db session in the active profile. */
|
|
221
318
|
lookupCliMeta(sid) {
|
|
222
319
|
try {
|
|
320
|
+
if (isClaudeCodeSessionId(sid))
|
|
321
|
+
return this.claudeCodeRows().find((r) => str(r.session_id) === sid) ?? null;
|
|
223
322
|
return this.deps.cliSessions(this.deps.activeProfile(), { sourceFilter: null }).rows.find((r) => str(r.session_id) === sid) ?? null;
|
|
224
323
|
}
|
|
225
324
|
catch {
|
|
226
325
|
return null;
|
|
227
326
|
}
|
|
228
327
|
}
|
|
328
|
+
claudeCodeRows() {
|
|
329
|
+
return this.deps.claudeCode?.rows(this.deps.workspaces.lastWorkspace(this.deps.activeProfile())) ?? [];
|
|
330
|
+
}
|
|
229
331
|
/** Python `_session_index_marks_was_webui`: an index row that once owned a WebUI sidecar (self-heal 404). */
|
|
230
332
|
indexMarksWasWebui(sid) {
|
|
231
333
|
let entries;
|
|
@@ -262,7 +364,7 @@ export class SessionService {
|
|
|
262
364
|
const subagentChild = stateDbSource === 'subagent';
|
|
263
365
|
if ((this.indexMarksWasWebui(sid) || (this.store.wasDeleted(sid) && ['', 'webui', 'fork'].includes(stateDbSource))) && !subagentChild)
|
|
264
366
|
return { session: null, reason: 'was_webui' };
|
|
265
|
-
const msgs = stateDbSessionMessages(dbPath, sid, { stitch: true });
|
|
367
|
+
const msgs = isClaudeCodeSessionId(sid) ? this.deps.claudeCode?.messages(sid) ?? [] : stateDbSessionMessages(dbPath, sid, { stitch: true });
|
|
266
368
|
if (!msgs.length)
|
|
267
369
|
return { session: null, reason: 'no_foreign_state' };
|
|
268
370
|
const meta = { ...(metaIn ?? this.lookupCliMeta(sid) ?? {}) };
|
|
@@ -309,7 +411,16 @@ export class SessionService {
|
|
|
309
411
|
throw error;
|
|
310
412
|
}
|
|
311
413
|
}
|
|
414
|
+
/**
|
|
415
|
+
* TAL-551: a Claude Code import is a live view of a transcript Claude Code keeps writing. Web never stores a copy,
|
|
416
|
+
* which would freeze its messages and pin it to one profile.
|
|
417
|
+
*/
|
|
418
|
+
rejectClaudeCode(sid, verb) {
|
|
419
|
+
if (isClaudeCodeSessionId(sid))
|
|
420
|
+
throw new HttpFailure(400, `Claude Code sessions are view-only and cannot be ${verb} from WebUI`);
|
|
421
|
+
}
|
|
312
422
|
rejectSubagent(sid, verb) {
|
|
423
|
+
this.rejectClaudeCode(sid, verb);
|
|
313
424
|
if (this.isSubagentViewOnly(sid))
|
|
314
425
|
throw new HttpFailure(400, `Subagent sessions are view-only and cannot be ${verb} from WebUI`);
|
|
315
426
|
}
|
|
@@ -321,8 +432,10 @@ export class SessionService {
|
|
|
321
432
|
publicSession(s, withMessages = true) {
|
|
322
433
|
const payload = this.wireRow(s);
|
|
323
434
|
// Mutation replies replace a client's transcript, so they carry the same server-built scenes as the detail.
|
|
324
|
-
if (withMessages)
|
|
435
|
+
if (withMessages) {
|
|
325
436
|
payload.messages = this.backgroundLinked(s, hydrateAnchorActivityScenes(withToolCallOutcomes(withBackgroundUpdates(withMarkerKinds(withTurnIds(s.messages)), s), s.tool_calls, s.active_stream_id), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id, runningScene: !this.journaledActiveTurn(s) }));
|
|
437
|
+
payload.compression_reference = compressionReference(s, payload.messages);
|
|
438
|
+
}
|
|
326
439
|
return redactSessionData(payload, this.deps.redactEnabled());
|
|
327
440
|
}
|
|
328
441
|
/** `compact()` with the wire streaming/read-only flags (TAL-312), for replies that return the session row. */
|
|
@@ -442,8 +555,10 @@ export class SessionService {
|
|
|
442
555
|
};
|
|
443
556
|
if (loadMessages)
|
|
444
557
|
raw.transcript_seq = journaled ? { stream_id: journaled.turnId, seq: 0 } : null;
|
|
445
|
-
if (loadMessages
|
|
446
|
-
attachTodoState(raw, all);
|
|
558
|
+
if (loadMessages)
|
|
559
|
+
attachTodoState(raw, all, s.extra[UNSETTLED_TODO_KEY]);
|
|
560
|
+
if (loadMessages)
|
|
561
|
+
raw.compression_reference = compressionReference(s, all);
|
|
447
562
|
if (mergedLast) {
|
|
448
563
|
raw.last_message_at = Math.max(Number(raw.last_message_at ?? 0) || 0, mergedLast);
|
|
449
564
|
raw.updated_at = Math.max(Number(raw.updated_at ?? 0) || 0, mergedLast);
|
|
@@ -518,7 +633,7 @@ export class SessionService {
|
|
|
518
633
|
const merged = withSessionWireFlags(meta ? mergeCliSidebarMetadata(sess, meta) : sess, this.deps.runtime.activeStreamIds);
|
|
519
634
|
return redactSessionData(merged, this.deps.redactEnabled());
|
|
520
635
|
}
|
|
521
|
-
/** Clear persisted streaming flags when no live stream backs them (Python `_clear_stale_stream_state
|
|
636
|
+
/** Clear persisted streaming flags when no live stream backs them (Python `_clear_stale_stream_state`). */
|
|
522
637
|
clearStaleStreamState(session) {
|
|
523
638
|
const streamId = session.active_stream_id;
|
|
524
639
|
if (!streamId)
|
|
@@ -545,15 +660,40 @@ export class SessionService {
|
|
|
545
660
|
return false;
|
|
546
661
|
}
|
|
547
662
|
}
|
|
548
|
-
// Python `_materialize_pending_user_turn_before_error` (#1361)
|
|
549
|
-
//
|
|
663
|
+
// Python `_materialize_pending_user_turn_before_error` (#1361) and `_recover_dead_run_journal`: the prompt that was in
|
|
664
|
+
// flight becomes a durable user turn, the output its journal holds follows it, and an interruption marker closes a
|
|
665
|
+
// run that never finished with an answer, so a dead stream never silently drops what the user sent or what streamed.
|
|
666
|
+
const turnId = str(target.active_stream_id);
|
|
667
|
+
// ponytail: one bounded tail read (Python's recovery window); a journal past it recovers its latest output only.
|
|
668
|
+
const events = this.deps.journal?.readRunEventTail(target.session_id, turnId, RECOVERY_JOURNAL_MAX_BYTES, RECOVERY_JOURNAL_MAX_ROWS).events ?? [];
|
|
669
|
+
const { rows: output, answered } = journalOutputRows(events, turnId);
|
|
550
670
|
const pendingText = str(target.pending_user_message);
|
|
671
|
+
const attachments = [...target.pending_attachments];
|
|
672
|
+
// The run's starting read died with its worker: the state.db rows from before it started stand in for it. Its own
|
|
673
|
+
// rows open with its prompt and run to the next prompt; anything else another client wrote meanwhile stays.
|
|
674
|
+
const read = this.stateDbRead(target);
|
|
675
|
+
const runStart = target.pending_started_at || events[0]?.created_at || this.deps.now();
|
|
676
|
+
const before = read.rows.filter((m) => Number(m.timestamp) < runStart);
|
|
677
|
+
const ownRows = target.hasPendingPrompt ? runStateDbRows(read.rows.filter((m) => Number(m.timestamp) >= runStart), pendingText) : null;
|
|
678
|
+
// Without this turn's rows: an eager save already put its prompt in the transcript a fresh context falls back to.
|
|
679
|
+
const previousContext = this.modelContext(target, before).filter((m) => m._turn_id !== turnId);
|
|
551
680
|
if (target.hasPendingPrompt) {
|
|
552
|
-
const turnId = str(target.active_stream_id);
|
|
553
681
|
const startedAt = typeof target.pending_started_at === 'number' && target.pending_started_at > 0 ? target.pending_started_at : this.deps.now();
|
|
554
|
-
|
|
555
|
-
target.messages.
|
|
556
|
-
|
|
682
|
+
// An eager save already checkpointed this prompt as the turn's user row.
|
|
683
|
+
if (!target.messages.some((m) => m.role === 'user' && !m._steer && m._turn_id === turnId))
|
|
684
|
+
target.messages.push({ role: 'user', content: pendingText, timestamp: Math.trunc(startedAt), ...(attachments.length ? { attachments } : {}), _recovered: true, _source: target.pending_user_source ?? 'webui', _turn_id: turnId });
|
|
685
|
+
// The model context settles as a Stop's does: the Agent's own rows when it committed the prompt, else the prompt it
|
|
686
|
+
// was sent; then the prose that streamed past them.
|
|
687
|
+
const prompt = attachedFilesPrompt((str(target.workspace) ? workspaceContextPrefix(str(target.workspace)) : '') + pendingText, attachments);
|
|
688
|
+
const streamed = output.map((m) => str(m.content)).filter(Boolean).join('\n\n');
|
|
689
|
+
target.context_messages = dedupeContext(stoppedTurnContext(previousContext, ownRows ? [...previousContext, ...ownRows] : null, prompt, pendingText, streamed, previousContext.length) ?? [...structuredClone(previousContext), { role: 'user', content: prompt }]);
|
|
690
|
+
}
|
|
691
|
+
if (target.hasPendingPrompt || output.length) {
|
|
692
|
+
target.messages.push(...output);
|
|
693
|
+
if (!answered)
|
|
694
|
+
target.messages.push({ role: 'assistant', content: '**Interrupted:** The reply was interrupted before it could be saved.', timestamp: Math.trunc(this.deps.now()), _error: true, _turn_id: turnId });
|
|
695
|
+
// Settled like a turn: the Agent's own rows are covered by the recovered turn; without them, every row past the run's start is.
|
|
696
|
+
this.settleStateDb(target, { turnId, previousContext, agentRows: ownRows, startId: stateDbSeenId(before) ?? (read.idCapable ? 0 : null) });
|
|
557
697
|
}
|
|
558
698
|
target.active_stream_id = null;
|
|
559
699
|
target.pending_user_message = null;
|
|
@@ -582,7 +722,8 @@ export class SessionService {
|
|
|
582
722
|
const wantState = params.showCliSessions || params.showCronSessions || params.showWebhookSessions || params.showKanbanSessions;
|
|
583
723
|
// Python reads every profile's state.db under all_profiles; this port projects the active profile only.
|
|
584
724
|
const cliRead = wantState ? this.deps.cliSessions(activeProfile, { sourceFilter: params.sourceFilter ?? null }) : undefined;
|
|
585
|
-
const
|
|
725
|
+
const claudeCodeRows = params.showCliSessions && params.showClaudeCodeSessions ? this.claudeCodeRows() : [];
|
|
726
|
+
const cliRows = cliRead ? [...cliRead.rows, ...claudeCodeRows] : undefined;
|
|
586
727
|
const gatewayIdentity = loadGatewaySessionIdentityMap(join(this.deps.profileHome(activeProfile), 'sessions', 'sessions.json'));
|
|
587
728
|
const truncatedSources = cliRead?.truncated;
|
|
588
729
|
const payload = buildSessionListPayload(this.store, { ...params, ...(cliRows ? { cliRows } : {}), ...(truncatedSources ? { truncatedSources } : {}), gatewayIdentity, stateDbSources: this.stateDbSources, activeProfile, isolatedProfileMode: this.deps.isolatedProfileMode(), profilesMatch: this.deps.profilesMatch });
|
|
@@ -609,15 +750,16 @@ export class SessionService {
|
|
|
609
750
|
const query = q.toLowerCase().trim();
|
|
610
751
|
if (!query)
|
|
611
752
|
return { sessions: sessions.map((s) => redactRow({ ...s })), all_profiles: opts.allProfiles, active_profile: activeProfile };
|
|
753
|
+
const terms = sessionSearchTerms(query);
|
|
612
754
|
const results = [];
|
|
613
755
|
for (const s of sessions) {
|
|
614
|
-
if (str(s.title)
|
|
756
|
+
if (sessionSearchMatches(str(s.title), terms)) {
|
|
615
757
|
results.push(redactRow({ ...s, match_type: 'title' }));
|
|
616
758
|
continue;
|
|
617
759
|
}
|
|
618
760
|
if (!opts.content)
|
|
619
761
|
continue;
|
|
620
|
-
const hit = this.contentMatch(str(s.session_id),
|
|
762
|
+
const hit = this.contentMatch(str(s.session_id), terms, opts.depth);
|
|
621
763
|
if (hit)
|
|
622
764
|
results.push(redactRow({ ...s, ...hit }));
|
|
623
765
|
}
|
|
@@ -638,22 +780,23 @@ export class SessionService {
|
|
|
638
780
|
const base = { all_profiles: params.allProfiles, active_profile: this.deps.activeProfile(), include_archived: params.includeArchived, sidebar_filtered: true };
|
|
639
781
|
if (!query)
|
|
640
782
|
return { ...base, sessions: rows };
|
|
783
|
+
const terms = sessionSearchTerms(query);
|
|
641
784
|
const results = [];
|
|
642
785
|
for (const row of rows) {
|
|
643
|
-
if (str(row.title)
|
|
786
|
+
if (sessionSearchMatches(str(row.title), terms))
|
|
644
787
|
results.push({ ...row, match_type: 'title' });
|
|
645
|
-
else if (['workspace', 'workspace_name', 'model', 'model_provider', 'profile', 'source_label'].some((k) => str(row[k])
|
|
788
|
+
else if (['workspace', 'workspace_name', 'model', 'model_provider', 'profile', 'source_label'].some((k) => sessionSearchMatches(str(row[k]), terms)))
|
|
646
789
|
results.push({ ...row, match_type: 'metadata' });
|
|
647
790
|
else if (opts.content) {
|
|
648
|
-
const hit = this.contentMatch(str(row.session_id),
|
|
791
|
+
const hit = this.contentMatch(str(row.session_id), terms, opts.depth);
|
|
649
792
|
if (hit)
|
|
650
793
|
results.push({ ...row, ...hit });
|
|
651
794
|
}
|
|
652
795
|
}
|
|
653
796
|
return { ...base, sessions: results, query, count: results.length };
|
|
654
797
|
}
|
|
655
|
-
/** The first of a stored session's first `depth` messages (0: all) containing
|
|
656
|
-
contentMatch(sid,
|
|
798
|
+
/** The first of a stored session's first `depth` messages (0: all) containing every term, with its redacted excerpt. */
|
|
799
|
+
contentMatch(sid, terms, depth) {
|
|
657
800
|
let sess;
|
|
658
801
|
try {
|
|
659
802
|
sess = this.store.get(sid, { promote: false, cacheOnMiss: false });
|
|
@@ -663,10 +806,10 @@ export class SessionService {
|
|
|
663
806
|
}
|
|
664
807
|
for (const m of depth ? sess.messages.slice(0, depth) : sess.messages) {
|
|
665
808
|
const c = sessionSearchMessageText(m);
|
|
666
|
-
if (!c
|
|
809
|
+
if (!sessionSearchMatches(c, terms))
|
|
667
810
|
continue;
|
|
668
811
|
const item = { match_type: 'content' };
|
|
669
|
-
const preview = sessionSearchPreview(c,
|
|
812
|
+
const preview = sessionSearchPreview(c, terms);
|
|
670
813
|
if (preview)
|
|
671
814
|
item.match_preview = redactText(preview, this.deps.redactEnabled());
|
|
672
815
|
return item;
|
|
@@ -721,14 +864,16 @@ export class SessionService {
|
|
|
721
864
|
const [workspace] = this.deps.workspaces.resolveImplicitWithRecovery(value, (p) => this.deps.workspaces.profileDefaultWorkspaceForBoot(p), profile);
|
|
722
865
|
return workspace;
|
|
723
866
|
}
|
|
867
|
+
/** The server owns the names' normalization (TAL-631): trimmed, blanks dropped, and nothing left is the profile's defaults. */
|
|
724
868
|
validateToolsetsShape(toolsets) {
|
|
725
869
|
if (toolsets === null || toolsets === undefined)
|
|
726
870
|
return null;
|
|
727
|
-
if (!Array.isArray(toolsets)
|
|
728
|
-
throw new HttpFailure(400, 'toolsets must be a
|
|
729
|
-
if (!toolsets.every((t) => typeof t === 'string'
|
|
730
|
-
throw new HttpFailure(400, 'each toolset must be a
|
|
731
|
-
|
|
871
|
+
if (!Array.isArray(toolsets))
|
|
872
|
+
throw new HttpFailure(400, 'toolsets must be a list or null');
|
|
873
|
+
if (!toolsets.every((t) => typeof t === 'string'))
|
|
874
|
+
throw new HttpFailure(400, 'each toolset must be a string');
|
|
875
|
+
const names = toolsets.map((t) => t.trim()).filter(Boolean);
|
|
876
|
+
return names.length ? names : null;
|
|
732
877
|
}
|
|
733
878
|
create(body, opts = {}) {
|
|
734
879
|
// Python `new_session`: a body without a profile takes the request's active profile (cookie first).
|
|
@@ -923,6 +1068,7 @@ export class SessionService {
|
|
|
923
1068
|
throw new HttpFailure(400, 'keep_count must be non-negative');
|
|
924
1069
|
await this.store.withLock(sid, () => {
|
|
925
1070
|
truncateSessionAtKeep(s, keep);
|
|
1071
|
+
this.markStateDbSeen(s, undefined, { boundary: true });
|
|
926
1072
|
this.store.save(s);
|
|
927
1073
|
});
|
|
928
1074
|
this.deps.runtime.evictAgent(sid);
|
|
@@ -1034,7 +1180,8 @@ export class SessionService {
|
|
|
1034
1180
|
if (streamState(live) !== streamBefore)
|
|
1035
1181
|
throw new HttpFailure(409, 'Session stream state changed during compression; please retry.');
|
|
1036
1182
|
// One state.db read serves the check, the kept display rows, and the boundary.
|
|
1037
|
-
const
|
|
1183
|
+
const read = this.stateDbRead(live);
|
|
1184
|
+
const stateRows = read.rows;
|
|
1038
1185
|
if (transcriptKey(live, sanitizeMessagesForApi(this.modelContext(live, stateRows))) !== historyKey)
|
|
1039
1186
|
throw new HttpFailure(409, 'Session was modified during compression; please retry.');
|
|
1040
1187
|
// Rows the sidecar returns without a timestamp take the newest one this compression saw, never the clock: the
|
|
@@ -1065,6 +1212,7 @@ export class SessionService {
|
|
|
1065
1212
|
live.truncation_watermark = truncationWatermarkFor(compressed);
|
|
1066
1213
|
live.truncation_boundary = live.truncation_watermark;
|
|
1067
1214
|
live.truncation_watermark_compressed = true;
|
|
1215
|
+
this.markStateDbSeen(live, read, { boundary: true });
|
|
1068
1216
|
live.last_prompt_tokens = result.after_tokens;
|
|
1069
1217
|
live.post_compression_context_tokens_estimate = result.after_tokens;
|
|
1070
1218
|
this.store.save(live);
|
|
@@ -1126,6 +1274,7 @@ export class SessionService {
|
|
|
1126
1274
|
s.pending_user_source = null;
|
|
1127
1275
|
s.clear_generation = hadMessages ? randomUUID().replace(/-/g, '') : null;
|
|
1128
1276
|
applySessionTitleRename(s, 'Untitled');
|
|
1277
|
+
this.markStateDbSeen(s, undefined, { boundary: true });
|
|
1129
1278
|
this.store.save(s);
|
|
1130
1279
|
if (hadMessages) {
|
|
1131
1280
|
try {
|
|
@@ -1156,6 +1305,7 @@ export class SessionService {
|
|
|
1156
1305
|
return { error: 'The last message has nothing to resend.' };
|
|
1157
1306
|
const removed = history.length - lastUser;
|
|
1158
1307
|
shrinkTo(s, lastUser);
|
|
1308
|
+
this.markStateDbSeen(s, undefined, { boundary: true });
|
|
1159
1309
|
this.store.save(s);
|
|
1160
1310
|
return { ok: true, last_user_text: lastUserText, last_user_prompt: lastUserPrompt, last_user_attachments: lastUserAttachments, removed_count: removed };
|
|
1161
1311
|
});
|
|
@@ -1171,6 +1321,7 @@ export class SessionService {
|
|
|
1171
1321
|
const removedText = extractText(history[lastUser]?.content);
|
|
1172
1322
|
const removed = history.length - lastUser;
|
|
1173
1323
|
shrinkTo(s, lastUser);
|
|
1324
|
+
this.markStateDbSeen(s, undefined, { boundary: true });
|
|
1174
1325
|
this.store.save(s);
|
|
1175
1326
|
const preview = removedText.length > 40 ? `${removedText.slice(0, 40)}...` : removedText;
|
|
1176
1327
|
return { ok: true, removed_count: removed, removed_preview: preview };
|
|
@@ -1246,6 +1397,19 @@ export class SessionService {
|
|
|
1246
1397
|
}
|
|
1247
1398
|
return { session_id: branch.session_id, title, parent_session_id: source.session_id };
|
|
1248
1399
|
}
|
|
1400
|
+
/** The run that keeps `delete` answering 409, if any; stream status reports it so a draining client can wait on it (TAL-622). */
|
|
1401
|
+
activeRunBlocking(sid) {
|
|
1402
|
+
const live = this.deps.runtime.activeRunStream(sid);
|
|
1403
|
+
if (live)
|
|
1404
|
+
return live;
|
|
1405
|
+
try {
|
|
1406
|
+
const candidate = str(this.store.get(sid, { metadataOnly: true, promote: false, cacheOnMiss: false }).active_stream_id).trim();
|
|
1407
|
+
if (candidate && this.deps.runtime.activeStreamIds.has(candidate))
|
|
1408
|
+
return candidate;
|
|
1409
|
+
}
|
|
1410
|
+
catch { /* absent */ }
|
|
1411
|
+
return null;
|
|
1412
|
+
}
|
|
1249
1413
|
async delete(sid) {
|
|
1250
1414
|
if (!sid)
|
|
1251
1415
|
throw new HttpFailure(400, 'session_id is required');
|
|
@@ -1278,24 +1442,11 @@ export class SessionService {
|
|
|
1278
1442
|
return true;
|
|
1279
1443
|
}
|
|
1280
1444
|
catch { /* absent */ } const meta = this.lookupCliMeta(sid); return meta !== null && isMessagingSessionRecord(meta); })();
|
|
1281
|
-
|
|
1282
|
-
const live = this.deps.runtime.activeRunStream(sid);
|
|
1283
|
-
if (live)
|
|
1284
|
-
return live;
|
|
1285
|
-
try {
|
|
1286
|
-
const snapshot = this.store.get(sid, { metadataOnly: true });
|
|
1287
|
-
const candidate = str(snapshot.active_stream_id).trim();
|
|
1288
|
-
if (candidate && this.deps.runtime.activeStreamIds.has(candidate))
|
|
1289
|
-
return candidate;
|
|
1290
|
-
}
|
|
1291
|
-
catch { /* absent */ }
|
|
1292
|
-
return null;
|
|
1293
|
-
};
|
|
1294
|
-
if (blocking())
|
|
1445
|
+
if (this.activeRunBlocking(sid))
|
|
1295
1446
|
throw new HttpFailure(409, 'Session has an active run; stop it before deleting');
|
|
1296
1447
|
try {
|
|
1297
1448
|
await this.store.withLock(sid, () => {
|
|
1298
|
-
if (
|
|
1449
|
+
if (this.activeRunBlocking(sid))
|
|
1299
1450
|
throw new HttpFailure(409, 'Session has an active run; stop it before deleting');
|
|
1300
1451
|
// A public share outlives its session file, and revokeShare needs the session, so revoke it first.
|
|
1301
1452
|
try {
|
|
@@ -1329,11 +1480,15 @@ export class SessionService {
|
|
|
1329
1480
|
// messaging channel's memory is never erased from the WebUI; the actual outcome is reported.
|
|
1330
1481
|
let stateDbCleanupFailed = false;
|
|
1331
1482
|
if (!isMessaging) {
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1483
|
+
// TAL-529: the compression continuations go too, tip first; the Agent's delete keeps and detaches them otherwise.
|
|
1484
|
+
for (const id of stateDbCompressionLineage(this.stateDbPath(eventProfile), sid).reverse()) {
|
|
1485
|
+
try {
|
|
1486
|
+
if (!(await this.deps.runtime.deleteCliSession(eventProfile, id)))
|
|
1487
|
+
stateDbCleanupFailed = true;
|
|
1488
|
+
}
|
|
1489
|
+
catch {
|
|
1490
|
+
stateDbCleanupFailed = true;
|
|
1491
|
+
}
|
|
1337
1492
|
}
|
|
1338
1493
|
}
|
|
1339
1494
|
this.publish('session_delete', eventProfile);
|
|
@@ -1603,6 +1758,7 @@ export class SessionService {
|
|
|
1603
1758
|
}
|
|
1604
1759
|
// ── shares ───────────────────────────────────────────────────────────────
|
|
1605
1760
|
createShare(sid) {
|
|
1761
|
+
this.rejectClaudeCode(sid, 'shared');
|
|
1606
1762
|
let s = this.get404(sid);
|
|
1607
1763
|
if (!this.visibleToActiveProfile(s.profile))
|
|
1608
1764
|
throw new HttpFailure(404, 'Session not found');
|
|
@@ -1621,7 +1777,7 @@ export class SessionService {
|
|
|
1621
1777
|
this.publish('session_share_create', s.profile, sid);
|
|
1622
1778
|
return {
|
|
1623
1779
|
ok: true,
|
|
1624
|
-
share: { token: meta.share_token, url:
|
|
1780
|
+
share: { token: meta.share_token, url: sharePath(meta.share_token) ?? '', title: meta.share_title, message_count: meta.share_message_count, created_at: meta.share_created_at, updated_at: meta.share_updated_at },
|
|
1625
1781
|
session: this.publicSession(s),
|
|
1626
1782
|
};
|
|
1627
1783
|
}
|
|
@@ -1688,6 +1844,44 @@ function findLastUserIndex(history) {
|
|
|
1688
1844
|
export function sanitizePaths(error) {
|
|
1689
1845
|
return str(error?.message ?? error).replace(/(?:(?:\/[a-zA-Z0-9_.-]+)+|(?:[A-Z]:\\[^\s]+))/g, '<path>');
|
|
1690
1846
|
}
|
|
1847
|
+
/** TAL-536: a dead run's own state.db rows: from its prompt to the next prompt (tool results and applied steers stay in it). */
|
|
1848
|
+
function runStateDbRows(rows, prompt) {
|
|
1849
|
+
const at = rows.findIndex((m) => looksLikeCurrentUserTurn(m, prompt));
|
|
1850
|
+
if (at < 0)
|
|
1851
|
+
return null;
|
|
1852
|
+
const toolResult = (m) => Array.isArray(m.content) && m.content.some((part) => isDict(part) && part.type === 'tool_result');
|
|
1853
|
+
const end = rows.findIndex((m, i) => i > at && m.role === 'user' && !toolResult(m) && agentSteerText(m) === null);
|
|
1854
|
+
return rows.slice(at, end < 0 ? undefined : end);
|
|
1855
|
+
}
|
|
1856
|
+
/** TAL-493: a row's full-text identity; one with no text (reasoning or media only) by its raw role, content, and reasoning. */
|
|
1857
|
+
function settledIdentity(m) {
|
|
1858
|
+
return messageIdentity(m, Infinity) ?? JSON.stringify([m.role ?? null, m.content ?? null, reasoningFieldsText(m)]);
|
|
1859
|
+
}
|
|
1860
|
+
/** `rows` minus one occurrence of each row of `base`, by `settledIdentity`. */
|
|
1861
|
+
function withoutRows(rows, base) {
|
|
1862
|
+
const left = new Map();
|
|
1863
|
+
for (const m of base)
|
|
1864
|
+
left.set(settledIdentity(m), (left.get(settledIdentity(m)) ?? 0) + 1);
|
|
1865
|
+
return rows.filter((m) => { const key = settledIdentity(m); const n = left.get(key) ?? 0; if (n > 0)
|
|
1866
|
+
left.set(key, n - 1); return n === 0; });
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* TAL-493: what the state.db marker was recorded under: the boundary fields every boundary writer sets (an older release
|
|
1870
|
+
* moves them without the marker) and the role, timestamp, and database file identity of the row the marker names (a
|
|
1871
|
+
* recreated state.db, whose ids start over, has no such row).
|
|
1872
|
+
*/
|
|
1873
|
+
function stateDbMarkKey(s, stateRows, seenId) {
|
|
1874
|
+
const anchor = seenId === null ? undefined : stateRows.find((m) => m._state_db_row_id === seenId);
|
|
1875
|
+
return JSON.stringify([s.truncation_watermark ?? null, s.truncation_boundary ?? null, s.intentional_shrink_generation ?? null, s.clear_generation ?? null, anchor ? [anchor.role ?? null, anchor.timestamp ?? null, anchor._state_db_generation ?? null] : null]);
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* The recorded state.db marker while what it was recorded under still holds and this version wrote the session last (an
|
|
1879
|
+
* older release can apply a boundary that changes no field), else null (the timestamp rules apply).
|
|
1880
|
+
*/
|
|
1881
|
+
function currentStateDbSeenId(s, stateRows) {
|
|
1882
|
+
const seenId = s.state_db_seen_id;
|
|
1883
|
+
return seenId !== null && s.state_db_seen_stamp === s.updated_at && s.state_db_seen_boundary === stateDbMarkKey(s, stateRows, seenId) ? seenId : null;
|
|
1884
|
+
}
|
|
1691
1885
|
function truncationWatermarkFor(messages) {
|
|
1692
1886
|
if (!messages.length)
|
|
1693
1887
|
return 0.0;
|