@astralyn/pi 1.0.4 → 1.1.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.
Files changed (332) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/bundle/chunks/{anthropic-messages-YIOJIMVL.js → anthropic-messages-3K3DWVY6.js} +1 -1
  3. package/dist/bundle/chunks/anthropic.js +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-LDW4FGAQ.js → azure-openai-responses-CH74HGP4.js} +1 -1
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  6. package/dist/bundle/chunks/{chunk-UCXU7KLO.js → chunk-3MMB5I7J.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-GIG5IHES.js → chunk-5KJH3GGH.js} +1 -1
  8. package/dist/bundle/chunks/chunk-6VYRLG5F.js +2 -0
  9. package/dist/bundle/chunks/{chunk-73WG7F7N.js → chunk-C2ARIVS3.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-23OTKHCH.js → chunk-D3XW5X3Z.js} +490 -260
  11. package/dist/bundle/chunks/{chunk-IFELM7MW.js → chunk-EJEOEBSJ.js} +1 -1
  12. package/dist/bundle/chunks/chunk-H35KWBT5.js +11 -0
  13. package/dist/bundle/chunks/chunk-KAC2YPTW.js +2 -0
  14. package/dist/bundle/chunks/chunk-MAC4N3BW.js +2 -0
  15. package/dist/bundle/chunks/chunk-QLU3LESZ.js +2 -0
  16. package/dist/bundle/chunks/{chunk-A6ALEEY5.js → chunk-TEAAYBTS.js} +1 -1
  17. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-XO45ZT3V.js +2 -0
  18. package/dist/bundle/chunks/codemode-worker.js +101 -5
  19. package/dist/bundle/chunks/github-copilot.js +1 -1
  20. package/dist/bundle/chunks/{google-generative-ai-S5A5IBU4.js → google-generative-ai-VVO64ZRQ.js} +1 -1
  21. package/dist/bundle/chunks/{google-vertex-UBRQFDB4.js → google-vertex-LKS5NUHA.js} +1 -1
  22. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  23. package/dist/bundle/chunks/{llama-cpp-classify-R7DQLTQN.js → llama-cpp-classify-H3IZDR5O.js} +2 -2
  24. package/dist/bundle/chunks/{mistral-conversations-A2N5FSOV.js → mistral-conversations-NJUOG4ET.js} +2 -2
  25. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  26. package/dist/bundle/chunks/{openai-codex-responses-Q6JHCWLE.js → openai-codex-responses-TZWBTTYM.js} +2 -2
  27. package/dist/bundle/chunks/openai-codex.js +1 -1
  28. package/dist/bundle/chunks/{openai-completions-H4VMO7AU.js → openai-completions-7HTTU6FH.js} +1 -1
  29. package/dist/bundle/chunks/openai-decisions-776H4VDZ.js +5 -0
  30. package/dist/bundle/chunks/{openai-responses-G4PGNM2H.js → openai-responses-7A6BAQ5X.js} +1 -1
  31. package/dist/bundle/chunks/{openrouter-images-YP3YVB54.js → openrouter-images-TDLJV5N4.js} +1 -1
  32. package/dist/bundle/chunks/{pi-messages-HZZ7GEEW.js → pi-messages-ZXNERWJG.js} +1 -1
  33. package/dist/bundle/chunks/typesafe-system-one-2DQLG4R2.js +2 -0
  34. package/dist/bundle/chunks/{virtual-modules-IJTAY26N.js → virtual-modules-2NHGQRS6.js} +1 -1
  35. package/dist/bundle/cli.js +1 -1
  36. package/dist/bundle/index.js +1 -1
  37. package/dist/bundle/rpc-entry.js +1 -1
  38. package/dist/cli/args.d.ts +2 -1
  39. package/dist/cli/args.d.ts.map +1 -1
  40. package/dist/cli/args.js +24 -5
  41. package/dist/cli/args.js.map +1 -1
  42. package/dist/core/agent-session.d.ts +38 -10
  43. package/dist/core/agent-session.d.ts.map +1 -1
  44. package/dist/core/agent-session.js +190 -186
  45. package/dist/core/agent-session.js.map +1 -1
  46. package/dist/core/bash-executor.d.ts.map +1 -1
  47. package/dist/core/bash-executor.js +40 -45
  48. package/dist/core/bash-executor.js.map +1 -1
  49. package/dist/core/context-snapshot.d.ts +4 -1
  50. package/dist/core/context-snapshot.d.ts.map +1 -1
  51. package/dist/core/context-snapshot.js +45 -0
  52. package/dist/core/context-snapshot.js.map +1 -1
  53. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  54. package/dist/core/export-html/tool-renderer.js +2 -0
  55. package/dist/core/export-html/tool-renderer.js.map +1 -1
  56. package/dist/core/extensions/types.d.ts +13 -0
  57. package/dist/core/extensions/types.d.ts.map +1 -1
  58. package/dist/core/extensions/types.js.map +1 -1
  59. package/dist/core/mcp-servers.d.ts +8 -0
  60. package/dist/core/mcp-servers.d.ts.map +1 -1
  61. package/dist/core/mcp-servers.js +30 -7
  62. package/dist/core/mcp-servers.js.map +1 -1
  63. package/dist/core/model-runtime.d.ts.map +1 -1
  64. package/dist/core/model-runtime.js +2 -1
  65. package/dist/core/model-runtime.js.map +1 -1
  66. package/dist/core/nested-tool-calls.d.ts +1 -0
  67. package/dist/core/nested-tool-calls.d.ts.map +1 -1
  68. package/dist/core/nested-tool-calls.js +1 -0
  69. package/dist/core/nested-tool-calls.js.map +1 -1
  70. package/dist/core/resource-loader.d.ts +3 -0
  71. package/dist/core/resource-loader.d.ts.map +1 -1
  72. package/dist/core/resource-loader.js +3 -3
  73. package/dist/core/resource-loader.js.map +1 -1
  74. package/dist/core/sdk.d.ts +13 -4
  75. package/dist/core/sdk.d.ts.map +1 -1
  76. package/dist/core/sdk.js +19 -6
  77. package/dist/core/sdk.js.map +1 -1
  78. package/dist/core/settings-manager.d.ts +13 -0
  79. package/dist/core/settings-manager.d.ts.map +1 -1
  80. package/dist/core/settings-manager.js +37 -13
  81. package/dist/core/settings-manager.js.map +1 -1
  82. package/dist/core/skills.d.ts +4 -1
  83. package/dist/core/skills.d.ts.map +1 -1
  84. package/dist/core/skills.js +6 -1
  85. package/dist/core/skills.js.map +1 -1
  86. package/dist/core/system-prompt.d.ts +6 -0
  87. package/dist/core/system-prompt.d.ts.map +1 -1
  88. package/dist/core/system-prompt.js +9 -4
  89. package/dist/core/system-prompt.js.map +1 -1
  90. package/dist/core/tasks/session.d.ts +9 -0
  91. package/dist/core/tasks/session.d.ts.map +1 -1
  92. package/dist/core/tasks/session.js +21 -0
  93. package/dist/core/tasks/session.js.map +1 -1
  94. package/dist/core/tools/read.d.ts +13 -0
  95. package/dist/core/tools/read.d.ts.map +1 -1
  96. package/dist/core/tools/read.js +18 -1
  97. package/dist/core/tools/read.js.map +1 -1
  98. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  99. package/dist/core/tools/renderers/bash.js +8 -3
  100. package/dist/core/tools/renderers/bash.js.map +1 -1
  101. package/dist/core/tools/renderers/edit.js +1 -1
  102. package/dist/core/tools/renderers/edit.js.map +1 -1
  103. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  104. package/dist/extensions/codemode/execute.js +65 -8
  105. package/dist/extensions/codemode/execute.js.map +1 -1
  106. package/dist/extensions/codemode/index.d.ts.map +1 -1
  107. package/dist/extensions/codemode/index.js +1 -0
  108. package/dist/extensions/codemode/index.js.map +1 -1
  109. package/dist/extensions/codemode/tool.d.ts +9 -2
  110. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  111. package/dist/extensions/codemode/tool.js +14 -6
  112. package/dist/extensions/codemode/tool.js.map +1 -1
  113. package/dist/extensions/index.js +2 -2
  114. package/dist/extensions/index.js.map +1 -1
  115. package/dist/extensions/llama/provider.d.ts.map +1 -1
  116. package/dist/extensions/llama/provider.js +34 -11
  117. package/dist/extensions/llama/provider.js.map +1 -1
  118. package/dist/extensions/mcp/cli.js +17 -23
  119. package/dist/extensions/mcp/cli.js.map +1 -1
  120. package/dist/extensions/mcp/index.d.ts.map +1 -1
  121. package/dist/extensions/mcp/index.js +165 -64
  122. package/dist/extensions/mcp/index.js.map +1 -1
  123. package/dist/extensions/mcp/oauth.d.ts +5 -3
  124. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  125. package/dist/extensions/mcp/oauth.js +36 -10
  126. package/dist/extensions/mcp/oauth.js.map +1 -1
  127. package/dist/extensions/mcp/resources.d.ts +3 -4
  128. package/dist/extensions/mcp/resources.d.ts.map +1 -1
  129. package/dist/extensions/mcp/resources.js +3 -4
  130. package/dist/extensions/mcp/resources.js.map +1 -1
  131. package/dist/extensions/mcp/runtime.d.ts +4 -1
  132. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  133. package/dist/extensions/mcp/runtime.js +22 -5
  134. package/dist/extensions/mcp/runtime.js.map +1 -1
  135. package/dist/extensions/mcp/tools.d.ts +2 -1
  136. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  137. package/dist/extensions/mcp/tools.js +2 -1
  138. package/dist/extensions/mcp/tools.js.map +1 -1
  139. package/dist/extensions/mcp/ui.d.ts +3 -3
  140. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  141. package/dist/extensions/mcp/ui.js +10 -2
  142. package/dist/extensions/mcp/ui.js.map +1 -1
  143. package/dist/extensions/search/code-search.d.ts +29 -0
  144. package/dist/extensions/search/code-search.d.ts.map +1 -0
  145. package/dist/extensions/search/code-search.js +120 -0
  146. package/dist/extensions/search/code-search.js.map +1 -0
  147. package/dist/extensions/search/command.d.ts +5 -0
  148. package/dist/extensions/search/command.d.ts.map +1 -0
  149. package/dist/extensions/search/command.js +69 -0
  150. package/dist/extensions/search/command.js.map +1 -0
  151. package/dist/extensions/search/credential.d.ts +25 -0
  152. package/dist/extensions/search/credential.d.ts.map +1 -0
  153. package/dist/extensions/search/credential.js +117 -0
  154. package/dist/extensions/search/credential.js.map +1 -0
  155. package/dist/extensions/search/devin.d.ts +34 -0
  156. package/dist/extensions/search/devin.d.ts.map +1 -0
  157. package/dist/extensions/search/devin.js +210 -0
  158. package/dist/extensions/search/devin.js.map +1 -0
  159. package/dist/extensions/search/index.d.ts +5 -0
  160. package/dist/extensions/search/index.d.ts.map +1 -0
  161. package/dist/extensions/search/index.js +110 -0
  162. package/dist/extensions/search/index.js.map +1 -0
  163. package/dist/extensions/search/panel.d.ts +53 -0
  164. package/dist/extensions/search/panel.d.ts.map +1 -0
  165. package/dist/extensions/search/panel.js +157 -0
  166. package/dist/extensions/search/panel.js.map +1 -0
  167. package/dist/extensions/search/prompt.d.ts +14 -0
  168. package/dist/extensions/search/prompt.d.ts.map +1 -0
  169. package/dist/extensions/search/prompt.js +221 -0
  170. package/dist/extensions/search/prompt.js.map +1 -0
  171. package/dist/extensions/search/render.d.ts +28 -0
  172. package/dist/extensions/search/render.d.ts.map +1 -0
  173. package/dist/extensions/search/render.js +86 -0
  174. package/dist/extensions/search/render.js.map +1 -0
  175. package/dist/extensions/search/workspace.d.ts +38 -0
  176. package/dist/extensions/search/workspace.d.ts.map +1 -0
  177. package/dist/extensions/search/workspace.js +245 -0
  178. package/dist/extensions/search/workspace.js.map +1 -0
  179. package/dist/main.d.ts.map +1 -1
  180. package/dist/main.js +1 -0
  181. package/dist/main.js.map +1 -1
  182. package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
  183. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  184. package/dist/modes/interactive/components/bash-execution.js +14 -14
  185. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  186. package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
  187. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  188. package/dist/modes/interactive/components/branch-summary-message.js +5 -2
  189. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  190. package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -1
  191. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  192. package/dist/modes/interactive/components/compaction-summary-message.js +5 -2
  193. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  194. package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
  195. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  196. package/dist/modes/interactive/components/custom-entry.js +7 -2
  197. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  198. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  199. package/dist/modes/interactive/components/custom-message.js +1 -0
  200. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  201. package/dist/modes/interactive/components/settings-selector.js +1 -1
  202. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  203. package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
  204. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  205. package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
  206. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  207. package/dist/modes/interactive/interactive-mode.d.ts +2 -0
  208. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  209. package/dist/modes/interactive/interactive-mode.js +52 -59
  210. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  211. package/dist/modes/interactive/program-status-reporter.d.ts +34 -0
  212. package/dist/modes/interactive/program-status-reporter.d.ts.map +1 -0
  213. package/dist/modes/interactive/program-status-reporter.js +107 -0
  214. package/dist/modes/interactive/program-status-reporter.js.map +1 -0
  215. package/dist/modes/interactive/tasks/host-hooks.d.ts +14 -0
  216. package/dist/modes/interactive/tasks/host-hooks.d.ts.map +1 -0
  217. package/dist/modes/interactive/tasks/host-hooks.js +31 -0
  218. package/dist/modes/interactive/tasks/host-hooks.js.map +1 -0
  219. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  220. package/dist/modes/interactive/theme/theme.js +1 -0
  221. package/dist/modes/interactive/theme/theme.js.map +1 -1
  222. package/dist/modes/interactive/tool-view/tool-execution.d.ts +5 -0
  223. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
  224. package/dist/modes/interactive/tool-view/tool-execution.js +7 -0
  225. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
  226. package/dist/package-manager-cli.d.ts.map +1 -1
  227. package/dist/package-manager-cli.js +24 -0
  228. package/dist/package-manager-cli.js.map +1 -1
  229. package/dist/utils/ansi.d.ts +8 -0
  230. package/dist/utils/ansi.d.ts.map +1 -1
  231. package/dist/utils/ansi.js +30 -11
  232. package/dist/utils/ansi.js.map +1 -1
  233. package/dist/utils/clipboard.d.ts.map +1 -1
  234. package/dist/utils/clipboard.js +12 -11
  235. package/dist/utils/clipboard.js.map +1 -1
  236. package/dist/utils/image-resize-core.d.ts +12 -0
  237. package/dist/utils/image-resize-core.d.ts.map +1 -1
  238. package/dist/utils/image-resize-core.js +5 -0
  239. package/dist/utils/image-resize-core.js.map +1 -1
  240. package/dist/utils/image-resize-worker.js +3 -2
  241. package/dist/utils/image-resize-worker.js.map +1 -1
  242. package/dist/utils/image-resize.d.ts.map +1 -1
  243. package/dist/utils/image-resize.js +9 -10
  244. package/dist/utils/image-resize.js.map +1 -1
  245. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  246. package/dist/utils/syntax-highlight.js +6 -1
  247. package/dist/utils/syntax-highlight.js.map +1 -1
  248. package/docs/bundled/README.md +1 -1
  249. package/docs/bundled/extensions/provider.md +1 -1
  250. package/docs/bundled/extensions/question.md +1 -1
  251. package/docs/bundled/extensions/search.md +50 -0
  252. package/docs/bundled/extensions/statusline.md +15 -41
  253. package/docs/codemode.md +26 -5
  254. package/docs/docs.json +0 -4
  255. package/docs/environment-variables.md +1 -0
  256. package/docs/extensions.md +6 -2
  257. package/docs/json.md +2 -2
  258. package/docs/llama-cpp.md +8 -1
  259. package/docs/mcp.md +3 -1
  260. package/docs/models.md +4 -1
  261. package/docs/providers.md +17 -0
  262. package/docs/rpc.md +6 -3
  263. package/docs/session-format.md +1 -0
  264. package/docs/settings.md +4 -4
  265. package/docs/terminal-setup.md +14 -0
  266. package/docs/usage.md +19 -5
  267. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  268. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  269. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  270. package/examples/extensions/gondolin/package-lock.json +2 -2
  271. package/examples/extensions/gondolin/package.json +1 -1
  272. package/examples/extensions/sandbox/package-lock.json +2 -2
  273. package/examples/extensions/sandbox/package.json +1 -1
  274. package/examples/extensions/with-deps/package-lock.json +2 -2
  275. package/examples/extensions/with-deps/package.json +1 -1
  276. package/npm-shrinkwrap.json +54 -54
  277. package/package.json +13 -11
  278. package/dist/bundle/chunks/chunk-57XI7YJH.js +0 -2
  279. package/dist/bundle/chunks/chunk-JI4WGISU.js +0 -2
  280. package/dist/bundle/chunks/chunk-TCQ4HHQD.js +0 -2
  281. package/dist/bundle/chunks/chunk-TXJO4AJ7.js +0 -11
  282. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-OWU5SM6J.js +0 -2
  283. package/dist/bundle/chunks/typesafe-system-one-KYKKNU3E.js +0 -2
  284. package/dist/extensions/web-search/auth.d.ts +0 -12
  285. package/dist/extensions/web-search/auth.d.ts.map +0 -1
  286. package/dist/extensions/web-search/auth.js +0 -90
  287. package/dist/extensions/web-search/auth.js.map +0 -1
  288. package/dist/extensions/web-search/constants.d.ts +0 -13
  289. package/dist/extensions/web-search/constants.d.ts.map +0 -1
  290. package/dist/extensions/web-search/constants.js +0 -26
  291. package/dist/extensions/web-search/constants.js.map +0 -1
  292. package/dist/extensions/web-search/execute.d.ts +0 -9
  293. package/dist/extensions/web-search/execute.d.ts.map +0 -1
  294. package/dist/extensions/web-search/execute.js +0 -96
  295. package/dist/extensions/web-search/execute.js.map +0 -1
  296. package/dist/extensions/web-search/format.d.ts +0 -21
  297. package/dist/extensions/web-search/format.d.ts.map +0 -1
  298. package/dist/extensions/web-search/format.js +0 -117
  299. package/dist/extensions/web-search/format.js.map +0 -1
  300. package/dist/extensions/web-search/index.d.ts +0 -6
  301. package/dist/extensions/web-search/index.d.ts.map +0 -1
  302. package/dist/extensions/web-search/index.js +0 -50
  303. package/dist/extensions/web-search/index.js.map +0 -1
  304. package/dist/extensions/web-search/providers/deepseek.d.ts +0 -13
  305. package/dist/extensions/web-search/providers/deepseek.d.ts.map +0 -1
  306. package/dist/extensions/web-search/providers/deepseek.js +0 -110
  307. package/dist/extensions/web-search/providers/deepseek.js.map +0 -1
  308. package/dist/extensions/web-search/providers/http.d.ts +0 -4
  309. package/dist/extensions/web-search/providers/http.d.ts.map +0 -1
  310. package/dist/extensions/web-search/providers/http.js +0 -42
  311. package/dist/extensions/web-search/providers/http.js.map +0 -1
  312. package/dist/extensions/web-search/providers/minimax.d.ts +0 -12
  313. package/dist/extensions/web-search/providers/minimax.d.ts.map +0 -1
  314. package/dist/extensions/web-search/providers/minimax.js +0 -61
  315. package/dist/extensions/web-search/providers/minimax.js.map +0 -1
  316. package/dist/extensions/web-search/render.d.ts +0 -15
  317. package/dist/extensions/web-search/render.d.ts.map +0 -1
  318. package/dist/extensions/web-search/render.js +0 -142
  319. package/dist/extensions/web-search/render.js.map +0 -1
  320. package/dist/extensions/web-search/results.d.ts +0 -35
  321. package/dist/extensions/web-search/results.d.ts.map +0 -1
  322. package/dist/extensions/web-search/results.js +0 -167
  323. package/dist/extensions/web-search/results.js.map +0 -1
  324. package/dist/extensions/web-search/schema.d.ts +0 -10
  325. package/dist/extensions/web-search/schema.d.ts.map +0 -1
  326. package/dist/extensions/web-search/schema.js +0 -36
  327. package/dist/extensions/web-search/schema.js.map +0 -1
  328. package/dist/extensions/web-search/types.d.ts +0 -51
  329. package/dist/extensions/web-search/types.d.ts.map +0 -1
  330. package/dist/extensions/web-search/types.js +0 -5
  331. package/dist/extensions/web-search/types.js.map +0 -1
  332. package/docs/bundled/extensions/web-search.md +0 -46
