@maudecode/talaria-web 1.16.1 → 1.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_release.json +4 -4
- package/dist/api/automation-raw.js +6 -3
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +137 -9
- package/dist/api/automation-router.js +9 -6
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +51 -0
- package/dist/api/chat-router.js +29 -12
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +12 -1
- package/dist/api/git-router.js +17 -7
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +6 -0
- package/dist/api/raw-routes.js +30 -0
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/sessions-router.d.ts +260 -0
- package/dist/api/sessions-router.js +30 -2
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +101 -2
- package/dist/api/settings-router.js +7 -2
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +11 -3
- package/dist/api/sse-routes.js +144 -64
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.js +6 -2
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +73 -8
- package/dist/api/tools-router.js +9 -7
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.d.ts +0 -9377
- package/dist/app.js +7 -2
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +3 -0
- package/dist/auth/gate.js.map +1 -1
- package/dist/config/agent-config.d.ts +2 -0
- package/dist/config/agent-config.js +9 -0
- package/dist/config/agent-config.js.map +1 -1
- package/dist/http/context.d.ts +3 -0
- package/dist/http/context.js +10 -4
- package/dist/http/context.js.map +1 -1
- package/dist/onboarding.js +4 -0
- package/dist/onboarding.js.map +1 -1
- package/dist/providers/catalog.d.ts +96 -7
- package/dist/providers/catalog.js +434 -113
- package/dist/providers/catalog.js.map +1 -1
- package/dist/redact.d.ts +1 -0
- package/dist/redact.js +27 -4
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +27 -9
- package/dist/runtime.js.map +1 -1
- package/dist/sessions/anchor.d.ts +2 -0
- package/dist/sessions/anchor.js +8 -3
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/claude-code.d.ts +19 -0
- package/dist/sessions/claude-code.js +250 -0
- package/dist/sessions/claude-code.js.map +1 -0
- package/dist/sessions/completions.d.ts +13 -1
- package/dist/sessions/completions.js +63 -11
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +14 -1
- package/dist/sessions/compress.js +52 -11
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/journal.d.ts +8 -0
- package/dist/sessions/journal.js +44 -10
- package/dist/sessions/journal.js.map +1 -1
- package/dist/sessions/list.d.ts +6 -2
- package/dist/sessions/list.js +33 -10
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +52 -2
- package/dist/sessions/merge.js +213 -10
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/service.d.ts +44 -2
- package/dist/sessions/service.js +251 -57
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +11 -1
- package/dist/sessions/session.js +23 -2
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/state-db.d.ts +26 -4
- package/dist/sessions/state-db.js +126 -8
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/store.js +5 -0
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +10 -0
- package/dist/sessions/streams.js +14 -3
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/todo.d.ts +6 -1
- package/dist/sessions/todo.js +11 -4
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +12 -1
- package/dist/sessions/tool-display.js +76 -1
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn.d.ts +30 -9
- package/dist/sessions/turn.js +247 -78
- package/dist/sessions/turn.js.map +1 -1
- package/dist/settings.d.ts +20 -2
- package/dist/settings.js +40 -2
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/fake.d.ts +2 -2
- package/dist/sidecar/fake.js +5 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/spa.js +2 -1
- package/dist/spa.js.map +1 -1
- package/dist/test/harness.js +2 -0
- package/dist/test/harness.js.map +1 -1
- package/dist/tools/insights.d.ts +8 -2
- package/dist/tools/insights.js +18 -2
- package/dist/tools/insights.js.map +1 -1
- package/dist/tools/kanban.d.ts +41 -1
- package/dist/tools/kanban.js +113 -2
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp.d.ts +2 -1
- package/dist/tools/mcp.js +11 -5
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/terminal.d.ts +1 -0
- package/dist/tools/terminal.js +1 -1
- package/dist/tools/terminal.js.map +1 -1
- package/dist/tools/updates.d.ts +7 -0
- package/dist/tools/updates.js +74 -7
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/fs.d.ts +7 -3
- package/dist/workspace/fs.js +5 -1
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/media.js +2 -0
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/preview.d.ts +28 -0
- package/dist/workspace/preview.js +110 -0
- package/dist/workspace/preview.js.map +1 -0
- package/dist/workspace/rollback.d.ts +5 -4
- package/dist/workspace/rollback.js +12 -9
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/upload.d.ts +2 -0
- package/dist/workspace/upload.js +4 -1
- package/dist/workspace/upload.js.map +1 -1
- package/package.json +2 -2
- package/sidecar/scripts/replay_sidecar.py +1 -1
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/__main__.py +7 -1
- package/sidecar/talaria_sidecar/home.py +39 -0
- package/sidecar/talaria_sidecar/methods/chat.py +422 -38
- package/sidecar/talaria_sidecar/methods/commands.py +15 -2
- package/sidecar/talaria_sidecar/methods/cron.py +10 -6
- package/sidecar/talaria_sidecar/methods/kanban.py +115 -15
- package/sidecar/talaria_sidecar/methods/process.py +60 -1
- package/sidecar/talaria_sidecar/methods/profiles.py +7 -1
- package/sidecar/talaria_sidecar/methods/runtime.py +3 -0
- package/sidecar/talaria_sidecar/methods/text.py +17 -1
- package/sidecar/talaria_sidecar/methods/usage.py +257 -4
- package/static/dist/FILES.txt +126 -125
- package/static/dist/assets/AppShell-fb2td9zi.js +1 -0
- package/static/dist/assets/ChatPage-cj96kiy9.js +25 -0
- package/static/dist/assets/Dialog-kxcg7ard.js +1 -0
- package/static/dist/assets/ExtensionRoute-jf7h0754.js +1 -0
- package/static/dist/assets/HubRoute-gmanpd5y.js +2 -0
- package/static/dist/assets/{Markdown-jqrx5es0.js → Markdown-mdwlvj3w.js} +29 -29
- package/static/dist/assets/RightPanel-ftvrjlcp.js +1 -0
- package/static/dist/assets/Select-bilaypej.js +1 -0
- package/static/dist/assets/SessionListPanel-og8n36qs.js +1 -0
- package/static/dist/assets/SettingsLayout-jonjefmj.js +1 -0
- package/static/dist/assets/States-nmejrwrm.js +1 -0
- package/static/dist/assets/Toaster-nnl8zkt9.js +1 -0
- package/static/dist/assets/_app-gdidzd94.js +1 -0
- package/static/dist/assets/_app.ext._extensionId-opyh9y0v.js +1 -0
- package/static/dist/assets/_app.index-hbarzbjx.js +1 -0
- package/static/dist/assets/_app.insights-luywlarz.js +1 -0
- package/static/dist/assets/_app.kanban-kincnbr8.js +1 -0
- package/static/dist/assets/_app.logs-oi2gr3gs.js +1 -0
- package/static/dist/assets/_app.memory-b6jfivt6.js +1 -0
- package/static/dist/assets/_app.profiles-lpvixmqp.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-hh27wwu2.js → _app.session._sessionId-bfd4h3id.js} +1 -1
- package/static/dist/assets/_app.settings-vowx3iq0.js +1 -0
- package/static/dist/assets/_app.settings._section-cnntg1tu.js +3 -0
- package/static/dist/assets/_app.skills-fb57lpau.js +1 -0
- package/static/dist/assets/_app.tasks-eszpx1q7.js +2 -0
- package/static/dist/assets/_app.todos-nr05ac6w.js +1 -0
- package/static/dist/assets/_app.workspaces-d2luomu6.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-oity9y4o.js → abnfDiagram-VCTEODGH-b2x1lqot.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +1 -0
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-ceaepnyr.js → architectureDiagram-5GKGNRK7-h38o5l7b.js} +1 -1
- package/static/dist/assets/{back-eu64w89w.js → back-bemaer09.js} +1 -1
- package/static/dist/assets/{blockDiagram-I7D4REHJ-n79st4pj.js → blockDiagram-I7D4REHJ-bqquxv2u.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-mi73akzk.js → c4Diagram-7LVT6UL2-f3fb8w6z.js} +1 -1
- package/static/dist/assets/{cancel-mzvkdjg8.js → cancel-drd0g6d9.js} +1 -1
- package/static/dist/assets/channel-cpdgf867.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-laat0g1q.js → chunk-4HAMMTFA-bzfyyzp3.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-0psy1tr2.js → chunk-75Z2AOVW-ly99rfx5.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-lw8uox8x.js → chunk-DU6HZSFF-bg6ecfqf.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-erassib3.js → chunk-F27PBJKO-e8k7mmqw.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-fz7rx619.js → chunk-GMAD6QVW-cmalnoaj.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-gdb0epb2.js → chunk-GVQU2GXP-gmif5o01.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-ea8t26qw.js → chunk-IMKFNOWR-f1nwwh6u.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-mb1gu9kz.js → chunk-L3NEJ4N5-oktfh5v7.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-eovmccvy.js → chunk-OSK3NFVY-b1sdx96z.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-bo55zjo5.js → chunk-P2QGCYS3-fhu4nzxt.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-ja7ohe4h.js → chunk-POPQ4Y6H-em31rnef.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-e30g9nus.js → chunk-PWAF6VOD-bxhhyftw.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-gbb798f7.js → chunk-SHT3W25Y-fmrvwcav.js} +1 -1
- package/static/dist/assets/{chunk-SVP7TREG-h2iw8urm.js → chunk-SVP7TREG-lymukl2j.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-fd2cottz.js → chunk-TICWLB2K-lmza6k23.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +1 -0
- package/static/dist/assets/{copied-h65fc3cx.js → copied-ima3pysb.js} +1 -1
- package/static/dist/assets/copy-fw5b1pc6.js +1 -0
- package/static/dist/assets/{cynefin-OW5HDTMX-lbltyl5j.js → cynefin-OW5HDTMX-czlhbyhs.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-lxhsqq4a.js → cynefinDiagram-5FMLGOSQ-gq7mvswb.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-gn4nnaln.js → dagre-GXQ25YYZ-cqdbf7dr.js} +1 -1
- package/static/dist/assets/{diagram-S7CK7UJ4-pa3ij6q7.js → diagram-S7CK7UJ4-o6arxa58.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-zbipyz57.js → diagram-UQ7AKVKN-nhnd68tz.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-d1kbpzgf.js → diagram-VSXAHHWV-dk2sclzn.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-i3ty14xl.js → diagram-VX7I27RA-n3k5nyx3.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-m8xefqa7.js → diagram-Z3DM3KII-m6q9cwdh.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-nz7wj05l.js → ebnfDiagram-PWID7BFC-lsa5641p.js} +1 -1
- package/static/dist/assets/endpoints-d33siokx.js +64 -0
- package/static/dist/assets/{erDiagram-RLTQ6QDP-fa41ib83.js → erDiagram-RLTQ6QDP-fo2ckbe6.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-n7zq01qu.js → ganttDiagram-EL5Y4UJY-nzqz6x9g.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-c89emb07.js → gitGraph-4MIJSDKK-gukvcxe6.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-cz7cgr6w.js → gitGraphDiagram-WWUBYQGX-lqhdp8f0.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-d9bapmni.js → highlighted-body-KPVGNVTW-igw6cp39.js} +1 -1
- package/static/dist/assets/index-cxq58xb1.js +11 -0
- package/static/dist/assets/index-hgtx08n5.css +2 -0
- package/static/dist/assets/{info-A6RAGUB7-ndddhhhh.js → info-A6RAGUB7-gvu7a93l.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-ccxigcpf.js → infoDiagram-27XIBGKW-m8t8g6w1.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-le0z9vtc.js → ishikawaDiagram-5VMMS53U-l07vkbgj.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-ivsmb26o.js → journeyDiagram-3NMN7TZE-hybkgj8l.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-h6n2awt0.js → kanban-definition-UXKFOSKX-by13uvtn.js} +1 -1
- package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +1 -0
- package/static/dist/assets/{line-dmzlfe0u.js → line-osxq6fq7.js} +1 -1
- package/static/dist/assets/link-jyxicdhg.js +1 -0
- package/static/dist/assets/{login-kjhasvp8.js → login-ec21t39x.js} +1 -1
- package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-gwyd5bnq.js → mermaid-parser.core-i91oxmou.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-l68gg5h7.js → mindmap-definition-YA3MSWOX-m82mx8ww.js} +1 -1
- package/static/dist/assets/onboarding-btnltvyz.js +1 -0
- package/static/dist/assets/onboarding_model_label-dp7xffoh.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-gpv06065.js → packet-AYTQ26CC-nbtgge2o.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-e52vs23u.js → pegDiagram-XKGWAZYB-f1zxzga1.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-l6m7nz5s.js → pie-WAS4IAKB-of8vuhxs.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-b4is36bq.js → pieDiagram-E7YTZNPT-o7y8ftio.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-m8vt2788.js → quadrantDiagram-AXDQQJYC-iqiwia1t.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-nxbrhiov.js → radar-RG4KPBEZ-delnsy2v.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-222mu9hi.js → railroad-74A4TZTK-nspnyq9u.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-o8lldfzv.js → railroadDiagram-O6MQD6OU-z41tqx5z.js} +1 -1
- package/static/dist/assets/refresh-b4uams1i.js +1 -0
- package/static/dist/assets/refresh-cw-nt1dtsx4.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-ovyq38kv.js → requirementDiagram-BXWQKSXE-bdvif194.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-ou7lznor.js → sankeyDiagram-P5KCCOFB-h73e0rol.js} +1 -1
- package/static/dist/assets/{saved-bazmcup9.js → saved-kg52csy7.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-ovckdzf2.js → sequenceDiagram-WJ2MYXX4-iv95mb1z.js} +1 -1
- package/static/dist/assets/{settings_section_extensions_title-ertwwhlx.js → settings_section_extensions_title-ej0iapxe.js} +1 -1
- package/static/dist/assets/share._token-f97e94r0.js +2 -0
- package/static/dist/assets/sliders-horizontal-fj18it47.js +1 -0
- package/static/dist/assets/sse-fwpqtzbg.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-fcrexkkv.js → stateDiagram-D77RDMKH-k417ixmf.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-f7usu8fw.js → swimlanes-42K2YHIH-esola70w.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-gp1hvz9f.js → timeline-definition-24CTP7MA-getrz2y8.js} +1 -1
- package/static/dist/assets/todoStore-eginf9h4.js +1 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-gb9gf11u.js → treeView-Q6P3EWNA-hc7ap1q7.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-nuvfnvvi.js → treemap-WGGIJYW6-b7k1syy5.js} +1 -1
- package/static/dist/assets/tts-lxdxnmjd.js +1 -0
- package/static/dist/assets/{untitled-htelhc68.js → untitled-ovpfthg4.js} +1 -1
- package/static/dist/assets/{useForm-h2t0u14e.js → useForm-bcblv1rx.js} +1 -1
- package/static/dist/assets/useLocale-fi5jb8ma.js +1 -0
- package/static/dist/assets/{useParams-dqd64jv7.js → useParams-lhg566ew.js} +1 -1
- package/static/dist/assets/{useSearch-j30pvsy7.js → useSearch-lbrh6ejn.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-fzchbzaj.js → vennDiagram-4TSXK5OY-n6pcy5qb.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-m47mhfbh.js → wardley-WFR3VGLG-lpa18vz1.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-odg6ct1z.js → wardleyDiagram-VM6X3IG4-kpclwwg7.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-mrhms5um.js → xychartDiagram-S5SC5T6Z-paa2n8y0.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +2 -2
- package/static/dist/assets/AppShell-ef3bhu32.js +0 -1
- package/static/dist/assets/Button-nx37f4u1.js +0 -1
- package/static/dist/assets/ChatPage-cdcpykcg.js +0 -25
- package/static/dist/assets/Dialog-mec42hvb.js +0 -1
- package/static/dist/assets/HubRoute-ecb65zpr.js +0 -2
- package/static/dist/assets/RightPanel-d1lgvk4s.js +0 -1
- package/static/dist/assets/Select-h4ivl9qf.js +0 -1
- package/static/dist/assets/SessionListPanel-ewib046b.js +0 -1
- package/static/dist/assets/SettingsLayout-lx654cup.js +0 -1
- package/static/dist/assets/States-ehsb6lzo.js +0 -1
- package/static/dist/assets/Toaster-mch1pa3t.js +0 -1
- package/static/dist/assets/_app-m8d961ef.js +0 -1
- package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +0 -1
- package/static/dist/assets/_app.index-dk6zp7e0.js +0 -1
- package/static/dist/assets/_app.insights-jt2fk4i1.js +0 -1
- package/static/dist/assets/_app.kanban-if4pubeu.js +0 -1
- package/static/dist/assets/_app.logs-mfaw9m6g.js +0 -1
- package/static/dist/assets/_app.memory-h3eaarb6.js +0 -1
- package/static/dist/assets/_app.profiles-ienktovs.js +0 -1
- package/static/dist/assets/_app.settings-dpoe0bzf.js +0 -1
- package/static/dist/assets/_app.settings._section-l468ynag.js +0 -3
- package/static/dist/assets/_app.skills-kcbncc8i.js +0 -1
- package/static/dist/assets/_app.tasks-occdrqhw.js +0 -2
- package/static/dist/assets/_app.todos-nnke2rcc.js +0 -1
- package/static/dist/assets/_app.workspaces-cdlatvwj.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +0 -1
- package/static/dist/assets/channel-mbvmf2vv.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +0 -1
- package/static/dist/assets/copy-e6977uwq.js +0 -1
- package/static/dist/assets/endpoints-k7yf25m0.js +0 -64
- package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +0 -1
- package/static/dist/assets/index-h00usru2.js +0 -11
- package/static/dist/assets/index-n73ijkv2.css +0 -2
- package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +0 -1
- package/static/dist/assets/link-budeg5t9.js +0 -1
- package/static/dist/assets/matchContext-f8oy3lo7.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +0 -1
- package/static/dist/assets/onboarding-cdfrk0pj.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +0 -1
- package/static/dist/assets/refresh-cw-kbcje1uy.js +0 -1
- package/static/dist/assets/search-jen74z4u.js +0 -1
- package/static/dist/assets/share._token-dan9hgvj.js +0 -2
- package/static/dist/assets/sliders-horizontal-f9cb3lh3.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +0 -8
- package/static/dist/assets/todoStore-eqtid4r4.js +0 -1
- package/static/dist/assets/useLocale-hcsb84pj.js +0 -1
- package/static/dist/assets/useNavigate-nwy70ztj.js +0 -1
|
@@ -15,7 +15,14 @@ log = logging.getLogger("talaria_sidecar.commands")
|
|
|
15
15
|
|
|
16
16
|
_NEVER_EXPOSE = frozenset({"sethome", "restart", "update", "commands"})
|
|
17
17
|
_ALIASES = {"reload_mcp": "reload-mcp", "reload_skills": "reload-skills", "codex_runtime": "codex-runtime"}
|
|
18
|
-
|
|
18
|
+
# The commands ``commands.exec`` runs, with the catalog row the sidecar lists when the Agent registry lacks one.
|
|
19
|
+
_RUNTIME_COMMANDS = {
|
|
20
|
+
"reload-mcp": ("Reload MCP servers from config", "Tools & Skills", ""),
|
|
21
|
+
"reload-skills": ("Re-scan skills from disk", "Tools & Skills", ""),
|
|
22
|
+
"codex-runtime": ("Toggle codex app-server runtime for OpenAI/Codex models", "Configuration", "[auto|codex_app_server]"),
|
|
23
|
+
"credits": ("Show your Nous credits", "Info", ""),
|
|
24
|
+
}
|
|
25
|
+
_ALLOWED = frozenset(_RUNTIME_COMMANDS)
|
|
19
26
|
_RELOAD_MCP_LOCK = threading.Lock()
|
|
20
27
|
_RELOAD_SKILLS_LOCK = threading.Lock()
|
|
21
28
|
_CODEX_RUNTIME_LOCK = threading.Lock()
|
|
@@ -46,7 +53,13 @@ def list_commands() -> list[dict[str, Any]]:
|
|
|
46
53
|
out.append({
|
|
47
54
|
"name": cmd.name, "description": cmd.description, "category": cmd.category, "aliases": list(cmd.aliases),
|
|
48
55
|
"args_hint": cmd.args_hint, "subcommands": list(cmd.subcommands), "cli_only": bool(cmd.cli_only), "gateway_only": bool(cmd.gateway_only),
|
|
56
|
+
"exec": cmd.name in _ALLOWED,
|
|
49
57
|
})
|
|
58
|
+
listed = {c["name"] for c in out}
|
|
59
|
+
for name, (description, category, args_hint) in _RUNTIME_COMMANDS.items():
|
|
60
|
+
if name not in listed:
|
|
61
|
+
out.append({"name": name, "description": description, "category": category, "aliases": [a for a, n in _ALIASES.items() if n == name],
|
|
62
|
+
"args_hint": args_hint, "subcommands": [], "cli_only": False, "gateway_only": False, "exec": True})
|
|
50
63
|
try:
|
|
51
64
|
from hermes_cli.plugins import get_plugin_commands
|
|
52
65
|
|
|
@@ -55,7 +68,7 @@ def list_commands() -> list[dict[str, Any]]:
|
|
|
55
68
|
if name in existing or name in _NEVER_EXPOSE:
|
|
56
69
|
continue
|
|
57
70
|
out.append({"name": name, "description": str(info.get("description", "Plugin command")), "category": "Plugin", "aliases": [],
|
|
58
|
-
"args_hint": str(info.get("args_hint", "")), "subcommands": [], "cli_only": False, "gateway_only": False})
|
|
71
|
+
"args_hint": str(info.get("args_hint", "")), "subcommands": [], "cli_only": False, "gateway_only": False, "exec": True})
|
|
59
72
|
except Exception: # noqa: BLE001 - plugin registry is optional
|
|
60
73
|
log.debug("plugin command listing failed", exc_info=True)
|
|
61
74
|
return out
|
|
@@ -252,14 +252,18 @@ def _run_in_child(job, execution_home, ctx: CallContext):
|
|
|
252
252
|
process.join(timeout=5)
|
|
253
253
|
status, payload = "cancelled", ["cancelled", ""]
|
|
254
254
|
break
|
|
255
|
-
if
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
else:
|
|
255
|
+
if not process.is_alive():
|
|
256
|
+
# The child may have put its result just before exiting; otherwise it died (OOM, signal) without one.
|
|
257
|
+
try:
|
|
258
|
+
status, *payload = result_queue.get_nowait()
|
|
259
|
+
except queue.Empty:
|
|
261
260
|
payload = [f"cron run subprocess exited with code {process.exitcode} without producing a result", ""]
|
|
262
261
|
break
|
|
262
|
+
if time.monotonic() >= deadline:
|
|
263
|
+
process.terminate()
|
|
264
|
+
process.join(timeout=5)
|
|
265
|
+
payload = [f"cron run subprocess produced no result within {_result_timeout(job):g}s and was terminated", ""]
|
|
266
|
+
break
|
|
263
267
|
process.join(timeout=5)
|
|
264
268
|
if process.is_alive():
|
|
265
269
|
process.terminate()
|
|
@@ -8,6 +8,7 @@ server; the sidecar receives typed params.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import secrets
|
|
11
12
|
import time
|
|
12
13
|
from dataclasses import asdict, is_dataclass
|
|
13
14
|
from typing import Any
|
|
@@ -82,10 +83,102 @@ def _obj_dict(value):
|
|
|
82
83
|
return dict(getattr(value, "__dict__", {}))
|
|
83
84
|
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
LIVE_CLAIM_MESSAGE = "task has a live worker; archive it to stop the worker"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _row_claim_live(row) -> bool:
|
|
90
|
+
"""The Agent's ``_claim_is_live`` for a ``tasks`` row: a running task's worker process still holds its claim.
|
|
91
|
+
|
|
92
|
+
Releasing that claim (block, a direct status change) leaves the worker running, so the card
|
|
93
|
+
policy withholds those writes and the write paths refuse them (TAL-557). Unknown liveness counts as live.
|
|
94
|
+
"""
|
|
95
|
+
if row is None or row["status"] != "running":
|
|
96
|
+
return False
|
|
97
|
+
columns = row.keys()
|
|
98
|
+
claim = {k: row[k] if k in columns else None for k in ("status", "claim_lock", "worker_pid", "worker_started_at")}
|
|
99
|
+
try:
|
|
100
|
+
return bool(_kb()._claim_is_live(claim))
|
|
101
|
+
except Exception: # noqa: BLE001 - an older Agent without the helper
|
|
102
|
+
return bool(claim["claim_lock"] and claim["worker_pid"])
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _claim_live(conn, task_id) -> bool:
|
|
106
|
+
return _row_claim_live(conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,)).fetchone())
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
RUNNING_EXIT_MESSAGE = "task is running; confirm leaving Running"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _guard_running_exit(row, confirm_running_exit: bool) -> None:
|
|
113
|
+
"""A write that takes a task out of Running needs the client's explicit confirmation, judged on the row the
|
|
114
|
+
write sees: a client's card policy can predate a dispatcher claim (TAL-557)."""
|
|
115
|
+
if row["status"] == "running" and not confirm_running_exit:
|
|
116
|
+
raise Conflict(RUNNING_EXIT_MESSAGE)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
FENCE_PREFIX = "talaria-fence:"
|
|
120
|
+
FENCE_SECONDS = 60
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _clear_stale_fences(conn) -> None:
|
|
124
|
+
"""Release fences whose write never finished (the sidecar died mid-write), so the dispatcher can claim again."""
|
|
125
|
+
now = int(time.time())
|
|
126
|
+
stale = []
|
|
127
|
+
for row in conn.execute("SELECT id, claim_lock FROM tasks WHERE claim_lock LIKE ?", (FENCE_PREFIX + "%",)).fetchall():
|
|
128
|
+
try:
|
|
129
|
+
expires = int(str(row["claim_lock"])[len(FENCE_PREFIX):].split(":", 1)[0])
|
|
130
|
+
except ValueError:
|
|
131
|
+
expires = 0
|
|
132
|
+
if expires < now:
|
|
133
|
+
stale.append((row["id"], row["claim_lock"]))
|
|
134
|
+
if not stale:
|
|
135
|
+
return
|
|
136
|
+
kb = _kb()
|
|
137
|
+
with kb.write_txn(conn):
|
|
138
|
+
for task_id, fence in stale:
|
|
139
|
+
conn.execute("UPDATE tasks SET claim_lock = NULL WHERE id = ? AND claim_lock = ?", (task_id, fence))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _fenced(conn, task_id: str, write, *, confirm_running_exit: bool, releases_claim: bool = True):
|
|
143
|
+
"""Run an Agent transition (block, complete, archive) with the dispatcher fenced out.
|
|
144
|
+
|
|
145
|
+
The Agent's helpers open their own write transaction, which cannot nest, so the checks and a fence lock share
|
|
146
|
+
one transaction first: ``claim_task`` claims only a ``ready`` task with ``claim_lock IS NULL``, so the card cannot
|
|
147
|
+
become a live run before the helper runs. ``releases_claim`` writes (block, complete) refuse a live worker's claim;
|
|
148
|
+
archive keeps it, because ``archive_task`` terminates that worker. The fence expires, so a write the sidecar never
|
|
149
|
+
finished stops holding the card once ``_clear_stale_fences`` next runs.
|
|
150
|
+
"""
|
|
151
|
+
kb = _kb()
|
|
152
|
+
_clear_stale_fences(conn)
|
|
153
|
+
fence = f"{FENCE_PREFIX}{int(time.time()) + FENCE_SECONDS}:{secrets.token_hex(8)}"
|
|
154
|
+
with kb.write_txn(conn):
|
|
155
|
+
row = conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,)).fetchone()
|
|
156
|
+
if row is None:
|
|
157
|
+
raise NotFound("task not found")
|
|
158
|
+
_guard_running_exit(row, confirm_running_exit)
|
|
159
|
+
live = _row_claim_live(row)
|
|
160
|
+
if live and releases_claim:
|
|
161
|
+
raise Conflict(LIVE_CLAIM_MESSAGE)
|
|
162
|
+
# Only an unclaimed ready task is claimable; anything else needs no fence.
|
|
163
|
+
fenced = row["status"] == "ready" and row["claim_lock"] is None
|
|
164
|
+
if fenced:
|
|
165
|
+
conn.execute("UPDATE tasks SET claim_lock = ? WHERE id = ?", (fence, task_id))
|
|
166
|
+
try:
|
|
167
|
+
return write()
|
|
168
|
+
finally:
|
|
169
|
+
if fenced:
|
|
170
|
+
with kb.write_txn(conn):
|
|
171
|
+
conn.execute("UPDATE tasks SET claim_lock = NULL WHERE id = ? AND claim_lock = ?", (task_id, fence))
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _task_dict(task, conn):
|
|
86
175
|
data = _obj_dict(task)
|
|
87
176
|
if not data:
|
|
88
177
|
return data
|
|
178
|
+
# Facts the server's card policy needs (TAL-557): the Agent completes a non-review task only with
|
|
179
|
+
# stored or supplied evidence, and refuses to release a live worker's claim.
|
|
180
|
+
data["claim_live"] = data.get("status") == "running" and _claim_live(conn, data.get("id"))
|
|
181
|
+
data["has_completion_evidence"] = bool(str(data.get("result") or "").strip())
|
|
89
182
|
try:
|
|
90
183
|
age = _kb().task_age(task)
|
|
91
184
|
except Exception: # noqa: BLE001
|
|
@@ -131,12 +224,16 @@ def _validate_status(status: str) -> str:
|
|
|
131
224
|
return value
|
|
132
225
|
|
|
133
226
|
|
|
134
|
-
def _set_status_direct(conn, task_id: str, new_status: str) -> bool:
|
|
227
|
+
def _set_status_direct(conn, task_id: str, new_status: str, *, confirm_running_exit: bool = False) -> bool:
|
|
135
228
|
kb = _kb()
|
|
136
229
|
with kb.write_txn(conn):
|
|
137
|
-
prev = conn.execute("SELECT
|
|
230
|
+
prev = conn.execute("SELECT * FROM tasks WHERE id = ?", (task_id,)).fetchone()
|
|
138
231
|
if prev is None:
|
|
139
232
|
return False
|
|
233
|
+
# Checked inside the write transaction, so a claim taken since the client's read is never released.
|
|
234
|
+
_guard_running_exit(prev, confirm_running_exit)
|
|
235
|
+
if _row_claim_live(prev):
|
|
236
|
+
raise Conflict(LIVE_CLAIM_MESSAGE)
|
|
140
237
|
was_running = prev["status"] == "running"
|
|
141
238
|
cur = conn.execute(
|
|
142
239
|
"UPDATE tasks SET status = ?, "
|
|
@@ -202,14 +299,15 @@ def _patch_task(conn, task_id: str, body: dict) -> None:
|
|
|
202
299
|
if "status" not in body or body.get("status") in (None, ""):
|
|
203
300
|
return
|
|
204
301
|
status = _validate_status(body.get("status"))
|
|
302
|
+
confirm = bool(body.get("confirm_running_exit"))
|
|
205
303
|
if status == "done":
|
|
206
|
-
if not kb.complete_task(conn, task_id, result=body.get("result"), summary=body.get("summary")):
|
|
304
|
+
if not _fenced(conn, task_id, lambda: kb.complete_task(conn, task_id, result=body.get("result"), summary=body.get("summary")), confirm_running_exit=confirm):
|
|
207
305
|
raise NotFound("task not found")
|
|
208
306
|
elif status == "blocked":
|
|
209
|
-
if not kb.block_task(conn, task_id, reason=body.get("block_reason") or body.get("reason")):
|
|
307
|
+
if not _fenced(conn, task_id, lambda: kb.block_task(conn, task_id, reason=body.get("block_reason") or body.get("reason")), confirm_running_exit=confirm):
|
|
210
308
|
raise NotFound("task not found")
|
|
211
309
|
elif status == "archived":
|
|
212
|
-
if not kb.archive_task(conn, task_id):
|
|
310
|
+
if not _fenced(conn, task_id, lambda: kb.archive_task(conn, task_id), confirm_running_exit=confirm, releases_claim=False):
|
|
213
311
|
raise NotFound("task not found")
|
|
214
312
|
elif status == "running":
|
|
215
313
|
raise InvalidParams("Cannot set status to 'running' directly; use the dispatcher/claim path")
|
|
@@ -220,10 +318,10 @@ def _patch_task(conn, task_id: str, body: dict) -> None:
|
|
|
220
318
|
if current.status == "blocked":
|
|
221
319
|
if not kb.unblock_task(conn, task_id):
|
|
222
320
|
raise NotFound("task not found")
|
|
223
|
-
elif not _set_status_direct(conn, task_id, "ready"):
|
|
321
|
+
elif not _set_status_direct(conn, task_id, "ready", confirm_running_exit=confirm):
|
|
224
322
|
raise NotFound("task not found")
|
|
225
323
|
elif status in ("triage", "todo"):
|
|
226
|
-
if not _set_status_direct(conn, task_id, status):
|
|
324
|
+
if not _set_status_direct(conn, task_id, status, confirm_running_exit=confirm):
|
|
227
325
|
raise NotFound("task not found")
|
|
228
326
|
|
|
229
327
|
|
|
@@ -320,6 +418,7 @@ def board_payload(params: dict) -> dict:
|
|
|
320
418
|
profile = _str(params, "profile") or "default"
|
|
321
419
|
assignee = profile
|
|
322
420
|
with _conn(board=board) as conn:
|
|
421
|
+
_clear_stale_fences(conn)
|
|
323
422
|
latest = _latest_event_id(conn)
|
|
324
423
|
if since is not None and since >= latest:
|
|
325
424
|
return {"changed": False, "latest_event_id": latest, "read_only": False}
|
|
@@ -327,7 +426,7 @@ def board_payload(params: dict) -> dict:
|
|
|
327
426
|
link_counts, comment_counts = _link_counts(conn, tasks), _comment_counts(conn)
|
|
328
427
|
|
|
329
428
|
def row(task):
|
|
330
|
-
data = _task_dict(task)
|
|
429
|
+
data = _task_dict(task, conn)
|
|
331
430
|
data["link_counts"] = link_counts.get(task.id, {"parents": 0, "children": 0})
|
|
332
431
|
data["comment_count"] = comment_counts.get(task.id, 0)
|
|
333
432
|
return data
|
|
@@ -365,7 +464,7 @@ def create_task_payload(params: dict) -> dict:
|
|
|
365
464
|
)
|
|
366
465
|
if body.get("status"):
|
|
367
466
|
_patch_task(conn, task_id, {"status": body.get("status")})
|
|
368
|
-
return {"task": _task_dict(kb.get_task(conn, task_id)), "read_only": False}
|
|
467
|
+
return {"task": _task_dict(kb.get_task(conn, task_id), conn), "read_only": False}
|
|
369
468
|
|
|
370
469
|
|
|
371
470
|
def patch_task_payload(params: dict) -> dict:
|
|
@@ -375,7 +474,7 @@ def patch_task_payload(params: dict) -> dict:
|
|
|
375
474
|
kb = _kb()
|
|
376
475
|
with _conn(board=_board(params)) as conn:
|
|
377
476
|
_patch_task(conn, task_id, params.get("patch") or {})
|
|
378
|
-
return {"task": _task_dict(kb.get_task(conn, task_id)), "read_only": False}
|
|
477
|
+
return {"task": _task_dict(kb.get_task(conn, task_id), conn), "read_only": False}
|
|
379
478
|
|
|
380
479
|
|
|
381
480
|
def comment_payload(params: dict) -> dict:
|
|
@@ -418,7 +517,7 @@ def task_detail_payload(params: dict) -> dict:
|
|
|
418
517
|
if not task:
|
|
419
518
|
raise NotFound("task not found")
|
|
420
519
|
return {
|
|
421
|
-
"task": _task_dict(task),
|
|
520
|
+
"task": _task_dict(task, conn),
|
|
422
521
|
"comments": [_obj_dict(c) for c in kb.list_comments(conn, task_id)],
|
|
423
522
|
"events": [_obj_dict(e) for e in kb.list_events(conn, task_id)],
|
|
424
523
|
"links": {"parents": kb.parent_ids(conn, task_id), "children": kb.child_ids(conn, task_id)},
|
|
@@ -533,7 +632,8 @@ def bulk_payload(params: dict) -> dict:
|
|
|
533
632
|
results.append(entry)
|
|
534
633
|
continue
|
|
535
634
|
if body.get("archive"):
|
|
536
|
-
|
|
635
|
+
# Bulk carries no running-exit confirmation, so a running row is refused like a card write.
|
|
636
|
+
if not _fenced(conn, task_id, lambda: kb.archive_task(conn, task_id), confirm_running_exit=False, releases_claim=False):
|
|
537
637
|
entry.update(ok=False, error="archive refused")
|
|
538
638
|
elif body.get("status") is not None:
|
|
539
639
|
_patch_task(conn, task_id, {"status": body.get("status")})
|
|
@@ -578,7 +678,7 @@ def task_action_payload(params: dict) -> dict:
|
|
|
578
678
|
if not kb.get_task(conn, task_id):
|
|
579
679
|
raise NotFound("task not found")
|
|
580
680
|
if action == "block":
|
|
581
|
-
ok = kb.block_task(conn, task_id, reason=params.get("reason"))
|
|
681
|
+
ok = _fenced(conn, task_id, lambda: kb.block_task(conn, task_id, reason=params.get("reason")), confirm_running_exit=bool(params.get("confirm_running_exit")))
|
|
582
682
|
elif action == "unblock":
|
|
583
683
|
if hasattr(kb, "unblock_task"):
|
|
584
684
|
ok = kb.unblock_task(conn, task_id)
|
|
@@ -589,7 +689,7 @@ def task_action_payload(params: dict) -> dict:
|
|
|
589
689
|
raise InvalidParams(f"invalid action: {action}")
|
|
590
690
|
if not ok:
|
|
591
691
|
raise Conflict(f"{action} refused")
|
|
592
|
-
return {"task": _task_dict(kb.get_task(conn, task_id)), "read_only": False}
|
|
692
|
+
return {"task": _task_dict(kb.get_task(conn, task_id), conn), "read_only": False}
|
|
593
693
|
|
|
594
694
|
|
|
595
695
|
def list_boards_payload(params: dict) -> dict:
|
|
@@ -12,7 +12,7 @@ import time
|
|
|
12
12
|
from contextlib import closing
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
|
|
15
|
-
from ..errors import InvalidParams
|
|
15
|
+
from ..errors import InvalidParams, RpcError
|
|
16
16
|
from ..home import profile_home_param, scoped_home
|
|
17
17
|
from ..rpc import CallContext
|
|
18
18
|
|
|
@@ -54,6 +54,14 @@ def drain(max_events: int) -> list[dict]:
|
|
|
54
54
|
completion_queue = getattr(registry, "completion_queue", None) if registry is not None else None
|
|
55
55
|
if completion_queue is None:
|
|
56
56
|
return []
|
|
57
|
+
try:
|
|
58
|
+
# A recovered process has no reader thread; only this probe notices its exit and queues its completion (TAL-533).
|
|
59
|
+
with registry._lock:
|
|
60
|
+
detached = [s for s in registry._running.values() if getattr(s, "detached", False)]
|
|
61
|
+
for session in detached:
|
|
62
|
+
registry._refresh_detached_session(session)
|
|
63
|
+
except Exception: # noqa: BLE001
|
|
64
|
+
log.debug("Failed to reconcile recovered processes", exc_info=True)
|
|
57
65
|
out = []
|
|
58
66
|
while len(out) < max_events:
|
|
59
67
|
try:
|
|
@@ -94,6 +102,22 @@ def mark_consumed(process_id: str) -> bool:
|
|
|
94
102
|
return False
|
|
95
103
|
|
|
96
104
|
|
|
105
|
+
def consumed_ids(process_ids: list[str]) -> list[str]:
|
|
106
|
+
"""The processes the agent already holds from its own turn: consumed via wait/log, or observed exiting via poll.
|
|
107
|
+
Checked at wakeup delivery, since the completion is usually drained before the agent's wait returns (TAL-532)."""
|
|
108
|
+
registry = _registry()
|
|
109
|
+
if registry is None:
|
|
110
|
+
return []
|
|
111
|
+
out = []
|
|
112
|
+
for process_id in process_ids:
|
|
113
|
+
try:
|
|
114
|
+
if registry.is_completion_consumed(process_id) or process_id in (getattr(registry, "_poll_observed", None) or ()):
|
|
115
|
+
out.append(process_id)
|
|
116
|
+
except Exception: # noqa: BLE001
|
|
117
|
+
log.debug("Completion consumed check failed for %r", process_id, exc_info=True)
|
|
118
|
+
return out
|
|
119
|
+
|
|
120
|
+
|
|
97
121
|
def _delivery_api():
|
|
98
122
|
"""The Agent's durable delivery ledger (``tools.async_delegation``), or None on an Agent without it."""
|
|
99
123
|
try:
|
|
@@ -387,12 +411,40 @@ def delegation_result(home: Path, session_id: str, delegation_id: str) -> str:
|
|
|
387
411
|
return format_notification(event) if event else ""
|
|
388
412
|
|
|
389
413
|
|
|
414
|
+
def recover(base_home: Path) -> int:
|
|
415
|
+
"""TAL-533: re-adopt every profile's checkpointed processes when a sidecar starts, so a process in a profile nobody
|
|
416
|
+
uses yet is watched (and its exit reported) from the start. Entering a home's scope recovers it once; a failed
|
|
417
|
+
recovery fails the call, so the server retries."""
|
|
418
|
+
from hermes_cli.profiles import _PROFILE_ID_RE
|
|
419
|
+
|
|
420
|
+
profiles_root = base_home / "profiles"
|
|
421
|
+
named = sorted(p for p in profiles_root.iterdir() if p.is_dir() and _PROFILE_ID_RE.match(p.name)) if profiles_root.is_dir() else []
|
|
422
|
+
failed = []
|
|
423
|
+
for home in [base_home, *named]:
|
|
424
|
+
try:
|
|
425
|
+
with scoped_home(home):
|
|
426
|
+
pass
|
|
427
|
+
except RpcError as exc:
|
|
428
|
+
if exc.data.get("condition") != "agent_incompatible":
|
|
429
|
+
failed.append(str(exc))
|
|
430
|
+
continue
|
|
431
|
+
# An Agent without profile isolation refuses named profiles for good; their processes stay unadopted.
|
|
432
|
+
log.warning("Background process recovery skipped for %s", home, exc_info=True)
|
|
433
|
+
if failed:
|
|
434
|
+
raise RpcError("; ".join(failed))
|
|
435
|
+
return 1 + len(named)
|
|
436
|
+
|
|
437
|
+
|
|
390
438
|
def register(registry_) -> None:
|
|
391
439
|
@registry_.method("process.drain")
|
|
392
440
|
def drain_(ctx: CallContext, params: dict) -> dict:
|
|
393
441
|
with scoped_home(profile_home_param(params)):
|
|
394
442
|
return {"events": drain(int(params.get("max_events") or 256))}
|
|
395
443
|
|
|
444
|
+
@registry_.method("process.recover")
|
|
445
|
+
def recover_(ctx: CallContext, params: dict) -> dict:
|
|
446
|
+
return {"homes": recover(profile_home_param(params, "base_home"))}
|
|
447
|
+
|
|
396
448
|
@registry_.method("process.requeue")
|
|
397
449
|
def requeue_(ctx: CallContext, params: dict) -> dict:
|
|
398
450
|
events = params.get("events")
|
|
@@ -407,6 +459,13 @@ def register(registry_) -> None:
|
|
|
407
459
|
raise InvalidParams("process_id is required")
|
|
408
460
|
return {"ok": mark_consumed(process_id)}
|
|
409
461
|
|
|
462
|
+
@registry_.method("process.consumed")
|
|
463
|
+
def consumed_(ctx: CallContext, params: dict) -> dict:
|
|
464
|
+
ids = params.get("process_ids")
|
|
465
|
+
if not isinstance(ids, list) or not all(isinstance(i, str) and i for i in ids):
|
|
466
|
+
raise InvalidParams("process_ids must be a list of process ids")
|
|
467
|
+
return {"consumed": consumed_ids(ids)}
|
|
468
|
+
|
|
410
469
|
def _delivery_params(params: dict) -> dict:
|
|
411
470
|
evt = params.get("event")
|
|
412
471
|
if not isinstance(evt, dict):
|
|
@@ -241,7 +241,13 @@ def register(registry) -> None:
|
|
|
241
241
|
|
|
242
242
|
@registry.method("profiles.delete")
|
|
243
243
|
def delete(ctx: CallContext, params: dict) -> dict:
|
|
244
|
-
|
|
244
|
+
base_home, name = profile_home_param(params, "base_home"), str(params.get("name") or "").strip()
|
|
245
|
+
validate_name(name)
|
|
246
|
+
# Idle cached agents end their memory sessions while the profile's home still exists.
|
|
247
|
+
from .chat import release_profile_agents
|
|
248
|
+
|
|
249
|
+
release_profile_agents(base_home / "profiles" / name)
|
|
250
|
+
delete_profile(base_home, name)
|
|
245
251
|
return {"ok": True}
|
|
246
252
|
|
|
247
253
|
@registry.method("profiles.runtime_env")
|
|
@@ -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}
|
|
@@ -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")
|