@maudecode/talaria-web 1.16.1 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_release.json +8 -8
- package/dist/api/auth-raw.d.ts +1 -1
- package/dist/api/auth-raw.js +4 -4
- package/dist/api/auth-raw.js.map +1 -1
- package/dist/api/automation-raw.d.ts +6 -0
- package/dist/api/automation-raw.js +59 -9
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +163 -10
- package/dist/api/automation-router.js +25 -8
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +700 -15
- package/dist/api/chat-router.js +74 -55
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +47 -2
- package/dist/api/git-router.js +31 -22
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +14 -0
- package/dist/api/raw-routes.js +277 -36
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +10 -0
- package/dist/api/router.js +10 -8
- package/dist/api/router.js.map +1 -1
- package/dist/api/sessions-router.d.ts +1710 -73
- package/dist/api/sessions-router.js +164 -10
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +132 -2
- package/dist/api/settings-router.js +15 -5
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +16 -3
- package/dist/api/sse-routes.js +194 -67
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.js +12 -25
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +425 -19
- package/dist/api/tools-router.js +157 -26
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.d.ts +0 -9377
- package/dist/app.js +42 -17
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +8 -2
- package/dist/auth/gate.js.map +1 -1
- package/dist/auth/oidc.d.ts +5 -2
- package/dist/auth/oidc.js +8 -7
- package/dist/auth/oidc.js.map +1 -1
- package/dist/bin/talaria-web.js +1 -1
- package/dist/bin/talaria-web.js.map +1 -1
- package/dist/cli/dotenv.js +1 -0
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/config/agent-config.d.ts +2 -0
- package/dist/config/agent-config.js +12 -2
- package/dist/config/agent-config.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/http/context.d.ts +20 -3
- package/dist/http/context.js +41 -8
- package/dist/http/context.js.map +1 -1
- package/dist/http/csp.d.ts +2 -1
- package/dist/http/csp.js +3 -2
- package/dist/http/csp.js.map +1 -1
- package/dist/onboarding.js +4 -0
- package/dist/onboarding.js.map +1 -1
- package/dist/profiles/profiles.d.ts +10 -0
- package/dist/profiles/profiles.js +40 -2
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/providers/catalog.d.ts +101 -8
- package/dist/providers/catalog.js +463 -123
- package/dist/providers/catalog.js.map +1 -1
- package/dist/raster-image.d.ts +7 -0
- package/dist/raster-image.js +267 -0
- package/dist/raster-image.js.map +1 -0
- package/dist/redact.d.ts +1 -0
- package/dist/redact.js +354 -44
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +111 -27
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +5 -0
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +2 -0
- package/dist/sessions/anchor.js +8 -3
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-tasks.d.ts +2 -9
- package/dist/sessions/background-tasks.js +2 -12
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/claude-code.d.ts +19 -0
- package/dist/sessions/claude-code.js +250 -0
- package/dist/sessions/claude-code.js.map +1 -0
- package/dist/sessions/cli-sessions.d.ts +15 -4
- package/dist/sessions/cli-sessions.js +120 -29
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +61 -9
- package/dist/sessions/completions.js +282 -34
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +14 -1
- package/dist/sessions/compress.js +52 -11
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/export.d.ts +5 -0
- package/dist/sessions/export.js +30 -0
- package/dist/sessions/export.js.map +1 -1
- package/dist/sessions/gateway-watcher.d.ts +7 -3
- package/dist/sessions/gateway-watcher.js +31 -19
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/handoff.d.ts +32 -0
- package/dist/sessions/handoff.js +114 -0
- package/dist/sessions/handoff.js.map +1 -0
- package/dist/sessions/journal.d.ts +8 -0
- package/dist/sessions/journal.js +44 -10
- package/dist/sessions/journal.js.map +1 -1
- package/dist/sessions/list.d.ts +13 -3
- package/dist/sessions/list.js +46 -15
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +53 -5
- package/dist/sessions/merge.js +219 -23
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/recovery.d.ts +22 -0
- package/dist/sessions/recovery.js +506 -0
- package/dist/sessions/recovery.js.map +1 -0
- package/dist/sessions/relay.d.ts +21 -2
- package/dist/sessions/relay.js +156 -11
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +152 -8
- package/dist/sessions/service.js +640 -72
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +17 -1
- package/dist/sessions/session.js +63 -4
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/state-db-worker.d.ts +1 -0
- package/dist/sessions/state-db-worker.js +33 -0
- package/dist/sessions/state-db-worker.js.map +1 -0
- package/dist/sessions/state-db.d.ts +87 -4
- package/dist/sessions/state-db.js +417 -8
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/store.d.ts +7 -0
- package/dist/sessions/store.js +36 -22
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +10 -0
- package/dist/sessions/streams.js +14 -3
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/titles.d.ts +2 -0
- package/dist/sessions/titles.js +4 -0
- package/dist/sessions/titles.js.map +1 -1
- package/dist/sessions/todo.d.ts +6 -1
- package/dist/sessions/todo.js +11 -4
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +12 -1
- package/dist/sessions/tool-display.js +50 -1
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn-context.d.ts +1 -1
- package/dist/sessions/turn-context.js +11 -7
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +67 -11
- package/dist/sessions/turn.js +413 -111
- package/dist/sessions/turn.js.map +1 -1
- package/dist/sessions/wakeup-pause.d.ts +59 -0
- package/dist/sessions/wakeup-pause.js +181 -0
- package/dist/sessions/wakeup-pause.js.map +1 -0
- package/dist/settings.d.ts +20 -2
- package/dist/settings.js +45 -9
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/fake.d.ts +4 -4
- package/dist/sidecar/fake.js +5 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/spa.js +2 -1
- package/dist/spa.js.map +1 -1
- package/dist/startup.d.ts +13 -5
- package/dist/startup.js +48 -0
- package/dist/startup.js.map +1 -1
- package/dist/test/harness.js +2 -0
- package/dist/test/harness.js.map +1 -1
- package/dist/test/ts-worker-hooks.d.ts +1 -0
- package/dist/test/ts-worker-hooks.js +24 -0
- package/dist/test/ts-worker-hooks.js.map +1 -0
- package/dist/text/diff.d.ts +9 -14
- package/dist/text/diff.js +74 -108
- package/dist/text/diff.js.map +1 -1
- package/dist/tools/crons.js +45 -8
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/dashboard-plugins.d.ts +53 -0
- package/dist/tools/dashboard-plugins.js +188 -0
- package/dist/tools/dashboard-plugins.js.map +1 -0
- package/dist/tools/extensions.d.ts +13 -1
- package/dist/tools/extensions.js +132 -60
- package/dist/tools/extensions.js.map +1 -1
- package/dist/tools/health.d.ts +32 -0
- package/dist/tools/health.js +111 -19
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/insights.d.ts +8 -2
- package/dist/tools/insights.js +18 -2
- package/dist/tools/insights.js.map +1 -1
- package/dist/tools/kanban.d.ts +41 -1
- package/dist/tools/kanban.js +113 -2
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp.d.ts +15 -1
- package/dist/tools/mcp.js +99 -5
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/project-os.d.ts +11 -0
- package/dist/tools/project-os.js +267 -0
- package/dist/tools/project-os.js.map +1 -0
- package/dist/tools/skills.d.ts +5 -1
- package/dist/tools/skills.js +5 -3
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/terminal.d.ts +1 -0
- package/dist/tools/terminal.js +1 -1
- package/dist/tools/terminal.js.map +1 -1
- package/dist/tools/updates.d.ts +33 -8
- package/dist/tools/updates.js +236 -57
- package/dist/tools/updates.js.map +1 -1
- package/dist/tools/wiki.d.ts +68 -0
- package/dist/tools/wiki.js +413 -0
- package/dist/tools/wiki.js.map +1 -0
- package/dist/workspace/escape.d.ts +61 -0
- package/dist/workspace/escape.js +149 -0
- package/dist/workspace/escape.js.map +1 -0
- package/dist/workspace/extract.d.ts +22 -0
- package/dist/workspace/extract.js +308 -0
- package/dist/workspace/extract.js.map +1 -0
- package/dist/workspace/fs.d.ts +19 -3
- package/dist/workspace/fs.js +96 -23
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/git.d.ts +18 -0
- package/dist/workspace/git.js +38 -25
- package/dist/workspace/git.js.map +1 -1
- package/dist/workspace/media.d.ts +4 -4
- package/dist/workspace/media.js +18 -45
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/preview.d.ts +28 -0
- package/dist/workspace/preview.js +110 -0
- package/dist/workspace/preview.js.map +1 -0
- package/dist/workspace/rollback.d.ts +36 -21
- package/dist/workspace/rollback.js +179 -270
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/unzip.js +4 -1
- package/dist/workspace/unzip.js.map +1 -1
- package/dist/workspace/upload.d.ts +9 -4
- package/dist/workspace/upload.js +9 -3
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/worktrees.d.ts +2 -1
- package/dist/workspace/worktrees.js +14 -15
- package/dist/workspace/worktrees.js.map +1 -1
- package/package.json +4 -2
- package/sidecar/agent_dependency.json +4 -4
- package/sidecar/scripts/replay_sidecar.py +25 -1
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/__main__.py +7 -1
- package/sidecar/talaria_sidecar/home.py +52 -2
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +39 -5
- package/sidecar/talaria_sidecar/methods/chat.py +431 -43
- package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
- package/sidecar/talaria_sidecar/methods/commands.py +96 -2
- package/sidecar/talaria_sidecar/methods/cron.py +39 -8
- package/sidecar/talaria_sidecar/methods/gateway.py +32 -15
- package/sidecar/talaria_sidecar/methods/kanban.py +140 -19
- package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
- package/sidecar/talaria_sidecar/methods/process.py +115 -2
- package/sidecar/talaria_sidecar/methods/profiles.py +84 -8
- package/sidecar/talaria_sidecar/methods/providers.py +27 -8
- package/sidecar/talaria_sidecar/methods/runtime.py +3 -0
- package/sidecar/talaria_sidecar/methods/state_db.py +39 -5
- package/sidecar/talaria_sidecar/methods/text.py +17 -1
- package/sidecar/talaria_sidecar/methods/usage.py +257 -4
- package/sidecar/talaria_sidecar/runtime.py +17 -1
- package/static/dist/FILES.txt +127 -125
- package/static/dist/assets/AppShell-g3bkgnvt.js +1 -0
- package/static/dist/assets/ChatPage-oo7bdan6.js +25 -0
- package/static/dist/assets/Dialog-g355qxhp.js +1 -0
- package/static/dist/assets/ExtensionRoute-i2y9fvjm.js +1 -0
- package/static/dist/assets/HubRoute-lmkrbw47.js +2 -0
- package/static/dist/assets/{Markdown-jqrx5es0.js → Markdown-j4kut4j2.js} +125 -125
- package/static/dist/assets/RightPanel-ohlsdzfl.js +1 -0
- package/static/dist/assets/Select-kddq75qc.js +1 -0
- package/static/dist/assets/SessionListPanel-lu3oy0hw.js +1 -0
- package/static/dist/assets/SettingsLayout-o9bv4mgb.js +1 -0
- package/static/dist/assets/States-eq6fe29m.js +1 -0
- package/static/dist/assets/Toaster-pc247u9f.js +1 -0
- package/static/dist/assets/_app-f8n1i0m1.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-gfbzpoou.js +1 -0
- package/static/dist/assets/_app.index-bzzv80hk.js +1 -0
- package/static/dist/assets/_app.insights-dzixbryi.js +1 -0
- package/static/dist/assets/_app.kanban-c6hep2us.js +1 -0
- package/static/dist/assets/_app.logs-i69qds98.js +1 -0
- package/static/dist/assets/_app.memory-kl4vf0gd.js +1 -0
- package/static/dist/assets/_app.profiles-b8zinmyp.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-hh27wwu2.js → _app.session._sessionId-fn1bhde6.js} +1 -1
- package/static/dist/assets/_app.settings-cg8plwmf.js +1 -0
- package/static/dist/assets/_app.settings._section-bkwbi9zn.js +3 -0
- package/static/dist/assets/_app.skills-cs47sbvs.js +1 -0
- package/static/dist/assets/_app.tasks-dwvk64tc.js +1 -0
- package/static/dist/assets/_app.todos-c8xjm8p3.js +1 -0
- package/static/dist/assets/_app.workspaces-ehvd1gds.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-oity9y4o.js → abnfDiagram-VCTEODGH-c8kdixke.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-6crvnylg.js +1 -0
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-ceaepnyr.js → architectureDiagram-5GKGNRK7-cku06x1p.js} +1 -1
- package/static/dist/assets/{back-eu64w89w.js → back-h7aun7ew.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-n79st4pj.js → blockDiagram-I7D4REHJ-jzthp1wa.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-mi73akzk.js → c4Diagram-7LVT6UL2-mwr67mt8.js} +1 -1
- package/static/dist/assets/{cancel-mzvkdjg8.js → cancel-fhi0vcnu.js} +1 -1
- package/static/dist/assets/channel-b2zo73z1.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-laat0g1q.js → chunk-4HAMMTFA-gpq1y228.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-0psy1tr2.js → chunk-75Z2AOVW-ktje58c4.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-lw8uox8x.js → chunk-DU6HZSFF-ofajdixh.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-erassib3.js → chunk-F27PBJKO-cmev85ti.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-fz7rx619.js → chunk-GMAD6QVW-htjgt22y.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-gdb0epb2.js → chunk-GVQU2GXP-qndvoxl7.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-ea8t26qw.js → chunk-IMKFNOWR-e5bkd5q6.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-mb1gu9kz.js → chunk-L3NEJ4N5-mj1155r6.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-eovmccvy.js → chunk-OSK3NFVY-e7gkikcw.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-bo55zjo5.js → chunk-P2QGCYS3-f7t54xfm.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-ja7ohe4h.js → chunk-POPQ4Y6H-i927v9oa.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-e30g9nus.js → chunk-PWAF6VOD-m84lmnyt.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-gbb798f7.js → chunk-SHT3W25Y-mi0tlcu9.js} +1 -1
- package/static/dist/assets/{chunk-SVP7TREG-h2iw8urm.js → chunk-SVP7TREG-dnau702j.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-fd2cottz.js → chunk-TICWLB2K-edem1gkg.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-oe99st8x.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-oe99st8x.js +1 -0
- package/static/dist/assets/{copied-h65fc3cx.js → copied-hcplv46p.js} +1 -1
- package/static/dist/assets/copy-magtofyp.js +1 -0
- package/static/dist/assets/{cynefin-OW5HDTMX-lbltyl5j.js → cynefin-OW5HDTMX-siqlulkl.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-lxhsqq4a.js → cynefinDiagram-5FMLGOSQ-i648tah9.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-gn4nnaln.js → dagre-GXQ25YYZ-mwn6uc17.js} +1 -1
- package/static/dist/assets/{diagram-S7CK7UJ4-pa3ij6q7.js → diagram-S7CK7UJ4-l8abxaes.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-zbipyz57.js → diagram-UQ7AKVKN-mekq7zgq.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-d1kbpzgf.js → diagram-VSXAHHWV-fnky6lvc.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-i3ty14xl.js → diagram-VX7I27RA-xe6r5qfw.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-m8xefqa7.js → diagram-Z3DM3KII-nq07dg7k.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-nz7wj05l.js → ebnfDiagram-PWID7BFC-c62ipm3g.js} +1 -1
- package/static/dist/assets/endpoints-klbxod4t.js +64 -0
- package/static/dist/assets/{erDiagram-RLTQ6QDP-fa41ib83.js → erDiagram-RLTQ6QDP-h39kmnzy.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-obfede4u.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-kdpsp1je.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-n7zq01qu.js → ganttDiagram-EL5Y4UJY-ngbsyp37.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-c89emb07.js → gitGraph-4MIJSDKK-fr2i7caa.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-cz7cgr6w.js → gitGraphDiagram-WWUBYQGX-eravdti4.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-d9bapmni.js → highlighted-body-KPVGNVTW-jwpop9p8.js} +1 -1
- package/static/dist/assets/host-i828xuo7.js +1 -0
- package/static/dist/assets/index-eh8zilnv.css +2 -0
- package/static/dist/assets/index-r648f4o1.js +11 -0
- package/static/dist/assets/{info-A6RAGUB7-ndddhhhh.js → info-A6RAGUB7-h11x0dxo.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-ccxigcpf.js → infoDiagram-27XIBGKW-dfh47dw9.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-le0z9vtc.js → ishikawaDiagram-5VMMS53U-i6ypq351.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-ivsmb26o.js → journeyDiagram-3NMN7TZE-lduf1z95.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-h6n2awt0.js → kanban-definition-UXKFOSKX-e18bu4pg.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-e1y4t2i9.js +1 -0
- package/static/dist/assets/{line-dmzlfe0u.js → line-meizqsvn.js} +1 -1
- package/static/dist/assets/link-oot2yn73.js +1 -0
- package/static/dist/assets/login-gu28l9ou.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-mtwrj8fn.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-gwyd5bnq.js → mermaid-parser.core-ntne45i9.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-l68gg5h7.js → mindmap-definition-YA3MSWOX-27b26eok.js} +1 -1
- package/static/dist/assets/onboarding-lkphzu1s.js +1 -0
- package/static/dist/assets/onboarding_model_label-ftpjdwqk.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-gpv06065.js → packet-AYTQ26CC-l6jdka8p.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-e52vs23u.js → pegDiagram-XKGWAZYB-g1er3bxj.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-l6m7nz5s.js → pie-WAS4IAKB-i0ylcrt9.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-b4is36bq.js → pieDiagram-E7YTZNPT-fbz1e55z.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-m8vt2788.js → quadrantDiagram-AXDQQJYC-hhue7d8o.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-nxbrhiov.js → radar-RG4KPBEZ-f9b70aa4.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-222mu9hi.js → railroad-74A4TZTK-lgsuoeda.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nf9d6pdx.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-f7ummkt5.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-oczq5tqs.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-o8lldfzv.js → railroadDiagram-O6MQD6OU-eqpy9fnz.js} +1 -1
- package/static/dist/assets/refresh-abtu93ke.js +1 -0
- package/static/dist/assets/refresh-cw-hlwb02qv.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-ovyq38kv.js → requirementDiagram-BXWQKSXE-ogf6puhi.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-ou7lznor.js → sankeyDiagram-P5KCCOFB-fqb8xcjf.js} +1 -1
- package/static/dist/assets/{saved-bazmcup9.js → saved-girnabkf.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-ovckdzf2.js → sequenceDiagram-WJ2MYXX4-dlcz6qjz.js} +1 -1
- package/static/dist/assets/{settings_section_extensions_title-ertwwhlx.js → settings_section_extensions_title-h14cwk6f.js} +1 -1
- package/static/dist/assets/share._token-kl0r7ido.js +2 -0
- package/static/dist/assets/sliders-horizontal-n1zm34qq.js +1 -0
- package/static/dist/assets/sse-iwku0sjo.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-fcrexkkv.js → stateDiagram-D77RDMKH-fyoznpcs.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-ixhx8r46.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-f7usu8fw.js → swimlanes-42K2YHIH-oefldhfy.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-h9ersk2e.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-gp1hvz9f.js → timeline-definition-24CTP7MA-b1vl2zil.js} +1 -1
- package/static/dist/assets/todoStore-jjr5yr78.js +1 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-gb9gf11u.js → treeView-Q6P3EWNA-f7hcci5o.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-nuvfnvvi.js → treemap-WGGIJYW6-nl85071a.js} +1 -1
- package/static/dist/assets/units-kgxzxfhi.js +1 -0
- package/static/dist/assets/{untitled-htelhc68.js → untitled-cikfjntn.js} +1 -1
- package/static/dist/assets/{useForm-h2t0u14e.js → useForm-kqoqg0k9.js} +1 -1
- package/static/dist/assets/useLocale-o59tbiea.js +1 -0
- package/static/dist/assets/{useParams-dqd64jv7.js → useParams-b4dq6n4q.js} +1 -1
- package/static/dist/assets/{useSearch-j30pvsy7.js → useSearch-ipfmv3he.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-fzchbzaj.js → vennDiagram-4TSXK5OY-h5hzbk0n.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-m47mhfbh.js → wardley-WFR3VGLG-jftvpm3e.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-odg6ct1z.js → wardleyDiagram-VM6X3IG4-hedh85ge.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mrhms5um.js → xychartDiagram-S5SC5T6Z-e49523ab.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +2 -2
- package/static/dist/assets/AppShell-ef3bhu32.js +0 -1
- package/static/dist/assets/Button-nx37f4u1.js +0 -1
- package/static/dist/assets/ChatPage-cdcpykcg.js +0 -25
- package/static/dist/assets/Dialog-mec42hvb.js +0 -1
- package/static/dist/assets/HubRoute-ecb65zpr.js +0 -2
- package/static/dist/assets/RightPanel-d1lgvk4s.js +0 -1
- package/static/dist/assets/Select-h4ivl9qf.js +0 -1
- package/static/dist/assets/SessionListPanel-ewib046b.js +0 -1
- package/static/dist/assets/SettingsLayout-lx654cup.js +0 -1
- package/static/dist/assets/States-ehsb6lzo.js +0 -1
- package/static/dist/assets/Toaster-mch1pa3t.js +0 -1
- package/static/dist/assets/_app-m8d961ef.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +0 -1
- package/static/dist/assets/_app.index-dk6zp7e0.js +0 -1
- package/static/dist/assets/_app.insights-jt2fk4i1.js +0 -1
- package/static/dist/assets/_app.kanban-if4pubeu.js +0 -1
- package/static/dist/assets/_app.logs-mfaw9m6g.js +0 -1
- package/static/dist/assets/_app.memory-h3eaarb6.js +0 -1
- package/static/dist/assets/_app.profiles-ienktovs.js +0 -1
- package/static/dist/assets/_app.settings-dpoe0bzf.js +0 -1
- package/static/dist/assets/_app.settings._section-l468ynag.js +0 -3
- package/static/dist/assets/_app.skills-kcbncc8i.js +0 -1
- package/static/dist/assets/_app.tasks-occdrqhw.js +0 -2
- package/static/dist/assets/_app.todos-nnke2rcc.js +0 -1
- package/static/dist/assets/_app.workspaces-cdlatvwj.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +0 -1
- package/static/dist/assets/channel-mbvmf2vv.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +0 -1
- package/static/dist/assets/copy-e6977uwq.js +0 -1
- package/static/dist/assets/endpoints-k7yf25m0.js +0 -64
- package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +0 -1
- package/static/dist/assets/index-h00usru2.js +0 -11
- package/static/dist/assets/index-n73ijkv2.css +0 -2
- package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +0 -1
- package/static/dist/assets/link-budeg5t9.js +0 -1
- package/static/dist/assets/login-kjhasvp8.js +0 -1
- package/static/dist/assets/matchContext-f8oy3lo7.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +0 -1
- package/static/dist/assets/onboarding-cdfrk0pj.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +0 -1
- package/static/dist/assets/refresh-cw-kbcje1uy.js +0 -1
- package/static/dist/assets/search-jen74z4u.js +0 -1
- package/static/dist/assets/share._token-dan9hgvj.js +0 -2
- package/static/dist/assets/sliders-horizontal-f9cb3lh3.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +0 -8
- package/static/dist/assets/todoStore-eqtid4r4.js +0 -1
- package/static/dist/assets/useLocale-hcsb84pj.js +0 -1
- package/static/dist/assets/useNavigate-nwy70ztj.js +0 -1
|
@@ -8,11 +8,12 @@ import json
|
|
|
8
8
|
import logging
|
|
9
9
|
import queue
|
|
10
10
|
import sqlite3
|
|
11
|
+
import threading
|
|
11
12
|
import time
|
|
12
13
|
from contextlib import closing
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
|
|
15
|
-
from ..errors import InvalidParams
|
|
16
|
+
from ..errors import InvalidParams, RpcError
|
|
16
17
|
from ..home import profile_home_param, scoped_home
|
|
17
18
|
from ..rpc import CallContext
|
|
18
19
|
|
|
@@ -42,18 +43,80 @@ def _event_row(evt: dict) -> dict:
|
|
|
42
43
|
if not row.get("origin_ui_session_id"):
|
|
43
44
|
row["origin_ui_session_id"] = str(getattr(proc, "origin_ui_session_id", "") or "") or str(getattr(proc, "spawn_session_id", "") or "")
|
|
44
45
|
try:
|
|
45
|
-
|
|
46
|
+
# Only the exit is consumed by the agent's wait or poll; a watch notice from the same process still wakes (TAL-724).
|
|
47
|
+
row["consumed"] = bool(registry is not None and process_id and row.get("type") in (None, "completion") and registry.is_completion_consumed(process_id))
|
|
46
48
|
except Exception: # noqa: BLE001
|
|
47
49
|
row["consumed"] = False
|
|
48
50
|
return row
|
|
49
51
|
|
|
50
52
|
|
|
53
|
+
# Recovered sessions, held so their exit is seen even when an Agent call other than drain prunes them first.
|
|
54
|
+
_RECOVERED: dict[str, object] = {}
|
|
55
|
+
_RECOVERED_LOCK = threading.Lock()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _reports_recovered_exits(registry) -> bool:
|
|
59
|
+
"""Agent 0.21.6 (hermes-agent 7550800d) closes or prunes a recovered session whose PID is gone without queuing a
|
|
60
|
+
completion, since it never collected an exit status. Talaria still wakes the session with an unknown exit code."""
|
|
61
|
+
return callable(getattr(registry, "_detached_host_fate", None)) and callable(getattr(registry, "_publish_finished", None))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def track_recovered(registry) -> None:
|
|
65
|
+
if not _reports_recovered_exits(registry):
|
|
66
|
+
return
|
|
67
|
+
try:
|
|
68
|
+
with registry._lock:
|
|
69
|
+
detached = [s for s in registry._running.values() if getattr(s, "detached", False)]
|
|
70
|
+
except Exception: # noqa: BLE001 - recovery itself succeeded; only the exit report is lost
|
|
71
|
+
log.warning("Failed to track recovered processes", exc_info=True)
|
|
72
|
+
return
|
|
73
|
+
with _RECOVERED_LOCK:
|
|
74
|
+
_RECOVERED.update((s.id, s) for s in detached)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _publish_recovered_exits(registry) -> None:
|
|
78
|
+
with _RECOVERED_LOCK:
|
|
79
|
+
exited = [s for s in _RECOVERED.values() if s.exited]
|
|
80
|
+
for session in exited:
|
|
81
|
+
del _RECOVERED[session.id]
|
|
82
|
+
for session in exited:
|
|
83
|
+
# A kill (or any path that collected a status) already queued its own completion through _move_to_finished.
|
|
84
|
+
if session.exit_code is not None or getattr(session, "_finish_claimed", False):
|
|
85
|
+
continue
|
|
86
|
+
try:
|
|
87
|
+
# Best effort, as in the Agent: a durable result must not block the live completion.
|
|
88
|
+
from tools.process_registry_results import save_completed_result
|
|
89
|
+
|
|
90
|
+
save_completed_result(session)
|
|
91
|
+
except Exception: # noqa: BLE001
|
|
92
|
+
log.debug("Failed to retain the result of recovered process %s", session.id, exc_info=True)
|
|
93
|
+
try:
|
|
94
|
+
with registry._lock:
|
|
95
|
+
registry._running.pop(session.id, None)
|
|
96
|
+
session.exited_at = session.exited_at or time.time()
|
|
97
|
+
registry._finished[session.id] = session
|
|
98
|
+
registry._publish_finished(session, True)
|
|
99
|
+
except Exception: # noqa: BLE001 - retried on the next drain
|
|
100
|
+
log.warning("Failed to report the exit of recovered process %s", session.id, exc_info=True)
|
|
101
|
+
with _RECOVERED_LOCK:
|
|
102
|
+
_RECOVERED.setdefault(session.id, session)
|
|
103
|
+
|
|
104
|
+
|
|
51
105
|
def drain(max_events: int) -> list[dict]:
|
|
52
106
|
"""Pop every queued completion event; the server requeues what it does not own."""
|
|
53
107
|
registry = _registry()
|
|
54
108
|
completion_queue = getattr(registry, "completion_queue", None) if registry is not None else None
|
|
55
109
|
if completion_queue is None:
|
|
56
110
|
return []
|
|
111
|
+
try:
|
|
112
|
+
# A recovered process has no reader thread; only this probe notices its exit and queues its completion (TAL-533).
|
|
113
|
+
with registry._lock:
|
|
114
|
+
detached = [s for s in registry._running.values() if getattr(s, "detached", False)]
|
|
115
|
+
for session in detached:
|
|
116
|
+
registry._refresh_detached_session(session)
|
|
117
|
+
_publish_recovered_exits(registry)
|
|
118
|
+
except Exception: # noqa: BLE001
|
|
119
|
+
log.debug("Failed to reconcile recovered processes", exc_info=True)
|
|
57
120
|
out = []
|
|
58
121
|
while len(out) < max_events:
|
|
59
122
|
try:
|
|
@@ -94,6 +157,22 @@ def mark_consumed(process_id: str) -> bool:
|
|
|
94
157
|
return False
|
|
95
158
|
|
|
96
159
|
|
|
160
|
+
def consumed_ids(process_ids: list[str]) -> list[str]:
|
|
161
|
+
"""The processes the agent already holds from its own turn: consumed via wait/log, or observed exiting via poll.
|
|
162
|
+
Checked at wakeup delivery, since the completion is usually drained before the agent's wait returns (TAL-532)."""
|
|
163
|
+
registry = _registry()
|
|
164
|
+
if registry is None:
|
|
165
|
+
return []
|
|
166
|
+
out = []
|
|
167
|
+
for process_id in process_ids:
|
|
168
|
+
try:
|
|
169
|
+
if registry.is_completion_consumed(process_id) or process_id in (getattr(registry, "_poll_observed", None) or ()):
|
|
170
|
+
out.append(process_id)
|
|
171
|
+
except Exception: # noqa: BLE001
|
|
172
|
+
log.debug("Completion consumed check failed for %r", process_id, exc_info=True)
|
|
173
|
+
return out
|
|
174
|
+
|
|
175
|
+
|
|
97
176
|
def _delivery_api():
|
|
98
177
|
"""The Agent's durable delivery ledger (``tools.async_delegation``), or None on an Agent without it."""
|
|
99
178
|
try:
|
|
@@ -387,12 +466,39 @@ def delegation_result(home: Path, session_id: str, delegation_id: str) -> str:
|
|
|
387
466
|
return format_notification(event) if event else ""
|
|
388
467
|
|
|
389
468
|
|
|
469
|
+
def recover(base_home: Path) -> int:
|
|
470
|
+
"""TAL-533: re-adopt every profile's checkpointed processes when a sidecar starts, so a process in a profile nobody
|
|
471
|
+
uses yet is watched (and its exit reported) from the start. Entering a home's scope recovers it once; a failed
|
|
472
|
+
recovery fails the call, so the server retries."""
|
|
473
|
+
from .profiles import named_profile_homes
|
|
474
|
+
|
|
475
|
+
named = [home for _, home in named_profile_homes(base_home)]
|
|
476
|
+
failed = []
|
|
477
|
+
for home in [base_home, *named]:
|
|
478
|
+
try:
|
|
479
|
+
with scoped_home(home):
|
|
480
|
+
pass
|
|
481
|
+
except RpcError as exc:
|
|
482
|
+
if exc.data.get("condition") != "agent_incompatible":
|
|
483
|
+
failed.append(str(exc))
|
|
484
|
+
continue
|
|
485
|
+
# An Agent without profile isolation refuses named profiles for good; their processes stay unadopted.
|
|
486
|
+
log.warning("Background process recovery skipped for %s", home, exc_info=True)
|
|
487
|
+
if failed:
|
|
488
|
+
raise RpcError("; ".join(failed))
|
|
489
|
+
return 1 + len(named)
|
|
490
|
+
|
|
491
|
+
|
|
390
492
|
def register(registry_) -> None:
|
|
391
493
|
@registry_.method("process.drain")
|
|
392
494
|
def drain_(ctx: CallContext, params: dict) -> dict:
|
|
393
495
|
with scoped_home(profile_home_param(params)):
|
|
394
496
|
return {"events": drain(int(params.get("max_events") or 256))}
|
|
395
497
|
|
|
498
|
+
@registry_.method("process.recover")
|
|
499
|
+
def recover_(ctx: CallContext, params: dict) -> dict:
|
|
500
|
+
return {"homes": recover(profile_home_param(params, "base_home"))}
|
|
501
|
+
|
|
396
502
|
@registry_.method("process.requeue")
|
|
397
503
|
def requeue_(ctx: CallContext, params: dict) -> dict:
|
|
398
504
|
events = params.get("events")
|
|
@@ -407,6 +513,13 @@ def register(registry_) -> None:
|
|
|
407
513
|
raise InvalidParams("process_id is required")
|
|
408
514
|
return {"ok": mark_consumed(process_id)}
|
|
409
515
|
|
|
516
|
+
@registry_.method("process.consumed")
|
|
517
|
+
def consumed_(ctx: CallContext, params: dict) -> dict:
|
|
518
|
+
ids = params.get("process_ids")
|
|
519
|
+
if not isinstance(ids, list) or not all(isinstance(i, str) and i for i in ids):
|
|
520
|
+
raise InvalidParams("process_ids must be a list of process ids")
|
|
521
|
+
return {"consumed": consumed_ids(ids)}
|
|
522
|
+
|
|
410
523
|
def _delivery_params(params: dict) -> dict:
|
|
411
524
|
evt = params.get("event")
|
|
412
525
|
if not isinstance(evt, dict):
|
|
@@ -24,6 +24,9 @@ log = logging.getLogger("talaria_sidecar.profiles")
|
|
|
24
24
|
_PROFILE_ID_RE = re.compile(r"[a-z0-9][a-z0-9_-]{0,63}")
|
|
25
25
|
_PROFILE_DIRS = ("skills", "memories", "sessions", "logs", "cron")
|
|
26
26
|
_CLONE_CONFIG_FILES = ("config.yaml", ".env", "SOUL.md")
|
|
27
|
+
_AVATAR_EXTS = ("png", "jpg", "webp")
|
|
28
|
+
# The Agent's ``INTERNAL_LISTING_SOURCES``: worker sessions are never a profile's conversation.
|
|
29
|
+
_INTERNAL_SOURCES = ("kanban", "tool", "oneshot")
|
|
27
30
|
_TERMINAL_ENV = {
|
|
28
31
|
"backend": "TERMINAL_ENV", "env_type": "TERMINAL_ENV", "cwd": "TERMINAL_CWD", "timeout": "TERMINAL_TIMEOUT", "lifetime_seconds": "TERMINAL_LIFETIME_SECONDS",
|
|
29
32
|
"modal_mode": "TERMINAL_MODAL_MODE", "docker_image": "TERMINAL_DOCKER_IMAGE", "docker_forward_env": "TERMINAL_DOCKER_FORWARD_ENV", "docker_env": "TERMINAL_DOCKER_ENV",
|
|
@@ -96,6 +99,58 @@ def _visible(profile_dir: Path) -> bool:
|
|
|
96
99
|
return not (isinstance(data, dict) and data.get("visible") is False)
|
|
97
100
|
|
|
98
101
|
|
|
102
|
+
def _bounded(value, limit: int) -> str:
|
|
103
|
+
"""One printable line of at most ``limit`` characters; anything but a string reads as empty."""
|
|
104
|
+
if not isinstance(value, str):
|
|
105
|
+
return ""
|
|
106
|
+
text = " ".join("".join(c if c.isprintable() else " " for c in value).split())
|
|
107
|
+
return text if len(text) <= limit else text[: limit - 1].rstrip() + "\u2026"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def bot_identity(home: Path) -> dict:
|
|
111
|
+
"""The presentation-only Bot Mode identity from ``profile.yaml`` and ``assets/``; never the raw ``ui_meta``."""
|
|
112
|
+
meta = _yaml_load(home / "profile.yaml") or {}
|
|
113
|
+
ui_meta = meta.get("ui_meta") if isinstance(meta.get("ui_meta"), dict) else {}
|
|
114
|
+
bots = ui_meta.get("hermes-bots") if isinstance(ui_meta.get("hermes-bots"), dict) else {}
|
|
115
|
+
return {
|
|
116
|
+
# Bot Mode's roster name (``ui_meta['hermes-bots'].title``) wins over the profile's own display name.
|
|
117
|
+
"display_name": _bounded(bots.get("title"), 80) or _bounded(meta.get("display_name"), 80),
|
|
118
|
+
"description": _bounded(meta.get("description"), 280), "has_avatar": any((home / "assets" / f"avatar.{ext}").is_file() for ext in _AVATAR_EXTS),
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def canonical_bot_chat(home: Path) -> dict | None:
|
|
123
|
+
"""The profile's canonical Bot Chat: its session titled exactly ``Bot Chat`` (Bot Mode's registry) and live
|
|
124
|
+
compression tip, read through a read-only handle. Missing, unreadable, archived, worker-owned, or an Agent
|
|
125
|
+
without Bot Mode answers None; the gateway's resurrection of accidental archives is a write and stays there."""
|
|
126
|
+
db_path = home / "state.db"
|
|
127
|
+
if not db_path.is_file():
|
|
128
|
+
return None
|
|
129
|
+
try:
|
|
130
|
+
from hermes_state import SessionDB
|
|
131
|
+
|
|
132
|
+
title = getattr(SessionDB, "CANONICAL_BOT_CHAT_TITLE", None)
|
|
133
|
+
if not title:
|
|
134
|
+
return None
|
|
135
|
+
db = SessionDB(db_path=db_path, read_only=True)
|
|
136
|
+
except Exception: # noqa: BLE001
|
|
137
|
+
return None
|
|
138
|
+
try:
|
|
139
|
+
row = db.get_session_by_title(title)
|
|
140
|
+
if not row or row.get("title") != title or row.get("archived") or str(row.get("source") or "").strip().lower() in _INTERNAL_SOURCES:
|
|
141
|
+
return None
|
|
142
|
+
session_id = str(row["id"])
|
|
143
|
+
return {"session_id": session_id, "tip_session_id": str(db.get_compression_tip(session_id) or session_id)}
|
|
144
|
+
except Exception: # noqa: BLE001
|
|
145
|
+
log.debug("canonical Bot Chat lookup failed for %s", db_path, exc_info=True)
|
|
146
|
+
return None
|
|
147
|
+
finally:
|
|
148
|
+
try:
|
|
149
|
+
db.close()
|
|
150
|
+
except Exception: # noqa: BLE001
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
|
|
99
154
|
def _row(home: Path, name: str, is_default: bool) -> dict:
|
|
100
155
|
from hermes_cli.profiles import _check_gateway_running, _read_config_model
|
|
101
156
|
|
|
@@ -111,21 +166,36 @@ def _row(home: Path, name: str, is_default: bool) -> dict:
|
|
|
111
166
|
return {
|
|
112
167
|
"name": name, "path": str(home), "is_default": is_default, "gateway_running": gateway_running, "model": model, "provider": provider,
|
|
113
168
|
"has_env": (home / ".env").exists(), "visible": _visible(home), "skill_count": enabled, "enabled_skills": enabled, "total_skills": total,
|
|
169
|
+
**bot_identity(home), "canonical_session": canonical_bot_chat(home),
|
|
114
170
|
}
|
|
115
171
|
|
|
116
172
|
|
|
117
|
-
def
|
|
118
|
-
"""
|
|
173
|
+
def named_profile_homes(base_home: Path) -> list[tuple[str, Path]]:
|
|
174
|
+
"""(name, home) for the ``profiles/*`` directories named like profiles, skipping any that resolve outside the resolved
|
|
175
|
+
profiles root (a symlink leading elsewhere is never read as a profile; TAL-579). A contained symlink answers the
|
|
176
|
+
target it was checked against, so retargeting the link afterwards cannot redirect the caller."""
|
|
119
177
|
from hermes_cli.profiles import _PROFILE_ID_RE as UPSTREAM_ID_RE
|
|
120
178
|
|
|
179
|
+
profiles_root = base_home / "profiles"
|
|
180
|
+
if not profiles_root.is_dir():
|
|
181
|
+
return []
|
|
182
|
+
root = profiles_root.resolve()
|
|
183
|
+
homes = []
|
|
184
|
+
for entry in sorted(profiles_root.iterdir()):
|
|
185
|
+
if not (entry.is_dir() and UPSTREAM_ID_RE.match(entry.name)):
|
|
186
|
+
continue
|
|
187
|
+
real = entry.resolve()
|
|
188
|
+
if real.is_relative_to(root):
|
|
189
|
+
homes.append((entry.name, real if entry.is_symlink() else entry))
|
|
190
|
+
return homes
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def list_profiles(base_home: Path) -> list[dict]:
|
|
194
|
+
"""Profile rows for the base Hermes home: the root profile plus ``profiles/*``."""
|
|
121
195
|
rows = []
|
|
122
196
|
if base_home.is_dir():
|
|
123
197
|
rows.append(_row(base_home, "default", True))
|
|
124
|
-
|
|
125
|
-
if profiles_root.is_dir():
|
|
126
|
-
for entry in sorted(profiles_root.iterdir()):
|
|
127
|
-
if entry.is_dir() and UPSTREAM_ID_RE.match(entry.name):
|
|
128
|
-
rows.append(_row(entry, entry.name, False))
|
|
198
|
+
rows.extend(_row(home, name, False) for name, home in named_profile_homes(base_home))
|
|
129
199
|
return rows
|
|
130
200
|
|
|
131
201
|
|
|
@@ -241,7 +311,13 @@ def register(registry) -> None:
|
|
|
241
311
|
|
|
242
312
|
@registry.method("profiles.delete")
|
|
243
313
|
def delete(ctx: CallContext, params: dict) -> dict:
|
|
244
|
-
|
|
314
|
+
base_home, name = profile_home_param(params, "base_home"), str(params.get("name") or "").strip()
|
|
315
|
+
validate_name(name)
|
|
316
|
+
# Idle cached agents end their memory sessions while the profile's home still exists.
|
|
317
|
+
from .chat import release_profile_agents
|
|
318
|
+
|
|
319
|
+
release_profile_agents(base_home / "profiles" / name)
|
|
320
|
+
delete_profile(base_home, name)
|
|
245
321
|
return {"ok": True}
|
|
246
322
|
|
|
247
323
|
@registry.method("profiles.runtime_env")
|
|
@@ -97,8 +97,10 @@ def _user_plugin_profiles() -> dict[int, tuple[Any, Path]]:
|
|
|
97
97
|
def _load_plugin(root: Path) -> None:
|
|
98
98
|
"""Load the scoped profile's installed plugin that the process-wide discovery (run under the launch profile) skipped.
|
|
99
99
|
|
|
100
|
-
Uses the Agent's own loader, as ``hermes plugins dev`` does, once per directory.
|
|
101
|
-
that is already registered, so one profile's plugin cannot
|
|
100
|
+
Uses the Agent's own loader, as ``hermes plugins dev`` does, once per directory. On an Agent with one process-wide
|
|
101
|
+
provider registry, a plugin never displaces a provider that is already registered, so one profile's plugin cannot
|
|
102
|
+
change what another profile's provider id runs. An Agent with per-home provider layers registers it in this home's
|
|
103
|
+
layer instead, so the same id is that profile's own provider.
|
|
102
104
|
"""
|
|
103
105
|
import providers
|
|
104
106
|
|
|
@@ -121,12 +123,12 @@ def _load_plugin(root: Path) -> None:
|
|
|
121
123
|
def installed_plugin_profiles() -> list[tuple[str, Any]]:
|
|
122
124
|
"""``(manifest name, profile | None)`` for each enabled model-provider plugin installed in the scoped home.
|
|
123
125
|
|
|
124
|
-
Bundled providers are built-ins, not plugins.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
name. ponytail: ownership is read from the plugin module's globals, so a plugin that registers an unbound
|
|
129
|
-
profile also reads as not loaded; track registrations in the Agent if one ever does.
|
|
126
|
+
Bundled providers are built-ins, not plugins. A profile belongs to this home only when the plugin module that
|
|
127
|
+
registered it lives in one of this home's plugin directories; a plugin the launch discovery skipped is loaded here.
|
|
128
|
+
``None`` means the plugin could not be loaded: it failed to import, another plugin took its provider id (only on an
|
|
129
|
+
Agent with one process-wide provider registry rather than per-home layers), or another profile's plugin has the same
|
|
130
|
+
directory name. ponytail: ownership is read from the plugin module's globals, so a plugin that registers an unbound
|
|
131
|
+
inline profile also reads as not loaded; track registrations in the Agent if one ever does.
|
|
130
132
|
"""
|
|
131
133
|
try:
|
|
132
134
|
from hermes_cli.plugins_discovery import _get_disabled_plugins, _get_enabled_plugins, collect_directory_manifests, gate_manifest
|
|
@@ -168,8 +170,25 @@ def _other_profile_plugin(provider_id: str) -> bool:
|
|
|
168
170
|
return not any(p is profile for _name, p in installed_plugin_profiles())
|
|
169
171
|
|
|
170
172
|
|
|
173
|
+
def _agent_knows_provider(name: str) -> bool:
|
|
174
|
+
"""Whether the Agent's auth layer can resolve this provider id at all.
|
|
175
|
+
|
|
176
|
+
Agent 0.21.3 resolves providers from a ``PROVIDER_REGISTRY`` snapshot of its import-time plugin discovery, so a
|
|
177
|
+
named profile's plugin loaded here on demand is unknown to it and cannot run. Registering it there would expose it
|
|
178
|
+
to every profile, so it reads as unavailable instead. Newer Agents look providers up live (``_registry_lookup``).
|
|
179
|
+
"""
|
|
180
|
+
try:
|
|
181
|
+
import hermes_cli.auth as auth
|
|
182
|
+
except Exception: # noqa: BLE001 - auth_status reports an unavailable auth layer
|
|
183
|
+
return True
|
|
184
|
+
registry = getattr(auth, "PROVIDER_REGISTRY", None)
|
|
185
|
+
return hasattr(auth, "_registry_lookup") or not isinstance(registry, dict) or name.strip().lower() in registry
|
|
186
|
+
|
|
187
|
+
|
|
171
188
|
def _setup_state(profile: Any) -> str:
|
|
172
189
|
"""The Agent's own setup verdict for a plugin provider, without spawning its CLI or reading its credentials."""
|
|
190
|
+
if not _agent_knows_provider(str(profile.name)):
|
|
191
|
+
return "unavailable"
|
|
173
192
|
try:
|
|
174
193
|
status = auth_status(profile.name)
|
|
175
194
|
except RpcError:
|
|
@@ -66,5 +66,8 @@ def register(registry) -> None:
|
|
|
66
66
|
code = params.get("exit_code", 0)
|
|
67
67
|
if not isinstance(code, int):
|
|
68
68
|
raise InvalidParams("exit_code must be an integer")
|
|
69
|
+
from .chat import drain_agents
|
|
70
|
+
|
|
71
|
+
drain_agents()
|
|
69
72
|
ctx.server.request_shutdown(exit_code=code)
|
|
70
73
|
return {"ok": True}
|
|
@@ -95,7 +95,8 @@ def sync_session_usage(home: Path, session_id: str, *, input_tokens=0, output_to
|
|
|
95
95
|
_close(db)
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def sync_session_title(home: Path, session_id: str, title: str) -> bool:
|
|
98
|
+
def sync_session_title(home: Path, session_id: str, title: str, *, manual: bool = False) -> bool:
|
|
99
|
+
"""A manual (user-requested) title lands with ``user`` provenance; an auto title is ``llm`` and never replaces a user name."""
|
|
99
100
|
if not title:
|
|
100
101
|
return False
|
|
101
102
|
db = _session_db(home)
|
|
@@ -104,15 +105,38 @@ def sync_session_title(home: Path, session_id: str, title: str) -> bool:
|
|
|
104
105
|
try:
|
|
105
106
|
db.ensure_session(session_id=session_id, source="webui")
|
|
106
107
|
source = getattr(db, "TITLE_SOURCE_LLM", "llm")
|
|
108
|
+
|
|
109
|
+
def write(value: str) -> None:
|
|
110
|
+
if manual:
|
|
111
|
+
db.set_session_title(session_id, value)
|
|
112
|
+
else:
|
|
113
|
+
db.set_auto_title(session_id, value, source=source)
|
|
114
|
+
|
|
107
115
|
try:
|
|
108
|
-
|
|
116
|
+
write(title)
|
|
109
117
|
except ValueError:
|
|
110
118
|
alt = db.get_next_title_in_lineage(title)
|
|
111
119
|
if alt and alt != title:
|
|
112
|
-
|
|
120
|
+
write(alt)
|
|
121
|
+
return True
|
|
122
|
+
except Exception: # noqa: BLE001
|
|
123
|
+
log.debug("Failed to sync session title", exc_info=True)
|
|
124
|
+
return False
|
|
125
|
+
finally:
|
|
126
|
+
_close(db)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def append_message(home: Path, session_id: str, *, role: str, content: str, tool_name=None, timestamp=None) -> bool:
|
|
130
|
+
"""TAL-258 (predecessor ``_persist_handoff_summary_to_state_db``): one row through ``SessionDB.append_message``,
|
|
131
|
+
which also bumps the session's ``message_count``. False without a state.db or when the write fails."""
|
|
132
|
+
db = _session_db(home)
|
|
133
|
+
if not db:
|
|
134
|
+
return False
|
|
135
|
+
try:
|
|
136
|
+
db.append_message(session_id, role, content=content, tool_name=tool_name or None, timestamp=timestamp)
|
|
113
137
|
return True
|
|
114
138
|
except Exception: # noqa: BLE001
|
|
115
|
-
log.
|
|
139
|
+
log.warning("Failed to append a %s row to state.db for %s", role, session_id, exc_info=True)
|
|
116
140
|
return False
|
|
117
141
|
finally:
|
|
118
142
|
_close(db)
|
|
@@ -408,7 +432,17 @@ def register(registry) -> None:
|
|
|
408
432
|
|
|
409
433
|
@registry.method("state_db.sync_title")
|
|
410
434
|
def title(ctx: CallContext, params: dict) -> dict:
|
|
411
|
-
return {"ok": sync_session_title(profile_home_param(params), _session_id(params), str(params.get("title") or ""))}
|
|
435
|
+
return {"ok": sync_session_title(profile_home_param(params), _session_id(params), str(params.get("title") or ""), manual=params.get("manual") is True)}
|
|
436
|
+
|
|
437
|
+
@registry.method("state_db.append_message")
|
|
438
|
+
def append(ctx: CallContext, params: dict) -> dict:
|
|
439
|
+
role = str(params.get("role") or "").strip()
|
|
440
|
+
if not role:
|
|
441
|
+
raise InvalidParams("role is required")
|
|
442
|
+
content = params.get("content")
|
|
443
|
+
if not isinstance(content, str):
|
|
444
|
+
raise InvalidParams("content must be a string")
|
|
445
|
+
return {"ok": append_message(profile_home_param(params), _session_id(params), role=role, content=content, tool_name=params.get("tool_name"), timestamp=params.get("timestamp"))}
|
|
412
446
|
|
|
413
447
|
@registry.method("state_db.delete_cli_session")
|
|
414
448
|
def delete(ctx: CallContext, params: dict) -> dict:
|
|
@@ -16,7 +16,7 @@ def image_mode(*, provider: str, model: str, cfg: dict | None, requested_provide
|
|
|
16
16
|
try:
|
|
17
17
|
from agent.image_routing import decide_image_input_mode
|
|
18
18
|
except Exception: # noqa: BLE001
|
|
19
|
-
return {"mode": "text", "reason": "image routing unavailable"}
|
|
19
|
+
return {"mode": "text", "reason": "image routing unavailable", "supports_vision": None}
|
|
20
20
|
try:
|
|
21
21
|
decision = decide_image_input_mode(provider, model, cfg, requested_provider=requested_provider)
|
|
22
22
|
except TypeError:
|
|
@@ -34,6 +34,18 @@ def image_mode(*, provider: str, model: str, cfg: dict | None, requested_provide
|
|
|
34
34
|
return {"mode": str(decision or "text"), "reason": "", "supports_vision": supports_vision}
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def _profile_config() -> dict | None:
|
|
38
|
+
"""The scoped profile's ``config.yaml``; None when the Agent cannot load it."""
|
|
39
|
+
try:
|
|
40
|
+
from hermes_cli.config import load_config
|
|
41
|
+
|
|
42
|
+
cfg = load_config()
|
|
43
|
+
except Exception: # noqa: BLE001
|
|
44
|
+
log.debug("image mode config load failed", exc_info=True)
|
|
45
|
+
return None
|
|
46
|
+
return cfg if isinstance(cfg, dict) else None
|
|
47
|
+
|
|
48
|
+
|
|
37
49
|
def portal_tags() -> dict:
|
|
38
50
|
try:
|
|
39
51
|
from agent.portal_tags import conversation_tag, hermes_client_tag, nous_portal_tags
|
|
@@ -58,6 +70,10 @@ def register(registry) -> None:
|
|
|
58
70
|
def image_mode_(ctx: CallContext, params: dict) -> dict:
|
|
59
71
|
cfg = params.get("cfg") if isinstance(params.get("cfg"), dict) else None
|
|
60
72
|
with scoped_home(profile_home_param(params)):
|
|
73
|
+
# TAL-545: without an explicit cfg the profile's config.yaml decides, so its vision overrides
|
|
74
|
+
# (``agent.image_input_mode``, ``supports_vision``) apply as they do for the Agent's own turn.
|
|
75
|
+
if cfg is None:
|
|
76
|
+
cfg = _profile_config()
|
|
61
77
|
return image_mode(provider=str(params.get("provider") or ""), model=str(params.get("model") or ""), cfg=cfg, requested_provider=str(params.get("requested_provider") or ""))
|
|
62
78
|
|
|
63
79
|
@registry.method("text.portal_tags")
|