@maudecode/talaria-web 1.15.0 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. package/_release.json +4 -4
  2. package/dist/api/automation-router.d.ts +21 -7
  3. package/dist/api/automation-router.js +3 -0
  4. package/dist/api/automation-router.js.map +1 -1
  5. package/dist/api/chat-router.d.ts +142 -6
  6. package/dist/api/chat-router.js +11 -5
  7. package/dist/api/chat-router.js.map +1 -1
  8. package/dist/api/git-router.js +44 -32
  9. package/dist/api/git-router.js.map +1 -1
  10. package/dist/api/raw-routes.js +5 -58
  11. package/dist/api/raw-routes.js.map +1 -1
  12. package/dist/api/router.d.ts +4 -2
  13. package/dist/api/router.js +8 -8
  14. package/dist/api/router.js.map +1 -1
  15. package/dist/api/sessions-router.d.ts +714 -42
  16. package/dist/api/sessions-router.js +57 -23
  17. package/dist/api/sessions-router.js.map +1 -1
  18. package/dist/api/settings-router.d.ts +153 -9
  19. package/dist/api/settings-router.js +61 -16
  20. package/dist/api/settings-router.js.map +1 -1
  21. package/dist/api/sse-routes.js +1 -1
  22. package/dist/api/sse-routes.js.map +1 -1
  23. package/dist/api/tools-router.d.ts +13 -1
  24. package/dist/api/tools-router.js +10 -8
  25. package/dist/api/tools-router.js.map +1 -1
  26. package/dist/app.d.ts +1047 -67
  27. package/dist/auth/gate.js +8 -4
  28. package/dist/auth/gate.js.map +1 -1
  29. package/dist/auth/oidc.d.ts +6 -2
  30. package/dist/auth/oidc.js +16 -11
  31. package/dist/auth/oidc.js.map +1 -1
  32. package/dist/auth/store.d.ts +14 -2
  33. package/dist/auth/store.js +26 -1
  34. package/dist/auth/store.js.map +1 -1
  35. package/dist/cli/dotenv.d.ts +1 -1
  36. package/dist/cli/dotenv.js +36 -3
  37. package/dist/cli/dotenv.js.map +1 -1
  38. package/dist/http/addresses.d.ts +6 -0
  39. package/dist/http/addresses.js +26 -0
  40. package/dist/http/addresses.js.map +1 -1
  41. package/dist/http/context.d.ts +3 -3
  42. package/dist/links.d.ts +26 -0
  43. package/dist/links.js +60 -0
  44. package/dist/links.js.map +1 -0
  45. package/dist/onboarding.js +26 -7
  46. package/dist/onboarding.js.map +1 -1
  47. package/dist/profiles/profiles.js +1 -1
  48. package/dist/profiles/profiles.js.map +1 -1
  49. package/dist/providers/catalog.d.ts +74 -1
  50. package/dist/providers/catalog.js +248 -42
  51. package/dist/providers/catalog.js.map +1 -1
  52. package/dist/providers/tables.d.ts +3 -1
  53. package/dist/providers/tables.js +9 -4
  54. package/dist/providers/tables.js.map +1 -1
  55. package/dist/redact.js +493 -13
  56. package/dist/redact.js.map +1 -1
  57. package/dist/runtime.js +52 -28
  58. package/dist/runtime.js.map +1 -1
  59. package/dist/sessions/anchor.d.ts +22 -3
  60. package/dist/sessions/anchor.js +87 -42
  61. package/dist/sessions/anchor.js.map +1 -1
  62. package/dist/sessions/background-tasks.d.ts +4 -1
  63. package/dist/sessions/background-tasks.js +7 -4
  64. package/dist/sessions/background-tasks.js.map +1 -1
  65. package/dist/sessions/completions.js +1 -1
  66. package/dist/sessions/completions.js.map +1 -1
  67. package/dist/sessions/list.d.ts +8 -4
  68. package/dist/sessions/list.js +24 -17
  69. package/dist/sessions/list.js.map +1 -1
  70. package/dist/sessions/merge.d.ts +70 -7
  71. package/dist/sessions/merge.js +331 -23
  72. package/dist/sessions/merge.js.map +1 -1
  73. package/dist/sessions/pending.d.ts +5 -0
  74. package/dist/sessions/pending.js +30 -10
  75. package/dist/sessions/pending.js.map +1 -1
  76. package/dist/sessions/service.d.ts +57 -3
  77. package/dist/sessions/service.js +327 -56
  78. package/dist/sessions/service.js.map +1 -1
  79. package/dist/sessions/session.d.ts +6 -1
  80. package/dist/sessions/session.js +6 -0
  81. package/dist/sessions/session.js.map +1 -1
  82. package/dist/sessions/shares.js +11 -2
  83. package/dist/sessions/shares.js.map +1 -1
  84. package/dist/sessions/store.js +1 -1
  85. package/dist/sessions/store.js.map +1 -1
  86. package/dist/sessions/turn.d.ts +19 -1
  87. package/dist/sessions/turn.js +218 -113
  88. package/dist/sessions/turn.js.map +1 -1
  89. package/dist/settings.js +9 -0
  90. package/dist/settings.js.map +1 -1
  91. package/dist/sidecar/fake.js +2 -0
  92. package/dist/sidecar/fake.js.map +1 -1
  93. package/dist/tools/commands.d.ts +15 -0
  94. package/dist/tools/commands.js +52 -0
  95. package/dist/tools/commands.js.map +1 -0
  96. package/dist/tools/crons.d.ts +4 -1
  97. package/dist/tools/crons.js +58 -11
  98. package/dist/tools/crons.js.map +1 -1
  99. package/dist/tools/mcp.js +5 -1
  100. package/dist/tools/mcp.js.map +1 -1
  101. package/dist/tools/update-notifications.d.ts +1 -1
  102. package/dist/tools/update-notifications.js +1 -1
  103. package/dist/tools/update-notifications.js.map +1 -1
  104. package/dist/tools/updates.d.ts +8 -3
  105. package/dist/tools/updates.js +133 -34
  106. package/dist/tools/updates.js.map +1 -1
  107. package/dist/workspace/git.d.ts +57 -10
  108. package/dist/workspace/git.js +302 -195
  109. package/dist/workspace/git.js.map +1 -1
  110. package/dist/workspace/media-refs.d.ts +13 -0
  111. package/dist/workspace/media-refs.js +165 -0
  112. package/dist/workspace/media-refs.js.map +1 -0
  113. package/dist/workspace/media.d.ts +19 -0
  114. package/dist/workspace/media.js +61 -2
  115. package/dist/workspace/media.js.map +1 -1
  116. package/dist/workspace/workspaces.d.ts +7 -1
  117. package/dist/workspace/workspaces.js +30 -21
  118. package/dist/workspace/workspaces.js.map +1 -1
  119. package/dist/workspace/worktrees.d.ts +2 -4
  120. package/dist/workspace/worktrees.js +28 -33
  121. package/dist/workspace/worktrees.js.map +1 -1
  122. package/package.json +4 -2
  123. package/sidecar/scripts/replay_sidecar.py +3 -1
  124. package/sidecar/talaria_sidecar/__init__.py +1 -1
  125. package/sidecar/talaria_sidecar/home.py +59 -2
  126. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  127. package/sidecar/talaria_sidecar/methods/aux.py +19 -3
  128. package/sidecar/talaria_sidecar/methods/chat.py +129 -23
  129. package/sidecar/talaria_sidecar/methods/commands.py +46 -31
  130. package/sidecar/talaria_sidecar/methods/config.py +14 -10
  131. package/sidecar/talaria_sidecar/methods/oauth.py +439 -0
  132. package/sidecar/talaria_sidecar/methods/profiles.py +5 -4
  133. package/sidecar/talaria_sidecar/methods/providers.py +161 -1
  134. package/sidecar/talaria_sidecar/methods/runtime.py +2 -0
  135. package/sidecar/talaria_sidecar/methods/text.py +1 -20
  136. package/sidecar/talaria_sidecar/methods/usage.py +7 -1
  137. package/static/dist/FILES.txt +124 -120
  138. package/static/dist/assets/AppShell-ef3bhu32.js +1 -0
  139. package/static/dist/assets/Button-nx37f4u1.js +1 -0
  140. package/static/dist/assets/ChatPage-cdcpykcg.js +25 -0
  141. package/static/dist/assets/Dialog-mec42hvb.js +1 -0
  142. package/static/dist/assets/HubRoute-ecb65zpr.js +2 -0
  143. package/static/dist/assets/{Markdown-dy8t4dy7.js → Markdown-jqrx5es0.js} +125 -125
  144. package/static/dist/assets/RightPanel-d1lgvk4s.js +1 -0
  145. package/static/dist/assets/Select-h4ivl9qf.js +1 -0
  146. package/static/dist/assets/SessionListPanel-ewib046b.js +1 -0
  147. package/static/dist/assets/SettingsLayout-lx654cup.js +1 -0
  148. package/static/dist/assets/States-ehsb6lzo.js +1 -0
  149. package/static/dist/assets/Toaster-mch1pa3t.js +1 -0
  150. package/static/dist/assets/_app-m8d961ef.js +1 -0
  151. package/static/dist/assets/_app.ext._extensionId-mp33hbzi.js +1 -0
  152. package/static/dist/assets/_app.index-dk6zp7e0.js +1 -0
  153. package/static/dist/assets/_app.insights-jt2fk4i1.js +1 -0
  154. package/static/dist/assets/_app.kanban-if4pubeu.js +1 -0
  155. package/static/dist/assets/_app.logs-mfaw9m6g.js +1 -0
  156. package/static/dist/assets/_app.memory-h3eaarb6.js +1 -0
  157. package/static/dist/assets/_app.profiles-ienktovs.js +1 -0
  158. package/static/dist/assets/{_app.session._sessionId-gyoh5ylx.js → _app.session._sessionId-hh27wwu2.js} +1 -1
  159. package/static/dist/assets/_app.settings-dpoe0bzf.js +1 -0
  160. package/static/dist/assets/_app.settings._section-l468ynag.js +3 -0
  161. package/static/dist/assets/_app.skills-kcbncc8i.js +1 -0
  162. package/static/dist/assets/_app.tasks-occdrqhw.js +2 -0
  163. package/static/dist/assets/_app.todos-nnke2rcc.js +1 -0
  164. package/static/dist/assets/_app.workspaces-cdlatvwj.js +1 -0
  165. package/static/dist/assets/{abnfDiagram-VCTEODGH-cjqletra.js → abnfDiagram-VCTEODGH-oity9y4o.js} +1 -1
  166. package/static/dist/assets/architecture-7GRP2DOG-hj11333z.js +1 -0
  167. package/static/dist/assets/architectureDiagram-5GKGNRK7-ceaepnyr.js +36 -0
  168. package/static/dist/assets/{back-e4m6nsnm.js → back-eu64w89w.js} +1 -1
  169. package/static/dist/assets/{blockDiagram-I7D4REHJ-b195z021.js → blockDiagram-I7D4REHJ-n79st4pj.js} +1 -1
  170. package/static/dist/assets/{c4Diagram-7LVT6UL2-olu212k1.js → c4Diagram-7LVT6UL2-mi73akzk.js} +1 -1
  171. package/static/dist/assets/cancel-mzvkdjg8.js +1 -0
  172. package/static/dist/assets/channel-mbvmf2vv.js +1 -0
  173. package/static/dist/assets/{chunk-4HAMMTFA-b8o1nufs.js → chunk-4HAMMTFA-laat0g1q.js} +1 -1
  174. package/static/dist/assets/{chunk-75Z2AOVW-l1seddto.js → chunk-75Z2AOVW-0psy1tr2.js} +1 -1
  175. package/static/dist/assets/{chunk-DU6HZSFF-lo5zg15v.js → chunk-DU6HZSFF-lw8uox8x.js} +3 -3
  176. package/static/dist/assets/{chunk-F27PBJKO-dsdzrp16.js → chunk-F27PBJKO-erassib3.js} +1 -1
  177. package/static/dist/assets/{chunk-GMAD6QVW-f3fxqq8b.js → chunk-GMAD6QVW-fz7rx619.js} +1 -1
  178. package/static/dist/assets/{chunk-GVQU2GXP-h8egxtf6.js → chunk-GVQU2GXP-gdb0epb2.js} +1 -1
  179. package/static/dist/assets/{chunk-IMKFNOWR-iolwd8s0.js → chunk-IMKFNOWR-ea8t26qw.js} +1 -1
  180. package/static/dist/assets/{chunk-L3NEJ4N5-b88bbtwi.js → chunk-L3NEJ4N5-mb1gu9kz.js} +1 -1
  181. package/static/dist/assets/{chunk-OSK3NFVY-e3e7nr6s.js → chunk-OSK3NFVY-eovmccvy.js} +1 -1
  182. package/static/dist/assets/{chunk-P2QGCYS3-mdc46rt1.js → chunk-P2QGCYS3-bo55zjo5.js} +1 -1
  183. package/static/dist/assets/{chunk-POPQ4Y6H-kqlllrrm.js → chunk-POPQ4Y6H-ja7ohe4h.js} +1 -1
  184. package/static/dist/assets/{chunk-PWAF6VOD-he585k2x.js → chunk-PWAF6VOD-e30g9nus.js} +1 -1
  185. package/static/dist/assets/{chunk-SHT3W25Y-gh94y9a4.js → chunk-SHT3W25Y-gbb798f7.js} +3 -3
  186. package/static/dist/assets/{chunk-SVP7TREG-euxp9y7e.js → chunk-SVP7TREG-h2iw8urm.js} +1 -1
  187. package/static/dist/assets/{chunk-TICWLB2K-c8cxes1q.js → chunk-TICWLB2K-fd2cottz.js} +1 -1
  188. package/static/dist/assets/classDiagram-ZZMXUADV-o8r05k0n.js +1 -0
  189. package/static/dist/assets/classDiagram-v2-VYDZK3BY-o8r05k0n.js +1 -0
  190. package/static/dist/assets/{copied-kq0u3ht7.js → copied-h65fc3cx.js} +1 -1
  191. package/static/dist/assets/copy-e6977uwq.js +1 -0
  192. package/static/dist/assets/{cynefin-OW5HDTMX-lxd44ux4.js → cynefin-OW5HDTMX-lbltyl5j.js} +1 -1
  193. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-njpiwat8.js → cynefinDiagram-5FMLGOSQ-lxhsqq4a.js} +1 -1
  194. package/static/dist/assets/{dagre-GXQ25YYZ-nvgy6yju.js → dagre-GXQ25YYZ-gn4nnaln.js} +4 -4
  195. package/static/dist/assets/{diagram-S7CK7UJ4-g98nyv72.js → diagram-S7CK7UJ4-pa3ij6q7.js} +3 -3
  196. package/static/dist/assets/{diagram-UQ7AKVKN-ovgm6lvv.js → diagram-UQ7AKVKN-zbipyz57.js} +1 -1
  197. package/static/dist/assets/{diagram-VSXAHHWV-pb2bn2e4.js → diagram-VSXAHHWV-d1kbpzgf.js} +1 -1
  198. package/static/dist/assets/{diagram-VX7I27RA-6j4mvfqo.js → diagram-VX7I27RA-i3ty14xl.js} +1 -1
  199. package/static/dist/assets/{diagram-Z3DM3KII-dqmb982r.js → diagram-Z3DM3KII-m8xefqa7.js} +1 -1
  200. package/static/dist/assets/{ebnfDiagram-PWID7BFC-ozbpzb6d.js → ebnfDiagram-PWID7BFC-nz7wj05l.js} +1 -1
  201. package/static/dist/assets/endpoints-k7yf25m0.js +64 -0
  202. package/static/dist/assets/{erDiagram-RLTQ6QDP-hl7m8vua.js → erDiagram-RLTQ6QDP-fa41ib83.js} +1 -1
  203. package/static/dist/assets/eventmodeling-NTZA5JFV-kpbq09bx.js +1 -0
  204. package/static/dist/assets/flowDiagram-HODETNUW-lcz0kx14.js +1 -0
  205. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ompixqmh.js → ganttDiagram-EL5Y4UJY-n7zq01qu.js} +1 -1
  206. package/static/dist/assets/{gitGraph-4MIJSDKK-b6vxwp9q.js → gitGraph-4MIJSDKK-c89emb07.js} +1 -1
  207. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-k98f57on.js → gitGraphDiagram-WWUBYQGX-cz7cgr6w.js} +1 -1
  208. package/static/dist/assets/{highlighted-body-KPVGNVTW-cd3ff6ge.js → highlighted-body-KPVGNVTW-d9bapmni.js} +1 -1
  209. package/static/dist/assets/{index-nqed3oum.js → index-h00usru2.js} +3 -3
  210. package/static/dist/assets/index-n73ijkv2.css +2 -0
  211. package/static/dist/assets/{info-A6RAGUB7-hjcwjami.js → info-A6RAGUB7-ndddhhhh.js} +1 -1
  212. package/static/dist/assets/infoDiagram-27XIBGKW-ccxigcpf.js +2 -0
  213. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-bxak4mwu.js → ishikawaDiagram-5VMMS53U-le0z9vtc.js} +1 -1
  214. package/static/dist/assets/{journeyDiagram-3NMN7TZE-khmihclr.js → journeyDiagram-3NMN7TZE-ivsmb26o.js} +1 -1
  215. package/static/dist/assets/{kanban-definition-UXKFOSKX-h1r32wdx.js → kanban-definition-UXKFOSKX-h6n2awt0.js} +1 -1
  216. package/static/dist/assets/lazyRouteComponent-m1rtyk4t.js +1 -0
  217. package/static/dist/assets/{line-friyjof3.js → line-dmzlfe0u.js} +1 -1
  218. package/static/dist/assets/link-budeg5t9.js +1 -0
  219. package/static/dist/assets/login-kjhasvp8.js +1 -0
  220. package/static/dist/assets/mermaid-HWGCJPDP-jb5d211j.js +1 -0
  221. package/static/dist/assets/{mermaid-parser.core-f1gvpwrt.js → mermaid-parser.core-gwyd5bnq.js} +3 -3
  222. package/static/dist/assets/{mindmap-definition-YA3MSWOX-mt2oxwue.js → mindmap-definition-YA3MSWOX-l68gg5h7.js} +1 -1
  223. package/static/dist/assets/onboarding-cdfrk0pj.js +1 -0
  224. package/static/dist/assets/{packet-AYTQ26CC-jik4ixlf.js → packet-AYTQ26CC-gpv06065.js} +1 -1
  225. package/static/dist/assets/{pegDiagram-XKGWAZYB-erxlv6cc.js → pegDiagram-XKGWAZYB-e52vs23u.js} +1 -1
  226. package/static/dist/assets/{pie-WAS4IAKB-mnkoldfl.js → pie-WAS4IAKB-l6m7nz5s.js} +1 -1
  227. package/static/dist/assets/{pieDiagram-E7YTZNPT-i7lwrada.js → pieDiagram-E7YTZNPT-b4is36bq.js} +3 -3
  228. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-fr8ejdoy.js → quadrantDiagram-AXDQQJYC-m8vt2788.js} +1 -1
  229. package/static/dist/assets/{radar-RG4KPBEZ-otarjte2.js → radar-RG4KPBEZ-nxbrhiov.js} +1 -1
  230. package/static/dist/assets/{railroad-74A4TZTK-lw362oto.js → railroad-74A4TZTK-222mu9hi.js} +1 -1
  231. package/static/dist/assets/railroad-abnf-HS5TGJTU-kdvgl6x8.js +1 -0
  232. package/static/dist/assets/railroad-ebnf-LZEXJU2U-itiqslby.js +1 -0
  233. package/static/dist/assets/railroad-peg-WCYAUIDC-go7kov78.js +1 -0
  234. package/static/dist/assets/{railroadDiagram-O6MQD6OU-esyn75pw.js → railroadDiagram-O6MQD6OU-o8lldfzv.js} +1 -1
  235. package/static/dist/assets/{refresh-cw-k66keho6.js → refresh-cw-kbcje1uy.js} +1 -1
  236. package/static/dist/assets/{requirementDiagram-BXWQKSXE-cyhi5u29.js → requirementDiagram-BXWQKSXE-ovyq38kv.js} +1 -1
  237. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-jljpbo0h.js → sankeyDiagram-P5KCCOFB-ou7lznor.js} +1 -1
  238. package/static/dist/assets/{saved-do49si3v.js → saved-bazmcup9.js} +1 -1
  239. package/static/dist/assets/search-jen74z4u.js +1 -0
  240. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-fz0dhlu7.js → sequenceDiagram-WJ2MYXX4-ovckdzf2.js} +1 -1
  241. package/static/dist/assets/{settings_section_extensions_title-b7lojn0o.js → settings_section_extensions_title-ertwwhlx.js} +1 -1
  242. package/static/dist/assets/share._token-dan9hgvj.js +2 -0
  243. package/static/dist/assets/{sliders-horizontal-c4wya4dy.js → sliders-horizontal-f9cb3lh3.js} +1 -1
  244. package/static/dist/assets/{stateDiagram-D77RDMKH-kdnithdx.js → stateDiagram-D77RDMKH-fcrexkkv.js} +1 -1
  245. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-lcfraua2.js +1 -0
  246. package/static/dist/assets/{swimlanes-42K2YHIH-esd6gmz3.js → swimlanes-42K2YHIH-f7usu8fw.js} +1 -1
  247. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ogmanni0.js +8 -0
  248. package/static/dist/assets/{timeline-definition-24CTP7MA-g0qygccv.js → timeline-definition-24CTP7MA-gp1hvz9f.js} +1 -1
  249. package/static/dist/assets/todoStore-eqtid4r4.js +1 -0
  250. package/static/dist/assets/{treeView-Q6P3EWNA-ndchzkuu.js → treeView-Q6P3EWNA-gb9gf11u.js} +1 -1
  251. package/static/dist/assets/{treemap-WGGIJYW6-hwjxj0zz.js → treemap-WGGIJYW6-nuvfnvvi.js} +1 -1
  252. package/static/dist/assets/{untitled-mbr6tuhu.js → untitled-htelhc68.js} +1 -1
  253. package/static/dist/assets/useForm-h2t0u14e.js +1 -0
  254. package/static/dist/assets/useLocale-hcsb84pj.js +1 -0
  255. package/static/dist/assets/useNavigate-nwy70ztj.js +1 -0
  256. package/static/dist/assets/{useParams-lo9u33d1.js → useParams-dqd64jv7.js} +1 -1
  257. package/static/dist/assets/{useSearch-lq1mr090.js → useSearch-j30pvsy7.js} +1 -1
  258. package/static/dist/assets/{vennDiagram-4TSXK5OY-gubovd1r.js → vennDiagram-4TSXK5OY-fzchbzaj.js} +1 -1
  259. package/static/dist/assets/{wardley-WFR3VGLG-ir3om65j.js → wardley-WFR3VGLG-m47mhfbh.js} +1 -1
  260. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-ce0or1ie.js → wardleyDiagram-VM6X3IG4-odg6ct1z.js} +2 -2
  261. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-dexylcjg.js → xychartDiagram-S5SC5T6Z-mrhms5um.js} +1 -1
  262. package/static/dist/index.html +1 -1
  263. package/static/dist/sw.js +1 -1
  264. package/static/dist/assets/AppShell-orat1s43.js +0 -1
  265. package/static/dist/assets/ChatPage-ojhka3hy.js +0 -22
  266. package/static/dist/assets/HubRoute-gxgw1t33.js +0 -2
  267. package/static/dist/assets/RightPanel-c66ani1s.js +0 -1
  268. package/static/dist/assets/Select-fswf66up.js +0 -1
  269. package/static/dist/assets/SessionListPanel-goh5mtt8.js +0 -1
  270. package/static/dist/assets/SettingsLayout-n5d4wq4m.js +0 -1
  271. package/static/dist/assets/States-kxyu50at.js +0 -1
  272. package/static/dist/assets/Toaster-6zmbcqgg.js +0 -1
  273. package/static/dist/assets/_app-fowyruiu.js +0 -1
  274. package/static/dist/assets/_app.ext._extensionId-nvjyrwhy.js +0 -1
  275. package/static/dist/assets/_app.index-c9zv4y7w.js +0 -1
  276. package/static/dist/assets/_app.insights-jf12nofo.js +0 -1
  277. package/static/dist/assets/_app.kanban-lri5a4yu.js +0 -1
  278. package/static/dist/assets/_app.logs-md1p0zqo.js +0 -1
  279. package/static/dist/assets/_app.memory-bzvf2e28.js +0 -1
  280. package/static/dist/assets/_app.profiles-jpg7zmbn.js +0 -1
  281. package/static/dist/assets/_app.settings-mpuwlx4j.js +0 -1
  282. package/static/dist/assets/_app.settings._section-knz8rwoj.js +0 -1
  283. package/static/dist/assets/_app.skills-fwu1dkir.js +0 -1
  284. package/static/dist/assets/_app.tasks-h9gphtl3.js +0 -2
  285. package/static/dist/assets/_app.todos-hd1dnvrh.js +0 -1
  286. package/static/dist/assets/_app.workspaces-l8toyn5f.js +0 -1
  287. package/static/dist/assets/architecture-7GRP2DOG-cavnusaw.js +0 -1
  288. package/static/dist/assets/architectureDiagram-5GKGNRK7-k5a7v36n.js +0 -36
  289. package/static/dist/assets/channel-gozy3dp3.js +0 -1
  290. package/static/dist/assets/classDiagram-ZZMXUADV-n0vs2f2q.js +0 -1
  291. package/static/dist/assets/classDiagram-v2-VYDZK3BY-n0vs2f2q.js +0 -1
  292. package/static/dist/assets/endpoints-k8agnro8.js +0 -9
  293. package/static/dist/assets/eventmodeling-NTZA5JFV-j1y2ekec.js +0 -1
  294. package/static/dist/assets/flowDiagram-HODETNUW-g2cvcbm5.js +0 -1
  295. package/static/dist/assets/index-nfy0ezs6.css +0 -2
  296. package/static/dist/assets/infoDiagram-27XIBGKW-fm06rj36.js +0 -2
  297. package/static/dist/assets/lazyRouteComponent-b2eg0fws.js +0 -1
  298. package/static/dist/assets/link-m90ahx3n.js +0 -1
  299. package/static/dist/assets/login-bw7m2fzo.js +0 -1
  300. package/static/dist/assets/mermaid-HWGCJPDP-njwcl62n.js +0 -1
  301. package/static/dist/assets/onboarding-ret37j1e.js +0 -1
  302. package/static/dist/assets/railroad-abnf-HS5TGJTU-m741owar.js +0 -1
  303. package/static/dist/assets/railroad-ebnf-LZEXJU2U-noa4fbia.js +0 -1
  304. package/static/dist/assets/railroad-peg-WCYAUIDC-o4bpw4nb.js +0 -1
  305. package/static/dist/assets/search-j5ki6a9o.js +0 -1
  306. package/static/dist/assets/share._token-kg8w647b.js +0 -2
  307. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-k2wg2645.js +0 -1
  308. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-n5kvjtgr.js +0 -8
  309. package/static/dist/assets/tabBuild-bjmyvmn5.js +0 -56
  310. package/static/dist/assets/todoStore-kjk5l0sy.js +0 -1
  311. package/static/dist/assets/useForm-ocxu460f.js +0 -1
  312. package/static/dist/assets/useLocale-fzy5jhg6.js +0 -1
