@maudecode/talaria-web 1.14.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 +123 -7
- package/dist/api/automation-router.js +5 -0
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +728 -55
- package/dist/api/chat-router.js +122 -126
- 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 +6 -3
- package/dist/api/router.js +10 -8
- package/dist/api/router.js.map +1 -1
- package/dist/api/sessions-router.d.ts +2583 -297
- package/dist/api/sessions-router.js +92 -47
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +188 -17
- package/dist/api/settings-router.js +75 -26
- 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 +3620 -343
- 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/config/agent-config.js +20 -15
- package/dist/config/agent-config.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 +7 -5
- package/dist/http/context.js.map +1 -1
- package/dist/links.d.ts +26 -0
- package/dist/links.js +60 -0
- package/dist/links.js.map +1 -0
- package/dist/onboarding.d.ts +1 -1
- package/dist/onboarding.js +28 -8
- 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 +85 -1
- package/dist/providers/catalog.js +280 -43
- 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 +104 -42
- 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 +140 -0
- package/dist/sessions/background-tasks.js +352 -0
- package/dist/sessions/background-tasks.js.map +1 -0
- package/dist/sessions/background-updates.d.ts +56 -0
- package/dist/sessions/background-updates.js +152 -0
- package/dist/sessions/background-updates.js.map +1 -0
- package/dist/sessions/cli-sessions.d.ts +6 -0
- package/dist/sessions/cli-sessions.js +20 -7
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +17 -1
- package/dist/sessions/completions.js +84 -13
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +33 -0
- package/dist/sessions/compress.js +66 -0
- package/dist/sessions/compress.js.map +1 -0
- package/dist/sessions/list.d.ts +22 -4
- package/dist/sessions/list.js +113 -33
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +81 -7
- package/dist/sessions/merge.js +391 -26
- 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/relay.d.ts +7 -1
- package/dist/sessions/relay.js +17 -4
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +118 -6
- package/dist/sessions/service.js +564 -65
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +22 -1
- package/dist/sessions/session.js +29 -2
- 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/source-kind.d.ts +22 -0
- package/dist/sessions/source-kind.js +54 -0
- package/dist/sessions/source-kind.js.map +1 -0
- package/dist/sessions/state-db.d.ts +10 -1
- package/dist/sessions/state-db.js +48 -17
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/store.d.ts +2 -0
- package/dist/sessions/store.js +24 -5
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +3 -0
- package/dist/sessions/streams.js +0 -5
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/titles.d.ts +4 -0
- package/dist/sessions/titles.js +16 -0
- package/dist/sessions/titles.js.map +1 -1
- package/dist/sessions/turn-context.d.ts +1 -0
- package/dist/sessions/turn-context.js +3 -0
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +85 -7
- package/dist/sessions/turn.js +518 -170
- package/dist/sessions/turn.js.map +1 -1
- package/dist/settings.d.ts +2 -0
- package/dist/settings.js +13 -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 +38 -4
- package/dist/tools/crons.js +323 -36
- 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 +360 -27
- package/sidecar/talaria_sidecar/methods/commands.py +46 -31
- package/sidecar/talaria_sidecar/methods/config.py +14 -10
- package/sidecar/talaria_sidecar/methods/cron.py +22 -14
- package/sidecar/talaria_sidecar/methods/oauth.py +439 -0
- package/sidecar/talaria_sidecar/methods/process.py +318 -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 -119
- 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-emii55o0.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-m6nx9g8t.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-kejgxpil.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-eu64w89w.js +1 -0
- package/static/dist/assets/{blockDiagram-I7D4REHJ-l1466a7j.js → blockDiagram-I7D4REHJ-n79st4pj.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-gg3aq3sr.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-oalgz5l8.js → chunk-4HAMMTFA-laat0g1q.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-babmzhdg.js → chunk-75Z2AOVW-0psy1tr2.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-lagu350c.js → chunk-DU6HZSFF-lw8uox8x.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-gjh2tqif.js → chunk-F27PBJKO-erassib3.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-ipdgja5c.js → chunk-GMAD6QVW-fz7rx619.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-j8wkn1at.js → chunk-GVQU2GXP-gdb0epb2.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-k00laqyk.js → chunk-IMKFNOWR-ea8t26qw.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-fju6xqj4.js → chunk-L3NEJ4N5-mb1gu9kz.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-bi6widqt.js → chunk-OSK3NFVY-eovmccvy.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-czr4tebv.js → chunk-P2QGCYS3-bo55zjo5.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-ktdhn67w.js → chunk-POPQ4Y6H-ja7ohe4h.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-ii4dsu0d.js → chunk-PWAF6VOD-e30g9nus.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-fpwk3xxp.js → chunk-SHT3W25Y-gbb798f7.js} +3 -3
- package/static/dist/assets/{chunk-SVP7TREG-k0jrvhei.js → chunk-SVP7TREG-h2iw8urm.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-nkqv9ot0.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-gpchexqu.js → copied-h65fc3cx.js} +1 -1
- package/static/dist/assets/copy-e6977uwq.js +1 -0
- package/static/dist/assets/{cynefin-OW5HDTMX-lqxt8rs3.js → cynefin-OW5HDTMX-lbltyl5j.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-j9eqovf5.js → cynefinDiagram-5FMLGOSQ-lxhsqq4a.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-m9agobjm.js → dagre-GXQ25YYZ-gn4nnaln.js} +4 -4
- package/static/dist/assets/{diagram-S7CK7UJ4-itodc50c.js → diagram-S7CK7UJ4-pa3ij6q7.js} +3 -3
- package/static/dist/assets/{diagram-UQ7AKVKN-n1h2t4ah.js → diagram-UQ7AKVKN-zbipyz57.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-lvtvm9bj.js → diagram-VSXAHHWV-d1kbpzgf.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-cgas58sy.js → diagram-VX7I27RA-i3ty14xl.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-d0aeps1q.js → diagram-Z3DM3KII-m8xefqa7.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-md345fyq.js → ebnfDiagram-PWID7BFC-nz7wj05l.js} +1 -1
- package/static/dist/assets/endpoints-k7yf25m0.js +64 -0
- package/static/dist/assets/{erDiagram-RLTQ6QDP-i4rua63b.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-geqx7zgl.js → ganttDiagram-EL5Y4UJY-n7zq01qu.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-leoq0z8t.js → gitGraph-4MIJSDKK-c89emb07.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-llrlxfha.js → gitGraphDiagram-WWUBYQGX-cz7cgr6w.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-kq2cnw6q.js → highlighted-body-KPVGNVTW-d9bapmni.js} +1 -1
- package/static/dist/assets/{index-f9bzglkn.js → index-h00usru2.js} +3 -3
- package/static/dist/assets/index-n73ijkv2.css +2 -0
- package/static/dist/assets/{info-A6RAGUB7-lkly4xj6.js → info-A6RAGUB7-ndddhhhh.js} +1 -1
- package/static/dist/assets/infoDiagram-27XIBGKW-ccxigcpf.js +2 -0
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-hq6jf374.js → ishikawaDiagram-5VMMS53U-le0z9vtc.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-is03ntb0.js → journeyDiagram-3NMN7TZE-ivsmb26o.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-jmerizqb.js → kanban-definition-UXKFOSKX-h6n2awt0.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +1 -0
- package/static/dist/assets/{line-laaa8h99.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-ix4junux.js → mermaid-parser.core-gwyd5bnq.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-o0e0adl1.js → mindmap-definition-YA3MSWOX-l68gg5h7.js} +1 -1
- package/static/dist/assets/onboarding-cdfrk0pj.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-kl8pwsyg.js → packet-AYTQ26CC-gpv06065.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-bbqn9jo4.js → pegDiagram-XKGWAZYB-e52vs23u.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-cpyo8bkr.js → pie-WAS4IAKB-l6m7nz5s.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-pelug34f.js → pieDiagram-E7YTZNPT-b4is36bq.js} +3 -3
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-jds4jmr5.js → quadrantDiagram-AXDQQJYC-m8vt2788.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-e02oxnvd.js → radar-RG4KPBEZ-nxbrhiov.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-kz3delwo.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-jgroj2ew.js → railroadDiagram-O6MQD6OU-o8lldfzv.js} +1 -1
- package/static/dist/assets/{refresh-cw-k7yxjdn3.js → refresh-cw-kbcje1uy.js} +1 -1
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-m4az5e0j.js → requirementDiagram-BXWQKSXE-ovyq38kv.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-vlryqiv3.js → sankeyDiagram-P5KCCOFB-ou7lznor.js} +1 -1
- package/static/dist/assets/{saved-brdfjjnw.js → saved-bazmcup9.js} +1 -1
- package/static/dist/assets/search-jen74z4u.js +1 -0
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-fr8hrpql.js → sequenceDiagram-WJ2MYXX4-ovckdzf2.js} +1 -1
- package/static/dist/assets/{settings_section_extensions_title-l0zodj0b.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-gcgscv8r.js → sliders-horizontal-f9cb3lh3.js} +1 -1
- package/static/dist/assets/{stateDiagram-D77RDMKH-bg548iyr.js → stateDiagram-D77RDMKH-fcrexkkv.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-hk5z3efh.js → swimlanes-42K2YHIH-f7usu8fw.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-olvknr62.js → timeline-definition-24CTP7MA-gp1hvz9f.js} +1 -1
- package/static/dist/assets/todoStore-eqtid4r4.js +1 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-ovvjsxtf.js → treeView-Q6P3EWNA-gb9gf11u.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-ggkipj59.js → treemap-WGGIJYW6-nuvfnvvi.js} +1 -1
- package/static/dist/assets/{untitled-c8ydw0bu.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-katwvzil.js → useParams-dqd64jv7.js} +1 -1
- package/static/dist/assets/{useSearch-c70sgau1.js → useSearch-j30pvsy7.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-hzld7zt7.js → vennDiagram-4TSXK5OY-fzchbzaj.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-hxkeoms8.js → wardley-WFR3VGLG-m47mhfbh.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ljh90mb1.js → wardleyDiagram-VM6X3IG4-odg6ct1z.js} +2 -2
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mnuaes03.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-haqi9qzu.js +0 -1
- package/static/dist/assets/ChatPage-hjyu2g64.js +0 -22
- package/static/dist/assets/HubRoute-gkd8o1vg.js +0 -2
- package/static/dist/assets/RightPanel-o73y98dn.js +0 -1
- package/static/dist/assets/Select-jld3yeni.js +0 -1
- package/static/dist/assets/SessionListPanel-d3qx4ric.js +0 -1
- package/static/dist/assets/SettingsLayout-lnn2wo2s.js +0 -1
- package/static/dist/assets/States-e5hv6gdh.js +0 -1
- package/static/dist/assets/Toaster-c4jq1i26.js +0 -1
- package/static/dist/assets/_app-bnip2pjg.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-egptzrfy.js +0 -1
- package/static/dist/assets/_app.index-vdz13ul5.js +0 -1
- package/static/dist/assets/_app.insights-lgjshsba.js +0 -1
- package/static/dist/assets/_app.kanban-c18cjrpz.js +0 -1
- package/static/dist/assets/_app.logs-ezhojgeg.js +0 -1
- package/static/dist/assets/_app.memory-i00paisv.js +0 -1
- package/static/dist/assets/_app.profiles-kd02bwjx.js +0 -1
- package/static/dist/assets/_app.settings-giaudkuk.js +0 -1
- package/static/dist/assets/_app.settings._section-k4qtlexk.js +0 -1
- package/static/dist/assets/_app.skills-bby2uvl8.js +0 -1
- package/static/dist/assets/_app.tasks-1kz9bosm.js +0 -2
- package/static/dist/assets/_app.todos-izjdbkm2.js +0 -1
- package/static/dist/assets/_app.workspaces-lfh2kw7s.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-b4u9z1w3.js +0 -1
- package/static/dist/assets/architectureDiagram-5GKGNRK7-hqnf84fc.js +0 -36
- package/static/dist/assets/channel-o77ioktg.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-f5rvod26.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-f5rvod26.js +0 -1
- package/static/dist/assets/endpoints-e58saih3.js +0 -9
- package/static/dist/assets/eventmodeling-NTZA5JFV-bn3fjsaq.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-li70d120.js +0 -1
- package/static/dist/assets/index-gkh7kum4.css +0 -2
- package/static/dist/assets/infoDiagram-27XIBGKW-oo7kdyte.js +0 -2
- package/static/dist/assets/lazyRouteComponent-b1h2ykmb.js +0 -1
- package/static/dist/assets/link-d8f0788e.js +0 -1
- package/static/dist/assets/login-llkohrcg.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-id0ffk2r.js +0 -1
- package/static/dist/assets/onboarding-lx0d6b38.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-l13ped2z.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-c7rg3g4g.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-od0b8niq.js +0 -1
- package/static/dist/assets/search-gt2ueyvg.js +0 -1
- package/static/dist/assets/share._token-oyjv046r.js +0 -2
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-j5v40qih.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-grzefo9c.js +0 -8
- package/static/dist/assets/tabBuild-idliyw9f.js +0 -56
- package/static/dist/assets/todoStore-j4c2xq0b.js +0 -1
- package/static/dist/assets/useForm-kd759sjk.js +0 -1
- package/static/dist/assets/useLocale-hds4xmja.js +0 -1
|
@@ -17,8 +17,8 @@ import { atomicWriteText } from '../fs/atomic.js';
|
|
|
17
17
|
import { str } from '../util.js';
|
|
18
18
|
import { loadEnvFile } from './env-file.js';
|
|
19
19
|
import { ACCOUNT_USAGE_PROVIDERS, FALLBACK_MODELS, OAUTH_PROVIDERS, PORTAL_PROVIDERS, PROVIDER_DISPLAY, PROVIDER_ENV_VAR, PROVIDER_ENV_VAR_ALIASES, PROVIDER_MODELS, SELF_HOSTED_PROVIDER_IDS, } from './tables.js';
|
|
20
|
-
import { activeProviderFromConfig, canonicaliseProviderId, configuredModelIds, configuredModelOptions, customProviderEntries, customProviderSlug, dict, effectiveDefaultModel, isDict, isOpenAiFamilyProvider, mainModelSupportsServiceTier, modelSection, providerIdentity, resolveProviderAlias, } from '../config/agent-config.js';
|
|
21
|
-
/** Python `_model_matches_picker_selection`: same bare id, and the routing hints agree when
|
|
20
|
+
import { activeProviderFromConfig, canonicaliseProviderId, configuredModelIds, configuredModelOptions, customProviderEntries, customProviderSlug, dict, effectiveDefaultModel, isDict, isOpenAiFamilyProvider, mainModelSupportsServiceTier, modelSection, parseProviderQualifiedModel, providerIdentity, resolveProviderAlias, } from '../config/agent-config.js';
|
|
21
|
+
/** Python `_model_matches_picker_selection`: same bare id, and the routing hints agree when the selection names one. */
|
|
22
22
|
function modelMatchesPickerSelection(modelId, selected, providerId) {
|
|
23
23
|
const candidate = modelId.trim();
|
|
24
24
|
const sel = selected.trim();
|
|
@@ -26,12 +26,28 @@ function modelMatchesPickerSelection(modelId, selected, providerId) {
|
|
|
26
26
|
return false;
|
|
27
27
|
if (candidate === sel)
|
|
28
28
|
return true;
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
const [candBare, candProvider] = parseProviderQualifiedModel(candidate) ?? [candidate, providerId.trim()];
|
|
30
|
+
const [selBare, selProvider] = parseProviderQualifiedModel(sel) ?? [sel, ''];
|
|
31
|
+
return selBare === candBare && (!selProvider || selProvider.toLowerCase() === candProvider.toLowerCase());
|
|
32
|
+
}
|
|
33
|
+
/** TAL-301: every entry names its routing provider and bare id, split once by `parseProviderQualifiedModel`. */
|
|
34
|
+
function stampModelEntries(models, providerId) {
|
|
35
|
+
return models.map((m) => {
|
|
36
|
+
const [bare, provider] = parseProviderQualifiedModel(m.id) ?? [m.id, providerId];
|
|
37
|
+
return { ...m, bare_id: bare, provider_id: provider };
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** TAL-301: the catalog entry a stored `(model, provider)` pair selects, so clients render the pairing instead of computing it. */
|
|
41
|
+
export function catalogOptionId(catalog, model, provider) {
|
|
42
|
+
const bare = str(model).trim();
|
|
43
|
+
const pid = str(provider).trim().toLowerCase();
|
|
44
|
+
if (!bare || !pid)
|
|
45
|
+
return null;
|
|
46
|
+
for (const g of catalog.groups)
|
|
47
|
+
for (const e of [...g.models, ...(g.extra_models ?? [])])
|
|
48
|
+
if (e.bare_id === bare && str(e.provider_id).toLowerCase() === pid)
|
|
49
|
+
return e.id;
|
|
50
|
+
return null;
|
|
35
51
|
}
|
|
36
52
|
/** Python `_split_picker_overflow_models`: past 25 rows the picker shows 15, keeping the selected model visible. */
|
|
37
53
|
export function splitPickerOverflow(models, selected, providerId) {
|
|
@@ -49,13 +65,41 @@ export function splitPickerOverflow(models, selected, providerId) {
|
|
|
49
65
|
}
|
|
50
66
|
return [visible, extras];
|
|
51
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* TAL-388: stamp each auxiliary slot with its display value and the catalog entry whose provider/model pair equals the
|
|
70
|
+
* saved one, so clients tick exactly one option (a bare id listed under two providers matches only its own provider).
|
|
71
|
+
*/
|
|
72
|
+
export function stampAuxiliarySelections(aux, catalog) {
|
|
73
|
+
const options = catalog.groups.flatMap((g) => [...g.models, ...(g.extra_models ?? [])].map((m) => {
|
|
74
|
+
const parsed = parseProviderQualifiedModel(m.id);
|
|
75
|
+
return { id: m.id, label: m.label, group: g.provider, provider: canonicaliseProviderId(parsed?.[1] ?? g.provider_id), bare: parsed?.[0] ?? m.id };
|
|
76
|
+
}));
|
|
77
|
+
const describe = (providerRaw, modelRaw) => {
|
|
78
|
+
const provider = str(providerRaw).trim() || 'auto';
|
|
79
|
+
const model = str(modelRaw).trim();
|
|
80
|
+
const key = canonicaliseProviderId(provider);
|
|
81
|
+
const match = provider === 'auto' ? undefined : options.find((o) => o.provider === key && o.bare === model);
|
|
82
|
+
if (match)
|
|
83
|
+
return { value_label: match.label || match.bare, provider_label: match.group, option_id: match.id };
|
|
84
|
+
const group = catalog.groups.find((g) => canonicaliseProviderId(g.provider_id) === key);
|
|
85
|
+
return { value_label: model || null, provider_label: provider === 'auto' ? null : group?.provider ?? displayName(provider), option_id: null };
|
|
86
|
+
};
|
|
87
|
+
// Auto falls back to the main chat model; name the effective one the catalog resolved (a legacy string `model` or a
|
|
88
|
+
// `HERMES_MODEL`-style override never reaches `aux.main`).
|
|
89
|
+
const mainParsed = parseProviderQualifiedModel(catalog.default_model);
|
|
90
|
+
const main = describe(mainParsed?.[1] ?? catalog.active_provider ?? aux.main.provider, mainParsed?.[0] ?? (catalog.default_model || aux.main.model));
|
|
91
|
+
const tasks = aux.tasks.map((t) => {
|
|
92
|
+
if ((str(t.provider).trim() || 'auto') === 'auto' && !str(t.model).trim())
|
|
93
|
+
return { ...t, is_auto: true, value_label: main.value_label, provider_label: main.provider_label, selected_option_id: null, in_catalog: true };
|
|
94
|
+
const pinned = describe(t.provider, t.model);
|
|
95
|
+
return { ...t, is_auto: false, value_label: pinned.value_label, provider_label: pinned.provider_label, selected_option_id: pinned.option_id, in_catalog: pinned.option_id !== null };
|
|
96
|
+
});
|
|
97
|
+
return { ...aux, tasks };
|
|
98
|
+
}
|
|
52
99
|
/** Python `_BESPOKE_CATALOG_PROVIDERS`: cards whose catalog is resolved by their own rule, never the generic live probe. */
|
|
53
100
|
const BESPOKE_CATALOG_PROVIDERS = new Set(['openai-codex', 'nous', 'xai-oauth', 'lmstudio', 'opencode-go']);
|
|
54
101
|
/** Python `_unqualified_model_id`: strip a picker routing hint (`@provider:`). */
|
|
55
|
-
|
|
56
|
-
const raw = id.trim();
|
|
57
|
-
return raw.startsWith('@') && raw.includes(':') ? raw.slice(raw.indexOf(':') + 1) : raw;
|
|
58
|
-
}
|
|
102
|
+
const unqualifiedModelId = (id) => parseProviderQualifiedModel(id)?.[0] ?? id.trim();
|
|
59
103
|
/** Python `_MODEL_PICKER_OVERFLOW_THRESHOLD` / `_MODEL_PICKER_VISIBLE_TARGET`. */
|
|
60
104
|
const MODEL_PICKER_OVERFLOW_THRESHOLD = 25;
|
|
61
105
|
const MODEL_PICKER_VISIBLE_TARGET = 15;
|
|
@@ -64,7 +108,110 @@ const LIVE_TTL_S = 86_400;
|
|
|
64
108
|
const PROVIDERS_TTL_S = 30;
|
|
65
109
|
const QUOTA_TIMEOUT_MS = 15_000;
|
|
66
110
|
const OPENROUTER_KEY_URL = 'https://openrouter.ai/api/v1/key';
|
|
111
|
+
const PLUGIN_LIST_TIMEOUT_MS = 15_000;
|
|
112
|
+
/** TAL-288: the card text for a plugin provider the Agent does not report ready. */
|
|
113
|
+
const PLUGIN_SETUP_ERRORS = {
|
|
114
|
+
missing_cli: "This provider's CLI was not found on the server. Install it and sign in, then refresh.",
|
|
115
|
+
needs_setup: "This provider is not set up yet. Finish its setup in Hermes, then refresh.",
|
|
116
|
+
not_loaded: 'This provider is installed but could not be loaded. Check it with hermes plugins doctor, then restart Talaria Web.',
|
|
117
|
+
unavailable: "This provider's setup status is unavailable.",
|
|
118
|
+
};
|
|
119
|
+
const PLUGIN_NO_MODELS = 'This provider listed no models.';
|
|
67
120
|
const COST_SNAPSHOT_MAX_DAYS = 365;
|
|
121
|
+
const FIVE_HOUR_WINDOW_S = 18_000;
|
|
122
|
+
const WEEK_WINDOW_S = 604_800;
|
|
123
|
+
/** Swift `rounded()`: half away from zero. */
|
|
124
|
+
function roundTo(value, digits) {
|
|
125
|
+
const scale = 10 ** digits;
|
|
126
|
+
return (Math.sign(value) * Math.round(Math.abs(value) * scale)) / scale;
|
|
127
|
+
}
|
|
128
|
+
const finite = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : null);
|
|
129
|
+
/** ISO-8601 UTC for epoch seconds, without a `.000` fraction. */
|
|
130
|
+
export const isoAt = (seconds) => new Date(seconds * 1000).toISOString().replace('.000Z', 'Z');
|
|
131
|
+
/** ISO-8601 UTC (`…Z`) or null. Accepts the pre-TAL-409 sidecar's `str(datetime)` space form; a zone-less stamp is UTC. */
|
|
132
|
+
export function isoUtc(value) {
|
|
133
|
+
if (typeof value !== 'string' || !value.trim())
|
|
134
|
+
return null;
|
|
135
|
+
let text = value.trim().replace(' ', 'T');
|
|
136
|
+
if (text.includes('T') && !/(Z|[+-]\d{2}:?\d{2})$/i.test(text))
|
|
137
|
+
text += 'Z';
|
|
138
|
+
const ms = Date.parse(text);
|
|
139
|
+
return Number.isFinite(ms) ? isoAt(ms / 1000) : null;
|
|
140
|
+
}
|
|
141
|
+
/** The forecast a pace implies: per-hour or per-day budget until reset, and whether the projection empties the window first. */
|
|
142
|
+
export function quotaForecast(pace, remaining) {
|
|
143
|
+
const daily = pace.minutes_to_reset >= 24 * 60;
|
|
144
|
+
const margin = pace.projected_minutes_to_empty === null ? null : pace.projected_minutes_to_empty - pace.minutes_to_reset;
|
|
145
|
+
return {
|
|
146
|
+
outcome: margin === null || margin >= 0 ? 'safe' : 'warning',
|
|
147
|
+
budget_unit: daily ? 'day' : 'hour',
|
|
148
|
+
budget_percent: remaining !== null && pace.minutes_to_reset > 0 ? remaining / (pace.minutes_to_reset / (daily ? 24 * 60 : 60)) : null,
|
|
149
|
+
depletion_margin_minutes: margin,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* TAL-409: the one normaliser for account-usage windows (Python `_snapshot_windows_payload` plus the pace math the
|
|
154
|
+
* App used to run). Blank labels drop; `reset_at` becomes ISO `Z`; each window gets its duration, pace and forecast
|
|
155
|
+
* as of `nowSeconds`; the indexes name the windows the App shows for pace, session and weekly selections.
|
|
156
|
+
*/
|
|
157
|
+
export function normalizeQuotaWindows(raw, nowSeconds) {
|
|
158
|
+
const nowMs = nowSeconds * 1000;
|
|
159
|
+
const windows = [];
|
|
160
|
+
for (const entry of Array.isArray(raw) ? raw : []) {
|
|
161
|
+
if (!isDict(entry))
|
|
162
|
+
continue;
|
|
163
|
+
const label = str(entry.label).trim();
|
|
164
|
+
if (!label)
|
|
165
|
+
continue;
|
|
166
|
+
const usedRaw = finite(entry.used_percent);
|
|
167
|
+
const remainingRaw = finite(entry.remaining_percent);
|
|
168
|
+
const clamp = (v) => Math.min(Math.max(v, 0), 100);
|
|
169
|
+
const used = usedRaw !== null ? clamp(usedRaw) : remainingRaw !== null ? clamp(100 - remainingRaw) : null;
|
|
170
|
+
const remaining = used === null ? null : 100 - used;
|
|
171
|
+
const resetAt = isoUtc(entry.reset_at);
|
|
172
|
+
const resetMs = resetAt === null ? null : Date.parse(resetAt);
|
|
173
|
+
const minutesToReset = resetMs === null ? null : Math.max(0, roundTo((resetMs - nowMs) / 60_000, 0));
|
|
174
|
+
const lower = label.toLowerCase();
|
|
175
|
+
const providedSeconds = finite(entry.window_seconds);
|
|
176
|
+
const windowSeconds = providedSeconds
|
|
177
|
+
?? (lower.includes('week') ? WEEK_WINDOW_S
|
|
178
|
+
: lower.includes('5h') ? FIVE_HOUR_WINDOW_S
|
|
179
|
+
// A "Session" window is 5h, or the weekly window a provider collapsed into one session bucket.
|
|
180
|
+
: lower.includes('session') && minutesToReset !== null ? (minutesToReset > 5 * 60 ? WEEK_WINDOW_S : FIVE_HOUR_WINDOW_S)
|
|
181
|
+
: null);
|
|
182
|
+
let pace = null;
|
|
183
|
+
if (resetAt !== null && resetMs !== null && minutesToReset !== null && resetMs > nowMs && used !== null && remaining !== null
|
|
184
|
+
&& (windowSeconds === FIVE_HOUR_WINDOW_S || windowSeconds === WEEK_WINDOW_S)) {
|
|
185
|
+
const windowMinutes = windowSeconds / 60;
|
|
186
|
+
const elapsed = Math.max(0, windowMinutes - minutesToReset);
|
|
187
|
+
const expectedRemaining = roundTo(Math.min(Math.max((minutesToReset / windowMinutes) * 100, 0), 100), 1);
|
|
188
|
+
const expectedUsed = roundTo(100 - expectedRemaining, 1);
|
|
189
|
+
const usagePerMinute = elapsed > 0 ? used / elapsed : 0;
|
|
190
|
+
pace = {
|
|
191
|
+
expected_remaining_percent: expectedRemaining,
|
|
192
|
+
pace_delta_percent: roundTo(remaining - expectedRemaining, 1),
|
|
193
|
+
burn_rate: expectedUsed > 0 ? roundTo(used / expectedUsed, 2) : 0,
|
|
194
|
+
minutes_to_reset: minutesToReset,
|
|
195
|
+
projected_minutes_to_empty: usagePerMinute > 0 ? roundTo(remaining / usagePerMinute, 0) : null,
|
|
196
|
+
elapsed_minutes: elapsed,
|
|
197
|
+
valid_until: resetAt,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
windows.push({
|
|
201
|
+
label, used_percent: usedRaw, remaining_percent: remaining, reset_at: resetAt, detail: typeof entry.detail === 'string' ? entry.detail : null,
|
|
202
|
+
window_seconds: windowSeconds, pace, forecast: pace ? quotaForecast(pace, remaining) : null,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
const index = (match) => { const i = windows.findIndex(match); return i < 0 ? null : i; };
|
|
206
|
+
const labelHas = (needle) => (w) => w.label.toLowerCase().includes(needle);
|
|
207
|
+
const knownPace = (w) => w.window_seconds === FIVE_HOUR_WINDOW_S || w.window_seconds === WEEK_WINDOW_S || ['week', 'session', '5h'].some((n) => labelHas(n)(w));
|
|
208
|
+
return {
|
|
209
|
+
windows,
|
|
210
|
+
pace_window_index: index(labelHas('week')) ?? index(knownPace),
|
|
211
|
+
session_window_index: index(labelHas('session')) ?? index(labelHas('5h')),
|
|
212
|
+
weekly_window_index: index(labelHas('week')),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
68
215
|
export function displayName(pid) {
|
|
69
216
|
return PROVIDER_DISPLAY[pid] ?? pid.split('-').map((w) => (w ? w[0].toUpperCase() + w.slice(1) : w)).join(' ');
|
|
70
217
|
}
|
|
@@ -84,9 +231,7 @@ export function formatOllamaLabel(mid) {
|
|
|
84
231
|
}
|
|
85
232
|
/** Python `_get_label_for_model`: reuse a known label, else prettify the bare id. */
|
|
86
233
|
export function labelForModel(modelId, groups) {
|
|
87
|
-
|
|
88
|
-
if (lookup.startsWith('@') && lookup.includes(':'))
|
|
89
|
-
lookup = lookup.slice(lookup.indexOf(':') + 1);
|
|
234
|
+
const lookup = unqualifiedModelId(modelId);
|
|
90
235
|
const hasScheme = (s) => s.includes('://');
|
|
91
236
|
const norm = (s) => (s.includes('/') && !hasScheme(s) ? s.slice(s.indexOf('/') + 1) : s).replaceAll('-', '.').toLowerCase();
|
|
92
237
|
const target = norm(lookup);
|
|
@@ -155,12 +300,20 @@ export function deduplicateModelIds(groups) {
|
|
|
155
300
|
m.id = `@${groups[gi].provider_id}:${m.id}`;
|
|
156
301
|
}
|
|
157
302
|
}
|
|
303
|
+
/** Quota sources keep the first row per source id, ordered by provider id, account label, then source id (TAL-272). */
|
|
304
|
+
export function uniqueQuotaSources(sources) {
|
|
305
|
+
const cmp = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
306
|
+
return sources.filter((q, i) => sources.findIndex((o) => o.source_id === q.source_id) === i)
|
|
307
|
+
.sort((a, b) => cmp(a.provider_id, b.provider_id) || cmp(a.account_label, b.account_label) || cmp(a.source_id, b.source_id));
|
|
308
|
+
}
|
|
158
309
|
export class ProviderCatalog {
|
|
159
310
|
deps;
|
|
160
311
|
liveFailed = new Set();
|
|
161
312
|
liveIds = new Map();
|
|
162
313
|
liveInflight = new Map();
|
|
163
314
|
providersCache = new Map();
|
|
315
|
+
/** TAL-301: the last catalog served per profile home, for the sync session payloads' `model_option_id`. */
|
|
316
|
+
lastModels = new Map();
|
|
164
317
|
constructor(deps) {
|
|
165
318
|
this.deps = deps;
|
|
166
319
|
}
|
|
@@ -183,6 +336,29 @@ export class ProviderCatalog {
|
|
|
183
336
|
this.liveIds.delete(key);
|
|
184
337
|
}
|
|
185
338
|
this.providersCache.clear();
|
|
339
|
+
// The picker catalog changed: option ids rebuild on the next read rather than pairing against the old one.
|
|
340
|
+
if (profileHome)
|
|
341
|
+
this.lastModels.delete(profileHome);
|
|
342
|
+
else
|
|
343
|
+
this.lastModels.clear();
|
|
344
|
+
}
|
|
345
|
+
/** TAL-301: the entry id a stored `(model, provider)` pair selects in the last catalog built for this home; a cold home starts building one. */
|
|
346
|
+
modelOptionFor(profileHome, model, provider) {
|
|
347
|
+
const catalog = this.lastModels.get(profileHome);
|
|
348
|
+
if (!catalog) {
|
|
349
|
+
void this.warmModelOptions(profileHome);
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
return catalogOptionId(catalog, model, provider);
|
|
353
|
+
}
|
|
354
|
+
/** Builds the catalog `modelOptionFor` reads once per home; an unavailable catalog leaves every option id null. */
|
|
355
|
+
async warmModelOptions(profileHome) {
|
|
356
|
+
if (this.lastModels.has(profileHome))
|
|
357
|
+
return;
|
|
358
|
+
try {
|
|
359
|
+
await this.models(profileHome);
|
|
360
|
+
}
|
|
361
|
+
catch { /* fail closed: no option ids */ }
|
|
186
362
|
}
|
|
187
363
|
/**
|
|
188
364
|
* The process-environment value of `name` as a named profile may see it: values `loadStartupEnv` copied from the
|
|
@@ -306,6 +482,23 @@ export class ProviderCatalog {
|
|
|
306
482
|
this.liveInflight.set(key, run);
|
|
307
483
|
return run;
|
|
308
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* TAL-288: the model-provider plugins installed and enabled in this profile, as the sidecar reads them from the Agent.
|
|
487
|
+
* A failed lookup lists none, so every other provider stays usable; an id that cannot be a provider routing hint is dropped.
|
|
488
|
+
*/
|
|
489
|
+
async pluginProviders(profileHome) {
|
|
490
|
+
const sidecar = this.deps.sidecar();
|
|
491
|
+
if (!sidecar)
|
|
492
|
+
return [];
|
|
493
|
+
try {
|
|
494
|
+
const { providers } = await sidecar.call('plugins.providers', { profile_home: profileHome }, { timeoutMs: PLUGIN_LIST_TIMEOUT_MS });
|
|
495
|
+
return providers.filter((p, i, all) => /^[a-z0-9][a-z0-9._-]{0,63}$/.test(p.name) && all.findIndex((q) => q.name === p.name) === i);
|
|
496
|
+
}
|
|
497
|
+
catch (error) {
|
|
498
|
+
this.deps.log(`[catalog] plugin providers failed: ${str(error.message)}`);
|
|
499
|
+
return [];
|
|
500
|
+
}
|
|
501
|
+
}
|
|
309
502
|
/** Python `get_providers`. */
|
|
310
503
|
async providers(profileHome) {
|
|
311
504
|
const config = await this.deps.config.read(profileHome);
|
|
@@ -316,10 +509,16 @@ export class ProviderCatalog {
|
|
|
316
509
|
return structuredClone(hit.payload);
|
|
317
510
|
const active = activeProviderFromConfig(config);
|
|
318
511
|
const known = new Set([...Object.keys(PROVIDER_DISPLAY), ...Object.keys(PROVIDER_MODELS), ...OAUTH_PROVIDERS]);
|
|
512
|
+
// A plugin never stands in for a built-in provider, by id or alias (that would route to the built-in's billing); it
|
|
513
|
+
// does own a `providers.<id>` config entry.
|
|
514
|
+
const plugins = (await this.pluginProviders(profileHome)).filter((p) => !known.has(p.name) && !known.has(providerIdentity(p.name)));
|
|
515
|
+
const pluginIds = new Set(plugins.map((p) => p.name));
|
|
319
516
|
const providersCfg = dict(config.providers);
|
|
320
517
|
for (const key of Object.keys(providersCfg)) {
|
|
321
518
|
const identity = canonicaliseProviderId(key);
|
|
322
|
-
known.
|
|
519
|
+
const id = known.has(identity) ? identity : key;
|
|
520
|
+
if (!pluginIds.has(id))
|
|
521
|
+
known.add(id);
|
|
323
522
|
}
|
|
324
523
|
const rows = [];
|
|
325
524
|
for (const pid of [...known].sort()) {
|
|
@@ -364,6 +563,17 @@ export class ProviderCatalog {
|
|
|
364
563
|
models_total: modelsTotal,
|
|
365
564
|
});
|
|
366
565
|
}
|
|
566
|
+
// TAL-288: a plugin is selectable only once the Agent reports its setup ready; it never borrows a built-in's key.
|
|
567
|
+
for (const plugin of plugins) {
|
|
568
|
+
const ready = plugin.setup === 'ready';
|
|
569
|
+
const live = ready ? await this.liveModelIds(profileHome, plugin.name) : [];
|
|
570
|
+
rows.push({
|
|
571
|
+
id: plugin.name, display_name: plugin.display_name || plugin.name, has_key: ready,
|
|
572
|
+
configurable: false, is_oauth: false, is_plugin_provider: true, is_self_hosted: false, is_custom: false, key_source: ready ? 'plugin' : 'none',
|
|
573
|
+
base_url: null, auth_error: plugin.setup === 'ready' ? (live.length ? null : PLUGIN_NO_MODELS) : PLUGIN_SETUP_ERRORS[plugin.setup], env_var: null,
|
|
574
|
+
models: live.map((id) => ({ id, label: labelForModel(id, []) })), models_total: live.length,
|
|
575
|
+
});
|
|
576
|
+
}
|
|
367
577
|
for (const cp of customProviderEntries(config)) {
|
|
368
578
|
const name = str(cp.name).trim();
|
|
369
579
|
if (!name)
|
|
@@ -383,6 +593,8 @@ export class ProviderCatalog {
|
|
|
383
593
|
// Python `_provider_sort_key`: active first, then `custom:*`, then keyed providers, then the rest (alphabetical within).
|
|
384
594
|
const rank = (p) => (str(p.id) === active ? 0 : str(p.id).startsWith('custom:') ? 1 : p.has_key ? 2 : 3);
|
|
385
595
|
rows.sort((a, b) => rank(a) - rank(b) || (str(a.id) < str(b.id) ? -1 : str(a.id) > str(b.id) ? 1 : 0));
|
|
596
|
+
for (const row of rows)
|
|
597
|
+
row.models = stampModelEntries(row.models, str(row.id));
|
|
386
598
|
const payload = { providers: rows, active_provider: active };
|
|
387
599
|
this.providersCache.set(profileHome, { at: this.deps.now(), key: cacheKey, payload });
|
|
388
600
|
return structuredClone(payload);
|
|
@@ -431,12 +643,18 @@ export class ProviderCatalog {
|
|
|
431
643
|
if (canonical && this.providerHasKey(canonical, config, envValues, profileHome))
|
|
432
644
|
detected.add(canonical);
|
|
433
645
|
}
|
|
434
|
-
// Python: OAuth providers the Agent reports as logged in join the picker with their live catalog (#1567, #2545)
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
646
|
+
// Python: OAuth providers the Agent reports as logged in join the picker with their live catalog (#1567, #2545); so do
|
|
647
|
+
// ready plugin providers (TAL-288), under their own name.
|
|
648
|
+
const signedIn = new Set();
|
|
649
|
+
const pluginNames = new Map();
|
|
650
|
+
for (const row of (await this.providers(profileHome)).providers) {
|
|
651
|
+
if (row.has_key !== true || (row.is_oauth !== true && row.is_plugin_provider !== true))
|
|
652
|
+
continue;
|
|
653
|
+
signedIn.add(str(row.id));
|
|
654
|
+
if (row.is_plugin_provider === true)
|
|
655
|
+
pluginNames.set(str(row.id), str(row.display_name) || str(row.id));
|
|
656
|
+
}
|
|
657
|
+
for (const pid of signedIn)
|
|
440
658
|
detected.add(pid);
|
|
441
659
|
const fallbackCfg = Array.isArray(config.fallback_providers) ? config.fallback_providers.filter(isDict) : [];
|
|
442
660
|
for (const entry of fallbackCfg) {
|
|
@@ -469,7 +687,7 @@ export class ProviderCatalog {
|
|
|
469
687
|
detected.add(named?.[0] ?? active ?? 'custom');
|
|
470
688
|
}
|
|
471
689
|
const groups = [];
|
|
472
|
-
for (const pid of [...detected].map((p) => (p.startsWith('custom') ? p : canonicaliseProviderId(p) || p)).filter((v, i, a) => v && a.indexOf(v) === i).sort()) {
|
|
690
|
+
for (const pid of [...detected].map((p) => (p.startsWith('custom') || pluginNames.has(p) ? p : canonicaliseProviderId(p) || p)).filter((v, i, a) => v && a.indexOf(v) === i).sort()) {
|
|
473
691
|
if (pid.startsWith('custom:')) {
|
|
474
692
|
const g = namedCustom.get(pid);
|
|
475
693
|
const models = [...(g?.models ?? [])];
|
|
@@ -490,7 +708,7 @@ export class ProviderCatalog {
|
|
|
490
708
|
let raw = [];
|
|
491
709
|
if ('models' in providerCfg && providerCfg.models_discovered !== true)
|
|
492
710
|
raw = configuredModelOptions(providerCfg.models);
|
|
493
|
-
if (!raw.length && (this.providerHasKey(pid, config, envValues, profileHome) ||
|
|
711
|
+
if (!raw.length && (this.providerHasKey(pid, config, envValues, profileHome) || signedIn.has(pid))) {
|
|
494
712
|
const live = await this.liveModelIds(profileHome, pid);
|
|
495
713
|
if (live.length)
|
|
496
714
|
raw = live.map((id) => ({ id, label: pid === 'nous' ? `${formatOllamaLabel(id.includes('/') ? id.slice(id.indexOf('/') + 1) : id)} (via Nous)` : labelForModel(id, []) }));
|
|
@@ -504,7 +722,7 @@ export class ProviderCatalog {
|
|
|
504
722
|
if (!raw.some((m) => m.id === id))
|
|
505
723
|
raw.push({ id, label: labelForModel(id, groups) });
|
|
506
724
|
if (raw.length)
|
|
507
|
-
groups.push({ provider: displayName(pid), provider_id: pid, models: applyProviderPrefix(raw, pid, active) });
|
|
725
|
+
groups.push({ provider: pluginNames.get(pid) ?? displayName(pid), provider_id: pid, models: applyProviderPrefix(raw, pid, active) });
|
|
508
726
|
}
|
|
509
727
|
if (defaultModel) {
|
|
510
728
|
const all = new Set(groups.flatMap((g) => g.models.map((m) => m.id)));
|
|
@@ -550,10 +768,20 @@ export class ProviderCatalog {
|
|
|
550
768
|
for (const [k, v] of Object.entries(rawAliases))
|
|
551
769
|
if (k && v)
|
|
552
770
|
aliases[k.trim()] = str(v).trim();
|
|
771
|
+
const [defaultBare, defaultProvider] = parseProviderQualifiedModel(defaultModel) ?? [defaultModel, active];
|
|
772
|
+
const defaults = { active_provider: active, default_model: defaultModel, default_provider_id: defaultProvider, default_bare_id: defaultBare };
|
|
553
773
|
if (!kept.length && defaultModel) {
|
|
554
|
-
|
|
774
|
+
const providerId = active ?? 'default';
|
|
775
|
+
return this.remember(profileHome, { ...defaults, groups: [{ provider: 'Default', provider_id: providerId, models: stampModelEntries([{ id: defaultModel, label: labelForModel(defaultModel, []) }], providerId) }], aliases: {}, configured_model_badges: {} });
|
|
555
776
|
}
|
|
556
|
-
|
|
777
|
+
const stamped = kept.map((g) => ({ ...g, models: stampModelEntries(g.models, g.provider_id), ...(g.extra_models ? { extra_models: stampModelEntries(g.extra_models, g.provider_id) } : {}) }));
|
|
778
|
+
return this.remember(profileHome, { ...defaults, groups: stamped, aliases, configured_model_badges: this.badges(kept, active, defaultModel, fallbackCfg) });
|
|
779
|
+
}
|
|
780
|
+
/** Stamps the default's entry id and keeps the catalog for `modelOptionFor`. */
|
|
781
|
+
remember(profileHome, catalog) {
|
|
782
|
+
catalog.default_option_id = catalogOptionId(catalog, catalog.default_bare_id ?? null, catalog.default_provider_id ?? null);
|
|
783
|
+
this.lastModels.set(profileHome, catalog);
|
|
784
|
+
return structuredClone(catalog);
|
|
557
785
|
}
|
|
558
786
|
/** Python `_configured_model_badges_from_static_catalog`: which picker rows are the main/fallback selections. */
|
|
559
787
|
badges(groups, active, defaultModel, fallback) {
|
|
@@ -609,7 +837,7 @@ export class ProviderCatalog {
|
|
|
609
837
|
if (provider !== 'nous' && ids.length > MODEL_PICKER_OVERFLOW_THRESHOLD)
|
|
610
838
|
ids = ids.slice(0, MODEL_PICKER_VISIBLE_TARGET);
|
|
611
839
|
const annotateFastTier = isOpenAiFamilyProvider(provider);
|
|
612
|
-
const models = ids.filter(Boolean).map((id) => ({ id, label: labelForModel(id, []), ...(annotateFastTier ? { supports_fast_tier: mainModelSupportsServiceTier(id, provider) } : {}) }));
|
|
840
|
+
const models = stampModelEntries(ids.filter(Boolean).map((id) => ({ id, label: labelForModel(id, []), ...(annotateFastTier ? { supports_fast_tier: mainModelSupportsServiceTier(id, provider) } : {}) })), provider);
|
|
613
841
|
return { provider, source, models, count: models.length };
|
|
614
842
|
}
|
|
615
843
|
/**
|
|
@@ -621,7 +849,7 @@ export class ProviderCatalog {
|
|
|
621
849
|
const config = await this.deps.config.read(profileHome);
|
|
622
850
|
const section = modelSection(config);
|
|
623
851
|
const pid = canonicaliseProviderId(provider ?? section.provider) || null;
|
|
624
|
-
const bare = model
|
|
852
|
+
const bare = unqualifiedModelId(model);
|
|
625
853
|
const positive = (v) => { const n = Math.trunc(Number(v)); return Number.isFinite(n) && n > 0 ? n : null; };
|
|
626
854
|
const fromModels = (models) => {
|
|
627
855
|
if (isDict(models)) {
|
|
@@ -644,7 +872,7 @@ export class ProviderCatalog {
|
|
|
644
872
|
let baseUrl = '';
|
|
645
873
|
let configContextLength = null;
|
|
646
874
|
const sectionModel = str(section.default || (typeof config.model === 'string' ? config.model : '')).trim();
|
|
647
|
-
if (sectionModel && [model, bare].includes(sectionModel
|
|
875
|
+
if (sectionModel && [model, bare].includes(unqualifiedModelId(sectionModel)))
|
|
648
876
|
configContextLength = positive(section.context_length);
|
|
649
877
|
if (!pid || canonicaliseProviderId(section.provider) === pid)
|
|
650
878
|
baseUrl = str(section.base_url).trim();
|
|
@@ -683,10 +911,12 @@ export class ProviderCatalog {
|
|
|
683
911
|
/** Python `get_provider_quota`. */
|
|
684
912
|
accountUsageCache = new Map();
|
|
685
913
|
async quota(profileHome, providerRaw, opts = {}) {
|
|
914
|
+
const at = opts.at ?? this.deps.now();
|
|
915
|
+
const computed_at = isoAt(at);
|
|
686
916
|
const config = await this.deps.config.read(profileHome);
|
|
687
917
|
const provider = (providerRaw ?? activeProviderFromConfig(config) ?? '').trim().toLowerCase();
|
|
688
918
|
if (!provider)
|
|
689
|
-
return { ok: false, provider: null, display_name: null, supported: false, status: 'unavailable', quota: null, message: 'No active provider is configured.' };
|
|
919
|
+
return { computed_at, ok: false, provider: null, display_name: null, supported: false, status: 'unavailable', quota: null, message: 'No active provider is configured.' };
|
|
690
920
|
const name = displayName(provider);
|
|
691
921
|
if (ACCOUNT_USAGE_PROVIDERS.has(provider)) {
|
|
692
922
|
const sidecar = this.deps.sidecar();
|
|
@@ -707,22 +937,25 @@ export class ProviderCatalog {
|
|
|
707
937
|
}
|
|
708
938
|
this.accountUsageCache.set(cacheKey, { at: this.deps.now(), limits });
|
|
709
939
|
}
|
|
940
|
+
// The cache keeps the Agent's raw windows; pace is recomputed as of every response.
|
|
941
|
+
if (limits)
|
|
942
|
+
limits = { ...limits, ...normalizeQuotaWindows(limits.windows, at), fetched_at: isoUtc(limits.fetched_at) };
|
|
710
943
|
if (limits?.available)
|
|
711
|
-
return { ok: true, provider, display_name: name, supported: true, status: limits.stale ? 'stale' : 'available', label: limits.title, quota: null, account_limits: limits, message: limits.stale ? `${name} refresh failed; showing last-known account limits.` : `${name} account limits loaded.` };
|
|
944
|
+
return { computed_at, ok: true, provider, display_name: name, supported: true, status: limits.stale ? 'stale' : 'available', label: limits.title, quota: null, account_limits: limits, message: limits.stale ? `${name} refresh failed; showing last-known account limits.` : `${name} account limits loaded.` };
|
|
712
945
|
const reason = str(limits?.unavailable_reason).trim();
|
|
713
|
-
return { ok: false, provider, display_name: name, supported: true, status: 'unavailable', quota: null, account_limits: limits, message: reason ? `${name} account limits are unavailable. ${reason}` : `${name} account limits are unavailable. Confirm provider authentication and try again.` };
|
|
946
|
+
return { computed_at, ok: false, provider, display_name: name, supported: true, status: 'unavailable', quota: null, account_limits: limits, message: reason ? `${name} account limits are unavailable. ${reason}` : `${name} account limits are unavailable. Confirm provider authentication and try again.` };
|
|
714
947
|
}
|
|
715
948
|
if (provider === 'openrouter') {
|
|
716
949
|
const apiKey = this.apiKeyFor('openrouter', profileHome, config);
|
|
717
950
|
if (!apiKey)
|
|
718
|
-
return { ok: false, provider, display_name: name, supported: true, status: 'no_key', quota: null, message: 'OpenRouter quota status needs an OPENROUTER_API_KEY configured on the server.' };
|
|
951
|
+
return { computed_at, ok: false, provider, display_name: name, supported: true, status: 'no_key', quota: null, message: 'OpenRouter quota status needs an OPENROUTER_API_KEY configured on the server.' };
|
|
719
952
|
const info = await this.fetchOpenRouterKey(apiKey);
|
|
720
953
|
if (info.kind === 'ok')
|
|
721
|
-
return { ok: true, provider, display_name: name, supported: true, status: 'available', label: 'OpenRouter credits', quota: info.quota, message: 'OpenRouter quota status loaded.' };
|
|
954
|
+
return { computed_at, ok: true, provider, display_name: name, supported: true, status: 'available', label: 'OpenRouter credits', quota: info.quota, message: 'OpenRouter quota status loaded.' };
|
|
722
955
|
const status = info.kind === 'invalid_key' ? 'invalid_key' : 'unavailable';
|
|
723
|
-
return { ok: false, provider, display_name: name, supported: true, status, quota: null, message: status === 'invalid_key' ? 'OpenRouter rejected the configured API key.' : 'OpenRouter quota status is temporarily unavailable.' };
|
|
956
|
+
return { computed_at, ok: false, provider, display_name: name, supported: true, status, quota: null, message: status === 'invalid_key' ? 'OpenRouter rejected the configured API key.' : 'OpenRouter quota status is temporarily unavailable.' };
|
|
724
957
|
}
|
|
725
|
-
return { ok: false, provider, display_name: name, supported: false, status: 'unsupported', quota: null, message: `No verified server-side quota or balance endpoint is available for ${name}.` };
|
|
958
|
+
return { computed_at, ok: false, provider, display_name: name, supported: false, status: 'unsupported', quota: null, message: `No verified server-side quota or balance endpoint is available for ${name}.` };
|
|
726
959
|
}
|
|
727
960
|
async fetchOpenRouterKey(apiKey) {
|
|
728
961
|
const f = this.deps.fetch ?? fetch;
|
|
@@ -776,28 +1009,32 @@ export class ProviderCatalog {
|
|
|
776
1009
|
quotaProfileScopeId(profile) {
|
|
777
1010
|
return `qscope_${createHash('sha256').update(`${this.quotaServerScopeId()}\0${profile}`).digest('hex').slice(0, 32)}`;
|
|
778
1011
|
}
|
|
779
|
-
/**
|
|
1012
|
+
/**
|
|
1013
|
+
* Python `get_provider_quotas`: one source per keyed provider, in the stable-identity envelope the iOS widget persists.
|
|
1014
|
+
* Each source id appears once (two custom providers can share a slug), ordered by provider, account label, then source id.
|
|
1015
|
+
*/
|
|
780
1016
|
async quotas(profileHome, profile, opts = {}) {
|
|
1017
|
+
const at = this.deps.now();
|
|
781
1018
|
const status = await this.providers(profileHome);
|
|
782
1019
|
const active = status.active_provider;
|
|
783
1020
|
const scopeId = this.quotaProfileScopeId(profile);
|
|
784
1021
|
// Python `_quota_source_id(profile, provider, "provider")`: the single-credential descriptor per provider.
|
|
785
1022
|
const sourceId = (pid) => `qsrc_${createHash('sha256').update(`${scopeId}\0${pid}\0provider`).digest('hex').slice(0, 32)}`;
|
|
786
|
-
let descriptors = status.providers.filter((p) => p.has_key || p.is_custom).map((p) => ({ source_id: sourceId(str(p.id)), provider_id: str(p.id), provider_label: str(p.display_name) || str(p.id) }));
|
|
1023
|
+
let descriptors = uniqueQuotaSources(status.providers.filter((p) => p.has_key || p.is_custom).map((p) => ({ source_id: sourceId(str(p.id)), provider_id: str(p.id), provider_label: str(p.display_name) || str(p.id), account_label: str(p.display_name) || str(p.id) })));
|
|
787
1024
|
const requested = str(opts.sourceId).trim() || null;
|
|
788
1025
|
if (requested)
|
|
789
1026
|
descriptors = descriptors.filter((d) => d.source_id === requested);
|
|
790
1027
|
const sources = await Promise.all(descriptors.map(async (d) => {
|
|
791
|
-
const q = await this.quota(profileHome, d.provider_id, { refresh: opts.refresh ?? false });
|
|
1028
|
+
const q = await this.quota(profileHome, d.provider_id, { refresh: opts.refresh ?? false, at });
|
|
792
1029
|
const limits = dict(q.account_limits);
|
|
793
1030
|
return {
|
|
794
|
-
source_id: d.source_id, provider_id: d.provider_id, provider_label: d.provider_label, account_label: d.
|
|
1031
|
+
source_id: d.source_id, provider_id: d.provider_id, provider_label: d.provider_label, account_label: d.account_label,
|
|
795
1032
|
is_active_provider: d.provider_id === active, supported: q.supported === true, status: str(limits.status) || str(q.status) || 'unavailable',
|
|
796
|
-
plan: limits.plan ?? null, windows: limits.windows ?? [], quota: q.quota ?? null, balances: q.balances ?? [], details: limits.details ?? [],
|
|
1033
|
+
plan: limits.plan ?? null, windows: limits.windows ?? [], pace_window_index: limits.pace_window_index ?? null, session_window_index: limits.session_window_index ?? null, weekly_window_index: limits.weekly_window_index ?? null, quota: q.quota ?? null, balances: q.balances ?? [], details: limits.details ?? [],
|
|
797
1034
|
unavailable_reason: limits.unavailable_reason ?? null, retry_after: limits.retry_after ?? null, fetched_at: limits.fetched_at ?? null, message: q.message ?? null,
|
|
798
1035
|
};
|
|
799
1036
|
}));
|
|
800
|
-
return { version: 1, scope_id: scopeId, profile_id: profile, active_provider: active, requested_source_id: requested, missing_source: Boolean(requested && !descriptors.length), sources };
|
|
1037
|
+
return { version: 1, computed_at: isoAt(at), scope_id: scopeId, profile_id: profile, active_provider: active, requested_source_id: requested, missing_source: Boolean(requested && !descriptors.length), sources };
|
|
801
1038
|
}
|
|
802
1039
|
/** Python `get_provider_cost_history` (OpenRouter only; daily snapshots under `<home>/cost-snapshots`). */
|
|
803
1040
|
async costHistory(profileHome, providerRaw, days) {
|