@maudecode/talaria-web 1.15.0 → 1.16.1
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-router.d.ts +21 -7
- package/dist/api/automation-router.js +3 -0
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +142 -6
- package/dist/api/chat-router.js +11 -5
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.js +44 -32
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.js +5 -58
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +4 -2
- package/dist/api/router.js +8 -8
- package/dist/api/router.js.map +1 -1
- package/dist/api/sessions-router.d.ts +714 -42
- package/dist/api/sessions-router.js +57 -23
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +153 -9
- package/dist/api/settings-router.js +61 -16
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.js +1 -1
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-router.d.ts +13 -1
- package/dist/api/tools-router.js +10 -8
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.d.ts +1047 -67
- package/dist/auth/gate.js +8 -4
- package/dist/auth/gate.js.map +1 -1
- package/dist/auth/oidc.d.ts +6 -2
- package/dist/auth/oidc.js +16 -11
- package/dist/auth/oidc.js.map +1 -1
- package/dist/auth/store.d.ts +14 -2
- package/dist/auth/store.js +26 -1
- package/dist/auth/store.js.map +1 -1
- package/dist/cli/dotenv.d.ts +1 -1
- package/dist/cli/dotenv.js +36 -3
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/http/addresses.d.ts +6 -0
- package/dist/http/addresses.js +26 -0
- package/dist/http/addresses.js.map +1 -1
- package/dist/http/context.d.ts +3 -3
- package/dist/links.d.ts +26 -0
- package/dist/links.js +60 -0
- package/dist/links.js.map +1 -0
- package/dist/onboarding.js +26 -7
- package/dist/onboarding.js.map +1 -1
- package/dist/profiles/profiles.js +1 -1
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/providers/catalog.d.ts +74 -1
- package/dist/providers/catalog.js +248 -42
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/tables.d.ts +3 -1
- package/dist/providers/tables.js +9 -4
- package/dist/providers/tables.js.map +1 -1
- package/dist/redact.js +493 -13
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +52 -28
- package/dist/runtime.js.map +1 -1
- package/dist/sessions/anchor.d.ts +22 -3
- package/dist/sessions/anchor.js +87 -42
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +4 -1
- package/dist/sessions/background-tasks.js +7 -4
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/completions.js +1 -1
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/list.d.ts +8 -4
- package/dist/sessions/list.js +24 -17
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +70 -7
- package/dist/sessions/merge.js +331 -23
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/pending.d.ts +5 -0
- package/dist/sessions/pending.js +30 -10
- package/dist/sessions/pending.js.map +1 -1
- package/dist/sessions/service.d.ts +57 -3
- package/dist/sessions/service.js +327 -56
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +6 -1
- package/dist/sessions/session.js +6 -0
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/shares.js +11 -2
- package/dist/sessions/shares.js.map +1 -1
- package/dist/sessions/store.js +1 -1
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/turn.d.ts +19 -1
- package/dist/sessions/turn.js +218 -113
- package/dist/sessions/turn.js.map +1 -1
- package/dist/settings.js +9 -0
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/fake.js +2 -0
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/tools/commands.d.ts +15 -0
- package/dist/tools/commands.js +52 -0
- package/dist/tools/commands.js.map +1 -0
- package/dist/tools/crons.d.ts +4 -1
- package/dist/tools/crons.js +58 -11
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/mcp.js +5 -1
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/update-notifications.d.ts +1 -1
- package/dist/tools/update-notifications.js +1 -1
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/updates.d.ts +8 -3
- package/dist/tools/updates.js +133 -34
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/git.d.ts +57 -10
- package/dist/workspace/git.js +302 -195
- package/dist/workspace/git.js.map +1 -1
- package/dist/workspace/media-refs.d.ts +13 -0
- package/dist/workspace/media-refs.js +165 -0
- package/dist/workspace/media-refs.js.map +1 -0
- package/dist/workspace/media.d.ts +19 -0
- package/dist/workspace/media.js +61 -2
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/workspaces.d.ts +7 -1
- package/dist/workspace/workspaces.js +30 -21
- package/dist/workspace/workspaces.js.map +1 -1
- package/dist/workspace/worktrees.d.ts +2 -4
- package/dist/workspace/worktrees.js +28 -33
- package/dist/workspace/worktrees.js.map +1 -1
- package/package.json +4 -2
- package/sidecar/scripts/replay_sidecar.py +3 -1
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/home.py +59 -2
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +19 -3
- package/sidecar/talaria_sidecar/methods/chat.py +129 -23
- package/sidecar/talaria_sidecar/methods/commands.py +46 -31
- package/sidecar/talaria_sidecar/methods/config.py +14 -10
- package/sidecar/talaria_sidecar/methods/oauth.py +439 -0
- package/sidecar/talaria_sidecar/methods/profiles.py +5 -4
- package/sidecar/talaria_sidecar/methods/providers.py +161 -1
- package/sidecar/talaria_sidecar/methods/runtime.py +2 -0
- package/sidecar/talaria_sidecar/methods/text.py +1 -20
- package/sidecar/talaria_sidecar/methods/usage.py +7 -1
- package/static/dist/FILES.txt +124 -120
- package/static/dist/assets/AppShell-ef3bhu32.js +1 -0
- package/static/dist/assets/Button-nx37f4u1.js +1 -0
- package/static/dist/assets/ChatPage-cdcpykcg.js +25 -0
- package/static/dist/assets/Dialog-mec42hvb.js +1 -0
- package/static/dist/assets/HubRoute-ecb65zpr.js +2 -0
- package/static/dist/assets/{Markdown-dy8t4dy7.js → Markdown-jqrx5es0.js} +125 -125
- package/static/dist/assets/RightPanel-d1lgvk4s.js +1 -0
- package/static/dist/assets/Select-h4ivl9qf.js +1 -0
- package/static/dist/assets/SessionListPanel-ewib046b.js +1 -0
- package/static/dist/assets/SettingsLayout-lx654cup.js +1 -0
- package/static/dist/assets/States-ehsb6lzo.js +1 -0
- package/static/dist/assets/Toaster-mch1pa3t.js +1 -0
- package/static/dist/assets/_app-m8d961ef.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +1 -0
- package/static/dist/assets/_app.index-dk6zp7e0.js +1 -0
- package/static/dist/assets/_app.insights-jt2fk4i1.js +1 -0
- package/static/dist/assets/_app.kanban-if4pubeu.js +1 -0
- package/static/dist/assets/_app.logs-mfaw9m6g.js +1 -0
- package/static/dist/assets/_app.memory-h3eaarb6.js +1 -0
- package/static/dist/assets/_app.profiles-ienktovs.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-gyoh5ylx.js → _app.session._sessionId-hh27wwu2.js} +1 -1
- package/static/dist/assets/_app.settings-dpoe0bzf.js +1 -0
- package/static/dist/assets/_app.settings._section-l468ynag.js +3 -0
- package/static/dist/assets/_app.skills-kcbncc8i.js +1 -0
- package/static/dist/assets/_app.tasks-occdrqhw.js +2 -0
- package/static/dist/assets/_app.todos-nnke2rcc.js +1 -0
- package/static/dist/assets/_app.workspaces-cdlatvwj.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-cjqletra.js → abnfDiagram-VCTEODGH-oity9y4o.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +1 -0
- package/static/dist/assets/architectureDiagram-5GKGNRK7-ceaepnyr.js +36 -0
- package/static/dist/assets/{back-e4m6nsnm.js → back-eu64w89w.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-b195z021.js → blockDiagram-I7D4REHJ-n79st4pj.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-olu212k1.js → c4Diagram-7LVT6UL2-mi73akzk.js} +1 -1
- package/static/dist/assets/cancel-mzvkdjg8.js +1 -0
- package/static/dist/assets/channel-mbvmf2vv.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-b8o1nufs.js → chunk-4HAMMTFA-laat0g1q.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-l1seddto.js → chunk-75Z2AOVW-0psy1tr2.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-lo5zg15v.js → chunk-DU6HZSFF-lw8uox8x.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-dsdzrp16.js → chunk-F27PBJKO-erassib3.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-f3fxqq8b.js → chunk-GMAD6QVW-fz7rx619.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-h8egxtf6.js → chunk-GVQU2GXP-gdb0epb2.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-iolwd8s0.js → chunk-IMKFNOWR-ea8t26qw.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-b88bbtwi.js → chunk-L3NEJ4N5-mb1gu9kz.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-e3e7nr6s.js → chunk-OSK3NFVY-eovmccvy.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-mdc46rt1.js → chunk-P2QGCYS3-bo55zjo5.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-kqlllrrm.js → chunk-POPQ4Y6H-ja7ohe4h.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-he585k2x.js → chunk-PWAF6VOD-e30g9nus.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-gh94y9a4.js → chunk-SHT3W25Y-gbb798f7.js} +3 -3
- package/static/dist/assets/{chunk-SVP7TREG-euxp9y7e.js → chunk-SVP7TREG-h2iw8urm.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-c8cxes1q.js → chunk-TICWLB2K-fd2cottz.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +1 -0
- package/static/dist/assets/{copied-kq0u3ht7.js → copied-h65fc3cx.js} +1 -1
- package/static/dist/assets/copy-e6977uwq.js +1 -0
- package/static/dist/assets/{cynefin-OW5HDTMX-lxd44ux4.js → cynefin-OW5HDTMX-lbltyl5j.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-njpiwat8.js → cynefinDiagram-5FMLGOSQ-lxhsqq4a.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-nvgy6yju.js → dagre-GXQ25YYZ-gn4nnaln.js} +4 -4
- package/static/dist/assets/{diagram-S7CK7UJ4-g98nyv72.js → diagram-S7CK7UJ4-pa3ij6q7.js} +3 -3
- package/static/dist/assets/{diagram-UQ7AKVKN-ovgm6lvv.js → diagram-UQ7AKVKN-zbipyz57.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-pb2bn2e4.js → diagram-VSXAHHWV-d1kbpzgf.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-6j4mvfqo.js → diagram-VX7I27RA-i3ty14xl.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-dqmb982r.js → diagram-Z3DM3KII-m8xefqa7.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-ozbpzb6d.js → ebnfDiagram-PWID7BFC-nz7wj05l.js} +1 -1
- package/static/dist/assets/endpoints-k7yf25m0.js +64 -0
- package/static/dist/assets/{erDiagram-RLTQ6QDP-hl7m8vua.js → erDiagram-RLTQ6QDP-fa41ib83.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ompixqmh.js → ganttDiagram-EL5Y4UJY-n7zq01qu.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-b6vxwp9q.js → gitGraph-4MIJSDKK-c89emb07.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-k98f57on.js → gitGraphDiagram-WWUBYQGX-cz7cgr6w.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-cd3ff6ge.js → highlighted-body-KPVGNVTW-d9bapmni.js} +1 -1
- package/static/dist/assets/{index-nqed3oum.js → index-h00usru2.js} +3 -3
- package/static/dist/assets/index-n73ijkv2.css +2 -0
- package/static/dist/assets/{info-A6RAGUB7-hjcwjami.js → info-A6RAGUB7-ndddhhhh.js} +1 -1
- package/static/dist/assets/infoDiagram-27XIBGKW-ccxigcpf.js +2 -0
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-bxak4mwu.js → ishikawaDiagram-5VMMS53U-le0z9vtc.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-khmihclr.js → journeyDiagram-3NMN7TZE-ivsmb26o.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-h1r32wdx.js → kanban-definition-UXKFOSKX-h6n2awt0.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +1 -0
- package/static/dist/assets/{line-friyjof3.js → line-dmzlfe0u.js} +1 -1
- package/static/dist/assets/link-budeg5t9.js +1 -0
- package/static/dist/assets/login-kjhasvp8.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-f1gvpwrt.js → mermaid-parser.core-gwyd5bnq.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-mt2oxwue.js → mindmap-definition-YA3MSWOX-l68gg5h7.js} +1 -1
- package/static/dist/assets/onboarding-cdfrk0pj.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-jik4ixlf.js → packet-AYTQ26CC-gpv06065.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-erxlv6cc.js → pegDiagram-XKGWAZYB-e52vs23u.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-mnkoldfl.js → pie-WAS4IAKB-l6m7nz5s.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-i7lwrada.js → pieDiagram-E7YTZNPT-b4is36bq.js} +3 -3
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-fr8ejdoy.js → quadrantDiagram-AXDQQJYC-m8vt2788.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-otarjte2.js → radar-RG4KPBEZ-nxbrhiov.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-lw362oto.js → railroad-74A4TZTK-222mu9hi.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-esyn75pw.js → railroadDiagram-O6MQD6OU-o8lldfzv.js} +1 -1
- package/static/dist/assets/{refresh-cw-k66keho6.js → refresh-cw-kbcje1uy.js} +1 -1
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-cyhi5u29.js → requirementDiagram-BXWQKSXE-ovyq38kv.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-jljpbo0h.js → sankeyDiagram-P5KCCOFB-ou7lznor.js} +1 -1
- package/static/dist/assets/{saved-do49si3v.js → saved-bazmcup9.js} +1 -1
- package/static/dist/assets/search-jen74z4u.js +1 -0
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-fz0dhlu7.js → sequenceDiagram-WJ2MYXX4-ovckdzf2.js} +1 -1
- package/static/dist/assets/{settings_section_extensions_title-b7lojn0o.js → settings_section_extensions_title-ertwwhlx.js} +1 -1
- package/static/dist/assets/share._token-dan9hgvj.js +2 -0
- package/static/dist/assets/{sliders-horizontal-c4wya4dy.js → sliders-horizontal-f9cb3lh3.js} +1 -1
- package/static/dist/assets/{stateDiagram-D77RDMKH-kdnithdx.js → stateDiagram-D77RDMKH-fcrexkkv.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-esd6gmz3.js → swimlanes-42K2YHIH-f7usu8fw.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-g0qygccv.js → timeline-definition-24CTP7MA-gp1hvz9f.js} +1 -1
- package/static/dist/assets/todoStore-eqtid4r4.js +1 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-ndchzkuu.js → treeView-Q6P3EWNA-gb9gf11u.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-hwjxj0zz.js → treemap-WGGIJYW6-nuvfnvvi.js} +1 -1
- package/static/dist/assets/{untitled-mbr6tuhu.js → untitled-htelhc68.js} +1 -1
- package/static/dist/assets/useForm-h2t0u14e.js +1 -0
- package/static/dist/assets/useLocale-hcsb84pj.js +1 -0
- package/static/dist/assets/useNavigate-nwy70ztj.js +1 -0
- package/static/dist/assets/{useParams-lo9u33d1.js → useParams-dqd64jv7.js} +1 -1
- package/static/dist/assets/{useSearch-lq1mr090.js → useSearch-j30pvsy7.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-gubovd1r.js → vennDiagram-4TSXK5OY-fzchbzaj.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-ir3om65j.js → wardley-WFR3VGLG-m47mhfbh.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ce0or1ie.js → wardleyDiagram-VM6X3IG4-odg6ct1z.js} +2 -2
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-dexylcjg.js → xychartDiagram-S5SC5T6Z-mrhms5um.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +1 -1
- package/static/dist/assets/AppShell-orat1s43.js +0 -1
- package/static/dist/assets/ChatPage-ojhka3hy.js +0 -22
- package/static/dist/assets/HubRoute-gxgw1t33.js +0 -2
- package/static/dist/assets/RightPanel-c66ani1s.js +0 -1
- package/static/dist/assets/Select-fswf66up.js +0 -1
- package/static/dist/assets/SessionListPanel-goh5mtt8.js +0 -1
- package/static/dist/assets/SettingsLayout-n5d4wq4m.js +0 -1
- package/static/dist/assets/States-kxyu50at.js +0 -1
- package/static/dist/assets/Toaster-6zmbcqgg.js +0 -1
- package/static/dist/assets/_app-fowyruiu.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-nvjyrwhy.js +0 -1
- package/static/dist/assets/_app.index-c9zv4y7w.js +0 -1
- package/static/dist/assets/_app.insights-jf12nofo.js +0 -1
- package/static/dist/assets/_app.kanban-lri5a4yu.js +0 -1
- package/static/dist/assets/_app.logs-md1p0zqo.js +0 -1
- package/static/dist/assets/_app.memory-bzvf2e28.js +0 -1
- package/static/dist/assets/_app.profiles-jpg7zmbn.js +0 -1
- package/static/dist/assets/_app.settings-mpuwlx4j.js +0 -1
- package/static/dist/assets/_app.settings._section-knz8rwoj.js +0 -1
- package/static/dist/assets/_app.skills-fwu1dkir.js +0 -1
- package/static/dist/assets/_app.tasks-h9gphtl3.js +0 -2
- package/static/dist/assets/_app.todos-hd1dnvrh.js +0 -1
- package/static/dist/assets/_app.workspaces-l8toyn5f.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-cavnusaw.js +0 -1
- package/static/dist/assets/architectureDiagram-5GKGNRK7-k5a7v36n.js +0 -36
- package/static/dist/assets/channel-gozy3dp3.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-n0vs2f2q.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-n0vs2f2q.js +0 -1
- package/static/dist/assets/endpoints-k8agnro8.js +0 -9
- package/static/dist/assets/eventmodeling-NTZA5JFV-j1y2ekec.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-g2cvcbm5.js +0 -1
- package/static/dist/assets/index-nfy0ezs6.css +0 -2
- package/static/dist/assets/infoDiagram-27XIBGKW-fm06rj36.js +0 -2
- package/static/dist/assets/lazyRouteComponent-b2eg0fws.js +0 -1
- package/static/dist/assets/link-m90ahx3n.js +0 -1
- package/static/dist/assets/login-bw7m2fzo.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-njwcl62n.js +0 -1
- package/static/dist/assets/onboarding-ret37j1e.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-m741owar.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-noa4fbia.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-o4bpw4nb.js +0 -1
- package/static/dist/assets/search-j5ki6a9o.js +0 -1
- package/static/dist/assets/share._token-kg8w647b.js +0 -2
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-k2wg2645.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-n5kvjtgr.js +0 -8
- package/static/dist/assets/tabBuild-bjmyvmn5.js +0 -56
- package/static/dist/assets/todoStore-kjk5l0sy.js +0 -1
- package/static/dist/assets/useForm-ocxu460f.js +0 -1
- package/static/dist/assets/useLocale-fzy5jhg6.js +0 -1
package/dist/sessions/service.js
CHANGED
|
@@ -4,19 +4,22 @@ 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
6
|
import { allSessions, buildSessionListPayload, CLI_IDENTITY_FIELDS, isClaimableCliSource, isMessagingSessionRecord, withOwnerLocks, withSessionWireFlags, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMessageText, sessionSearchPreview } from './list.js';
|
|
7
|
-
import { anchorSceneIntOrNull, hydrateAnchorActivityScenes, normalizeAnchorSceneMessageRef, readAnchorSceneRows, storeAnchorScene, withTurnIds } from './anchor.js';
|
|
8
|
-
import { isSafeSessionId, lastMessageTimestamp, Session, titleFrom } from './session.js';
|
|
7
|
+
import { anchorSceneIntOrNull, fullToolResult, hydrateAnchorActivityScenes, normalizeAnchorSceneMessageRef, readAnchorSceneRows, storeAnchorScene, withTurnIds } from './anchor.js';
|
|
8
|
+
import { isSafeSessionId, lastMessageTimestamp, Session, stripAttachedFilesMarker, titleFrom } from './session.js';
|
|
9
9
|
import { SessionBusy, SessionNotFound, statSignature } from './store.js';
|
|
10
10
|
import { attachTodoState } from './todo.js';
|
|
11
11
|
import { stateDbSessionMessages, stateDbSessionRow, stateDbSessionSources } from './state-db.js';
|
|
12
12
|
import { anchorMessageKey, anchorSummary, CompressionJobs, visibleMessagesForAnchor } from './compress.js';
|
|
13
13
|
import { SidecarError } from '../sidecar/client.js';
|
|
14
|
-
import { attachmentObjects, isContextCompressionMarker, mergeSessionMessagesAppendOnly, pendingUserRow, sanitizeMessagesForApi, withAttachmentObjects, withBodyExcerpts, withPendingUserTurn, withToolCallOutcomes, withoutRunningTurnOutput } from './merge.js';
|
|
14
|
+
import { attachmentObjects, isContextCompressionMarker, mergeSessionMessagesAppendOnly, pendingUserRow, sanitizeMessagesForApi, stripWorkspacePrefix, withAttachmentObjects, withBodyExcerpts, withDisplayMedia, withMarkerKinds, withSceneRowMedia, withPendingUserTurn, withToolCallOutcomes, withoutRunningTurnOutput } from './merge.js';
|
|
15
15
|
import { withBackgroundUpdates } from './background-updates.js';
|
|
16
16
|
import { withBackgroundLinks } from './background-tasks.js';
|
|
17
17
|
import { messagesForLimitedPayload, messageWindowForDisplay, MAX_MSG_LIMIT, parseMsgLimit, toolCallsForMessageWindow } from './window.js';
|
|
18
18
|
import { redactText } from '../redact.js';
|
|
19
|
+
import { workspaceDisplayName } from '../workspace/workspaces.js';
|
|
19
20
|
import { buildShareSnapshot } from './shares.js';
|
|
21
|
+
import { mediaAnchorRoot, mediaRefPath, mediaTarget } from '../workspace/media.js';
|
|
22
|
+
import { projectMediaRefs } from '../workspace/media-refs.js';
|
|
20
23
|
import { loadGatewaySessionIdentityMap } from './list.js';
|
|
21
24
|
import { join } from 'node:path';
|
|
22
25
|
export class HttpFailure extends Error {
|
|
@@ -57,6 +60,37 @@ export class SessionService {
|
|
|
57
60
|
this.compressionJobs = new CompressionJobs();
|
|
58
61
|
}
|
|
59
62
|
get store() { return this.deps.store; }
|
|
63
|
+
/**
|
|
64
|
+
* TAL-186: rewrites a session's media references to their URLs. A local path is rewritten only when `/api/media`
|
|
65
|
+
* serves it for this session, under the same resolution, so every rewritten reference loads.
|
|
66
|
+
*/
|
|
67
|
+
mediaProjector(s) {
|
|
68
|
+
const media = this.deps.media;
|
|
69
|
+
const served = new Map();
|
|
70
|
+
const localUrl = (path) => {
|
|
71
|
+
if (!media?.localIo(s.profile))
|
|
72
|
+
return null;
|
|
73
|
+
if (served.has(path))
|
|
74
|
+
return served.get(path) ?? null;
|
|
75
|
+
let url = null;
|
|
76
|
+
try {
|
|
77
|
+
const target = mediaTarget(mediaRefPath(path));
|
|
78
|
+
if (mediaAnchorRoot(target, s, media.access))
|
|
79
|
+
url = `./api/media?${new URLSearchParams({ path: target, session_id: s.session_id }).toString()}`;
|
|
80
|
+
}
|
|
81
|
+
catch { /* an invalid path stays text */ }
|
|
82
|
+
served.set(path, url);
|
|
83
|
+
return url;
|
|
84
|
+
};
|
|
85
|
+
const workspace = s.workspace.trim() || null;
|
|
86
|
+
// A scene's final answer usually repeats its row's text: each distinct text is parsed once.
|
|
87
|
+
const projected = new Map();
|
|
88
|
+
return (text) => {
|
|
89
|
+
if (!projected.has(text))
|
|
90
|
+
projected.set(text, projectMediaRefs(text, { workspace, localUrl }));
|
|
91
|
+
return projected.get(text) ?? null;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
60
94
|
publish(reason, profile, sessionId) {
|
|
61
95
|
this.deps.events.publish(reason, { profile: profile ?? null, sessionId: sessionId ?? null });
|
|
62
96
|
}
|
|
@@ -163,7 +197,7 @@ export class SessionService {
|
|
|
163
197
|
mergedTranscript(s, local = s.messages, stateRows = this.stateDbRows(s)) {
|
|
164
198
|
if (!stateRows.length)
|
|
165
199
|
return local;
|
|
166
|
-
return mergeSessionMessagesAppendOnly(local, stateRows, { truncationWatermark: s.truncation_watermark });
|
|
200
|
+
return mergeSessionMessagesAppendOnly(local, stateRows, { truncationWatermark: s.truncation_watermark, compressedWatermark: s.truncation_watermark_compressed });
|
|
167
201
|
}
|
|
168
202
|
/**
|
|
169
203
|
* Python `reconciled_state_db_messages_for_session(prefer_context=True)`: the model history is the owner context
|
|
@@ -174,6 +208,15 @@ export class SessionService {
|
|
|
174
208
|
const local = s.context_messages.length ? s.context_messages : s.messages.filter((m) => !m._error && !m._partial);
|
|
175
209
|
return local.some((m) => isContextCompressionMarker(m)) ? local : this.mergedTranscript(s, local, stateRows ?? this.stateDbRows(s));
|
|
176
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* TAL-518: the model context a `/btw` clone inherits: the chat's history plus its running turn's prompt, which
|
|
213
|
+
* deferred save keeps out of `messages` and `context_messages` until settlement.
|
|
214
|
+
*/
|
|
215
|
+
sideQuestionContext(s) {
|
|
216
|
+
const context = structuredClone(this.modelContext(s));
|
|
217
|
+
const pending = this.pendingTurn(s);
|
|
218
|
+
return pending ? withPendingUserTurn(context, pending) : context;
|
|
219
|
+
}
|
|
177
220
|
/** Python `_lookup_cli_session_metadata`: the sidebar row for a state.db session in the active profile. */
|
|
178
221
|
lookupCliMeta(sid) {
|
|
179
222
|
try {
|
|
@@ -279,12 +322,33 @@ export class SessionService {
|
|
|
279
322
|
const payload = this.wireRow(s);
|
|
280
323
|
// Mutation replies replace a client's transcript, so they carry the same server-built scenes as the detail.
|
|
281
324
|
if (withMessages)
|
|
282
|
-
payload.messages = this.backgroundLinked(s, hydrateAnchorActivityScenes(withToolCallOutcomes(withBackgroundUpdates(withTurnIds(s.messages), s), s.tool_calls, s.active_stream_id), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id }));
|
|
325
|
+
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) }));
|
|
283
326
|
return redactSessionData(payload, this.deps.redactEnabled());
|
|
284
327
|
}
|
|
285
328
|
/** `compact()` with the wire streaming/read-only flags (TAL-312), for replies that return the session row. */
|
|
286
329
|
wireRow(s) {
|
|
287
|
-
return withSessionWireFlags({ ...s.compact({ contextLengthFor: this.deps.contextLengthFor }), read_only: this.isReadOnly(s), assistant_name: this.assistantName(s) }, this.deps.runtime.activeStreamIds);
|
|
330
|
+
return withSessionWireFlags({ ...s.compact({ contextLengthFor: this.deps.contextLengthFor, modelOptionFor: this.deps.modelOptionFor }), read_only: this.isReadOnly(s), assistant_name: this.assistantName(s), workspace_name: this.workspaceNames()(s) }, this.deps.runtime.activeStreamIds);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* TAL-303: the label for a session's workspace, from its own profile's registry (a profileless row is the root's).
|
|
334
|
+
* One resolver serves one response, so each profile's registry is read once however many rows it names.
|
|
335
|
+
*/
|
|
336
|
+
workspaceNames() {
|
|
337
|
+
const registries = new Map();
|
|
338
|
+
return (row) => {
|
|
339
|
+
const profile = str(row.profile) || 'default';
|
|
340
|
+
let entries = registries.get(profile);
|
|
341
|
+
if (!entries) {
|
|
342
|
+
try {
|
|
343
|
+
entries = this.deps.workspaces.entries(profile);
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
entries = [];
|
|
347
|
+
}
|
|
348
|
+
registries.set(profile, entries);
|
|
349
|
+
}
|
|
350
|
+
return workspaceDisplayName(str(row.workspace), entries);
|
|
351
|
+
};
|
|
288
352
|
}
|
|
289
353
|
/** The agent's display name for a session's profile (`assistant_name`). */
|
|
290
354
|
assistantName(s) {
|
|
@@ -328,7 +392,7 @@ export class SessionService {
|
|
|
328
392
|
if (journaled)
|
|
329
393
|
transcript = withoutRunningTurnOutput(transcript, { ...journaled, localCount: s.messages.length });
|
|
330
394
|
// Turn ids, tool outcomes and scenes are computed over the full transcript, so every window reports the same values.
|
|
331
|
-
const all = loadMessages ?
|
|
395
|
+
const all = loadMessages ? this.backgroundLinked(s, hydrateAnchorActivityScenes(withToolCallOutcomes(withBackgroundUpdates(withMarkerKinds(withTurnIds(withAttachmentObjects(transcript))), s), s.tool_calls, s.active_stream_id), s.anchor_activity_scenes, { activeTurnId: s.active_stream_id, runningScene: !journaled, clipToolResults: msgLimit !== null })) : [];
|
|
332
396
|
let truncated = [];
|
|
333
397
|
let offset = 0;
|
|
334
398
|
let summaryCount = null;
|
|
@@ -344,6 +408,8 @@ export class SessionService {
|
|
|
344
408
|
truncated = all.slice(prompt, offset + truncated.length);
|
|
345
409
|
offset = prompt;
|
|
346
410
|
}
|
|
411
|
+
// Per-row display fields (TAL-186 media, TAL-456 excerpts cut from that display text) only for the rows sent.
|
|
412
|
+
truncated = withBodyExcerpts(withDisplayMedia(truncated, this.mediaProjector(s)), s.active_stream_id);
|
|
347
413
|
if (msgLimit !== null)
|
|
348
414
|
truncated = messagesForLimitedPayload(truncated);
|
|
349
415
|
}
|
|
@@ -362,7 +428,7 @@ export class SessionService {
|
|
|
362
428
|
}
|
|
363
429
|
const activeStreamIds = this.deps.runtime.activeStreamIds;
|
|
364
430
|
const raw = {
|
|
365
|
-
...s.compact({ includeRuntime: true, activeStreamIds, contextLengthFor: this.deps.contextLengthFor }),
|
|
431
|
+
...s.compact({ includeRuntime: true, activeStreamIds, contextLengthFor: this.deps.contextLengthFor, modelOptionFor: this.deps.modelOptionFor }),
|
|
366
432
|
messages: truncated,
|
|
367
433
|
message_count: mergedCount,
|
|
368
434
|
tool_calls: toolCalls,
|
|
@@ -390,6 +456,7 @@ export class SessionService {
|
|
|
390
456
|
raw._load_revision = revisionBefore !== null && revisionBefore === revisionAfter ? hashRevision(revisionBefore) : `unstable-${randomUUID().replace(/-/g, '')}`;
|
|
391
457
|
raw.read_only = this.isReadOnly(s);
|
|
392
458
|
raw.assistant_name = this.assistantName(s);
|
|
459
|
+
raw.workspace_name = this.workspaceNames()(s);
|
|
393
460
|
withSessionWireFlags(raw, activeStreamIds);
|
|
394
461
|
raw.pending_steers = raw.active_stream_id ? (this.deps.runtime.pendingSteers?.(str(raw.active_stream_id)) ?? []) : [];
|
|
395
462
|
return redactSessionData(raw, this.deps.redactEnabled());
|
|
@@ -437,7 +504,7 @@ export class SessionService {
|
|
|
437
504
|
foreignSessionDetail(sid) {
|
|
438
505
|
const { synth, meta } = this.foreignSession(sid);
|
|
439
506
|
// The same turn projection as a WebUI session: turn ids, tool outcomes, then each completed turn's scene.
|
|
440
|
-
const msgs = hydrateAnchorActivityScenes(withToolCallOutcomes(withTurnIds(synth.messages), [], null), {});
|
|
507
|
+
const msgs = hydrateAnchorActivityScenes(withToolCallOutcomes(withMarkerKinds(withTurnIds(synth.messages)), [], null), {});
|
|
441
508
|
const lastTs = Number(msgs[msgs.length - 1]?.timestamp ?? 0) || 0;
|
|
442
509
|
const sess = {
|
|
443
510
|
session_id: synth.session_id, title: synth.title, workspace: synth.workspace, model: synth.model, message_count: msgs.length,
|
|
@@ -445,7 +512,7 @@ export class SessionService {
|
|
|
445
512
|
pinned: synth.pinned, archived: synth.archived, project_id: synth.project_id ?? null, profile: synth.profile,
|
|
446
513
|
is_cli_session: synth.is_cli_session, source_tag: synth.source_tag, raw_source: synth.raw_source, session_source: synth.session_source,
|
|
447
514
|
source_label: synth.source_label, read_only: synth.read_only, can_duplicate: false, messages: msgs, tool_calls: [], transcript_seq: null,
|
|
448
|
-
assistant_name: this.assistantName(synth),
|
|
515
|
+
assistant_name: this.assistantName(synth), workspace_name: this.workspaceNames()(synth),
|
|
449
516
|
};
|
|
450
517
|
attachTodoState(sess, msgs);
|
|
451
518
|
const merged = withSessionWireFlags(meta ? mergeCliSidebarMetadata(sess, meta) : sess, this.deps.runtime.activeStreamIds);
|
|
@@ -519,7 +586,7 @@ export class SessionService {
|
|
|
519
586
|
const gatewayIdentity = loadGatewaySessionIdentityMap(join(this.deps.profileHome(activeProfile), 'sessions', 'sessions.json'));
|
|
520
587
|
const truncatedSources = cliRead?.truncated;
|
|
521
588
|
const payload = buildSessionListPayload(this.store, { ...params, ...(cliRows ? { cliRows } : {}), ...(truncatedSources ? { truncatedSources } : {}), gatewayIdentity, stateDbSources: this.stateDbSources, activeProfile, isolatedProfileMode: this.deps.isolatedProfileMode(), profilesMatch: this.deps.profilesMatch });
|
|
522
|
-
return sessionListResponse(payload, this.deps.runtime, this.deps.redactEnabled(), this.deps.now());
|
|
589
|
+
return sessionListResponse(payload, this.deps.runtime, this.deps.redactEnabled(), this.deps.now(), this.workspaceNames());
|
|
523
590
|
}
|
|
524
591
|
search(q, opts) {
|
|
525
592
|
const activeProfile = this.deps.activeProfile();
|
|
@@ -528,8 +595,10 @@ export class SessionService {
|
|
|
528
595
|
sessions = sessions.filter((r) => this.deps.profilesMatch(str(r.profile) || null, activeProfile));
|
|
529
596
|
sessions = withOwnerLocks(sessions, this.stateDbSources);
|
|
530
597
|
const redact = this.deps.redactEnabled();
|
|
598
|
+
const workspaceName = this.workspaceNames();
|
|
531
599
|
const redactRow = (item) => {
|
|
532
600
|
withSessionWireFlags(item, this.deps.runtime.activeStreamIds);
|
|
601
|
+
item.workspace_name = workspaceName(item);
|
|
533
602
|
if (typeof item.title === 'string')
|
|
534
603
|
item.title = redactText(item.title, redact);
|
|
535
604
|
for (const f of ['display_title', '_state_db_title', 'parent_title'])
|
|
@@ -548,27 +617,61 @@ export class SessionService {
|
|
|
548
617
|
}
|
|
549
618
|
if (!opts.content)
|
|
550
619
|
continue;
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
620
|
+
const hit = this.contentMatch(str(s.session_id), query, opts.depth);
|
|
621
|
+
if (hit)
|
|
622
|
+
results.push(redactRow({ ...s, ...hit }));
|
|
623
|
+
}
|
|
624
|
+
return { sessions: results, query, count: results.length, all_profiles: opts.allProfiles, active_profile: activeProfile };
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* TAL-308: the sidebar search. The candidates are exactly the `/api/sessions` rows for `params` (visibility, source,
|
|
628
|
+
* archived, projection and order), narrowed to `projectId` (`none`: rows without a project), then matched on the
|
|
629
|
+
* title, then the metadata the row shows (workspace path and name, model, provider, profile, source label), then message content.
|
|
630
|
+
*/
|
|
631
|
+
sidebarSearch(q, params, opts) {
|
|
632
|
+
let rows = this.list(params).body.sessions;
|
|
633
|
+
if (opts.projectId === 'none')
|
|
634
|
+
rows = rows.filter((r) => !r.project_id);
|
|
635
|
+
else if (opts.projectId)
|
|
636
|
+
rows = rows.filter((r) => str(r.project_id) === opts.projectId);
|
|
637
|
+
const query = q.toLowerCase().trim();
|
|
638
|
+
const base = { all_profiles: params.allProfiles, active_profile: this.deps.activeProfile(), include_archived: params.includeArchived, sidebar_filtered: true };
|
|
639
|
+
if (!query)
|
|
640
|
+
return { ...base, sessions: rows };
|
|
641
|
+
const results = [];
|
|
642
|
+
for (const row of rows) {
|
|
643
|
+
if (str(row.title).toLowerCase().includes(query))
|
|
644
|
+
results.push({ ...row, match_type: 'title' });
|
|
645
|
+
else if (['workspace', 'workspace_name', 'model', 'model_provider', 'profile', 'source_label'].some((k) => str(row[k]).toLowerCase().includes(query)))
|
|
646
|
+
results.push({ ...row, match_type: 'metadata' });
|
|
647
|
+
else if (opts.content) {
|
|
648
|
+
const hit = this.contentMatch(str(row.session_id), query, opts.depth);
|
|
649
|
+
if (hit)
|
|
650
|
+
results.push({ ...row, ...hit });
|
|
554
651
|
}
|
|
555
|
-
|
|
652
|
+
}
|
|
653
|
+
return { ...base, sessions: results, query, count: results.length };
|
|
654
|
+
}
|
|
655
|
+
/** The first of a stored session's first `depth` messages (0: all) containing `query`, with its redacted excerpt. */
|
|
656
|
+
contentMatch(sid, query, depth) {
|
|
657
|
+
let sess;
|
|
658
|
+
try {
|
|
659
|
+
sess = this.store.get(sid, { promote: false, cacheOnMiss: false });
|
|
660
|
+
}
|
|
661
|
+
catch {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
for (const m of depth ? sess.messages.slice(0, depth) : sess.messages) {
|
|
665
|
+
const c = sessionSearchMessageText(m);
|
|
666
|
+
if (!c.toLowerCase().includes(query))
|
|
556
667
|
continue;
|
|
557
|
-
}
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const item = { ...s, match_type: 'content' };
|
|
563
|
-
const preview = sessionSearchPreview(c, query);
|
|
564
|
-
if (preview)
|
|
565
|
-
item.match_preview = redactText(preview, redact);
|
|
566
|
-
results.push(redactRow(item));
|
|
567
|
-
break;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
668
|
+
const item = { match_type: 'content' };
|
|
669
|
+
const preview = sessionSearchPreview(c, query);
|
|
670
|
+
if (preview)
|
|
671
|
+
item.match_preview = redactText(preview, this.deps.redactEnabled());
|
|
672
|
+
return item;
|
|
570
673
|
}
|
|
571
|
-
return
|
|
674
|
+
return null;
|
|
572
675
|
}
|
|
573
676
|
// ── status / usage ───────────────────────────────────────────────────────
|
|
574
677
|
status(sid) {
|
|
@@ -628,7 +731,8 @@ export class SessionService {
|
|
|
628
731
|
return toolsets;
|
|
629
732
|
}
|
|
630
733
|
create(body, opts = {}) {
|
|
631
|
-
|
|
734
|
+
// Python `new_session`: a body without a profile takes the request's active profile (cookie first).
|
|
735
|
+
const profile = (typeof body.profile === 'string' && body.profile) || this.deps.activeProfile();
|
|
632
736
|
let prevSessionId = typeof body.prev_session_id === 'string' && body.prev_session_id ? body.prev_session_id : null;
|
|
633
737
|
if (prevSessionId && !this.sessionIdVisible(prevSessionId))
|
|
634
738
|
prevSessionId = null;
|
|
@@ -960,6 +1064,7 @@ export class SessionService {
|
|
|
960
1064
|
// #4836: an intentional-shrink boundary, so append-only state.db reconciliation does not replay compressed rows.
|
|
961
1065
|
live.truncation_watermark = truncationWatermarkFor(compressed);
|
|
962
1066
|
live.truncation_boundary = live.truncation_watermark;
|
|
1067
|
+
live.truncation_watermark_compressed = true;
|
|
963
1068
|
live.last_prompt_tokens = result.after_tokens;
|
|
964
1069
|
live.post_compression_context_tokens_estimate = result.after_tokens;
|
|
965
1070
|
this.store.save(live);
|
|
@@ -1029,7 +1134,7 @@ export class SessionService {
|
|
|
1029
1134
|
catch { /* ignore */ }
|
|
1030
1135
|
}
|
|
1031
1136
|
});
|
|
1032
|
-
this.deps.runtime.evictAgent(sid);
|
|
1137
|
+
this.deps.runtime.evictAgent(sid, true);
|
|
1033
1138
|
return { ok: true, session: this.wireRow(s) };
|
|
1034
1139
|
}
|
|
1035
1140
|
async retry(sid) {
|
|
@@ -1040,11 +1145,19 @@ export class SessionService {
|
|
|
1040
1145
|
const lastUser = findLastUserIndex(history);
|
|
1041
1146
|
if (lastUser === null)
|
|
1042
1147
|
return { error: 'No previous message to retry.' };
|
|
1043
|
-
|
|
1148
|
+
// What a client resends (TAL-515): the files that reached the model, which only ever got attachments with a path,
|
|
1149
|
+
// and the prompt as typed. The attached-files line is the server's only when such files exist; otherwise the user
|
|
1150
|
+
// typed it. Nothing to resend fails before the exchange is removed.
|
|
1151
|
+
const prompt = history[lastUser];
|
|
1152
|
+
const lastUserText = extractText(prompt.content);
|
|
1153
|
+
const lastUserAttachments = attachmentObjects(Array.isArray(prompt.attachments) ? prompt.attachments : []).filter((a) => isDict(a) && Boolean(str(a.path).trim()));
|
|
1154
|
+
const lastUserPrompt = stripWorkspacePrefix(lastUserAttachments.length ? stripAttachedFilesMarker(lastUserText) : lastUserText, true);
|
|
1155
|
+
if (!lastUserPrompt && !lastUserAttachments.length)
|
|
1156
|
+
return { error: 'The last message has nothing to resend.' };
|
|
1044
1157
|
const removed = history.length - lastUser;
|
|
1045
1158
|
shrinkTo(s, lastUser);
|
|
1046
1159
|
this.store.save(s);
|
|
1047
|
-
return { ok: true, last_user_text: lastUserText, removed_count: removed };
|
|
1160
|
+
return { ok: true, last_user_text: lastUserText, last_user_prompt: lastUserPrompt, last_user_attachments: lastUserAttachments, removed_count: removed };
|
|
1048
1161
|
});
|
|
1049
1162
|
}
|
|
1050
1163
|
async undo(sid) {
|
|
@@ -1069,12 +1182,14 @@ export class SessionService {
|
|
|
1069
1182
|
if (!session)
|
|
1070
1183
|
throw new HttpFailure(404, 'Session not found');
|
|
1071
1184
|
const now = this.deps.now();
|
|
1185
|
+
// A truncation cut names deleted state.db rows of the source; the copy's own state.db rows are all genuine (TAL-504).
|
|
1186
|
+
const watermark = session.truncation_watermark_compressed ? { truncation_watermark: session.truncation_watermark, truncation_boundary: session.truncation_boundary, truncation_watermark_compressed: true } : {};
|
|
1072
1187
|
const copied = new Session({
|
|
1073
1188
|
title: `${session.title || 'Untitled'} (copy)`, workspace: session.workspace, model: session.model, model_provider: session.model_provider,
|
|
1074
1189
|
messages: copyJson(session.messages), tool_calls: copyJson(session.tool_calls), pinned: false, archived: false, project_id: session.project_id, profile: session.profile,
|
|
1075
1190
|
input_tokens: session.input_tokens, output_tokens: session.output_tokens, estimated_cost: session.estimated_cost, cache_read_tokens: session.cache_read_tokens, cache_write_tokens: session.cache_write_tokens,
|
|
1076
1191
|
personality: session.personality, enabled_toolsets: session.enabled_toolsets, context_length: session.context_length, threshold_tokens: session.threshold_tokens,
|
|
1077
|
-
|
|
1192
|
+
...watermark, context_messages: copyJson(session.context_messages),
|
|
1078
1193
|
gateway_routing: copyJson(session.gateway_routing), gateway_routing_history: copyJson(session.gateway_routing_history), llm_title_generated: session.llm_title_generated,
|
|
1079
1194
|
manual_title: session.manual_title, composer_draft: copyJson(session.composer_draft), context_engine: session.context_engine, context_engine_state: copyJson(session.context_engine_state),
|
|
1080
1195
|
created_at: now, updated_at: now,
|
|
@@ -1182,6 +1297,14 @@ export class SessionService {
|
|
|
1182
1297
|
await this.store.withLock(sid, () => {
|
|
1183
1298
|
if (blocking())
|
|
1184
1299
|
throw new HttpFailure(409, 'Session has an active run; stop it before deleting');
|
|
1300
|
+
// A public share outlives its session file, and revokeShare needs the session, so revoke it first.
|
|
1301
|
+
try {
|
|
1302
|
+
this.deps.shares.revoke(this.store.get(sid, { metadataOnly: true }));
|
|
1303
|
+
}
|
|
1304
|
+
catch (error) {
|
|
1305
|
+
if (!(error instanceof SessionNotFound))
|
|
1306
|
+
throw error;
|
|
1307
|
+
}
|
|
1185
1308
|
if (!this.store.deleteFiles(sid))
|
|
1186
1309
|
throw new HttpFailure(500, 'Failed to delete session data');
|
|
1187
1310
|
}, { timeoutMs: 5000 });
|
|
@@ -1191,7 +1314,7 @@ export class SessionService {
|
|
|
1191
1314
|
throw new HttpFailure(503, 'Session busy, try again');
|
|
1192
1315
|
throw error;
|
|
1193
1316
|
}
|
|
1194
|
-
this.deps.runtime.evictAgent(sid);
|
|
1317
|
+
this.deps.runtime.evictAgent(sid, true);
|
|
1195
1318
|
try {
|
|
1196
1319
|
rmSync(this.deps.attachmentDir(sid), { recursive: true, force: true });
|
|
1197
1320
|
}
|
|
@@ -1226,6 +1349,13 @@ export class SessionService {
|
|
|
1226
1349
|
const shouldDelete = zeroOnly ? s.messages.length === 0 : s.title === 'Untitled' && s.messages.length === 0;
|
|
1227
1350
|
if (!shouldDelete)
|
|
1228
1351
|
continue;
|
|
1352
|
+
// A cleared session keeps its share; keep the session (and its revoke route) if the share cannot be revoked.
|
|
1353
|
+
try {
|
|
1354
|
+
this.deps.shares.revoke(s);
|
|
1355
|
+
}
|
|
1356
|
+
catch {
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1229
1359
|
this.store.sessions.delete(s.session_id);
|
|
1230
1360
|
rmSync(this.store.pathFor(s.session_id), { force: true });
|
|
1231
1361
|
cleaned += 1;
|
|
@@ -1426,36 +1556,50 @@ export class SessionService {
|
|
|
1426
1556
|
return { ok: true, ...placement };
|
|
1427
1557
|
});
|
|
1428
1558
|
}
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
const messageRef = normalizeAnchorSceneMessageRef(query.message_ref);
|
|
1432
|
-
const messageIndex = anchorSceneIntOrNull(query.message_index);
|
|
1433
|
-
if (!sid || (!messageRef && messageIndex === null))
|
|
1434
|
-
throw new HttpFailure(400, 'session_id and message_ref or message_index are required');
|
|
1435
|
-
let session;
|
|
1436
|
-
let transcript;
|
|
1559
|
+
/** The session and the full transcript its detail is built from; a state.db-only session gives its synthesized one. */
|
|
1560
|
+
fullTranscript(sid) {
|
|
1437
1561
|
try {
|
|
1438
|
-
session = this.store.get(sid);
|
|
1562
|
+
let session = this.store.get(sid);
|
|
1439
1563
|
if (session.loadedMetadataOnly)
|
|
1440
1564
|
session = this.store.load(sid) ?? session;
|
|
1441
1565
|
if (!this.visibleToActiveProfile(session.profile))
|
|
1442
1566
|
throw new HttpFailure(404, 'Session not found');
|
|
1443
|
-
transcript
|
|
1567
|
+
return { session, transcript: this.mergedTranscript(session), stored: true };
|
|
1444
1568
|
}
|
|
1445
1569
|
catch (error) {
|
|
1446
1570
|
if (error instanceof HttpFailure)
|
|
1447
1571
|
throw error;
|
|
1448
|
-
|
|
1449
|
-
session
|
|
1450
|
-
transcript = session.messages;
|
|
1572
|
+
const session = this.foreignSession(sid).synth;
|
|
1573
|
+
return { session, transcript: session.messages, stored: false };
|
|
1451
1574
|
}
|
|
1575
|
+
}
|
|
1576
|
+
readAnchorScene(query) {
|
|
1577
|
+
const sid = str(query.session_id).trim();
|
|
1578
|
+
const messageRef = normalizeAnchorSceneMessageRef(query.message_ref);
|
|
1579
|
+
const messageIndex = anchorSceneIntOrNull(query.message_index);
|
|
1580
|
+
if (!sid || (!messageRef && messageIndex === null))
|
|
1581
|
+
throw new HttpFailure(400, 'session_id and message_ref or message_index are required');
|
|
1582
|
+
const { session, transcript, stored } = this.fullTranscript(sid);
|
|
1452
1583
|
const result = readAnchorSceneRows(session, { messageRef, messageIndex, before: anchorSceneIntOrNull(query.before), limit: anchorSceneIntOrNull(query.limit) }, withToolCallOutcomes(withTurnIds(transcript), session.tool_calls, session.active_stream_id));
|
|
1453
1584
|
if (!result)
|
|
1454
1585
|
throw new HttpFailure(404, 'Anchor activity scene not found');
|
|
1455
1586
|
// Paged rows come from the raw transcript, so they take the same credential redaction as the detail's preview.
|
|
1456
1587
|
const enabled = this.deps.redactEnabled();
|
|
1457
1588
|
const redacted = redactValue(result, enabled);
|
|
1458
|
-
|
|
1589
|
+
const rows = withSceneToolDisplay(result.rows, redacted.rows, enabled);
|
|
1590
|
+
// `/api/media` serves stored sessions only, so a state.db-only session's rows stay as written, as its detail does.
|
|
1591
|
+
return { ...redacted, rows: stored ? withSceneRowMedia(rows, this.mediaProjector(session)) : rows };
|
|
1592
|
+
}
|
|
1593
|
+
/** TAL-331: one tool call's whole result, which a limited response clipped (`result_truncated`), redacted like the detail. */
|
|
1594
|
+
readToolResult(query) {
|
|
1595
|
+
const sid = query.session_id.trim();
|
|
1596
|
+
const id = query.tool_call_id.trim();
|
|
1597
|
+
if (!sid || !id)
|
|
1598
|
+
throw new HttpFailure(400, 'session_id and tool_call_id are required');
|
|
1599
|
+
const full = fullToolResult(this.fullTranscript(sid).transcript, id);
|
|
1600
|
+
if (full === null)
|
|
1601
|
+
throw new HttpFailure(404, 'Tool result not found');
|
|
1602
|
+
return { tool_call_id: id, ...redactValue(full, this.deps.redactEnabled()) };
|
|
1459
1603
|
}
|
|
1460
1604
|
// ── shares ───────────────────────────────────────────────────────────────
|
|
1461
1605
|
createShare(sid) {
|
|
@@ -1557,17 +1701,142 @@ function stampIntentionalShrink(session, oldCount, newCount) {
|
|
|
1557
1701
|
session.intentional_shrink_generation = randomUUID().replace(/-/g, '');
|
|
1558
1702
|
return true;
|
|
1559
1703
|
}
|
|
1560
|
-
/**
|
|
1704
|
+
/** Python truthiness for the JSON values a transcript row carries. */
|
|
1705
|
+
function pyTruthy(v) {
|
|
1706
|
+
if (Array.isArray(v))
|
|
1707
|
+
return v.length > 0;
|
|
1708
|
+
if (isDict(v))
|
|
1709
|
+
return Object.keys(v).length > 0;
|
|
1710
|
+
return Boolean(v);
|
|
1711
|
+
}
|
|
1712
|
+
/** JSON with sorted object keys (Python `json.dumps(..., sort_keys=True)`). */
|
|
1713
|
+
function sortedJson(v) {
|
|
1714
|
+
return JSON.stringify(v, (_key, value) => (isDict(value) ? Object.fromEntries(Object.keys(value).sort().map((k) => [k, value[k]])) : value)) ?? '';
|
|
1715
|
+
}
|
|
1716
|
+
/** Equality key for a row `id`/`timestamp`; `null` when the value is absent. Numbers compare by value (`2 == 2.0`). */
|
|
1717
|
+
function identityKey(v) {
|
|
1718
|
+
if (v === null || v === undefined)
|
|
1719
|
+
return null;
|
|
1720
|
+
return typeof v === 'string' ? `s${v}` : typeof v === 'number' ? `n${String(v)}` : `j${sortedJson(v)}`;
|
|
1721
|
+
}
|
|
1722
|
+
function rowSignature(row) {
|
|
1723
|
+
if (!isDict(row))
|
|
1724
|
+
return null;
|
|
1725
|
+
const field = (v) => (!pyTruthy(v) ? '' : typeof v === 'string' ? v : sortedJson(v));
|
|
1726
|
+
return JSON.stringify([field(row.role), field(row.content), field(row.tool_call_id), field(row.tool_use_id), field(row.tool_name || row.name), field(row.tool_calls)]);
|
|
1727
|
+
}
|
|
1728
|
+
/** First index in sorted `positions` whose value is `>= start`. */
|
|
1729
|
+
function lowerBound(positions, start) {
|
|
1730
|
+
let lo = 0;
|
|
1731
|
+
let hi = positions.length;
|
|
1732
|
+
while (lo < hi) {
|
|
1733
|
+
const mid = (lo + hi) >> 1;
|
|
1734
|
+
if (positions[mid] < start)
|
|
1735
|
+
lo = mid + 1;
|
|
1736
|
+
else
|
|
1737
|
+
hi = mid;
|
|
1738
|
+
}
|
|
1739
|
+
return lo;
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Map each display row to the context row it represents, scanning forward. An `id` match wins; otherwise the role+content
|
|
1743
|
+
* signature must match, and a shared `timestamp` makes it exact. A signature match where an identity is missing is weak:
|
|
1744
|
+
* one weak candidate counts as a match, a second one before any exact match leaves the row ambiguous.
|
|
1745
|
+
*/
|
|
1746
|
+
function alignDisplayToContext(ctx, full) {
|
|
1747
|
+
const index = () => new Map();
|
|
1748
|
+
const push = (map, key, idx) => {
|
|
1749
|
+
const list = map.get(key);
|
|
1750
|
+
if (list)
|
|
1751
|
+
list.push(idx);
|
|
1752
|
+
else
|
|
1753
|
+
map.set(key, [idx]);
|
|
1754
|
+
};
|
|
1755
|
+
const first = (list, start) => list?.[lowerBound(list, start)];
|
|
1756
|
+
const byId = index(), bySigTs = index(), bySigTsNoId = index();
|
|
1757
|
+
const weakAny = index(), weakNoId = index(), weakNoTs = index(), weakNoIdNoTs = index();
|
|
1758
|
+
ctx.forEach((row, idx) => {
|
|
1759
|
+
const sig = rowSignature(row);
|
|
1760
|
+
if (sig === null)
|
|
1761
|
+
return;
|
|
1762
|
+
const id = identityKey(row.id);
|
|
1763
|
+
const ts = identityKey(row.timestamp);
|
|
1764
|
+
push(weakAny, sig, idx);
|
|
1765
|
+
if (id === null)
|
|
1766
|
+
push(weakNoId, sig, idx);
|
|
1767
|
+
if (ts === null)
|
|
1768
|
+
push(weakNoTs, sig, idx);
|
|
1769
|
+
if (id === null && ts === null)
|
|
1770
|
+
push(weakNoIdNoTs, sig, idx);
|
|
1771
|
+
if (id !== null)
|
|
1772
|
+
push(byId, id, idx);
|
|
1773
|
+
if (ts !== null) {
|
|
1774
|
+
push(bySigTs, `${sig}\0${ts}`, idx);
|
|
1775
|
+
if (id === null)
|
|
1776
|
+
push(bySigTsNoId, `${sig}\0${ts}`, idx);
|
|
1777
|
+
}
|
|
1778
|
+
});
|
|
1779
|
+
const matches = [];
|
|
1780
|
+
const ambiguous = [];
|
|
1781
|
+
let next = 0;
|
|
1782
|
+
for (const message of full) {
|
|
1783
|
+
let match = null;
|
|
1784
|
+
let ambiguousAt = null;
|
|
1785
|
+
const sig = rowSignature(message);
|
|
1786
|
+
if (sig !== null) {
|
|
1787
|
+
const id = identityKey(message.id);
|
|
1788
|
+
const ts = identityKey(message.timestamp);
|
|
1789
|
+
const exact = [id !== null ? first(byId.get(id), next) : undefined, ts !== null ? first((id !== null ? bySigTsNoId : bySigTs).get(`${sig}\0${ts}`), next) : undefined]
|
|
1790
|
+
.filter((idx) => idx !== undefined);
|
|
1791
|
+
const exactIdx = exact.length ? Math.min(...exact) : null;
|
|
1792
|
+
const weakList = (id !== null ? (ts !== null ? weakNoIdNoTs : weakNoId) : ts !== null ? weakNoTs : weakAny).get(sig) ?? [];
|
|
1793
|
+
const w = lowerBound(weakList, next);
|
|
1794
|
+
const [firstWeak, secondWeak] = [weakList[w], weakList[w + 1]];
|
|
1795
|
+
if (secondWeak !== undefined && (exactIdx === null || secondWeak < exactIdx))
|
|
1796
|
+
ambiguousAt = firstWeak;
|
|
1797
|
+
else
|
|
1798
|
+
match = exactIdx ?? firstWeak ?? null;
|
|
1799
|
+
}
|
|
1800
|
+
matches.push(match);
|
|
1801
|
+
ambiguous.push(ambiguousAt);
|
|
1802
|
+
if (match !== null)
|
|
1803
|
+
next = match + 1;
|
|
1804
|
+
}
|
|
1805
|
+
return { matches, ambiguous };
|
|
1806
|
+
}
|
|
1807
|
+
/** Align model context with the display prefix `full[:keep]` (Python `truncate_context_for_display_keep`, #5096/#5563). */
|
|
1561
1808
|
export function truncateContextForDisplayKeep(context, full, keep) {
|
|
1562
1809
|
if (keep <= 0)
|
|
1563
1810
|
return [];
|
|
1564
|
-
const
|
|
1565
|
-
if (!
|
|
1811
|
+
const ctx = context ?? [];
|
|
1812
|
+
if (!ctx.length || !full.length)
|
|
1566
1813
|
return [];
|
|
1567
|
-
if (keep
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1814
|
+
if (keep < full.length) {
|
|
1815
|
+
const { matches, ambiguous } = alignDisplayToContext(ctx, full);
|
|
1816
|
+
const lastKept = matches[keep - 1];
|
|
1817
|
+
const firstUnkept = matches[keep];
|
|
1818
|
+
const boundary = full[keep - 1];
|
|
1819
|
+
const keptUser = isDict(boundary) && boundary.role === 'user';
|
|
1820
|
+
// Cut at the first unkept display row; a kept user turn ends at its own row so unkept tool rows after it drop.
|
|
1821
|
+
if (firstUnkept !== null)
|
|
1822
|
+
return lastKept !== null && keptUser ? ctx.slice(0, lastKept + 1) : ctx.slice(0, firstUnkept);
|
|
1823
|
+
if (lastKept !== null) {
|
|
1824
|
+
const ambiguousUnkept = ambiguous[keep];
|
|
1825
|
+
return ambiguousUnkept !== null && isDict(boundary) && !keptUser ? ctx.slice(0, ambiguousUnkept) : ctx.slice(0, lastKept + 1);
|
|
1826
|
+
}
|
|
1827
|
+
// Both boundary rows unresolved in a shorter (compressed) context: cut past the last kept display row that resolved,
|
|
1828
|
+
// accepting a weak match. Under-keeping beats slicing at the raw display index.
|
|
1829
|
+
if (ctx.length < full.length) {
|
|
1830
|
+
for (let i = keep - 1; i >= 0; i -= 1) {
|
|
1831
|
+
const resolved = matches[i] ?? ambiguous[i];
|
|
1832
|
+
if (resolved !== null && resolved !== undefined)
|
|
1833
|
+
return ctx.slice(0, resolved + 1);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
// Unalignable (or nothing cut): keep the compaction prefix a longer context carries, then `keep` rows (#5096).
|
|
1838
|
+
const prefixLen = Math.max(0, ctx.length - full.length);
|
|
1839
|
+
return ctx.slice(0, prefixLen + keep);
|
|
1571
1840
|
}
|
|
1572
1841
|
export function truncateSessionAtKeep(session, keep) {
|
|
1573
1842
|
const full = [...session.messages];
|
|
@@ -1578,6 +1847,7 @@ export function truncateSessionAtKeep(session, keep) {
|
|
|
1578
1847
|
session.context_messages = truncateContextForDisplayKeep(session.context_messages, full, keep);
|
|
1579
1848
|
session.truncation_watermark = truncationWatermarkFor(session.messages);
|
|
1580
1849
|
session.truncation_boundary = session.truncation_watermark;
|
|
1850
|
+
session.truncation_watermark_compressed = false;
|
|
1581
1851
|
return [oldMsgCount, oldCtxCount];
|
|
1582
1852
|
}
|
|
1583
1853
|
function shrinkTo(session, lastUserIdx) {
|
|
@@ -1586,6 +1856,7 @@ function shrinkTo(session, lastUserIdx) {
|
|
|
1586
1856
|
stampIntentionalShrink(session, history.length, session.messages.length);
|
|
1587
1857
|
session.truncation_watermark = truncationWatermarkFor(session.messages);
|
|
1588
1858
|
session.truncation_boundary = session.truncation_watermark;
|
|
1859
|
+
session.truncation_watermark_compressed = false;
|
|
1589
1860
|
if (session.context_messages.length) {
|
|
1590
1861
|
const ctxLast = findLastUserIndex(session.context_messages);
|
|
1591
1862
|
if (ctxLast !== null)
|