@@ -14,12 +14,19 @@ fall through to another profile's process environment. Agent 0.21.3 has the
14
14
  multiplex switch and secret scopes but not the launch-profile policy module, so
15
15
  the sidecar mirrors that policy for it. If the installed Agent has no secret
16
16
  scope, named-profile calls fail closed instead.
17
+
18
+ Terminal policy follows the same split. Under a home override the Agent skips its
19
+ config-to-env terminal bridge, so every call also binds the profile's complete
20
+ ``TERMINAL_*`` scope from its own ``.env`` and ``config.yaml``; the launch profile layers
21
+ its launch-process ``TERMINAL_*`` under those files.
17
22
  """
18
23
 
19
24
  from __future__ import annotations
20
25
 
21
26
  import contextlib
27
+ import importlib
22
28
  import os
29
+ import sys
23
30
  import threading
24
31
  from pathlib import Path
25
32
 
@@ -47,6 +54,24 @@ def _frozen_launch_env() -> dict[str, str]:
47
54
  return dict(_LAUNCH_ENV)
48
55
 
49
56
 
57
+ def edit_launch_env(to_set: dict[str, str], to_unset: list[str]) -> None:
58
+ """Carry a Web-owned ``.env`` edit into the frozen launch environments, so a removed credential stops resolving for the launch profile."""
59
+
60
+ def edit(snapshot: dict[str, str] | None) -> None:
61
+ if snapshot is not None:
62
+ for name in to_unset:
63
+ snapshot.pop(name, None)
64
+ snapshot.update(to_set)
65
+
66
+ with _LAUNCH_ENV_LOCK:
67
+ edit(_LAUNCH_ENV)
68
+ # Only an imported policy module can hold a frozen snapshot; importing it waits out a first import still running elsewhere.
69
+ if sys.modules.get("tui_gateway.launch_profile_policy") is not None:
70
+ policy = importlib.import_module("tui_gateway.launch_profile_policy")
71
+ with policy._lock:
72
+ edit(policy._snapshot)
73
+
74
+
50
75
  def _activate_multi_profile_hosting() -> None:
51
76
  """Agent 0.21.3 twin of ``tui_gateway.launch_profile_policy.activate_multi_profile_hosting``."""
52
77
  from agent.secret_scope import set_multiplex_active
@@ -99,6 +124,38 @@ def _secret_scope(home: Path):
99
124
  reset_secret_scope(scope_token)
100
125
 
101
126
 
127
+ @contextlib.contextmanager
128
+ def _terminal_scope(home: Path):
129
+ """Install ``home``'s terminal policy for the call; a policy file that cannot be read refuses terminal execution."""
130
+ named = _is_named_profile(home)
131
+ try:
132
+ from tools.terminal_scope import install_profile_terminal_scope, reset_terminal_scope
133
+ except Exception: # noqa: BLE001 - older Agent without terminal scopes
134
+ if named:
135
+ raise RpcError(
136
+ "profile terminal isolation is unavailable in this Hermes Agent; named-profile calls are refused",
137
+ condition="agent_incompatible",
138
+ )
139
+ yield
140
+ return
141
+ if named:
142
+ token = install_profile_terminal_scope(home)
143
+ else:
144
+ try:
145
+ from agent.secret_scope import is_multiplex_active
146
+ from tui_gateway.launch_profile_policy import launch_terminal_env
147
+ except ImportError: # Agent 0.21.3 cannot layer the launch env, so the launch profile keeps the process env
148
+ yield
149
+ return
150
+ # Like the launch secret scope: the live process env until multiplexing freezes it.
151
+ launch = launch_terminal_env() if is_multiplex_active() else {k: v for k, v in os.environ.items() if k.startswith("TERMINAL_")}
152
+ token = install_profile_terminal_scope(home, env_overlay=launch)
153
+ try:
154
+ yield
155
+ finally:
156
+ reset_terminal_scope(token)
157
+
158
+
102
159
  def profile_home_param(params: dict, key: str = "profile_home") -> Path:
