@maudecode/talaria-web 1.21.0 → 1.22.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 +4 -4
- package/dist/api/automation-router.d.ts +14 -14
- package/dist/api/chat-router.d.ts +217 -68
- package/dist/api/groups-router.d.ts +764 -0
- package/dist/api/groups-router.js +79 -0
- package/dist/api/groups-router.js.map +1 -0
- package/dist/api/raw-routes.js +3 -1
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/sessions-router.d.ts +559 -160
- package/dist/api/sessions-router.js +9 -12
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +911 -1
- package/dist/api/settings-router.js +53 -2
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +1 -1
- package/dist/api/sse-routes.js +11 -3
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.js +27 -136
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +109 -24
- package/dist/api/tools-router.js +64 -7
- package/dist/api/tools-router.js.map +1 -1
- package/dist/app.js +5 -1
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +5 -1
- package/dist/auth/gate.js.map +1 -1
- package/dist/config/agent-config.d.ts +6 -1
- package/dist/config/agent-config.js +75 -3
- package/dist/config/agent-config.js.map +1 -1
- package/dist/feedback.d.ts +18 -0
- package/dist/feedback.js +145 -0
- package/dist/feedback.js.map +1 -0
- package/dist/fs/stat.d.ts +2 -0
- package/dist/fs/stat.js +4 -0
- package/dist/fs/stat.js.map +1 -1
- package/dist/http/context.d.ts +7 -0
- package/dist/http/context.js +0 -6
- package/dist/http/context.js.map +1 -1
- package/dist/http/pinned.js +19 -8
- package/dist/http/pinned.js.map +1 -1
- package/dist/providers/catalog.d.ts +9 -1
- package/dist/providers/catalog.js +86 -6
- package/dist/providers/catalog.js.map +1 -1
- package/dist/redact.js +9 -3
- package/dist/redact.js.map +1 -1
- package/dist/runtime.js +27 -4
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +3 -2
- package/dist/sessions/anchor.js +11 -10
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/cli-sessions.js +11 -6
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/compress.d.ts +10 -9
- package/dist/sessions/compress.js +31 -20
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/gateway-sessions.d.ts +11 -0
- package/dist/sessions/gateway-sessions.js +79 -24
- package/dist/sessions/gateway-sessions.js.map +1 -1
- package/dist/sessions/gateway-watcher.js +8 -4
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/groups.d.ts +60 -0
- package/dist/sessions/groups.js +339 -0
- package/dist/sessions/groups.js.map +1 -0
- package/dist/sessions/list.d.ts +7 -2
- package/dist/sessions/list.js +13 -4
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +14 -5
- package/dist/sessions/merge.js +42 -13
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/pending.d.ts +1 -1
- package/dist/sessions/pending.js +15 -6
- package/dist/sessions/pending.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +1 -14
- package/dist/sessions/prefix-index.js +1 -50
- package/dist/sessions/prefix-index.js.map +1 -1
- package/dist/sessions/reasoning-display.d.ts +2 -0
- package/dist/sessions/reasoning-display.js +31 -0
- package/dist/sessions/reasoning-display.js.map +1 -0
- package/dist/sessions/relay.d.ts +4 -1
- package/dist/sessions/relay.js +44 -7
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +7 -2
- package/dist/sessions/service.js +104 -64
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +6 -0
- package/dist/sessions/session.js +13 -0
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/shares.d.ts +1 -1
- package/dist/sessions/shares.js +13 -4
- package/dist/sessions/shares.js.map +1 -1
- package/dist/sessions/state-db.d.ts +2 -1
- package/dist/sessions/state-db.js +7 -3
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/storage/json-documents.js +2 -0
- package/dist/sessions/storage/json-documents.js.map +1 -1
- package/dist/sessions/store.d.ts +1 -0
- package/dist/sessions/store.js +10 -3
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +2 -0
- package/dist/sessions/streams.js +12 -0
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/todo.js +10 -1
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/turn.js +33 -9
- package/dist/sessions/turn.js.map +1 -1
- package/dist/settings.js +2 -1
- package/dist/settings.js.map +1 -1
- package/dist/spa.js +1 -1
- package/dist/spa.js.map +1 -1
- package/dist/test/group-fixture.d.ts +66 -0
- package/dist/test/group-fixture.js +89 -0
- package/dist/test/group-fixture.js.map +1 -0
- package/dist/test/harness.d.ts +3 -0
- package/dist/test/harness.js +3 -0
- package/dist/test/harness.js.map +1 -1
- package/dist/tools/connectors.d.ts +9 -1
- package/dist/tools/connectors.js +48 -0
- package/dist/tools/connectors.js.map +1 -1
- package/dist/tools/gateway-restart.d.ts +1 -1
- package/dist/tools/skills.d.ts +6 -0
- package/dist/tools/skills.js +17 -0
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/updates.d.ts +16 -9
- package/dist/tools/updates.js +63 -25
- package/dist/tools/updates.js.map +1 -1
- package/dist/workspace/fs.d.ts +2 -0
- package/dist/workspace/fs.js +63 -1
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/upload.d.ts +1 -1
- package/dist/workspace/upload.js +52 -37
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/workspaces.d.ts +5 -1
- package/dist/workspace/workspaces.js +32 -6
- package/dist/workspace/workspaces.js.map +1 -1
- package/package.json +2 -2
- package/sidecar/agent_importer.json +8 -0
- package/sidecar/scripts/agent_importer_contract.py +19 -0
- package/sidecar/scripts/test.sh +3 -1
- package/sidecar/talaria_sidecar/__init__.py +1 -1
- package/sidecar/talaria_sidecar/home.py +12 -5
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/agent_imports.py +346 -0
- package/sidecar/talaria_sidecar/methods/chat.py +141 -58
- package/sidecar/talaria_sidecar/methods/commands.py +6 -4
- package/sidecar/talaria_sidecar/methods/config.py +8 -3
- package/sidecar/talaria_sidecar/methods/connectors.py +138 -4
- package/sidecar/talaria_sidecar/methods/dashboard_plugins.py +21 -0
- package/sidecar/talaria_sidecar/methods/delegation.py +126 -0
- package/sidecar/talaria_sidecar/methods/gateway.py +5 -0
- package/sidecar/talaria_sidecar/methods/gateway_sessions.py +35 -6
- package/sidecar/talaria_sidecar/methods/groups.py +120 -0
- package/sidecar/talaria_sidecar/methods/memory.py +27 -3
- package/sidecar/talaria_sidecar/methods/nous_account.py +130 -0
- package/sidecar/talaria_sidecar/methods/oauth.py +25 -4
- package/sidecar/talaria_sidecar/methods/outbound_drafts.py +1 -19
- package/sidecar/talaria_sidecar/methods/plugin_catalog.py +73 -2
- package/sidecar/talaria_sidecar/methods/providers.py +51 -1
- package/sidecar/talaria_sidecar/methods/skill_revisions.py +177 -0
- package/sidecar/talaria_sidecar/methods/skills.py +10 -0
- package/sidecar/talaria_sidecar/methods/tts.py +67 -0
- package/sidecar/talaria_sidecar/rpc.py +11 -2
- package/static/dist/FILES.txt +155 -143
- package/static/dist/THIRD_PARTY_LICENSES.md +1 -1
- package/static/dist/assets/AppShell-hvysbd9x.js +8 -0
- package/static/dist/assets/{Button-nuaikybd.js → Button-dlsibkzq.js} +1 -1
- package/static/dist/assets/ChatPage-jikwrwfd.js +2 -0
- package/static/dist/assets/Composer-mnke8ss2.js +5 -0
- package/static/dist/assets/ConnectTargets-ejplzo4q.js +1 -0
- package/static/dist/assets/Dialog-rksfyyq5.js +1 -0
- package/static/dist/assets/{ExtensionRoute-l1yjrso4.js → ExtensionRoute-igk5h0rj.js} +1 -1
- package/static/dist/assets/HubRoute-eooassx4.js +2 -0
- package/static/dist/assets/Markdown-m5pzgvtx.js +2 -0
- package/static/dist/assets/{MarkdownRenderer-ccgqrza3.js → MarkdownRenderer-74ysuomr.js} +6 -6
- package/static/dist/assets/OAuthSignIn-i4flsuq2.js +1 -0
- package/static/dist/assets/QueueCard-msz9wd1m.js +1 -0
- package/static/dist/assets/ResourceSwitch-b70zg4xd.js +1 -0
- package/static/dist/assets/RightPanel-f5v61m8j.js +1 -0
- package/static/dist/assets/Select-f3l897pt.js +1 -0
- package/static/dist/assets/SessionListPanel-brnzacw9.js +1 -0
- package/static/dist/assets/SettingsLayout-f4akmrt2.js +1 -0
- package/static/dist/assets/States-msohx3c0.js +1 -0
- package/static/dist/assets/TerminalPanel-bnu5xawo.js +16 -0
- package/static/dist/assets/Toaster-d6col3ch.js +1 -0
- package/static/dist/assets/_app-lrjgufcy.js +1 -0
- package/static/dist/assets/{_app.ext._extensionId-n797jp72.js → _app.ext._extensionId-k3xitxr1.js} +1 -1
- package/static/dist/assets/_app.groups-bt4wdwnd.js +1 -0
- package/static/dist/assets/{_app.index-ne43mdw2.js → _app.index-n3otiki0.js} +1 -1
- package/static/dist/assets/{_app.insights-fqonovb4.js → _app.insights-b0mzlh6m.js} +1 -1
- package/static/dist/assets/{_app.kanban-kysliv19.js → _app.kanban-d923g7j5.js} +1 -1
- package/static/dist/assets/{_app.logs-febut82r.js → _app.logs-donegue1.js} +1 -1
- package/static/dist/assets/{_app.memory-ha86oj1c.js → _app.memory-hdnled08.js} +1 -1
- package/static/dist/assets/{_app.profiles-cnu3gxxq.js → _app.profiles-fumot3jk.js} +1 -1
- package/static/dist/assets/{_app.session._sessionId-ifzjpcgn.js → _app.session._sessionId-crmdl2ux.js} +1 -1
- package/static/dist/assets/{_app.settings-nmakdiaf.js → _app.settings-jui8iesz.js} +1 -1
- package/static/dist/assets/_app.settings._section-do84hsqw.js +3 -0
- package/static/dist/assets/{_app.skills-f3wad8yo.js → _app.skills-heqcn21m.js} +1 -1
- package/static/dist/assets/_app.tasks-jiudtutt.js +1 -0
- package/static/dist/assets/{_app.todos-bml1m3r1.js → _app.todos-bl6kk2zq.js} +1 -1
- package/static/dist/assets/{_app.workspaces-f3d066lx.js → _app.workspaces-frvh3o7w.js} +1 -1
- package/static/dist/assets/_delete-qnxuo87s.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-i53jc4yp.js → abnfDiagram-VCTEODGH-dppg3yfx.js} +1 -1
- package/static/dist/assets/{architecture-7GRP2DOG-e3bv5m6f.js → architecture-7GRP2DOG-gbajejh3.js} +1 -1
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-pakekxu2.js → architectureDiagram-5GKGNRK7-bzrxyais.js} +1 -1
- package/static/dist/assets/archive-yhdyz231.js +1 -0
- package/static/dist/assets/autoReadClaim-nlyv8tu9.js +1 -0
- package/static/dist/assets/{blockDiagram-I7D4REHJ-bc6bo1n6.js → blockDiagram-I7D4REHJ-gmk9koab.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-btvwk2qx.js → c4Diagram-7LVT6UL2-bfqiqqcz.js} +1 -1
- package/static/dist/assets/channel-grt3rob4.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-dlwab11c.js → chunk-4HAMMTFA-i9s6h4wv.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-dp5gh7i8.js → chunk-75Z2AOVW-gnt6pnso.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-bi06zl1c.js → chunk-DU6HZSFF-gq439wot.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-kvv1rnlh.js → chunk-F27PBJKO-wvx90pbt.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-ji0rx9by.js → chunk-GMAD6QVW-mc2gu30k.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-nmz0j82p.js → chunk-GVQU2GXP-f8fxa2ym.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-kmi1qx88.js → chunk-IMKFNOWR-lnsl31hj.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-xhb7mebj.js → chunk-L3NEJ4N5-kbfdidwu.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-5a9sgscq.js → chunk-OSK3NFVY-dvxsduj6.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-dfezp4vu.js → chunk-P2QGCYS3-ivo3i1wf.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-gd2vq3c0.js → chunk-POPQ4Y6H-i0gfu0hx.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-wvw2nksf.js → chunk-PWAF6VOD-jb0fdyb0.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-f58q97px.js → chunk-SHT3W25Y-b7ou2xsp.js} +1 -1
- package/static/dist/assets/{chunk-SVP7TREG-abgwpyz9.js → chunk-SVP7TREG-e2v7me5v.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-h4sbs8ds.js → chunk-TICWLB2K-e5zlai62.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-nnsp49jr.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-nnsp49jr.js +1 -0
- package/static/dist/assets/completionAudio-c5at041z.js +1 -0
- package/static/dist/assets/{copy-m9h56qa8.js → copy-jj3oiw13.js} +1 -1
- package/static/dist/assets/{cynefin-OW5HDTMX-g081vffs.js → cynefin-OW5HDTMX-n5n1ck70.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-odxvjesk.js → cynefinDiagram-5FMLGOSQ-b33npu4f.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-cpdwzjs4.js → dagre-GXQ25YYZ-miwvae07.js} +1 -1
- package/static/dist/assets/{diagram-S7CK7UJ4-clv5mxvu.js → diagram-S7CK7UJ4-j8fphsp4.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-m2ia1mbf.js → diagram-UQ7AKVKN-5cixo166.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-ea6zv636.js → diagram-VSXAHHWV-ii3bf92m.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-oqlef685.js → diagram-VX7I27RA-b3cfgx81.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-kjubcbwu.js → diagram-Z3DM3KII-bey9lqr8.js} +1 -1
- package/static/dist/assets/{dist-carq1azj.js → dist-cb8um5dh.js} +4 -4
- package/static/dist/assets/{dist-crc46di9.js → dist-kpg5ccm9.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-fg0zri3e.js → ebnfDiagram-PWID7BFC-2m4wrnqc.js} +1 -1
- package/static/dist/assets/{erDiagram-RLTQ6QDP-eb7pmk3x.js → erDiagram-RLTQ6QDP-kak5te0n.js} +1 -1
- package/static/dist/assets/{eventmodeling-NTZA5JFV-gvi1fxhn.js → eventmodeling-NTZA5JFV-ojcc486t.js} +1 -1
- package/static/dist/assets/flowDiagram-HODETNUW-kxr9sicu.js +1 -0
- package/static/dist/assets/folder-plus-fk6j7tlv.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-jmisowrc.js → ganttDiagram-EL5Y4UJY-k6nfmhrh.js} +1 -1
- package/static/dist/assets/getPseudoElementBounds-mwj3vqni.js +1 -0
- package/static/dist/assets/{gitGraph-4MIJSDKK-m7kt3u6e.js → gitGraph-4MIJSDKK-bxq1lbhy.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-nq7vfzh2.js → gitGraphDiagram-WWUBYQGX-ehvoankt.js} +1 -1
- package/static/dist/assets/group_discussions-fk5hry4l.js +1 -0
- package/static/dist/assets/{highlighted-body-KPVGNVTW-gcu017ay.js → highlighted-body-KPVGNVTW-nr4nfdq7.js} +1 -1
- package/static/dist/assets/{host-ipp4e84c.js → host-dhgqiozp.js} +1 -1
- package/static/dist/assets/index-hx7z4wdj.js +13 -0
- package/static/dist/assets/index-o8ebuc5x.css +2 -0
- package/static/dist/assets/{info-A6RAGUB7-idazwfqe.js → info-A6RAGUB7-dtsj0ybw.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-bb9jh8gl.js → infoDiagram-27XIBGKW-jena90ao.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-nqc132rv.js → ishikawaDiagram-5VMMS53U-kia6bn5u.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-fpvnhy44.js → journeyDiagram-3NMN7TZE-ipsa6icb.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-ndzqm6fu.js → kanban-definition-UXKFOSKX-moxx59kp.js} +1 -1
- package/static/dist/assets/katex-ic33v820.js +257 -0
- package/static/dist/assets/katex-qcv7xo0t.css +1 -0
- package/static/dist/assets/{lazyRouteComponent-javud235.js → lazyRouteComponent-i74ujrfk.js} +1 -1
- package/static/dist/assets/{line-g625e7cj.js → line-lgrkg9no.js} +1 -1
- package/static/dist/assets/link-2-fp49mwl2.js +1 -0
- package/static/dist/assets/{link-gfdaho08.js → link-es18mse1.js} +2 -2
- package/static/dist/assets/{locale-cs-n41hptse.js → locale-cs-brltdkcp.js} +1 -1
- package/static/dist/assets/{locale-de-k7ht47ew.js → locale-de-h6e9oq6v.js} +1 -1
- package/static/dist/assets/{locale-es-ih078lco.js → locale-es-oklmh80f.js} +1 -1
- package/static/dist/assets/{locale-fr-ojabnf41.js → locale-fr-b17ozoi2.js} +1 -1
- package/static/dist/assets/{locale-it-kb96jufy.js → locale-it-whe01eef.js} +1 -1
- package/static/dist/assets/{locale-ja-jpsp3xs1.js → locale-ja-g1s0rtpc.js} +1 -1
- package/static/dist/assets/{locale-pl-dbap4leu.js → locale-pl-d9p3lqcb.js} +1 -1
- package/static/dist/assets/{locale-pt-nci7w72x.js → locale-pt-l75on74f.js} +1 -1
- package/static/dist/assets/{locale-ru-soghe4cs.js → locale-ru-wl3mbsaw.js} +1 -1
- package/static/dist/assets/{locale-tr-ks00mu68.js → locale-tr-cz87itrq.js} +1 -1
- package/static/dist/assets/{locale-vi-ij7twfm6.js → locale-vi-elqj1y4k.js} +1 -1
- package/static/dist/assets/{locale-zh-Hant-feakwr7a.js → locale-zh-Hant-hf8gqm7d.js} +1 -1
- package/static/dist/assets/{locale-zh-ren0vjyv.js → locale-zh-cdckwb0u.js} +1 -1
- package/static/dist/assets/login-o6gfl4gy.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-n2kbzsao.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-plzkuzov.js → mermaid-parser.core-fflovwf2.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-ojrgs569.js → mindmap-definition-YA3MSWOX-ic8l9whi.js} +1 -1
- package/static/dist/assets/onboarding-bxm7gdrr.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-gyaf9s8h.js → packet-AYTQ26CC-ntci3088.js} +1 -1
- package/static/dist/assets/{pegDiagram-XKGWAZYB-bf6xj8mq.js → pegDiagram-XKGWAZYB-e3btz04w.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-f5ymzelo.js → pie-WAS4IAKB-o2dc7l36.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-d0qjl3zi.js → pieDiagram-E7YTZNPT-gro55rrw.js} +1 -1
- package/static/dist/assets/presence-lq6m12ga.js +1 -0
- package/static/dist/assets/prompt_queue_cancelled-cebcuagu.js +1 -0
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-oqy1mras.js → quadrantDiagram-AXDQQJYC-fxulmd7d.js} +1 -1
- package/static/dist/assets/queryKeys-cnvn6pea.js +9 -0
- package/static/dist/assets/{radar-RG4KPBEZ-b6jcjvda.js → radar-RG4KPBEZ-9pcospra.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-e3a6lk5k.js → railroad-74A4TZTK-nzdga12j.js} +1 -1
- package/static/dist/assets/{railroad-abnf-HS5TGJTU-ff5hocrx.js → railroad-abnf-HS5TGJTU-ep3ytel0.js} +1 -1
- package/static/dist/assets/{railroad-ebnf-LZEXJU2U-exkhyw4n.js → railroad-ebnf-LZEXJU2U-iw7uc1wy.js} +1 -1
- package/static/dist/assets/{railroad-peg-WCYAUIDC-jefk9b7c.js → railroad-peg-WCYAUIDC-fo3b3gme.js} +1 -1
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-e4amks1i.js → railroadDiagram-O6MQD6OU-lxpxf8f0.js} +1 -1
- package/static/dist/assets/{refresh-cw-lfp4u1oh.js → refresh-cw-d14h79x5.js} +1 -1
- package/static/dist/assets/rename-ccd52yws.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-c77k1e2y.js → requirementDiagram-BXWQKSXE-lrozucd2.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-oa1cc52s.js → sankeyDiagram-P5KCCOFB-iusxy9mq.js} +1 -1
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-j20gqt22.js → sequenceDiagram-WJ2MYXX4-o987q8ti.js} +1 -1
- package/static/dist/assets/{share._token-kmfoflw6.js → share._token-bfw7f9m5.js} +2 -2
- package/static/dist/assets/sliders-horizontal-l65hoa3x.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-co2ghkdp.js → stateDiagram-D77RDMKH-hh23v7y5.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-jukr0d8h.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-m30cktqe.js → swimlanes-42K2YHIH-gj2t3rm8.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ik9m9j2m.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-liuep6fl.js → timeline-definition-24CTP7MA-84s2w2sr.js} +1 -1
- package/static/dist/assets/toast-gqqcvxiy.js +56 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-np5d2jv2.js → treeView-Q6P3EWNA-cmuj50l7.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-cmpltxh1.js → treemap-WGGIJYW6-dpjlg0xc.js} +1 -1
- package/static/dist/assets/tts-jw84jlqy.js +1 -0
- package/static/dist/assets/{useForm-f1udzsjf.js → useForm-lxzhiqao.js} +1 -1
- package/static/dist/assets/{useParams-ierevvts.js → useParams-dt6gkoq7.js} +1 -1
- package/static/dist/assets/{useSearch-i7nr9ypl.js → useSearch-o8t49csk.js} +1 -1
- package/static/dist/assets/useTranscript-gx9umcc2.js +1 -0
- package/static/dist/assets/{vennDiagram-4TSXK5OY-b2g42qrg.js → vennDiagram-4TSXK5OY-g9g5o8vy.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-lb0eqbff.js → wardley-WFR3VGLG-ij35obrl.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ermwaqha.js → wardleyDiagram-VM6X3IG4-f9my7q7w.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-dll0jldk.js → xychartDiagram-S5SC5T6Z-olqx1s1p.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +1 -1
- package/static/dist/assets/AppShell-c5989995.js +0 -8
- package/static/dist/assets/ChatPage-bfg4khph.js +0 -6
- package/static/dist/assets/ConnectTargets-k5wo9yo8.js +0 -1
- package/static/dist/assets/Dialog-o8vo2aws.js +0 -1
- package/static/dist/assets/Field-j7o8cfps.js +0 -1
- package/static/dist/assets/HubRoute-efnwe4xz.js +0 -2
- package/static/dist/assets/Markdown-clqf5m22.js +0 -2
- package/static/dist/assets/OAuthSignIn-h7bjaqp6.js +0 -1
- package/static/dist/assets/ResourceSwitch-oai2zqaj.js +0 -1
- package/static/dist/assets/RightPanel-ho161a45.js +0 -1
- package/static/dist/assets/Select-d1g5a8bm.js +0 -1
- package/static/dist/assets/SessionListPanel-i7kaokhi.js +0 -1
- package/static/dist/assets/SettingsLayout-lnecm87w.js +0 -1
- package/static/dist/assets/States-easntmry.js +0 -1
- package/static/dist/assets/TerminalPanel-lxhwd4jl.js +0 -16
- package/static/dist/assets/Toaster-l4sciy8t.js +0 -1
- package/static/dist/assets/_app-mqexqbg8.js +0 -1
- package/static/dist/assets/_app.settings._section-djglnjmi.js +0 -3
- package/static/dist/assets/_app.tasks-l10py1c0.js +0 -1
- package/static/dist/assets/archive-ihqi7z2x.js +0 -1
- package/static/dist/assets/channel-jn4f8443.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-dzrw66se.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-dzrw66se.js +0 -1
- package/static/dist/assets/completionAudio-ce86msbu.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-abekab15.js +0 -1
- package/static/dist/assets/folder-plus-ksaons88.js +0 -1
- package/static/dist/assets/index-d6vbxlra.js +0 -13
- package/static/dist/assets/index-ey6qo0zx.css +0 -2
- package/static/dist/assets/katex-cbdd1ohw.css +0 -1
- package/static/dist/assets/katex-pbij2oo6.js +0 -257
- package/static/dist/assets/login-iv6yq4xf.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-cwj5cl6k.js +0 -1
- package/static/dist/assets/onboarding-ff4emacu.js +0 -1
- package/static/dist/assets/queryKeys-x8fjxhut.js +0 -9
- package/static/dist/assets/sliders-horizontal-g5jkzd9k.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-faw1opgh.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-hfil433g.js +0 -8
- package/static/dist/assets/toast-zmb35u3r.js +0 -56
|
@@ -18,6 +18,7 @@ import importlib.util
|
|
|
18
18
|
import inspect
|
|
19
19
|
import json
|
|
20
20
|
import logging
|
|
21
|
+
import math
|
|
21
22
|
import os
|
|
22
23
|
import queue
|
|
23
24
|
import re
|
|
@@ -34,7 +35,7 @@ from ..errors import InvalidParams, RpcError
|
|
|
34
35
|
from ..home import profile_home_param, scoped_home, session_workspace
|
|
35
36
|
from ..rpc import CallContext
|
|
36
37
|
from .checkpoints import checkpoint_kwargs
|
|
37
|
-
from .providers import runtime_failure
|
|
38
|
+
from .providers import require_runtime_ownership, runtime_failure
|
|
38
39
|
from .state_db import release_all, release_home, release_session_db
|
|
39
40
|
from .toolsets import disabled_toolsets
|
|
40
41
|
|
|
@@ -69,6 +70,12 @@ class _Run:
|
|
|
69
70
|
self.session_ended = False
|
|
70
71
|
self.home = None # the profile home its agent runs under, set by ``start``
|
|
71
72
|
self.mcp_discovery_outcome = "ok"
|
|
73
|
+
self.deadline: float | None = None
|
|
74
|
+
|
|
75
|
+
def prompt_cancelled(self, data: dict) -> bool:
|
|
76
|
+
# Vault answers racing a clear retain their existing unlock-then-release cleanup at turn end.
|
|
77
|
+
ended = self.session_ended and not str(data.get("kind") or "").startswith("vault_")
|
|
78
|
+
return self.ctx.cancelled or self.cancel.is_set() or self.finished.is_set() or ended
|
|
72
79
|
|
|
73
80
|
|
|
74
81
|
class _ClarifyEntry:
|
|
@@ -80,7 +87,77 @@ class _ClarifyEntry:
|
|
|
80
87
|
self.deadline: float | None = None
|
|
81
88
|
|
|
82
89
|
|
|
90
|
+
def _ask_clarify(run: _Run, data: dict, timeout: int, emit=None) -> str | None:
|
|
91
|
+
"""Park on a prompt the server relays until it is answered, the turn is cancelled or ends, or ``timeout``
|
|
92
|
+
passes (``<= 0``: no limit). The answer, or None, goes back to the Agent and is never emitted."""
|
|
93
|
+
emit = emit or run.ctx.emit
|
|
94
|
+
entry = _ClarifyEntry(data)
|
|
95
|
+
entry.data["clarify_id"] = entry.clarify_id
|
|
96
|
+
entry.deadline = None if timeout <= 0 else time.monotonic() + float(timeout)
|
|
97
|
+
if run.deadline is not None:
|
|
98
|
+
entry.deadline = min(entry.deadline, run.deadline) if entry.deadline is not None else run.deadline
|
|
99
|
+
with run.lock:
|
|
100
|
+
if run.prompt_cancelled(data) or (entry.deadline is not None and entry.deadline <= time.monotonic()):
|
|
101
|
+
return None
|
|
102
|
+
run.clarify_entries[entry.clarify_id] = entry
|
|
103
|
+
try:
|
|
104
|
+
emit("clarify", dict(entry.data))
|
|
105
|
+
while not entry.event.is_set():
|
|
106
|
+
if run.prompt_cancelled(data):
|
|
107
|
+
break
|
|
108
|
+
if entry.deadline is None:
|
|
109
|
+
entry.event.wait(0.1)
|
|
110
|
+
continue
|
|
111
|
+
remaining = entry.deadline - time.monotonic()
|
|
112
|
+
if remaining <= 0:
|
|
113
|
+
break
|
|
114
|
+
entry.event.wait(min(0.1, remaining))
|
|
115
|
+
finally:
|
|
116
|
+
with run.lock:
|
|
117
|
+
run.clarify_entries.pop(entry.clarify_id, None)
|
|
118
|
+
emit("clarify_resolved", {"clarify_id": entry.clarify_id, "session_id": run.session_id})
|
|
119
|
+
return None if run.prompt_cancelled(data) else entry.result
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _clarify_callback(run: _Run, params: dict, emit=None):
|
|
123
|
+
def clarify_callback(question, choices=None, multi_select=False, questions=None):
|
|
124
|
+
# TAL-351: remove the legacy signature path when v0.21.6 is the oldest supported Agent.
|
|
125
|
+
structured = isinstance(question, list)
|
|
126
|
+
if structured:
|
|
127
|
+
questions, question = question, ""
|
|
128
|
+
choices_list = [str(c) for c in (choices or [])]
|
|
129
|
+
# Predecessor `_clarify_timeout_seconds`: the Agent's own resolver over this profile's config
|
|
130
|
+
# (``clarify.timeout`` else ``agent.clarify_timeout`` else 3600); ``<= 0`` waits until answered or cancelled.
|
|
131
|
+
# The advertised ``timeout_seconds`` is what the clients count down, so it is the same number.
|
|
132
|
+
timeout = _clarify_timeout(params)
|
|
133
|
+
if run.deadline is not None:
|
|
134
|
+
remaining = max(1, math.ceil(run.deadline - time.monotonic()))
|
|
135
|
+
timeout = min(timeout, remaining) if timeout > 0 else remaining
|
|
136
|
+
data = {"question": str(question or ""), "choices_offered": choices_list, "session_id": run.session_id, "kind": "clarify", "requested_at": time.time(), "timeout_seconds": timeout}
|
|
137
|
+
if multi_select:
|
|
138
|
+
data["multi_select"] = True
|
|
139
|
+
# Batch prompts (the Agent's ``_run_batch``) carry no top-level question and expect the ``{"answers": {...}}`` reply.
|
|
140
|
+
if isinstance(questions, list) and questions:
|
|
141
|
+
data["questions"] = questions
|
|
142
|
+
answer = _ask_clarify(run, data, timeout, emit)
|
|
143
|
+
if answer is not None:
|
|
144
|
+
if structured:
|
|
145
|
+
return {"answers": json.loads(answer)["answers"], "outcome": "submitted"}
|
|
146
|
+
return answer
|
|
147
|
+
cancelled = run.prompt_cancelled(data)
|
|
148
|
+
if structured:
|
|
149
|
+
return {"answers": {}, "outcome": "cancelled" if cancelled else "timed_out",
|
|
150
|
+
"notice": "The user cancelled the clarification." if cancelled else "The clarification timed out."}
|
|
151
|
+
# Older tools have no outcome field. A batch understands timed_out; a single needs an empty answer.
|
|
152
|
+
if questions:
|
|
153
|
+
return json.dumps({"answers": {}, "timed_out": not cancelled})
|
|
154
|
+
return ""
|
|
155
|
+
|
|
156
|
+
return clarify_callback
|
|
157
|
+
|
|
158
|
+
|
|
83
159
|
_RUNS: dict[str, _Run] = {}
|
|
160
|
+
_COMMAND_RUNS: dict[str, _Run] = {}
|
|
84
161
|
_RUNS_BY_SESSION: dict[str, str] = {}
|
|
85
162
|
# Which run owns the Agent's gateway approval callback per session; register/unregister happen under one lock so a
|
|
86
163
|
# stale run can never remove a successor's callback, and a successor can never leak a predecessor's.
|
|
@@ -108,6 +185,43 @@ _MCP_REDISCOVERY_WAIT = 2.0
|
|
|
108
185
|
_MCP_PENDING_KEY = "mcp_discovery_pending"
|
|
109
186
|
|
|
110
187
|
|
|
188
|
+
def cancel_command_choices(session_id: str | None = None, home=None) -> None:
|
|
189
|
+
with _RUNS_LOCK:
|
|
190
|
+
for run in _COMMAND_RUNS.values():
|
|
191
|
+
if (session_id is None or run.session_id == session_id) and (home is None or run.home == os.path.realpath(home)):
|
|
192
|
+
run.session_ended = True
|
|
193
|
+
run.cancel.set()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@contextlib.contextmanager
|
|
197
|
+
def command_choices(ctx: CallContext, params: dict):
|
|
198
|
+
session_id = str(params.get("session_id") or "").strip()
|
|
199
|
+
try:
|
|
200
|
+
from hermes_cli.plugin_choices import bind_asker, clarify_asker
|
|
201
|
+
except ImportError:
|
|
202
|
+
yield
|
|
203
|
+
return
|
|
204
|
+
if not session_id:
|
|
205
|
+
yield
|
|
206
|
+
return
|
|
207
|
+
run = _Run(uuid.uuid4().hex, session_id, ctx)
|
|
208
|
+
# The server's commands.exec budget includes every question and the handler's final output.
|
|
209
|
+
run.deadline = time.monotonic() + 120
|
|
210
|
+
run.home = os.path.realpath(profile_home_param(params))
|
|
211
|
+
with _MCP_DISCOVERY_LOCK, _RUNS_LOCK:
|
|
212
|
+
ctx.check_cancelled()
|
|
213
|
+
if _DRAINING.is_set() or run.home in _MCP_CLOSING_HOMES:
|
|
214
|
+
raise RpcError("Command profile is unavailable", condition="profile_unavailable")
|
|
215
|
+
_COMMAND_RUNS[run.stream_id] = run
|
|
216
|
+
try:
|
|
217
|
+
with bind_asker(clarify_asker(_clarify_callback(run, params))):
|
|
218
|
+
yield
|
|
219
|
+
finally:
|
|
220
|
+
run.finished.set()
|
|
221
|
+
with _RUNS_LOCK:
|
|
222
|
+
_COMMAND_RUNS.pop(run.stream_id, None)
|
|
223
|
+
|
|
224
|
+
|
|
111
225
|
def _snippet(raw: Any, limit: int = _TOOL_RESULT_SNIPPET_MAX) -> str:
|
|
112
226
|
"""Predecessor ``_tool_result_snippet``: the ``output``/``result``/``error`` of a dict (or JSON) result, hard-cut."""
|
|
113
227
|
if limit <= 0:
|
|
@@ -313,8 +427,14 @@ def _usage(agent: Any) -> dict:
|
|
|
313
427
|
value = getattr(agent, name, None)
|
|
314
428
|
return value if isinstance(value, (int, float)) else 0
|
|
315
429
|
|
|
430
|
+
try:
|
|
431
|
+
from gateway.session_usage import plan_gauge
|
|
432
|
+
gauge = plan_gauge(agent)
|
|
433
|
+
except Exception: # noqa: BLE001 - older Agent capability omission clears a complete snapshot
|
|
434
|
+
gauge = None
|
|
316
435
|
cost = getattr(agent, "session_estimated_cost_usd", None)
|
|
317
436
|
return {
|
|
437
|
+
**({"plan_gauge": gauge} if gauge is not None else {}),
|
|
318
438
|
"prompt_tokens": int(_num("session_prompt_tokens")),
|
|
319
439
|
"completion_tokens": int(_num("session_completion_tokens")),
|
|
320
440
|
"cache_read_tokens": int(_num("session_cache_read_tokens")),
|
|
@@ -695,6 +815,7 @@ def _cancel_checkpoint(run: _Run) -> list | None:
|
|
|
695
815
|
|
|
696
816
|
|
|
697
817
|
def _resolve_runtime(provider: str | None, model: str) -> dict:
|
|
818
|
+
require_runtime_ownership(provider)
|
|
698
819
|
try:
|
|
699
820
|
from hermes_cli.runtime_provider import resolve_runtime_provider
|
|
700
821
|
except Exception as exc: # noqa: BLE001
|
|
@@ -1363,6 +1484,7 @@ def _cancel_background_reviews(entries, message: str) -> list[threading.Thread]:
|
|
|
1363
1484
|
|
|
1364
1485
|
def evict_all_agents() -> int:
|
|
1365
1486
|
"""Drop every cached agent (credentials or environment changed underneath them)."""
|
|
1487
|
+
cancel_command_choices()
|
|
1366
1488
|
with _AGENT_CACHE_LOCK:
|
|
1367
1489
|
entries = list(_AGENT_CACHE.values())
|
|
1368
1490
|
_AGENT_CACHE.clear()
|
|
@@ -1387,7 +1509,7 @@ def drain_agents(timeout: float = _AGENT_RELEASE_TIMEOUT) -> None:
|
|
|
1387
1509
|
run.cancel.set()
|
|
1388
1510
|
while time.monotonic() < deadline:
|
|
1389
1511
|
with _AGENT_CACHE_LOCK, _RUNS_LOCK:
|
|
1390
|
-
if not _COMMITTING and not any(_RUNS.get(run.stream_id) is run for run in runs):
|
|
1512
|
+
if not _COMMITTING and not _COMMAND_RUNS and not any(_RUNS.get(run.stream_id) is run for run in runs):
|
|
1391
1513
|
break
|
|
1392
1514
|
time.sleep(0.05)
|
|
1393
1515
|
# A turn may have cached its agent after the first eviction.
|
|
@@ -1440,6 +1562,7 @@ def release_profile_agents(home):
|
|
|
1440
1562
|
raise RpcError("The profile is already being deleted.", condition="profile_unavailable")
|
|
1441
1563
|
_MCP_CLOSING_HOMES.add(target)
|
|
1442
1564
|
try:
|
|
1565
|
+
cancel_command_choices(home=home)
|
|
1443
1566
|
with _AGENT_CACHE_LOCK:
|
|
1444
1567
|
entries = [_AGENT_CACHE.pop(sid) for sid, entry in list(_AGENT_CACHE.items()) if os.path.realpath(entry[2]) == target]
|
|
1445
1568
|
started = _release_agents_locked(entries)
|
|
@@ -1470,8 +1593,8 @@ def release_profile_agents(home):
|
|
|
1470
1593
|
|
|
1471
1594
|
|
|
1472
1595
|
def _holding_home(target: str) -> bool:
|
|
1473
|
-
with _AGENT_CACHE_LOCK:
|
|
1474
|
-
return any(os.path.realpath(home) == target for _agent, home in _COMMITTING)
|
|
1596
|
+
with _AGENT_CACHE_LOCK, _RUNS_LOCK:
|
|
1597
|
+
return any(os.path.realpath(home) == target for _agent, home in _COMMITTING) or any(run.home == target for run in _COMMAND_RUNS.values())
|
|
1475
1598
|
|
|
1476
1599
|
|
|
1477
1600
|
def _acquire_session_db(home):
|
|
@@ -1889,28 +2012,7 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
|
|
|
1889
2012
|
emit("notice_clear", {"key": str(key)})
|
|
1890
2013
|
|
|
1891
2014
|
def ask(data: dict, timeout: int) -> str | None:
|
|
1892
|
-
|
|
1893
|
-
passes (``<= 0``: no limit). The answer, or None, goes back to the Agent and is never emitted."""
|
|
1894
|
-
entry = _ClarifyEntry(data)
|
|
1895
|
-
entry.data["clarify_id"] = entry.clarify_id
|
|
1896
|
-
entry.deadline = None if timeout <= 0 else time.monotonic() + float(timeout)
|
|
1897
|
-
with run.lock:
|
|
1898
|
-
run.clarify_entries[entry.clarify_id] = entry
|
|
1899
|
-
emit("clarify", dict(entry.data))
|
|
1900
|
-
while not entry.event.is_set():
|
|
1901
|
-
if run.cancel.is_set() or run.finished.is_set() or (data.get("kind") == "skill_secret" and (ctx.cancelled or run.session_ended)):
|
|
1902
|
-
break
|
|
1903
|
-
if entry.deadline is None:
|
|
1904
|
-
entry.event.wait(1.0)
|
|
1905
|
-
continue
|
|
1906
|
-
remaining = entry.deadline - time.monotonic()
|
|
1907
|
-
if remaining <= 0:
|
|
1908
|
-
break
|
|
1909
|
-
entry.event.wait(min(1.0, remaining))
|
|
1910
|
-
with run.lock:
|
|
1911
|
-
run.clarify_entries.pop(entry.clarify_id, None)
|
|
1912
|
-
emit("clarify_resolved", {"clarify_id": entry.clarify_id, "session_id": session_id})
|
|
1913
|
-
return entry.result
|
|
2015
|
+
return _ask_clarify(run, data, timeout, emit)
|
|
1914
2016
|
|
|
1915
2017
|
def ask_vault(kind: str, fields: dict) -> str:
|
|
1916
2018
|
"""TAL-887: a password-manager prompt; an empty answer is the Agent's decline, as are expiry and cancel."""
|
|
@@ -1966,35 +2068,7 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
|
|
|
1966
2068
|
except Exception: # noqa: BLE001 - never expose an exception that could include the submitted value
|
|
1967
2069
|
return {**skipped, "success": False}
|
|
1968
2070
|
|
|
1969
|
-
|
|
1970
|
-
# TAL-351: remove the legacy signature path when v0.21.6 is the oldest supported Agent.
|
|
1971
|
-
structured = isinstance(question, list)
|
|
1972
|
-
if structured:
|
|
1973
|
-
questions, question = question, ""
|
|
1974
|
-
choices_list = [str(c) for c in (choices or [])]
|
|
1975
|
-
# Predecessor `_clarify_timeout_seconds`: the Agent's own resolver over this profile's config
|
|
1976
|
-
# (``clarify.timeout`` else ``agent.clarify_timeout`` else 3600); ``<= 0`` waits until answered or cancelled.
|
|
1977
|
-
# The advertised ``timeout_seconds`` is what the clients count down, so it is the same number.
|
|
1978
|
-
timeout = _clarify_timeout(params)
|
|
1979
|
-
data = {"question": str(question or ""), "choices_offered": choices_list, "session_id": session_id, "kind": "clarify", "requested_at": time.time(), "timeout_seconds": timeout}
|
|
1980
|
-
if multi_select:
|
|
1981
|
-
data["multi_select"] = True
|
|
1982
|
-
# Batch prompts (the Agent's ``_run_batch``) carry no top-level question and expect the ``{"answers": {...}}`` reply.
|
|
1983
|
-
if isinstance(questions, list) and questions:
|
|
1984
|
-
data["questions"] = questions
|
|
1985
|
-
answer = ask(data, timeout)
|
|
1986
|
-
if answer is not None:
|
|
1987
|
-
if structured:
|
|
1988
|
-
return {"answers": json.loads(answer)["answers"], "outcome": "submitted"}
|
|
1989
|
-
return answer
|
|
1990
|
-
cancelled = run.cancel.is_set() or run.finished.is_set()
|
|
1991
|
-
if structured:
|
|
1992
|
-
return {"answers": {}, "outcome": "cancelled" if cancelled else "timed_out",
|
|
1993
|
-
"notice": "The user cancelled the clarification." if cancelled else "The clarification timed out."}
|
|
1994
|
-
# Older tools have no outcome field. A batch understands timed_out; a single needs an empty answer.
|
|
1995
|
-
if questions:
|
|
1996
|
-
return json.dumps({"answers": {}, "timed_out": not cancelled})
|
|
1997
|
-
return ""
|
|
2071
|
+
clarify_callback = _clarify_callback(run, params, emit)
|
|
1998
2072
|
|
|
1999
2073
|
# TAL-818: a ``manage_connections`` card (a hosted connect, an MCP install) opened; the server turns the frame into
|
|
2000
2074
|
# the chat's connect card, which reads and answers the operation through ``connectors.operation`` / ``respond``.
|
|
@@ -2465,10 +2539,18 @@ def refine(params: dict) -> str:
|
|
|
2465
2539
|
return f"⚗ Reviewing this conversation in the background{tail} — any memory/skill updates will be reported when done."
|
|
2466
2540
|
|
|
2467
2541
|
|
|
2468
|
-
def _run_for(params: dict) -> _Run | None:
|
|
2542
|
+
def _run_for(params: dict, *, include_commands: bool = False) -> _Run | None:
|
|
2469
2543
|
stream_id = str(params.get("stream_id") or "").strip()
|
|
2470
2544
|
session_id = str(params.get("session_id") or "").strip()
|
|
2471
2545
|
with _RUNS_LOCK:
|
|
2546
|
+
clarify_id = str(params.get("clarify_id") or "")
|
|
2547
|
+
home = params.get("profile_home")
|
|
2548
|
+
if include_commands and clarify_id and session_id and home:
|
|
2549
|
+
for run in _COMMAND_RUNS.values():
|
|
2550
|
+
if run.session_id == session_id and run.home == os.path.realpath(home):
|
|
2551
|
+
with run.lock:
|
|
2552
|
+
if clarify_id in run.clarify_entries:
|
|
2553
|
+
return run
|
|
2472
2554
|
if stream_id:
|
|
2473
2555
|
return _RUNS.get(stream_id)
|
|
2474
2556
|
if session_id:
|
|
@@ -2619,6 +2701,7 @@ def register(registry) -> None:
|
|
|
2619
2701
|
in place."""
|
|
2620
2702
|
session_id = str(params.get("session_id") or "").strip()
|
|
2621
2703
|
end_session = params.get("clear_session") is True
|
|
2704
|
+
cancel_command_choices(session_id)
|
|
2622
2705
|
with _AGENT_CACHE_LOCK:
|
|
2623
2706
|
with _RUNS_LOCK:
|
|
2624
2707
|
run = _RUNS.get(_RUNS_BY_SESSION.get(session_id) or "")
|
|
@@ -2775,7 +2858,7 @@ def register(registry) -> None:
|
|
|
2775
2858
|
def clarify_respond_(ctx: CallContext, params: dict) -> dict:
|
|
2776
2859
|
response = str(params.get("response") or "")
|
|
2777
2860
|
clarify_id = str(params.get("clarify_id") or "").strip()
|
|
2778
|
-
run = _run_for(params)
|
|
2861
|
+
run = _run_for(params, include_commands=True)
|
|
2779
2862
|
if run is None:
|
|
2780
2863
|
return {"ok": False}
|
|
2781
2864
|
if params.get("session_id") and str(params["session_id"]) != run.session_id:
|
|
@@ -2786,7 +2869,7 @@ def register(registry) -> None:
|
|
|
2786
2869
|
if target is None or target.event.is_set() or (target.deadline is not None and time.monotonic() >= target.deadline):
|
|
2787
2870
|
return {"ok": False}
|
|
2788
2871
|
skill_secret = target.data.get("kind") == "skill_secret"
|
|
2789
|
-
if
|
|
2872
|
+
if ctx.cancelled or run.prompt_cancelled(target.data) or (skill_secret and not clarify_id):
|
|
2790
2873
|
return {"ok": False}
|
|
2791
2874
|
# Secure answers are as typed; an empty reply is their decline. Only the first answer releases a waiter.
|
|
2792
2875
|
secure = str(target.data.get("kind") or "").startswith("vault_") or skill_secret
|
|
@@ -239,7 +239,7 @@ def forget_profile_mcp_tools(home) -> None:
|
|
|
239
239
|
_MCP_DISCOVERED_HOMES.discard(os.path.realpath(home))
|
|
240
240
|
|
|
241
241
|
|
|
242
|
-
def _reload_mcp() -> str:
|
|
242
|
+
def _reload_mcp(*, log_errors=True) -> str:
|
|
243
243
|
with _RELOAD_MCP_LOCK:
|
|
244
244
|
try:
|
|
245
245
|
from agent.secret_scope import is_multiplex_active
|
|
@@ -274,7 +274,8 @@ def _reload_mcp() -> str:
|
|
|
274
274
|
with _lock:
|
|
275
275
|
tools = [name for name in tools if _mcp_tool_server_names.get(name) in connected]
|
|
276
276
|
except Exception as exc: # noqa: BLE001
|
|
277
|
-
|
|
277
|
+
if log_errors:
|
|
278
|
+
log.warning("Failed to reload MCP servers", exc_info=True)
|
|
278
279
|
raise RpcError("Failed to reload MCP servers", condition="mcp_reload_failed") from exc
|
|
279
280
|
added, removed, reconnected = connected - old, old - connected, connected & old
|
|
280
281
|
lines = ["Reloaded MCP servers from configuration."]
|
|
@@ -846,11 +847,12 @@ def register(registry) -> None:
|
|
|
846
847
|
output = execute_agent_command(command, session_id, workspace)
|
|
847
848
|
source = "agent"
|
|
848
849
|
if output is None:
|
|
849
|
-
from .chat import _turn_identity
|
|
850
|
+
from .chat import _turn_identity, command_choices
|
|
850
851
|
|
|
851
852
|
# TAL-904: a chat's plugin command runs under that chat's session and workspace, as its turns do.
|
|
852
|
-
with _turn_identity(session_id, workspace) if session_id else contextlib.nullcontext():
|
|
853
|
+
with command_choices(ctx, params), (_turn_identity(session_id, workspace) if session_id else contextlib.nullcontext()):
|
|
853
854
|
output = execute_plugin_command(command, session_id)
|
|
855
|
+
ctx.check_cancelled()
|
|
854
856
|
source = "plugin"
|
|
855
857
|
if output is None:
|
|
856
858
|
raise RpcError(f"unknown command {parse_slash_command(command)[0]!r}", condition="command_not_found")
|
|
@@ -133,9 +133,8 @@ def _split_config_aliases(text: str, desired: dict) -> str:
|
|
|
133
133
|
return output.getvalue()
|
|
134
134
|
|
|
135
135
|
|
|
136
|
-
def
|
|
137
|
-
|
|
138
|
-
raise InvalidParams("config must be an object")
|
|
136
|
+
def assert_config_writable(profile_home: Path | None = None) -> None:
|
|
137
|
+
"""Verify the owning profile policy before any config publication; uncertainty refuses."""
|
|
139
138
|
try:
|
|
140
139
|
managed = importlib.import_module("hermes_constants").get_managed_system(profile_home)
|
|
141
140
|
except Exception as exc: # noqa: BLE001
|
|
@@ -144,6 +143,12 @@ def write_config(path: Path, config: dict, *, profile_home: Path | None = None)
|
|
|
144
143
|
if managed is not None:
|
|
145
144
|
raise RpcError("config.yaml is package-managed. Update the declarative configuration instead.",
|
|
146
145
|
condition="config_write_refused")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def write_config(path: Path, config: dict, *, profile_home: Path | None = None) -> dict:
|
|
149
|
+
if not isinstance(config, dict):
|
|
150
|
+
raise InvalidParams("config must be an object")
|
|
151
|
+
assert_config_writable(profile_home)
|
|
147
152
|
target = _write_target(path)
|
|
148
153
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
149
154
|
try:
|
|
@@ -8,10 +8,13 @@ registers its session operation here through ``remember_chat_operation``. Every
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import contextvars
|
|
12
|
+
import hashlib
|
|
11
13
|
import inspect
|
|
12
14
|
import json
|
|
13
15
|
import logging
|
|
14
16
|
import threading
|
|
17
|
+
import uuid
|
|
15
18
|
from collections import OrderedDict
|
|
16
19
|
from pathlib import Path
|
|
17
20
|
from types import SimpleNamespace
|
|
@@ -130,11 +133,46 @@ def accounts() -> dict:
|
|
|
130
133
|
client = _portal()
|
|
131
134
|
if not _authenticated(client):
|
|
132
135
|
return {"accounts": []}
|
|
136
|
+
rows = client.list_accounts()
|
|
137
|
+
try:
|
|
138
|
+
from hermes_cli.free_tier_offer import note_connected_apps_seen
|
|
139
|
+
note_connected_apps_seen([{"connected": row.get("active") is True and not row.get("disabled")} for row in rows])
|
|
140
|
+
except ImportError:
|
|
141
|
+
pass # older Agents have no connector offer
|
|
142
|
+
except Exception:
|
|
143
|
+
log.warning("connector sighting unavailable")
|
|
133
144
|
return {"accounts": [{
|
|
134
145
|
"connection_id": row["connectionId"], "connector": row["connector"], "status": row["status"],
|
|
135
146
|
"status_reason": row.get("statusReason"), "label": row["label"], "alias": row.get("alias"),
|
|
136
147
|
"active": bool(row["active"]), "disabled": bool(row.get("disabled")), "created_at": row["createdAt"],
|
|
137
|
-
} for row in
|
|
148
|
+
} for row in rows]}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def sign_in_offer(home: Path, claim_guest: str | None = None) -> dict:
|
|
152
|
+
"""Native policy and CAS only. The server owns retention of the delivered page result."""
|
|
153
|
+
result = {"available": False, "guest_id": None, "eligible": False, "due_in": None, "claimed": False}
|
|
154
|
+
try:
|
|
155
|
+
from hermes_cli import anon_auth, free_tier_offer as native
|
|
156
|
+
if not all(callable(getattr(native, name, None)) for name in ("_eligible", "offer_due_in", "claim_offer")):
|
|
157
|
+
return result
|
|
158
|
+
|
|
159
|
+
def identity():
|
|
160
|
+
state = anon_auth.current_nous_state()
|
|
161
|
+
token = state.get("anon_token") if anon_auth.is_guest_state(state) else None
|
|
162
|
+
return hashlib.sha256(f"{home.resolve()}\0{token}".encode()).hexdigest() if isinstance(token, str) and token else None
|
|
163
|
+
|
|
164
|
+
guest = identity()
|
|
165
|
+
result["guest_id"] = guest
|
|
166
|
+
eligible = bool(native._eligible(native.CONNECTOR))
|
|
167
|
+
due = native.offer_due_in(native.CONNECTOR)
|
|
168
|
+
claimed = bool(guest and guest == claim_guest and native.claim_offer(native.CONNECTOR)) if claim_guest else False
|
|
169
|
+
if identity() != guest:
|
|
170
|
+
return {**result, "guest_id": None}
|
|
171
|
+
return {"available": True, "guest_id": guest, "eligible": eligible, "due_in": due, "claimed": claimed}
|
|
172
|
+
except ImportError:
|
|
173
|
+
return result
|
|
174
|
+
except Exception:
|
|
175
|
+
return result # retain a proven identity, never raw auth or native error details
|
|
138
176
|
|
|
139
177
|
|
|
140
178
|
def remove(connection_id: str) -> dict:
|
|
@@ -201,6 +239,14 @@ def _operation(home: Path, op_id: str):
|
|
|
201
239
|
operation = _OPS.get((str(home), op_id))
|
|
202
240
|
if operation is None:
|
|
203
241
|
raise RpcError("No connection operation with that id.", condition="operation_not_found")
|
|
242
|
+
account_id = getattr(operation, "_talaria_nous_account_id", None)
|
|
243
|
+
if account_id:
|
|
244
|
+
from . import nous_account
|
|
245
|
+
current = nous_account.read(home)
|
|
246
|
+
if not current or current["account_id"] != account_id:
|
|
247
|
+
from tools.connectors.contract import SettleReason
|
|
248
|
+
operation.settle(SettleReason.interrupt)
|
|
249
|
+
raise RpcError("No connection operation for the current account.", condition="operation_not_found")
|
|
204
250
|
return operation
|
|
205
251
|
|
|
206
252
|
|
|
@@ -226,8 +272,62 @@ def operation_view(operation) -> dict:
|
|
|
226
272
|
}
|
|
227
273
|
|
|
228
274
|
|
|
229
|
-
def
|
|
275
|
+
def _reconnect(home: Path, connector: str, account_id: str) -> dict:
|
|
276
|
+
"""Compose the existing native operation with an account-fenced, noncreating client.
|
|
277
|
+
|
|
278
|
+
Native account.find_or_start_operation always uses a creating, live-credential client
|
|
279
|
+
in its later thread. Its lifecycle primitives accept the client this result needs.
|
|
280
|
+
"""
|
|
281
|
+
from tools.connectors import account, live, managed
|
|
282
|
+
from tools.connectors.gateway.client import ConnectorClient
|
|
283
|
+
from tools.connectors.operation import ConnectionOperation, Target
|
|
284
|
+
from tools.connectors.run import drive_operation
|
|
285
|
+
from tools.connectors.contract import SettleReason
|
|
286
|
+
from . import nous_account
|
|
287
|
+
|
|
288
|
+
with account._start_lock:
|
|
289
|
+
existing = live.find_target(connector, profile_home=str(home))
|
|
290
|
+
if existing is not None:
|
|
291
|
+
if getattr(existing, "_talaria_nous_account_id", None) != account_id:
|
|
292
|
+
raise RpcError("Finish the current app connection before reconnecting this result.", condition="operation_refused")
|
|
293
|
+
_remember(home, existing)
|
|
294
|
+
return operation_view(_operation(home, existing.op_id))
|
|
295
|
+
client = ConnectorClient(initiator="desktop_page", header_provider=lambda url: nous_account.connector_headers(home, account_id, url))
|
|
296
|
+
operation = ConnectionOperation([Target(connector, "connector", "connect")], session_key=f"account:{uuid.uuid4().hex}")
|
|
297
|
+
operation._talaria_nous_account_id = account_id
|
|
298
|
+
operation._talaria_nous_client = client
|
|
299
|
+
start = account.AccountOperationStart(operation=operation, started=True)
|
|
300
|
+
context = contextvars.copy_context()
|
|
301
|
+
|
|
302
|
+
def run():
|
|
303
|
+
try:
|
|
304
|
+
drive_operation(operation, managed.managed_kind(client, "connect", force=False),
|
|
305
|
+
connection_callback=lambda payload: start.done.set(),
|
|
306
|
+
tick_seconds=managed.WATCH_TICK_SECONDS, with_urls_in_result=False)
|
|
307
|
+
except Exception:
|
|
308
|
+
start.failed = True
|
|
309
|
+
operation.settle(SettleReason.interrupt)
|
|
310
|
+
finally:
|
|
311
|
+
live.close(operation)
|
|
312
|
+
start.done.set()
|
|
313
|
+
|
|
314
|
+
live.open(operation)
|
|
315
|
+
_remember(home, operation)
|
|
316
|
+
try:
|
|
317
|
+
threading.Thread(target=lambda: context.run(run), daemon=True, name="connector-account-operation").start()
|
|
318
|
+
except Exception:
|
|
319
|
+
live.close(operation)
|
|
320
|
+
operation.settle(SettleReason.interrupt)
|
|
321
|
+
raise
|
|
322
|
+
if account.wait_for_prepare(start) and start.failed:
|
|
323
|
+
raise RpcError("Connector request failed.", condition="connectors_failed")
|
|
324
|
+
return operation_view(_operation(home, operation.op_id))
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def connect(home: Path, connector: str, *, account_id: str | None = None) -> dict:
|
|
230
328
|
"""Start (or rejoin) the account-owned connect for ``connector`` and wait for its authorization link."""
|
|
329
|
+
if account_id is not None:
|
|
330
|
+
return _reconnect(home, connector, account_id)
|
|
231
331
|
from tools.connectors import account
|
|
232
332
|
from tools.connectors.contract import TargetState
|
|
233
333
|
from tools.connectors.run import reissue
|
|
@@ -236,8 +336,11 @@ def connect(home: Path, connector: str) -> dict:
|
|
|
236
336
|
page = {"initiator": "desktop_page"} if "initiator" in inspect.signature(account.find_or_start_operation).parameters else {}
|
|
237
337
|
start = account.find_or_start_operation([connector], action="connect", profile_home=str(home), **page)
|
|
238
338
|
_remember(home, start.operation)
|
|
339
|
+
_operation(home, start.operation.op_id)
|
|
239
340
|
if not start.started:
|
|
240
341
|
target = start.operation.target(connector)
|
|
342
|
+
if target is not None and target.state in (TargetState.failed, TargetState.expired) and getattr(start.operation, "_talaria_nous_client", None) is not None:
|
|
343
|
+
return respond(home, start.operation.op_id, "retry", connector, {})
|
|
241
344
|
if target is not None and target.state in (TargetState.failed, TargetState.expired) and reissue(start.operation, [connector], **page):
|
|
242
345
|
raise RpcError("This connection cannot be started again.", condition="operation_refused")
|
|
243
346
|
return operation_view(start.operation)
|
|
@@ -262,7 +365,14 @@ def respond(home: Path, op_id: str, action: str, target: str | None, env: dict)
|
|
|
262
365
|
if action == "continue":
|
|
263
366
|
apply_answer(operation, json.dumps({"settled_by": SettleReason.continue_.value}))
|
|
264
367
|
elif action == "retry" and row.kind == "connector":
|
|
265
|
-
|
|
368
|
+
client = getattr(operation, "_talaria_nous_client", None)
|
|
369
|
+
if client is not None:
|
|
370
|
+
from tools.connectors.managed import mint
|
|
371
|
+
from tools.connectors.contract import Actor, TargetState
|
|
372
|
+
if row.state not in (TargetState.failed, TargetState.expired):
|
|
373
|
+
raise RpcError("This target cannot be run again.", condition="operation_refused")
|
|
374
|
+
mint(client, operation, [row.name], reinitiate=True, actor=Actor.user)
|
|
375
|
+
elif reissue(operation, [row.name]):
|
|
266
376
|
raise RpcError("This target cannot be run again.", condition="operation_refused")
|
|
267
377
|
else:
|
|
268
378
|
status = "skipped" if action == "skip" else "approved"
|
|
@@ -288,6 +398,21 @@ def remember_chat_operation(home: Path, payload: dict) -> dict | None:
|
|
|
288
398
|
|
|
289
399
|
|
|
290
400
|
def register(registry_) -> None:
|
|
401
|
+
@registry_.method("connectors.offer.status")
|
|
402
|
+
def offer_status_(ctx: CallContext, params: dict) -> dict:
|
|
403
|
+
home = profile_home_param(params)
|
|
404
|
+
with scoped_home(home):
|
|
405
|
+
return sign_in_offer(home)
|
|
406
|
+
|
|
407
|
+
@registry_.method("connectors.offer.claim")
|
|
408
|
+
def offer_claim_(ctx: CallContext, params: dict) -> dict:
|
|
409
|
+
guest = params.get("guest_id")
|
|
410
|
+
if not isinstance(guest, str) or not guest:
|
|
411
|
+
raise InvalidParams("guest_id is required")
|
|
412
|
+
home = profile_home_param(params)
|
|
413
|
+
with scoped_home(home):
|
|
414
|
+
return sign_in_offer(home, guest)
|
|
415
|
+
|
|
291
416
|
def page(params: dict, read, *, creates_guest: bool = False):
|
|
292
417
|
with scoped_home(profile_home_param(params)):
|
|
293
418
|
_open(creates_guest=creates_guest)
|
|
@@ -346,7 +471,16 @@ def register(registry_) -> None:
|
|
|
346
471
|
def connect_(ctx: CallContext, params: dict) -> dict:
|
|
347
472
|
slug = _slug(params)
|
|
348
473
|
home = profile_home_param(params)
|
|
349
|
-
|
|
474
|
+
def begin():
|
|
475
|
+
if "nous_account_id" in params:
|
|
476
|
+
from . import nous_account
|
|
477
|
+
view = nous_account.read(home)
|
|
478
|
+
if not view or view["account_id"] != params["nous_account_id"] or slug not in view["reconnect"]:
|
|
479
|
+
raise RpcError("The signed-in account or reconnect result changed. Refresh before reconnecting.", condition="connectors_forbidden")
|
|
480
|
+
if not any(row["slug"] == slug for row in catalog()["connectors"]):
|
|
481
|
+
raise RpcError("This app is not available to reconnect.", condition="connectors_forbidden")
|
|
482
|
+
return connect(home, slug, account_id=params.get("nous_account_id"))
|
|
483
|
+
return page(params, begin, creates_guest="nous_account_id" not in params)
|
|
350
484
|
|
|
351
485
|
def gated() -> None:
|
|
352
486
|
# Reads and moves on an operation pass the availability gate too, without creating an identity.
|
|
@@ -190,6 +190,27 @@ def _plugins(home):
|
|
|
190
190
|
return out
|
|
191
191
|
|
|
192
192
|
|
|
193
|
+
def reviewed_producer(home, name, pin, sources):
|
|
194
|
+
"""Verify a store adapter's native registration, profile consent and reviewed bytes without loading it."""
|
|
195
|
+
try:
|
|
196
|
+
from hermes_cli import plugins_cmd as pc
|
|
197
|
+
metadata = pc._read_install_metadata()
|
|
198
|
+
for plugin in _plugins(home):
|
|
199
|
+
if plugin['name'] != name or not plugin['enabled'] or plugin.get('source') != 'user':
|
|
200
|
+
continue
|
|
201
|
+
root, anchor = Path(plugin['_dir']).parent, Path(plugin['_asset_anchor'])
|
|
202
|
+
record = metadata.get(root.name, {})
|
|
203
|
+
catalog = record.get('catalog', {})
|
|
204
|
+
if catalog.get('name') != name or catalog.get('sha') != pin or record.get('revision') != pin:
|
|
205
|
+
continue
|
|
206
|
+
if all((body := _read(root, file, anchor=anchor)) is not None
|
|
207
|
+
and hashlib.sha256(body).hexdigest() == digest for file, digest in sources.items()):
|
|
208
|
+
return pin
|
|
209
|
+
except (ImportError, AttributeError, OSError, ValueError, TypeError):
|
|
210
|
+
pass
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
|
|
193
214
|
def _named(home, name, *, require_panel=True):
|
|
194
215
|
return next((p for p in _plugins(home) if p['name'] == name and p['enabled'] and (p['panel'] if require_panel else p.get('_api_file'))), None)
|
|
195
216
|
|