@@ -16,7 +16,7 @@ import { createTasksToolDefinition } from "./tools/tasks.js";
16
16
  import { readFileSync } from "node:fs";
17
17
  import { basename, dirname } from "node:path";
18
18
  import { runToolCall, } from "@earendil-works/pi-agent-core";
19
- import { contentText, getCurrentSystemMessage, getSystemMessageText, retryDelayMs } from "@earendil-works/pi-ai";
19
+ import { contentText, getCurrentSystemMessage, retryDelayMs } from "@earendil-works/pi-ai";
20
20
  import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, isRecoverableLength, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@earendil-works/pi-ai/compat";
21
21
  import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
22
22
  import { stripFrontmatter } from "../utils/frontmatter.js";
@@ -27,18 +27,20 @@ import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth
27
27
  import { executeBashWithOperations } from "./bash-executor.js";
28
28
  import { generateBugReportSummary } from "./bug-report.js";
29
29
  import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateProjectedContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
30
+ import { captureContextSnapshot } from "./context-snapshot.js";
30
31
  import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "./defaults.js";
31
32
  import { exportSessionToHtml } from "./export-html/index.js";
32
33
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
33
34
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
34
35
  import { emitSessionShutdownEvent } from "./extensions/runner.js";
36
+ import { createToolNameMatcher, isMcpToolName } from "./mcp-servers.js";
35
37
  import { convertToLlm } from "./messages.js";