103
160
  raw = params.get(key)
104
161
  if not isinstance(raw, str) or not raw.strip():
@@ -117,7 +174,7 @@ def scoped_home(home: Path):
117
174
  if set_hermes_home_override is not None:
118
175
  token = set_hermes_home_override(home)
119
176
  try:
120
- with _secret_scope(home):
177
+ with _secret_scope(home), _terminal_scope(home):
121
178
  yield home
122
179
  finally:
123
180
  reset_hermes_home_override(token)
@@ -126,7 +183,7 @@ def scoped_home(home: Path):
126
183
  previous = os.environ.get("HERMES_HOME")
127
184
  os.environ["HERMES_HOME"] = str(home)
128
185
  try:
129
- with _secret_scope(home):
186
+ with _secret_scope(home), _terminal_scope(home):
130
187
  yield home
131
188
  finally:
132
189
  if previous is None:
@@ -29,9 +29,9 @@ class Registry:
29
29
 
30
30
  def build_methods(runtime: AgentRuntime) -> dict[str, Handler]:
31
31
  registry = Registry(runtime)
32
- from . import aux, chat, commands, config, cron, gateway, goals, kanban, mcp, process, profiles, providers, skills, state_db, stt, text, usage, worktree # noqa: WPS433
32
+ from . import aux, chat, commands, config, cron, gateway, goals, kanban, mcp, oauth, process, profiles, providers, skills, state_db, stt, text, usage, worktree # noqa: WPS433
33
33
  from . import runtime as runtime_methods
34
34
 
35
- for module in (runtime_methods, goals, commands, kanban, state_db, profiles, skills, mcp, stt, cron, providers, aux, text, process, usage, gateway, worktree, chat, config):
35
+ for module in (runtime_methods, goals, commands, kanban, state_db, profiles, skills, mcp, stt, cron, providers, oauth, aux, text, process, usage, gateway, worktree, chat, config):
36
36
  module.register(registry)
37
37
  return registry.methods
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import contextlib
5
6
  import logging
6
7
  import threading
7
8
  import uuid
@@ -39,8 +40,10 @@ def resolve_main_runtime(hint: dict | None) -> dict | None:
39
40
 
40
41
 
41
42
  def _main_model_completion(messages: list, runtime: dict, *, task: str) -> dict:
42
- """Predecessor fallback: run the main model through ``AIAgent`` with no tools when no auxiliary client answers."""
43
- from .chat import _agent_class
43
+ """Predecessor fallback: run the main model through ``AIAgent`` with no tools when no auxiliary client answers.
44
+
45
+ The throwaway agent never touches long-term memory (the prompt is a raw git diff) and is always closed."""
46
+ from .chat import _agent_class, _supported
44
47
 
45
48
  AIAgent = _agent_class()
46
49
 
@@ -51,8 +54,21 @@ def _main_model_completion(messages: list, runtime: dict, *, task: str) -> dict:
51
54
  for name in ("api_mode", "acp_command", "acp_args", "credential_pool"):