36
38
  import { ModelRegistry } from "./model-registry.js";
37
39
  import { NestedToolCallRunner } from "./nested-tool-calls.js";
38
40
  import { expandPromptTemplate } from "./prompt-templates.js";
39
41
  import { exportSessionToJsonl } from "./session-export.js";
40
42
  import { getLatestCompactionEntry, SessionManager, } from "./session-manager.js";
41
- import { DEFAULT_TOOL_NAMES } from "./settings-manager.js";
43
+ import { applyToolModifiers, DEFAULT_TOOL_NAMES, } from "./settings-manager.js";
42
44
  import { BUILTIN_PATH_PREFIX, createSyntheticSourceInfo, isSyntheticPath } from "./source-info.js";
43
45
  import { buildSystemPrompt, buildSystemPromptSections, diffSystemPromptSections, normalizeBuildSystemPromptOptions, } from "./system-prompt.js";
44
46
  import { TaskSession } from "./tasks/session.js";
@@ -121,6 +123,11 @@ export class AgentSession {
121
123
  * `setActiveToolsByName()` deactivates a tool or the next agent run starts.
122
124
  */
123
125
  this._pendingToolNames = new Set();
126
+ /**
127
+ * Whether the allowlist filters MCP tools: it is empty (`--no-tools`) or names an MCP tool
128
+ * (`mcp__*`). Otherwise it keeps MCP tools registered for codemode and tool_search.
129
+ */
130
+ this._allowlistFiltersMcp = false;
124
131
  this._extensionMode = "print";
125
132
  // Tool registry for extension getTools/setTools
126
133
  this._toolRegistry = new Map();
@@ -261,8 +268,13 @@ export class AgentSession {
261
268
  this._extensionRunnerRef = config.extensionRunnerRef;
262
269
  this._initialActiveToolNames = config.initialActiveToolNames;
263
270
  this._usesDefaultTools = config.usesDefaultTools ?? false;
264
- this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
265
- this._excludedToolNames = config.excludedToolNames ? new Set(config.excludedToolNames) : undefined;
271
+ this._defaultToolModifiers = config.defaultToolModifiers ?? [];
272
+ if (config.allowedToolNames) {
273
+ this._allowedTools = createToolNameMatcher(config.allowedToolNames);
274
+ this._allowlistFiltersMcp =
275
+ config.allowedToolNames.length === 0 || config.allowedToolNames.some((entry) => entry.startsWith("mcp__"));
276
+ }
277
+ this._excludedTools = config.excludedToolNames ? createToolNameMatcher(config.excludedToolNames) : undefined;
266
278
  this._baseToolsOverride = config.baseToolsOverride;
267
279
  this._sessionStartEvent = config.sessionStartEvent ?? { type: "session_start", reason: "startup" };
268
280
  // Always subscribe to agent events for internal handling
@@ -287,6 +299,10 @@ export class AgentSession {
287
299
  get quarantinedTaskSettlements() {
288
300
  return this._tasksHost.quarantinedSettlements;
289
301
  }
302
+ /** Running tasks that navigating to `targetId` would cancel, so a host can confirm first. */
303
+ tasksStoppedByTreeNavigation(targetId) {
304
+ return this._tasksHost.stoppedByTreeNavigation(targetId);
305
+ }
290
306
  /** Pause delivery across asynchronous lifecycle/preflight gaps. Nestable. */
291
307
  pauseTaskNotifications() {
292
308
  return this._tasksHost.delivery.pause();
@@ -312,48 +328,8 @@ export class AgentSession {
312
328
  return this._modelRuntime;
313
329
  }
314
330
  /** Capture stable state before any asynchronous context preparation. Never includes a partial stream. */
315
- async getContextSnapshot() {
316
- const model = this.model;
317
- if (!model)
318
- throw new Error("No model selected");
319
- const requestOptions = {
320
- sessionId: this.agent.sessionId ?? this.sessionManager.getSessionId(),
321
- transport: this.agent.transport,
322
- thinkingBudgets: structuredClone(this.agent.thinkingBudgets),
323
- maxRetryDelayMs: this.agent.maxRetryDelayMs,
324
- onPayload: this.agent.onPayload,
325
- onResponse: this.agent.onResponse,
326
- };
327
- const snapshot = {
328
- capturedAt: Date.now(),
329
- sessionId: this.sessionManager.getSessionId(),
330
- leafId: this.sessionManager.getLeafId(),
331
- model: structuredClone(model),
332
- thinkingLevel: this.thinkingLevel,
333
- tools: this.agent.state.tools.map(({ name, description, parameters, constrainedSampling }) => ({
334
- name,
335
- description,
336
- parameters: structuredClone(parameters),
337
- ...(constrainedSampling === undefined ? {} : { constrainedSampling: structuredClone(constrainedSampling) }),
338
- })),
339
- streamOptions: this._contextSource?.resolveStreamOptions(model, requestOptions) ?? requestOptions,
340
- };
341
- const currentSystemPrompt = this.systemPrompt;
342
- // The canonical projection is what the next request converts; the inspection cache may lag it.
343
- const messages = structuredClone(this.sessionManager.buildSessionProjection().messages);
344
- const convert = this.agent.convertToLlm;
345
- const transform = this.agent.transformContext;
346
- const prepared = this._contextSource
347
- ? await this._contextSource.prepareMessages(messages)
348
- : await convert(transform ? await transform(messages) : messages);
349
- // The prepared transcript declares the prompt the provider received, including a forced
350
- // prompt projected for the last request; before the first request there is none yet.
351
- const declared = getCurrentSystemMessage(prepared);
352
- return {
353
- ...snapshot,
354
- systemPrompt: declared ? getSystemMessageText(declared) : currentSystemPrompt,
355
- messages: structuredClone(prepared),
356
- };
331
+ getContextSnapshot() {
332
+ return captureContextSnapshot(this, this._contextSource);
357
333
  }
358
334
  async _getRequiredRequestAuth(model, signal) {
359
335
  let result;
@@ -831,8 +807,9 @@ export class AgentSession {
831
807
  this._isAgentRunActive = false;
832
808
  this._isEmittingAgentSettled = true;
833
809
  try {
834
- await this._extensionRunner.emit({ type: "agent_settled" });
835
- this._emit({ type: "agent_settled" });
810
+ const aborted = this._agentRunAbortRequested;
811
+ await this._extensionRunner.emit({ type: "agent_settled", aborted });
812
+ this._emit({ type: "agent_settled", aborted });
836
813
  }
837
814
  finally {
838
815
  this._isEmittingAgentSettled = false;
@@ -1026,6 +1003,7 @@ export class AgentSession {
1026
1003
  toolName: event.toolName,
1027
1004
  result: event.result,
1028
1005
  isError: event.isError,
1006
+ ...(event.durationMs === undefined ? {} : { durationMs: event.durationMs }),
1029
1007
  };
1030
1008
  await this._extensionRunner.emit(extensionEvent);
1031
1009
  }
@@ -1179,8 +1157,27 @@ export class AgentSession {
1179
1157
  this._pendingToolNames.delete(tool.name);
1180
1158
  this._rebuildSystemPrompt(tools.map((tool) => tool.name));
1181
1159
  }
1160
+ /**
1161
+ * Whether `--tools` and `--exclude-tools` keep the tool registered. MCP tools stay registered
1162
+ * unless the allowlist filters them (see `_allowlistFiltersMcp`).
1163
+ */
1182
1164
  _isAllowedTool(name) {
1183
- return (!this._allowedToolNames || this._allowedToolNames.has(name)) && !this._excludedToolNames?.has(name);
1165
+ if (this._excludedTools?.(name))
1166
+ return false;
1167
+ if (!this._allowedTools || this._allowedTools(name))
1168
+ return true;
1169
+ return !this._allowlistFiltersMcp && isMcpToolName(name);
1170
+ }
1171
+ /**
1172
+ * Whether the tool may be active, which declares it to the model. MCP tools the allowlist keeps
1173
+ * without matching them are only for codemode and tool_search: they may be declared only when
1174
+ * tool_search can load them (non-`direct` exposure and tool_search registered). This also applies
1175
+ * to tools restored from the transcript or set by extensions.
1176
+ */
1177
+ _isActivatable(name) {
1178
+ if (!this._allowedTools || this._allowedTools(name) || !isMcpToolName(name))
1179
+ return true;
1180
+ return this._getToolExposure(name) !== "direct" && this._toolRegistry.has("tool_search");
1184
1181
  }
1185
1182
  _getToolExposure(name) {
1186
1183
  return this._toolDefinitions.get(name)?.definition.exposure ?? "direct";
@@ -1204,7 +1201,7 @@ export class AgentSession {
1204
1201
  _applyToolLoadout(toolNames) {
1205
1202
  const tools = [...new Set(toolNames)].flatMap((name) => {
1206
1203
  const tool = this._toolRegistry.get(name);
1207
- return tool && this._getToolExposure(name) !== "hidden" ? [tool] : [];
1204
+ return tool && this._getToolExposure(name) !== "hidden" && this._isActivatable(name) ? [tool] : [];
1208
1205
  });
1209
1206
  const hooks = tools.flatMap((tool) => {
1210
1207
  const entry = this._toolDefinitions.get(tool.name);
@@ -1219,6 +1216,7 @@ export class AgentSession {
1219
1216
  registered: [...this._toolRegistry.values()],
1220
1217
  getExposure: (name) => this._getToolExposure(name),
1221
1218
  getNamespace: (name) => this._toolDefinitions.get(name)?.definition.namespace,
1219
+ getPromptGuidelines: (name) => this._toolPromptGuidelines.get(name) ?? [],
1222
1220
  };
1223
1221
  const descriptions = new Map();
1224
1222
  for (const { definition, sourceInfo } of hooks) {
@@ -1317,8 +1315,8 @@ export class AgentSession {
1317
1315
  const toolSnippets = {};
1318
1316
  for (const name of this._toolRegistry.keys()) {
1319
1317
  const snippet = this._toolPromptSnippets.get(name);
1320
- // Tools without a snippet are not listed. Hidden tools are only callable through another tool.
1321
- if (snippet && !this._hiddenDeclarations.has(name))
1318
+ // Tools without a snippet are not listed.
1319
+ if (snippet)
1322
1320
  toolSnippets[name] = snippet;
1323
1321
  }
1324
1322
  const loaderSystemPrompt = this._resourceLoader.getSystemPrompt();
@@ -1333,6 +1331,7 @@ export class AgentSession {
1333
1331
  customPrompt: loaderSystemPrompt,
1334
1332
  appendSystemPrompt,
1335
1333
  selectedTools: validToolNames,
1334
+ hiddenTools: [...this._hiddenDeclarations],
1336
1335
  toolSnippets,
1337
1336
  toolGuidelines: Object.fromEntries(this._toolPromptGuidelines),
1338
1337
  });
@@ -1349,8 +1348,8 @@ export class AgentSession {
1349
1348
  */
1350
1349
  _preparePromptAndToolLoadout(options, messages = this.agent.state.messages) {
1351
1350
  options.selectedTools = this._applyToolLoadout(options.selectedTools).map((tool) => tool.name);
1352
- // The tool list must match the declarations the request carries, so hidden tools are not listed.
1353
- options.toolSnippets = Object.fromEntries(Object.entries(options.toolSnippets).filter(([name]) => !this._hiddenDeclarations.has(name)));
1351
+ // The tool list and rules must match the declarations the request carries.
1352
+ options.hiddenTools = [...this._hiddenDeclarations];
1354
1353
  const sections = diffSystemPromptSections(getCurrentSystemMessage(messages)?.sections ?? {}, buildSystemPromptSections(options));
1355
1354
  return sections ? { role: "system", content: "", sections, timestamp: Date.now() } : undefined;
1356
1355
  }
@@ -1562,131 +1561,147 @@ export class AgentSession {
1562
1561
  * @throws Error if no model selected or no API key available (when not streaming)
1563
1562
  */
1564
1563
  async prompt(text, options) {
1564
+ // A deferred prompt re-enters here after the settled handlers finish.
1565
+ if (this._isEmittingAgentSettled)
1566
+ return this._promptBody(text, options);
1567
+ // A user-initiated prompt is the recovery point for failed completion deliveries.
1568
+ this.retryTaskNotifications();
1569
+ // Extension commands may stay open indefinitely; only model input holds the preflight pause,
1570
+ // released once the prompt is handled, queued, or started.
1571
+ if (this._isExtensionCommandPrompt(text, options))
1572
+ return this._promptBody(text, options);
1573
+ const resumeBackground = this.pauseTaskNotifications();
1574
+ try {
1575
+ await this._promptBody(text, {
1576
+ ...options,
1577
+ preflightResult: (result) => {
1578
+ resumeBackground();
1579
+ options?.preflightResult?.(result);
1580
+ },
1581
+ });
1582
+ }
1583
+ finally {
1584
+ resumeBackground();
1585
+ }
1586
+ }
1587
+ _isExtensionCommandPrompt(text, options) {
1588
+ if (!(options?.expandPromptTemplates ?? true) || !text.startsWith("/"))
1589
+ return false;
1590
+ const spaceIndex = text.indexOf(" ");
1591
+ return (this._extensionRunner.getCommand(spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex)) !== undefined);
1592
+ }
1593
+ async _promptBody(text, options) {
1565
1594
  if (this._isEmittingAgentSettled) {
1566
1595
  this._deferredSettledActions.push(async () => await this.prompt(text, options));
1567
1596
  return;
1568
1597
  }
1569
- // A user-initiated prompt is the recovery point for failed completion deliveries.
1570
- this.retryTaskNotifications();
1571
1598
  const expandPromptTemplates = options?.expandPromptTemplates ?? true;
1572
1599
  const preflightResult = options?.preflightResult;
1573
- let messages;
1574
- let resumeBackground;
1575
- try {
1576
- // Handle extension commands first (execute immediately, even during streaming)
1577
- // Extension commands manage their own LLM interaction via pi.sendMessage()
1578
- if (expandPromptTemplates && text.startsWith("/")) {
1579
- const handled = await this._tryExecuteExtensionCommand(text);
1580
- if (handled) {
1581
- // Extension command executed, no prompt to send
1582
- preflightResult?.("handled");
1583
- return;
1584
- }
1585
- }
1586
- // Observer commands above may stay open indefinitely; only real model input owns
1587
- // the preflight pause, released once the user message is established.
1588
- resumeBackground = this.pauseTaskNotifications();
1589
- if (this._compactionAbortController !== undefined) {
1590
- throw new Error("Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.");
1591
- }
1592
- // Emit input event for extension interception (before skill/template expansion)
1593
- const processedInput = await this._runInputHandlers(text, options?.images, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
1594
- if (!processedInput) {
1600
+ // Handle extension commands first (execute immediately, even during streaming)
1601
+ // Extension commands manage their own LLM interaction via pi.sendMessage()
1602
+ if (expandPromptTemplates && text.startsWith("/")) {
1603
+ const handled = await this._tryExecuteExtensionCommand(text);
1604
+ if (handled) {
1605
+ // Extension command executed, no prompt to send
1595
1606
  preflightResult?.("handled");
1596
1607
  return;
1597
1608
  }
1598
- const { text: currentText, images: currentImages } = processedInput;
1599
- // Expand skill commands (/skill:name args) and prompt templates (/template args)
1600
- let expandedText = currentText;
1601
- if (expandPromptTemplates) {
1602
- expandedText = this._expandSkillCommand(expandedText);
1603
- expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1604
- }
1605
- // If streaming, queue via steer() or followUp() based on option
1606
- if (this.isStreaming) {
1607
- if (!options?.streamingBehavior) {
1608
- throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
1609
- }
1610
- if (options.streamingBehavior === "followUp") {
1611
- await this._queueFollowUp(expandedText, currentImages);
1612
- }
1613
- else {
1614
- await this._queueSteer(expandedText, currentImages);
1615
- }
1616
- preflightResult?.("queued");
1617
- return;
1609
+ }
1610
+ if (this._compactionAbortController !== undefined) {
1611
+ throw new Error("Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.");
1612
+ }
1613
+ // Emit input event for extension interception (before skill/template expansion)
1614
+ const processedInput = await this._runInputHandlers(text, options?.images, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
1615
+ if (!processedInput) {
1616
+ preflightResult?.("handled");
1617
+ return;
1618
+ }
1619
+ const { text: currentText, images: currentImages } = processedInput;
1620
+ // Expand skill commands (/skill:name args) and prompt templates (/template args)
1621
+ let expandedText = currentText;
1622
+ if (expandPromptTemplates) {
1623
+ expandedText = this._expandSkillCommand(expandedText);
1624
+ expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1625
+ }
1626
+ // If streaming, queue via steer() or followUp() based on option
1627
+ if (this.isStreaming) {
1628
+ if (!options?.streamingBehavior) {
1629
+ throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
1618
1630
  }
1619
- // Flush any pending bash and custom messages before the new prompt
1620
- this._flushPendingBashMessages();
1621
- this._flushPendingCustomMessages();
1622
- // Validate model
1623
- if (!this.model) {
1624
- throw new Error(formatNoModelSelectedMessage());
1631
+ if (options.streamingBehavior === "followUp") {
1632
+ await this._queueFollowUp(expandedText, currentImages);
1625
1633
  }
1626
- const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) ||
1627
- (await this._modelRuntime.checkAuth(this.model.provider)) !== undefined;
1628
- if (!hasConfiguredAuth) {
1629
- const isOAuth = this._modelRuntime.isUsingOAuth(this.model.provider);
1630
- if (isOAuth) {
1631
- throw new Error(`Authentication failed for "${this.model.provider}". ` +
1632
- `Credentials may have expired or network is unavailable. ` +
1633
- `Run '/login ${this.model.provider}' to re-authenticate.`);
1634
- }
1635
- throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
1636
- }
1637
- // Check if we need to compact before sending (catches aborted responses).
1638
- // The user's new prompt is sent below, so do not call agent.continue() here.
1639
- const lastAssistant = this._findLastAssistantMessage();
1640
- if (lastAssistant) {
1641
- await this._checkCompaction(lastAssistant, false);
1642
- }
1643
- // Emit before_agent_start before normalizing images so extension-driven model
1644
- // selection determines the resize profile used for the request and history.
1645
- const selectedToolsBefore = this._baseSystemPromptOptions.selectedTools;
1646
- const result = await this._extensionRunner.emitBeforeAgentStart(expandedText, currentImages, this._baseSystemPromptOptions);
1647
- // Handlers may edit event.systemPromptOptions.selectedTools or call setActiveTools(),
1648
- // which updates the live loadout instead. An explicit edit wins; otherwise the live
1649
- // loadout is authoritative, so a setActiveTools() call is not undone here.
1650
- const handlerEditedTools = result.systemPromptOptions.selectedTools.length !== selectedToolsBefore.length ||
1651
- result.systemPromptOptions.selectedTools.some((name, index) => name !== selectedToolsBefore[index]);
1652
- if (!handlerEditedTools)
1653
- result.systemPromptOptions.selectedTools = this.getActiveToolNames();
1654
- const normalized = await this._normalizePromptImages(currentImages);
1655
- const userText = normalized.hints.length > 0 ? `${expandedText}\n\n${normalized.hints.join("\n")}` : expandedText;
1656
- // Build messages only after hooks and image normalization have completed.
1657
- messages = [];
1658
- const userContent = [{ type: "text", text: userText }];
1659
- userContent.push(...normalized.images);
1634
+ else {
1635
+ await this._queueSteer(expandedText, currentImages);
1636
+ }
1637
+ preflightResult?.("queued");
1638
+ return;
1639
+ }
1640
+ // Flush any pending bash and custom messages before the new prompt
1641
+ this._flushPendingBashMessages();
1642
+ this._flushPendingCustomMessages();
1643
+ // Validate model
1644
+ if (!this.model) {
1645
+ throw new Error(formatNoModelSelectedMessage());
1646
+ }
1647
+ const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) ||
1648
+ (await this._modelRuntime.checkAuth(this.model.provider)) !== undefined;
1649
+ if (!hasConfiguredAuth) {
1650
+ const isOAuth = this._modelRuntime.isUsingOAuth(this.model.provider);
1651
+ if (isOAuth) {
1652
+ throw new Error(`Authentication failed for "${this.model.provider}". ` +
1653
+ `Credentials may have expired or network is unavailable. ` +
1654
+ `Run '/login ${this.model.provider}' to re-authenticate.`);
1655
+ }
1656
+ throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
1657
+ }
1658
+ // Check if we need to compact before sending (catches aborted responses).
1659
+ // The user's new prompt is sent below, so do not call agent.continue() here.
1660
+ const lastAssistant = this._findLastAssistantMessage();
1661
+ if (lastAssistant) {
1662
+ await this._checkCompaction(lastAssistant, false);
1663
+ }
1664
+ // Emit before_agent_start before normalizing images so extension-driven model
1665
+ // selection determines the resize profile used for the request and history.
1666
+ const selectedToolsBefore = this._baseSystemPromptOptions.selectedTools;
1667
+ const result = await this._extensionRunner.emitBeforeAgentStart(expandedText, currentImages, this._baseSystemPromptOptions);
1668
+ // Handlers may edit event.systemPromptOptions.selectedTools or call setActiveTools(),
1669
+ // which updates the live loadout instead. An explicit edit wins; otherwise the live
1670
+ // loadout is authoritative, so a setActiveTools() call is not undone here.
1671
+ const handlerEditedTools = result.systemPromptOptions.selectedTools.length !== selectedToolsBefore.length ||
1672
+ result.systemPromptOptions.selectedTools.some((name, index) => name !== selectedToolsBefore[index]);
1673
+ if (!handlerEditedTools)
1674
+ result.systemPromptOptions.selectedTools = this.getActiveToolNames();
1675
+ const normalized = await this._normalizePromptImages(currentImages);
1676
+ const userText = normalized.hints.length > 0 ? `${expandedText}\n\n${normalized.hints.join("\n")}` : expandedText;
1677
+ // Build messages only after hooks and image normalization have completed.
1678
+ const messages = [];
1679
+ const userContent = [{ type: "text", text: userText }];
1680
+ userContent.push(...normalized.images);
1681
+ messages.push({
1682
+ role: "user",
1683
+ content: userContent,
1684
+ timestamp: Date.now(),
1685
+ });
1686
+ // Inject any pending "nextTurn" messages as context alongside the user message
1687
+ for (const msg of this._pendingNextTurnMessages) {
1688
+ messages.push(msg);
1689
+ }
1690
+ for (const msg of result.messages) {
1660
1691
  messages.push({
1661
- role: "user",
1662
- content: userContent,
1692
+ role: "custom",
1693
+ customType: msg.customType,
1694
+ // Untyped extensions can pass null/missing content; normalize at ingestion.
1695
+ content: msg.content ?? [],
1696
+ display: msg.display,
1697
+ details: msg.details,
1663
1698
  timestamp: Date.now(),
1664
1699
  });
1665
- // Inject any pending "nextTurn" messages as context alongside the user message
1666
- for (const msg of this._pendingNextTurnMessages) {
1667
- messages.push(msg);
1668
- }
1669
- for (const msg of result.messages) {
1670
- messages.push({
1671
- role: "custom",
1672
- customType: msg.customType,
1673
- // Untyped extensions can pass null/missing content; normalize at ingestion.
1674
- content: msg.content ?? [],
1675
- display: msg.display,
1676
- details: msg.details,
1677
- timestamp: Date.now(),
1678
- });
1679
- }
1680
- const updateMessage = this._preparePromptAndToolLoadout(result.systemPromptOptions);
1681
- this._runSystemPromptOptions = result.systemPromptOptions;
1682
- if (updateMessage)
1683
- messages.unshift(updateMessage);
1684
1700
  }
1685
- finally {
1686
- resumeBackground?.();
1687
- }
1688
- if (!messages)
1689
- return;
1701
+ const updateMessage = this._preparePromptAndToolLoadout(result.systemPromptOptions);
1702
+ this._runSystemPromptOptions = result.systemPromptOptions;
1703
+ if (updateMessage)
1704
+ messages.unshift(updateMessage);
1690
1705
  preflightResult?.("started");
1691
1706
  await this._runAgentPrompt(messages);
1692
1707
  }
@@ -2889,7 +2904,7 @@ export class AgentSession {
2889
2904
  // `direct` or `model-only` (for example from `hidden`) is activated like a new tool.
2890
2905
  const previousActivatedOnRegistration = new Set([...this._toolRegistry.keys()].filter((name) => this._isActivatedOnRegistration(name)));
2891
2906
  const previousActiveToolNames = this.getActiveToolNames();
2892
- const allowedToolNames = this._allowedToolNames;
2907
+ const allowedTools = this._allowedTools;
2893
2908
  const registeredTools = this._extensionRunner.getAllRegisteredTools();
2894
2909
  const allCustomTools = [
2895
2910
  ...registeredTools,
@@ -2942,10 +2957,11 @@ export class AgentSession {
2942
2957
  }
2943
2958
  this._toolRegistry = toolRegistry;
2944
2959
  const nextActiveToolNames = (options?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]).filter((name) => this._isAllowedTool(name));
2945
- if (allowedToolNames) {
2960
+ if (allowedTools) {
2946
2961
  for (const toolName of this._toolRegistry.keys()) {
2947
- // Naming a tool activates it even when it is not active by default.
2948
- if (allowedToolNames.has(toolName) && this._isDeclarable(toolName)) {
2962
+ // Naming or matching a tool activates it even when it is not active by default. MCP tools
2963
+ // kept registered without being named stay inactive.
2964
+ if (allowedTools(toolName) && this._isDeclarable(toolName)) {
2949
2965
  nextActiveToolNames.push(toolName);
2950
2966
  }
2951
2967
  }
@@ -3027,7 +3043,10 @@ export class AgentSession {
3027
3043
  await Promise.all([this.tasks.shutdown(), this.abort()]);
3028
3044
  await emitSessionShutdownEvent(oldRunner, { type: "session_shutdown", reason: "reload" });
3029
3045
  oldRunner.invalidate();
3030
- const previousDefaultTools = new Set(this._usesDefaultTools ? (this.settingsManager.getDefaultTools() ?? DEFAULT_TOOL_NAMES) : []);
3046
+ const getDefaultTools = () => this._usesDefaultTools
3047
+ ? applyToolModifiers(this.settingsManager.getDefaultTools() ?? DEFAULT_TOOL_NAMES, this._defaultToolModifiers)
3048
+ : [];
3049
+ const previousDefaultTools = new Set(getDefaultTools());
3031
3050
  await this.settingsManager.reload();
3032
3051
  this.syncQueueModesFromSettings();
3033
3052
  resetApiProviders();
@@ -3035,9 +3054,7 @@ export class AgentSession {
3035
3054
  this._tasksHost.replaceService();
3036
3055
  // Activate tools newly added to defaultTools. Removed ones stay active, and tools disabled
3037
3056
  // during the session stay disabled unless the setting newly adds them.
3038
- const addedDefaultTools = this._usesDefaultTools
3039
- ? (this.settingsManager.getDefaultTools() ?? DEFAULT_TOOL_NAMES).filter((name) => !previousDefaultTools.has(name))
3040
- : [];
3057
+ const addedDefaultTools = getDefaultTools().filter((name) => !previousDefaultTools.has(name));
3041
3058
  // Tools the new extensions register later, such as MCP tools, are pending until then.
3042
3059
  for (const name of this.getActiveToolNames())
3043
3060
  this._pendingToolNames.add(name);
@@ -3286,19 +3303,6 @@ export class AgentSession {
3286
3303
  * @param options.label Label to attach to the branch summary entry
3287
3304
  * @returns Result with editorText (if user message) and cancelled status
3288
3305
  */
3289
- /**
3290
- * Running tasks that navigating to `targetId` would cancel, so a host can confirm first.
3291
- * Mirrors navigateTree's destination: selecting a user or custom message moves the leaf to its parent.
3292
- */
3293
- tasksStoppedByTreeNavigation(targetId) {
3294
- const target = this.sessionManager.getEntry(targetId);
3295
- if (!target)
3296
- return [];
3297
- const leafId = (target.type === "message" && target.message.role === "user") || target.type === "custom_message"
3298
- ? target.parentId
3299
- : targetId;
3300
- return this.tasks.activeOutsideBranch(new Set(leafId === null ? [] : this.sessionManager.getBranch(leafId).map((entry) => entry.id)));
3301
- }
3302
3306
  async navigateTree(targetId, options = {}) {
3303
3307
  if (this.isStreaming) {
3304
3308
  throw new Error("Wait for the current response to finish before navigating the session tree.");
@@ -3418,7 +3422,7 @@ export class AgentSession {
3418
3422
  // Non-user message: leaf = selected node
3419
3423
  newLeafId = targetId;
3420
3424
  }
3421
- await this.tasks.cancelOutsideBranch(new Set(newLeafId === null ? [] : this.sessionManager.getBranch(newLeafId).map((entry) => entry.id)));
3425
+ await this._tasksHost.cancelOutsideBranch(newLeafId);
3422
3426
  // Switch leaf (with or without summary)
3423
3427
  // Summary is attached at the navigation target position (newLeafId), not the old branch
3424
3428
  let summaryEntry;