52
55
  if runtime.get(name) is not None:
53
56
  kwargs[name] = runtime[name]
57
+ for name in ("skip_memory", "skip_background_review"):
58
+ if _supported(AIAgent, name):
59
+ kwargs[name] = True
54
60
  agent = AIAgent(**kwargs)
55
- result = agent.run_conversation(user_message=user, system_message=system, conversation_history=[], task_id=kwargs["session_id"])
61
+ try:
62
+ result = agent.run_conversation(user_message=user, system_message=system, conversation_history=[], task_id=kwargs["session_id"])
63
+ finally:
64
+ with contextlib.suppress(Exception):
65
+ agent._end_session_on_close = False
66
+ close = getattr(agent, "close", None)
67
+ if callable(close):
68
+ try:
69
+ close()
70
+ except Exception: # noqa: BLE001
71
+ log.debug("%s fallback agent close failed", task, exc_info=True)
56
72
  return {"model": str(runtime.get("model") or ""), "text": str((result or {}).get("final_response") or "").strip(), "usage": None}
57
73
 
58
74
 
@@ -11,6 +11,7 @@ through ``approval.respond`` / ``clarify.respond``; ``rpc.cancel`` or
11
11
  from __future__ import annotations
12
12
 
13
13
  import contextlib
14
+ import contextvars
14
15
  import hashlib
15
16
  import inspect
16
17
  import json
@@ -372,7 +373,7 @@ def _resolve_runtime(provider: str | None, model: str) -> dict:
372
373
  def _turn_identity(session_id: str, workspace: str):
373
374
  """Bind this turn's identity to the calling context the way the predecessor's ``_set_turn_session_identity`` did:
374
375
  the approval session key (so ``register_gateway_notify`` cards reach this turn and dangerous commands are gated
375
- instead of auto-approved), the gateway session vars (platform ``webui``, chat/ui session ids), and the session cwd
376
+ instead of auto-approved), the gateway session vars (platform ``webui``, chat/ui session ids, profile), and the session cwd
376
377
  (so terminals and AGENTS.md discovery run in the selected workspace, not the sidecar's launch directory). Every
377
378
  binding is a context variable, so concurrent turns cannot overwrite each other. Missing Agent surfaces are logged,
378
379
  not fatal."""
@@ -388,10 +389,14 @@ def _turn_identity(session_id: str, workspace: str):
388
389
  log.debug("per-turn approval session-key bind failed", exc_info=True)
389
390
  try:
390
391
  from gateway import session_context as sc
392
+ from hermes_cli.profiles import get_active_profile_name
393
+ from hermes_constants import get_hermes_home, profile_name_for_home
391
394
 
395
+ # The persistent Docker sandbox is keyed by the profile name; unbound, every profile reuses "default".
396
+ profile = profile_name_for_home(get_hermes_home()) or get_active_profile_name()
392
397
  pairs = [
393
398
  (sc._SESSION_KEY, session_id), (sc._SESSION_UI_SESSION_ID, session_id), (sc._SESSION_PLATFORM, "webui"),
394
- (sc._SESSION_CHAT_ID, session_id), (sc._SESSION_ID, session_id),
399
+ (sc._SESSION_CHAT_ID, session_id), (sc._SESSION_ID, session_id), (sc._SESSION_PROFILE, profile),
395
400
  ]
396
401
  for var, value in pairs:
397
402
  tok = var.set(value)
@@ -415,6 +420,63 @@ def _turn_identity(session_id: str, workspace: str):
415
420
  log.debug("per-turn identity reset failed", exc_info=True)
416
421
 
417
422
 
423
+ #: Older configs named the CLI composite ``hermes``; the Agent registers it split in two (predecessor
424
+ #: ``_LEGACY_CLI_TOOLSET_ALIASES``).
425
+ _LEGACY_TOOLSET_ALIASES = {"hermes": ("hermes-cli", "hermes-api-server")}
426
+
427
+
428
+ def _turn_toolsets(toolsets) -> list[str]:
429
+ """The session's override as sent, else the profile's configured toolsets. ``None`` would hand the Agent every
430
+ registered toolset."""
431
+ return toolsets if isinstance(toolsets, list) else _profile_toolsets()
432
+
433
+
434
+ def _profile_toolsets() -> list[str]:
435
+ """The profile's ``platform_toolsets.cli`` through the Agent's own resolver (default-off toolsets stay off), like
436
+ ``hermes chat``. Runs under the call's ``scoped_home``."""
437
+ from hermes_cli.config import load_config
438
+ from hermes_cli.tools_config import _get_platform_tools
439
+
440
+ resolved = sorted(_get_platform_tools(load_config() or {}, "cli"))
441
+ return list(dict.fromkeys(name for raw in resolved for name in _LEGACY_TOOLSET_ALIASES.get(raw, (raw,))))
442
+
443
+
444
+ def _discover_mcp_tools(run: _Run) -> None:
445
+ """Connect the profile's MCP servers before the turn's agent snapshots its tools, like the predecessor's turn start.
446
+ The Agent keys connections by profile scope and skips live ones, so later turns are cheap. Runs under the call's
447
+ ``scoped_home``; a failure leaves the turn without MCP tools rather than failing it. A Stop does not wait for a slow
448
+ server: the turn moves on to its cancelled end while the connect finishes in the background."""
449
+ from .commands import retire_unscoped_launch_mcp_servers
450
+
451
+ done = threading.Event()
452
+
453
+ def discover() -> None:
454
+ try:
455
+ from tools.mcp_tool_discovery import discover_mcp_tools
456
+
457
+ retire_unscoped_launch_mcp_servers()
458
+ discover_mcp_tools()
459
+ except Exception: # noqa: BLE001
460
+ log.warning("MCP discovery failed", exc_info=True)
461
+ finally:
462
+ done.set()
463
+
464
+ # The copied context carries the turn's home override and secret scope into the worker.
465
+ threading.Thread(target=contextvars.copy_context().run, args=(discover,), daemon=True, name=f"chat-mcp-{run.stream_id[:8]}").start()
466
+ while not done.wait(0.25):
467
+ if run.cancel.is_set() or run.ctx.cancelled:
468
+ return
469
+
470
+
471
+ def _profile_fallback_chain() -> list[dict] | None:
472
+ """The profile's fallback routes (``fallback_providers`` first, then legacy ``fallback_model``, deduplicated)
473
+ through the Agent's own resolver, like the CLI and gateway. Runs under the call's ``scoped_home``."""
474
+ from hermes_cli.config import load_config
475
+ from hermes_cli.fallback_config import get_fallback_chain
476
+
477
+ return get_fallback_chain(load_config() or {}) or None
478
+
479
+
418
480
  def _agent_signature(model: str, provider, runtime: dict, toolsets, home: str, kwargs: dict) -> str:
419
481
  """Cache identity of an ``AIAgent``: everything its constructor bound from the resolved runtime, so a rotated key,
420
482
  a different API mode, ACP command, or credential pool never reuses an agent built for the old bundle. The key
@@ -430,6 +492,8 @@ def _agent_signature(model: str, provider, runtime: dict, toolsets, home: str, k
430
492
  "max_iterations": kwargs.get("max_iterations"), "max_tokens": kwargs.get("max_tokens"),
431
493
  # Bound at construction too: a reasoning-effort change from the composer must build a fresh agent.
432
494
  "reasoning_config": kwargs.get("reasoning_config"),
495
+ # Entries may carry their own ``api_key``.
496
+ "fallback_model": hashlib.sha256(json.dumps(kwargs.get("fallback_model"), sort_keys=True, default=str).encode("utf-8")).hexdigest()[:16],
433
497
  }
434
498
  return json.dumps(bundle, sort_keys=True, default=str)
435
499
 
@@ -472,6 +536,34 @@ def _supported(cls, name: str) -> bool:
472
536
  return name in parameters or any(p.kind is inspect.Parameter.VAR_KEYWORD for p in parameters.values())
473
537
 
474
538
 
539
+ def _approval_notifier(session_id: str, emit):
540
+ """The Agent's gateway notify callback for one turn: emits each parked approval, then ``approval_resolved``
541
+ (id plus the Agent's reason) once its wait ends by any path, an ``approvals.timeout`` expiry included (TAL-514)."""
542
+ try:
543
+ from tools.approval import register_gateway_settle
544
+ except Exception: # noqa: BLE001
545
+ register_gateway_settle = None
546
+
547
+ def notify(data):
548
+ payload = dict(data or {})
549
+ payload.setdefault("session_id", session_id)
550
+ payload.setdefault("approval_id", str(payload.get("request_id") or uuid.uuid4().hex))
551
+ emit("approval", payload)
552
+ request_id = str(payload.get("request_id") or "")
553
+ if register_gateway_settle is None or not request_id:
554
+ return
555
+ approval_id = payload["approval_id"]
556
+
557
+ def settle(reason):
558
+ emit("approval_resolved", {"approval_id": approval_id, "session_id": session_id, "reason": str(reason or "")})
559
+
560
+ # False: the wait already ended between the emit and this registration.
561
+ if not register_gateway_settle(session_id, request_id, settle):
562
+ settle("resolved")
563
+
564
+ return notify
565
+
566
+
475
567
  def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn, one function
476
568
  session_id = str(params.get("session_id") or "").strip()
477
569
  stream_id = str(params.get("stream_id") or "").strip()
@@ -487,7 +579,7 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
487
579
  history = []
488
580
  if not isinstance(history, list):
489
581
  raise InvalidParams("conversation_history must be a list")
490
- toolsets = params.get("enabled_toolsets")
582
+ toolsets = _turn_toolsets(params.get("enabled_toolsets"))
491
583
  system_message = params.get("system_message")
492
584
  run = _Run(stream_id, session_id, ctx)
493
585
  with _RUNS_LOCK:
@@ -510,6 +602,7 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
510
602
  raw_emit("steer_pending", {"text": pending})
511
603
  raw_emit(event, data)
512
604
  try:
605
+ _discover_mcp_tools(run)
513
606
  runtime = _resolve_runtime(provider, model)
514
607
  resolved_model = model or str(runtime.get("model") or "")
515
608
  resolved_provider = provider or runtime.get("provider")
@@ -626,15 +719,7 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
626
719
  from tools.approval import register_gateway_notify, unregister_gateway_notify
627
720
  except Exception: # noqa: BLE001
628
721
  register_gateway_notify = unregister_gateway_notify = None
629
- if register_gateway_notify is not None:
630
- def _approval_cb(data):
631
- payload = dict(data or {})
632
- payload.setdefault("session_id", session_id)
633
- payload.setdefault("approval_id", str(payload.get("request_id") or uuid.uuid4().hex))
634
- emit("approval", payload)
635
- approval_cb = _approval_cb
636
- else:
637
- approval_cb = None
722
+ approval_cb = _approval_notifier(session_id, emit) if register_gateway_notify is not None else None
638
723
 
639
724
  kwargs: dict = dict(
640
725
  model=resolved_model,
@@ -643,7 +728,7 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
643
728
  api_key=runtime.get("api_key"),
644
729
  platform="webui",
645
730
  quiet_mode=True,
646
- enabled_toolsets=toolsets if isinstance(toolsets, list) else None,
731
+ enabled_toolsets=toolsets,
647
732
  session_id=session_id,
648
733
  stream_delta_callback=on_token,
649
734
  reasoning_callback=on_reasoning,
@@ -671,6 +756,9 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
671
756
  reasoning_config = params.get("reasoning_config")
672
757
  if isinstance(reasoning_config, dict) and _supported(AIAgent, "reasoning_config"):
673
758
  kwargs["reasoning_config"] = reasoning_config
759
+ fallback_chain = _profile_fallback_chain()
760
+ if fallback_chain and _supported(AIAgent, "fallback_model"):
761
+ kwargs["fallback_model"] = fallback_chain
674
762
  signature = _agent_signature(resolved_model, resolved_provider, runtime, toolsets, str(params.get("profile_home")), kwargs)
675
763
  agent = None
676
764
  if not session_busy:
@@ -772,14 +860,22 @@ def start(ctx: CallContext, params: dict) -> dict: # noqa: PLR0915 - one turn,
772
860
  error = str(last_error)
773
861
  if not error and isinstance(result.get("error"), str) and result.get("error"):
774
862
  error = str(result["error"])
775
- status = "cancelled" if cancelled else ("error" if error and not result.get("messages") else "completed")
863
+ # The Agent ends a failed turn with ``failed``/``partial`` (never ``status``), often after text streamed and with
864
+ # the turn's messages; a failed turn is an error whatever it carries.
865
+ failed = bool(result.get("failed"))
866
+ partial = bool(result.get("partial"))
867
+ if not error and failed and result.get("final_response"):
868
+ error = str(result["final_response"])
869
+ status = "cancelled" if cancelled else ("error" if failed or (error and not result.get("messages")) else "completed")
776
870
  pending_steer = str(result.get("pending_steer") or "") if isinstance(result, dict) else ""
777
871
  return {
778
872
  "status": status,
779
873
  "messages": [m for m in (result.get("messages") or []) if isinstance(m, dict)],
780
874
  "final_response": str(result.get("final_response") or ""),
781
875
  "error": error,
782
- "result_status": str(result.get("status") or result.get("state") or ""),
876
+ "failed": failed,
877
+ "partial": partial,
878
+ "compression_exhausted": bool(result.get("compression_exhausted")),
783
879
  "tool_limit_reached": bool(result.get("tool_limit_reached") or result.get("max_iterations_reached")),
784
880
  "usage": _usage(agent),
785
881
  "context": _context_length(agent),
@@ -861,7 +957,7 @@ def compress(ctx: CallContext, params: dict) -> dict:
861
957
  model = str(params.get("model") or "").strip()
862
958
  provider = str(params.get("model_provider") or "").strip() or None
863
959
  focus_topic = str(params.get("focus_topic") or "").strip()[:500] or None
864
- toolsets = params.get("enabled_toolsets")
960
+ toolsets = _turn_toolsets(params.get("enabled_toolsets"))
865
961
  runtime = _resolve_runtime(provider, model)
866
962
  if not runtime.get("api_key"):
867
963
  raise RpcError("No provider configured -- cannot compress.", condition="credential_missing")
@@ -875,7 +971,7 @@ def compress(ctx: CallContext, params: dict) -> dict:
875
971
  api_key=runtime.get("api_key"),
876
972
  platform="webui",
877
973
  quiet_mode=True,
878
- enabled_toolsets=toolsets if isinstance(toolsets, list) else None,
974
+ enabled_toolsets=toolsets,
879
975
  session_id=session_id,
880
976
  )
881
977
  for name, value in (
@@ -1017,14 +1113,22 @@ def register(registry) -> None:
1017
1113
 
1018
1114
  @registry.method("chat.evict_agent", requires_agent=False)
1019
1115
  def evict_(ctx: CallContext, params: dict) -> dict:
1116
+ """Drop a session's cached agent. Only delete/clear (``clear_session``) end its approval grants, parked
1117
+ approvals and kernels; a model switch, truncate or compress leaves a running turn's agent in place."""
1020
1118
  session_id = str(params.get("session_id") or "").strip()
1119
+ end_session = params.get("clear_session") is True
1021
1120
  with _AGENT_CACHE_LOCK:
1121
+ with _RUNS_LOCK:
1122
+ run = _RUNS.get(_RUNS_BY_SESSION.get(session_id) or "")
1123
+ if not end_session and run is not None and not run.finished.is_set():
1124
+ return {"evicted": False}
1022
1125
  evicted = _AGENT_CACHE.pop(session_id, None) is not None
1023
- try:
1024
- from tools.approval import clear_session
1025
- clear_session(session_id)
1026
- except Exception: # noqa: BLE001
1027
- pass
1126
+ if end_session:
1127
+ try:
1128
+ from tools.approval import clear_session
1129
+ clear_session(session_id)
1130
+ except Exception: # noqa: BLE001
1131
+ pass
1028
1132
  return {"evicted": evicted}
1029
1133
 
1030
1134
  @registry.method("chat.commit_memory", requires_agent=False)
@@ -1101,7 +1205,9 @@ def register(registry) -> None:
1101
1205
  except Exception as exc: # noqa: BLE001
1102
1206
  raise RpcError(f"approval module unavailable: {exc}", condition="agent_unavailable") from exc
1103
1207
  (enable_session_yolo if enabled else disable_session_yolo)(session_id)
1104
- released = resolve_gateway_approval(session_id, "session", resolve_all=True) if enabled else 0
1208
+ # Parked approvals are released `once`: a `session` or `always` grant would keep their patterns approved after
1209
+ # YOLO turns off, whatever choice the card that enabled it carried.
1210
+ released = resolve_gateway_approval(session_id, "once", resolve_all=True) if enabled else 0
1105
1211
  return {"yolo_enabled": bool(is_session_yolo_enabled(session_id)), "released": int(released or 0)}
1106
1212
 
1107
1213
  @registry.method("clarify.respond", requires_agent=False)
@@ -7,8 +7,9 @@ import threading
7
7
  from typing import Any
8
8
 
9
9
  from ..errors import InvalidParams, RpcError
10
- from ..home import profile_home_param, scoped_home
10
+ from ..home import _is_named_profile, profile_home_param, scoped_home
11
11
  from ..rpc import CallContext
12
+ from .providers import plugin_providers
12
13
 
13
14
  log = logging.getLogger("talaria_sidecar.commands")
14
15
 
@@ -60,19 +61,54 @@ def list_commands() -> list[dict[str, Any]]:
60
61
  return out
61
62
 
62
63
 
64
+ def retire_unscoped_launch_mcp_servers() -> set[str]:
65
+ """Close the launch profile's connections opened before multiplexing started; returns their server names.
66
+
67
+ Until the first named-profile call, the launch profile's connections and tools are unscoped (process-wide). Once
68
+ multiplexing is active, a scoped shutdown never selects them and scoped discovery opens duplicates beside them, so
69
+ the launch profile's own calls close them first and its scope reconnects them from the current config."""
70
+ from agent.secret_scope import is_multiplex_active
71
+ from hermes_constants import get_hermes_home
72
+ from tools.mcp_tool import _lock, _servers
73
+ from tools.mcp_tool_lifecycle import shutdown_mcp_servers
74
+ from tools.mcp_tool_scope import _key_name, _key_scope
75
+
76
+ if not is_multiplex_active() or _is_named_profile(get_hermes_home()):
77
+ return set()
78
+ with _lock:
79
+ names = {_key_name(key) for key in _servers if _key_scope(key) is None}
80
+ if names:
81
+ shutdown_mcp_servers(scope=None, names=names)
82
+ return names
83
+
84
+
63
85
  def _reload_mcp() -> str:
64
86
  with _RELOAD_MCP_LOCK:
65
87
  try:
66
- from tools.mcp_tool import _lock, _servers, discover_mcp_tools, shutdown_mcp_servers
88
+ from agent.secret_scope import is_multiplex_active
89
+ from tools.mcp_tool import _lock, _mcp_tool_server_names, _server_visible_in_scope, _servers
90
+ from tools.mcp_tool_discovery import discover_mcp_tools
91
+ from tools.mcp_tool_lifecycle import shutdown_mcp_servers
92
+ from tools.mcp_tool_scope import _key_name
93
+ from tools.registry import registry
67
94
  except Exception as exc: # noqa: BLE001
68
95
  raise RpcError("MCP runtime unavailable", condition="mcp_unavailable") from exc
69
- try:
70
- with _lock:
71
- old = set(_servers.keys())
72
- shutdown_mcp_servers()
73
- tools = discover_mcp_tools()
96
+ # Like the gateway's ``_execute_mcp_reload``: under multiplexing only this profile's connections go down and
97
+ # come back. The bare shutdown is the process-wide wildcard, which would drop every other profile's servers.
98
+ scope = registry.current_scope_key() if is_multiplex_active() else None
99
+
100
+ def server_names() -> set[str]:
74
101
  with _lock:
75
- connected = set(_servers.keys())
102
+ return {_key_name(key) for key in _servers if _server_visible_in_scope(key, scope)}
103
+
104
+ try:
105
+ old = server_names() | retire_unscoped_launch_mcp_servers()
106
+ shutdown_mcp_servers(scope=scope)
107
+ tools = discover_mcp_tools() or []
108
+ connected = server_names()
109
+ if scope is not None:
110
+ with _lock:
111
+ tools = [name for name in tools if _mcp_tool_server_names.get(name) in connected]
76
112
  except Exception as exc: # noqa: BLE001
77
113
  log.warning("Failed to reload MCP servers", exc_info=True)
78
114
  raise RpcError("Failed to reload MCP servers", condition="mcp_reload_failed") from exc
@@ -84,7 +120,7 @@ def _reload_mcp() -> str:
84
120
  lines.append(f"Added: {', '.join(sorted(added))}")
85
121
  if removed:
86
122
  lines.append(f"Removed: {', '.join(sorted(removed))}")
87
- lines.append(f"{len(tools or [])} tool(s) available across {len(connected)} server(s)" if connected else "No MCP servers connected")
123
+ lines.append(f"{len(tools)} tool(s) available across {len(connected)} server(s)" if connected else "No MCP servers connected")
88
124
  if not reconnected and not added and not removed:
89
125
  lines.append("Tooling state was already current")
90
126
  return "\n".join(lines)
@@ -230,27 +266,6 @@ def resolve_moa_config(preset: str | None) -> dict:
230
266
  return resolved
231
267
 
232
268
 
233
- def plugin_provider_profiles() -> list[dict]:
234
- """Model-provider plugins registered with the Agent's provider registry."""
235
- try:
236
- from providers import list_providers
237
- except Exception: # noqa: BLE001
238
- return []
239
- out = []
240
- try:
241
- for profile in list_providers():
242
- name = str(getattr(profile, "name", "") or "").strip().lower()
243
- if not name:
244
- continue
245
- env_vars = [str(v) for v in (getattr(profile, "env_vars", ()) or ())]
246
- api_key_env = next((v for v in env_vars if not v.upper().endswith(("_BASE_URL", "_URL", "_FOLDER_ID"))), None)
247
- out.append({"name": name, "display_name": str(getattr(profile, "display_name", "") or name).strip(), "env_vars": env_vars, "api_key_env": api_key_env})
248
- except Exception: # noqa: BLE001
249
- log.debug("Failed to enumerate model-provider plugins", exc_info=True)
250
- return []
251
- return out
252
-
253
-
254
269
  PLUGIN_VISIBILITY_HOOKS = ("pre_tool_call", "post_tool_call", "pre_llm_call", "post_llm_call")
255
270
 
256
271
 
@@ -332,7 +347,7 @@ def register(registry) -> None:
332
347
  @registry.method("plugins.providers")
333
348
  def providers(ctx: CallContext, params: dict) -> dict:
334
349
  with scoped_home(profile_home_param(params)):
335
- return {"providers": plugin_provider_profiles()}
350
+ return {"providers": plugin_providers()}
336
351
 
337
352
  @registry.method("plugins.list")
338
353
  def list_(ctx: CallContext, params: dict) -> dict:
@@ -2,12 +2,13 @@
2
2
  Agent's per-model reasoning capability.
3
3
 
4
4
  The TypeScript server owns every config.yaml *policy* (which keys mean what);
5
- the sidecar only parses and serialises YAML with the Agent's PyYAML so the Node
6
- side needs no YAML dependency. Writes are atomic and keep the file's mode.
5
+ the sidecar only parses and serialises YAML with the Agent's own parser so the
6
+ Node side needs no YAML dependency. Writes are atomic and keep the file's mode.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ import importlib
11
12
  import logging
12
13
  import os
13
14
  import tempfile
@@ -20,12 +21,15 @@ from ..rpc import CallContext
20
21
  log = logging.getLogger("talaria_sidecar.config")
21
22
 
22
23
 
23
- def _yaml():
24
- try:
25
- import yaml
26
- except Exception as exc: # noqa: BLE001
27
- raise RpcError(f"PyYAML unavailable: {exc}", condition="yaml_unavailable") from exc
28
- return yaml
24
+ def yaml_parser():
25
+ """The Agent's YAML module: ``hermes_yaml`` on Agents that ship it, PyYAML on released Agents."""
26
+ failures = []
27
+ for name in ("hermes_yaml", "yaml"):
28
+ try:
29
+ return importlib.import_module(name)
30
+ except Exception as exc: # noqa: BLE001
31
+ failures.append(f"{name}: {exc}")
32
+ raise RpcError(f"No YAML parser available ({'; '.join(failures)})", condition="yaml_unavailable")
29
33
 
30
34
 
31
35
  def config_path_param(params: dict) -> Path:
@@ -45,7 +49,7 @@ def read_config(path: Path) -> dict:
45
49
  if not path.exists():
46
50
  return {"path": str(path), "exists": False, "config": {}}
47
51
  try:
48
- data = _yaml().safe_load(path.read_text(encoding="utf-8"))
52
+ data = yaml_parser().safe_load(path.read_text(encoding="utf-8"))
49
53
  except RpcError:
50
54
  raise
51
55
  except Exception as exc: # noqa: BLE001
@@ -70,7 +74,7 @@ def write_config(path: Path, config: dict) -> dict:
70
74
  raise InvalidParams("config must be an object")
71
75
  target = _write_target(path)
72
76
  target.parent.mkdir(parents=True, exist_ok=True)
73
- text = _yaml().safe_dump(config, sort_keys=False, allow_unicode=True)
77
+ text = yaml_parser().safe_dump(config, sort_keys=False, allow_unicode=True)
74
78
  mode = None
75
79
  try:
76
80
  mode = target.stat().st_mode & 0o777