@astralyn/pi 0.87.5 → 0.99.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 (786) hide show
  1. package/CHANGELOG.md +51 -6
  2. package/README.md +3 -3
  3. package/dist/bun/runtime-setup.js +4 -1
  4. package/dist/bun/runtime-setup.js.map +1 -1
  5. package/dist/bundle/chunks/anthropic-messages-KIXY7EDT.js +6 -0
  6. package/dist/bundle/chunks/anthropic.js +2 -2
  7. package/dist/bundle/chunks/azure-openai-responses-RPBERDXD.js +2 -0
  8. package/dist/bundle/chunks/bedrock-converse-stream.js +8 -8
  9. package/dist/bundle/chunks/{chunk-LPQCB2VJ.js → chunk-A576H74Y.js} +2 -2
  10. package/dist/bundle/chunks/{chunk-NW5FIDD7.js → chunk-ABVRAYXT.js} +3 -3
  11. package/dist/bundle/chunks/{chunk-I5IVW2WS.js → chunk-CLLDCO64.js} +1 -1
  12. package/dist/bundle/chunks/chunk-DEWXBB6W.js +2 -0
  13. package/dist/bundle/chunks/chunk-G4RY3GN7.js +11 -0
  14. package/dist/bundle/chunks/chunk-GCKVOFWP.js +2 -0
  15. package/dist/bundle/chunks/chunk-MPDALHNJ.js +2 -0
  16. package/dist/bundle/chunks/chunk-OO6DJ3CL.js +31 -0
  17. package/dist/bundle/chunks/{chunk-EWLAVDVN.js → chunk-VW2P3X6P.js} +921 -293
  18. package/dist/bundle/chunks/chunk-VWCWZD6E.js +2 -0
  19. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-ZYSAFXXL.js +2 -0
  20. package/dist/bundle/chunks/codemode-worker.js +295 -0
  21. package/dist/bundle/chunks/github-copilot.js +1 -1
  22. package/dist/bundle/chunks/google-generative-ai-SDNQVVXA.js +2 -0
  23. package/dist/bundle/chunks/google-vertex-LZXOLBIO.js +2 -0
  24. package/dist/bundle/chunks/llama-cpp-classify-7IYGGPND.js +22 -0
  25. package/dist/bundle/chunks/meta.js +2 -0
  26. package/dist/bundle/chunks/mistral-conversations-VYKPSSAM.js +5 -0
  27. package/dist/bundle/chunks/openai-chatgpt.js +75 -0
  28. package/dist/bundle/chunks/openai-codex-responses-HZ4VUDXD.js +10 -0
  29. package/dist/bundle/chunks/openai-codex.js +2 -2
  30. package/dist/bundle/chunks/openai-completions-SKDGF6OE.js +7 -0
  31. package/dist/bundle/chunks/openai-responses-FPML4SSG.js +3 -0
  32. package/dist/bundle/chunks/{openrouter-images-6XDE2CEW.js → openrouter-images-5524IQHX.js} +1 -1
  33. package/dist/bundle/chunks/openrouter.js +2 -2
  34. package/dist/bundle/chunks/{pi-messages-MQMPIPNC.js → pi-messages-HZZ7GEEW.js} +2 -2
  35. package/dist/bundle/chunks/radius.js +2 -2
  36. package/dist/bundle/chunks/typesafe-system-one-Z2CDLKEY.js +2 -0
  37. package/dist/bundle/chunks/virtual-modules-TQRORWJQ.js +2 -0
  38. package/dist/bundle/cli.js +1 -1
  39. package/dist/bundle/index.js +1 -1
  40. package/dist/bundle/rpc-entry.js +1 -1
  41. package/dist/cli/args.d.ts.map +1 -1
  42. package/dist/cli/args.js +4 -3
  43. package/dist/cli/args.js.map +1 -1
  44. package/dist/cli/startup-ui.d.ts.map +1 -1
  45. package/dist/cli/startup-ui.js +38 -30
  46. package/dist/cli/startup-ui.js.map +1 -1
  47. package/dist/config.d.ts +18 -4
  48. package/dist/config.d.ts.map +1 -1
  49. package/dist/config.js +30 -4
  50. package/dist/config.js.map +1 -1
  51. package/dist/core/agent-session-runtime.d.ts +1 -1
  52. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  53. package/dist/core/agent-session-runtime.js +13 -13
  54. package/dist/core/agent-session-runtime.js.map +1 -1
  55. package/dist/core/agent-session-services.d.ts +2 -2
  56. package/dist/core/agent-session-services.d.ts.map +1 -1
  57. package/dist/core/agent-session-services.js +14 -1
  58. package/dist/core/agent-session-services.js.map +1 -1
  59. package/dist/core/agent-session.d.ts +107 -58
  60. package/dist/core/agent-session.d.ts.map +1 -1
  61. package/dist/core/agent-session.js +505 -298
  62. package/dist/core/agent-session.js.map +1 -1
  63. package/dist/core/bug-report.js +1 -1
  64. package/dist/core/bug-report.js.map +1 -1
  65. package/dist/core/compaction/compaction.d.ts.map +1 -1
  66. package/dist/core/compaction/compaction.js +1 -22
  67. package/dist/core/compaction/compaction.js.map +1 -1
  68. package/dist/core/compaction/utils.d.ts +2 -1
  69. package/dist/core/compaction/utils.d.ts.map +1 -1
  70. package/dist/core/compaction/utils.js +25 -18
  71. package/dist/core/compaction/utils.js.map +1 -1
  72. package/dist/core/context-snapshot.d.ts +17 -4
  73. package/dist/core/context-snapshot.d.ts.map +1 -1
  74. package/dist/core/context-snapshot.js +48 -50
  75. package/dist/core/context-snapshot.js.map +1 -1
  76. package/dist/core/crash-log.d.ts.map +1 -1
  77. package/dist/core/crash-log.js +2 -1
  78. package/dist/core/crash-log.js.map +1 -1
  79. package/dist/core/export-html/template.css +10 -0
  80. package/dist/core/export-html/template.js +66 -17
  81. package/dist/core/extensions/distribution-api.d.ts +1 -8
  82. package/dist/core/extensions/distribution-api.d.ts.map +1 -1
  83. package/dist/core/extensions/distribution-api.js +6 -6
  84. package/dist/core/extensions/distribution-api.js.map +1 -1
  85. package/dist/core/extensions/index.d.ts +3 -3
  86. package/dist/core/extensions/index.d.ts.map +1 -1
  87. package/dist/core/extensions/index.js +1 -1
  88. package/dist/core/extensions/index.js.map +1 -1
  89. package/dist/core/extensions/loader.d.ts +1 -1
  90. package/dist/core/extensions/loader.d.ts.map +1 -1
  91. package/dist/core/extensions/loader.js +58 -7
  92. package/dist/core/extensions/loader.js.map +1 -1
  93. package/dist/core/extensions/runner.d.ts +22 -3
  94. package/dist/core/extensions/runner.d.ts.map +1 -1
  95. package/dist/core/extensions/runner.js +124 -8
  96. package/dist/core/extensions/runner.js.map +1 -1
  97. package/dist/core/extensions/types.d.ts +306 -30
  98. package/dist/core/extensions/types.d.ts.map +1 -1
  99. package/dist/core/extensions/types.js +1 -1
  100. package/dist/core/extensions/types.js.map +1 -1
  101. package/dist/core/extensions/wrapper.d.ts +2 -2
  102. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  103. package/dist/core/extensions/wrapper.js +3 -3
  104. package/dist/core/extensions/wrapper.js.map +1 -1
  105. package/dist/core/keybindings.d.ts +40 -5
  106. package/dist/core/keybindings.d.ts.map +1 -1
  107. package/dist/core/keybindings.js +10 -1
  108. package/dist/core/keybindings.js.map +1 -1
  109. package/dist/core/mcp-servers.d.ts +98 -0
  110. package/dist/core/mcp-servers.d.ts.map +1 -0
  111. package/dist/core/mcp-servers.js +158 -0
  112. package/dist/core/mcp-servers.js.map +1 -0
  113. package/dist/core/model-registry.d.ts +13 -1
  114. package/dist/core/model-registry.d.ts.map +1 -1
  115. package/dist/core/model-registry.js +25 -0
  116. package/dist/core/model-registry.js.map +1 -1
  117. package/dist/core/model-resolver.d.ts +2 -2
  118. package/dist/core/model-resolver.d.ts.map +1 -1
  119. package/dist/core/model-resolver.js +5 -5
  120. package/dist/core/model-resolver.js.map +1 -1
  121. package/dist/core/model-runtime.d.ts +41 -3
  122. package/dist/core/model-runtime.d.ts.map +1 -1
  123. package/dist/core/model-runtime.js +167 -17
  124. package/dist/core/model-runtime.js.map +1 -1
  125. package/dist/core/nested-tool-calls.d.ts +102 -0
  126. package/dist/core/nested-tool-calls.d.ts.map +1 -0
  127. package/dist/core/nested-tool-calls.js +177 -0
  128. package/dist/core/nested-tool-calls.js.map +1 -0
  129. package/dist/core/package-manager.d.ts +4 -0
  130. package/dist/core/package-manager.d.ts.map +1 -1
  131. package/dist/core/package-manager.js +58 -12
  132. package/dist/core/package-manager.js.map +1 -1
  133. package/dist/core/provider-composer.d.ts +40 -21
  134. package/dist/core/provider-composer.d.ts.map +1 -1
  135. package/dist/core/provider-composer.js +92 -40
  136. package/dist/core/provider-composer.js.map +1 -1
  137. package/dist/core/remote-catalog-provider.d.ts +8 -1
  138. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  139. package/dist/core/remote-catalog-provider.js +18 -3
  140. package/dist/core/remote-catalog-provider.js.map +1 -1
  141. package/dist/core/resource-loader.d.ts +7 -1
  142. package/dist/core/resource-loader.d.ts.map +1 -1
  143. package/dist/core/resource-loader.js +160 -35
  144. package/dist/core/resource-loader.js.map +1 -1
  145. package/dist/core/sdk.d.ts +3 -3
  146. package/dist/core/sdk.d.ts.map +1 -1
  147. package/dist/core/sdk.js +84 -14
  148. package/dist/core/sdk.js.map +1 -1
  149. package/dist/core/session-manager.d.ts +9 -0
  150. package/dist/core/session-manager.d.ts.map +1 -1
  151. package/dist/core/session-manager.js +22 -22
  152. package/dist/core/session-manager.js.map +1 -1
  153. package/dist/core/settings-manager.d.ts +36 -1
  154. package/dist/core/settings-manager.d.ts.map +1 -1
  155. package/dist/core/settings-manager.js +108 -2
  156. package/dist/core/settings-manager.js.map +1 -1
  157. package/dist/core/slash-commands.d.ts.map +1 -1
  158. package/dist/core/slash-commands.js +1 -0
  159. package/dist/core/slash-commands.js.map +1 -1
  160. package/dist/core/source-info.d.ts +8 -0
  161. package/dist/core/source-info.d.ts.map +1 -1
  162. package/dist/core/source-info.js +16 -0
  163. package/dist/core/source-info.js.map +1 -1
  164. package/dist/core/system-prompt.js +1 -1
  165. package/dist/core/system-prompt.js.map +1 -1
  166. package/dist/core/tasks/delivery.d.ts +40 -0
  167. package/dist/core/tasks/delivery.d.ts.map +1 -0
  168. package/dist/core/tasks/delivery.js +157 -0
  169. package/dist/core/tasks/delivery.js.map +1 -0
  170. package/dist/core/tasks/history.d.ts +4 -0
  171. package/dist/core/tasks/history.d.ts.map +1 -0
  172. package/dist/core/{background → tasks}/history.js +24 -48
  173. package/dist/core/tasks/history.js.map +1 -0
  174. package/dist/core/{background → tasks}/output.d.ts +4 -4
  175. package/dist/core/tasks/output.d.ts.map +1 -0
  176. package/dist/core/{background → tasks}/output.js +11 -11
  177. package/dist/core/tasks/output.js.map +1 -0
  178. package/dist/core/tasks/presentation.d.ts +9 -0
  179. package/dist/core/tasks/presentation.d.ts.map +1 -0
  180. package/dist/core/{background → tasks}/presentation.js +53 -51
  181. package/dist/core/tasks/presentation.js.map +1 -0
  182. package/dist/core/{background/service.d.ts → tasks/runtime.d.ts} +22 -23
  183. package/dist/core/tasks/runtime.d.ts.map +1 -0
  184. package/dist/core/{background/service.js → tasks/runtime.js} +154 -198
  185. package/dist/core/tasks/runtime.js.map +1 -0
  186. package/dist/core/tasks/session.d.ts +49 -0
  187. package/dist/core/tasks/session.d.ts.map +1 -0
  188. package/dist/core/tasks/session.js +129 -0
  189. package/dist/core/tasks/session.js.map +1 -0
  190. package/dist/core/tasks/store.d.ts +32 -0
  191. package/dist/core/tasks/store.d.ts.map +1 -0
  192. package/dist/core/tasks/store.js +135 -0
  193. package/dist/core/tasks/store.js.map +1 -0
  194. package/dist/core/{background → tasks}/types.d.ts +80 -62
  195. package/dist/core/tasks/types.d.ts.map +1 -0
  196. package/dist/core/{background → tasks}/types.js +9 -9
  197. package/dist/core/tasks/types.js.map +1 -0
  198. package/dist/core/tasks/view-data.d.ts +8 -0
  199. package/dist/core/tasks/view-data.d.ts.map +1 -0
  200. package/dist/core/tasks/view-data.js +61 -0
  201. package/dist/core/tasks/view-data.js.map +1 -0
  202. package/dist/core/tasks/view.d.ts +30 -0
  203. package/dist/core/tasks/view.d.ts.map +1 -0
  204. package/dist/core/tasks/view.js +50 -0
  205. package/dist/core/tasks/view.js.map +1 -0
  206. package/dist/core/tools/bash.d.ts +8 -95
  207. package/dist/core/tools/bash.d.ts.map +1 -1
  208. package/dist/core/tools/bash.js +8 -240
  209. package/dist/core/tools/bash.js.map +1 -1
  210. package/dist/core/tools/find.d.ts.map +1 -1
  211. package/dist/core/tools/find.js +0 -1
  212. package/dist/core/tools/find.js.map +1 -1
  213. package/dist/core/tools/grep.d.ts +2 -0
  214. package/dist/core/tools/grep.d.ts.map +1 -1
  215. package/dist/core/tools/grep.js +2 -1
  216. package/dist/core/tools/grep.js.map +1 -1
  217. package/dist/core/tools/index.d.ts +2 -1
  218. package/dist/core/tools/index.d.ts.map +1 -1
  219. package/dist/core/tools/index.js +9 -0
  220. package/dist/core/tools/index.js.map +1 -1
  221. package/dist/core/tools/ls.d.ts.map +1 -1
  222. package/dist/core/tools/ls.js +0 -1
  223. package/dist/core/tools/ls.js.map +1 -1
  224. package/dist/core/tools/output-accumulator.d.ts +11 -0
  225. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  226. package/dist/core/tools/output-accumulator.js +36 -0
  227. package/dist/core/tools/output-accumulator.js.map +1 -1
  228. package/dist/core/tools/powershell.d.ts +6 -2
  229. package/dist/core/tools/powershell.d.ts.map +1 -1
  230. package/dist/core/tools/powershell.js +1 -1
  231. package/dist/core/tools/powershell.js.map +1 -1
  232. package/dist/core/tools/read.d.ts.map +1 -1
  233. package/dist/core/tools/read.js +0 -1
  234. package/dist/core/tools/read.js.map +1 -1
  235. package/dist/core/tools/render-utils.d.ts +6 -7
  236. package/dist/core/tools/render-utils.d.ts.map +1 -1
  237. package/dist/core/tools/render-utils.js +26 -11
  238. package/dist/core/tools/render-utils.js.map +1 -1
  239. package/dist/core/tools/renderers/bash.d.ts +1 -1
  240. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  241. package/dist/core/tools/renderers/bash.js +65 -12
  242. package/dist/core/tools/renderers/bash.js.map +1 -1
  243. package/dist/core/tools/renderers/edit.d.ts.map +1 -1
  244. package/dist/core/tools/renderers/edit.js +4 -22
  245. package/dist/core/tools/renderers/edit.js.map +1 -1
  246. package/dist/core/tools/renderers/find.d.ts.map +1 -1
  247. package/dist/core/tools/renderers/find.js +7 -6
  248. package/dist/core/tools/renderers/find.js.map +1 -1
  249. package/dist/core/tools/renderers/grep.d.ts.map +1 -1
  250. package/dist/core/tools/renderers/grep.js +8 -7
  251. package/dist/core/tools/renderers/grep.js.map +1 -1
  252. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  253. package/dist/core/tools/renderers/index.js +5 -7
  254. package/dist/core/tools/renderers/index.js.map +1 -1
  255. package/dist/core/tools/renderers/ls.d.ts.map +1 -1
  256. package/dist/core/tools/renderers/ls.js +3 -2
  257. package/dist/core/tools/renderers/ls.js.map +1 -1
  258. package/dist/core/tools/renderers/read.d.ts.map +1 -1
  259. package/dist/core/tools/renderers/read.js +10 -14
  260. package/dist/core/tools/renderers/read.js.map +1 -1
  261. package/dist/core/tools/renderers/shell-task.d.ts +4 -0
  262. package/dist/core/tools/renderers/shell-task.d.ts.map +1 -0
  263. package/dist/core/tools/renderers/shell-task.js +35 -0
  264. package/dist/core/tools/renderers/shell-task.js.map +1 -0
  265. package/dist/core/tools/renderers/write.d.ts.map +1 -1
  266. package/dist/core/tools/renderers/write.js +3 -2
  267. package/dist/core/tools/renderers/write.js.map +1 -1
  268. package/dist/core/tools/shell-execution.d.ts +4 -5
  269. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  270. package/dist/core/tools/shell-execution.js +19 -3
  271. package/dist/core/tools/shell-execution.js.map +1 -1
  272. package/dist/core/tools/shell-tool.d.ts +93 -0
  273. package/dist/core/tools/shell-tool.d.ts.map +1 -0
  274. package/dist/core/tools/shell-tool.js +251 -0
  275. package/dist/core/tools/shell-tool.js.map +1 -0
  276. package/dist/core/tools/tasks/actions.d.ts +12 -0
  277. package/dist/core/tools/tasks/actions.d.ts.map +1 -0
  278. package/dist/{extensions/background → core/tools/tasks}/actions.js +20 -19
  279. package/dist/core/tools/tasks/actions.js.map +1 -0
  280. package/dist/core/tools/tasks/constants.d.ts +24 -0
  281. package/dist/core/tools/tasks/constants.d.ts.map +1 -0
  282. package/dist/{extensions/background → core/tools/tasks}/constants.js +11 -9
  283. package/dist/core/tools/tasks/constants.js.map +1 -0
  284. package/dist/{extensions/background → core/tools/tasks}/schema.d.ts +6 -6
  285. package/dist/core/tools/tasks/schema.d.ts.map +1 -0
  286. package/dist/{extensions/background → core/tools/tasks}/schema.js +17 -17
  287. package/dist/core/tools/tasks/schema.js.map +1 -0
  288. package/dist/{extensions/background → core/tools/tasks}/types.d.ts +15 -17
  289. package/dist/core/tools/tasks/types.d.ts.map +1 -0
  290. package/dist/core/tools/tasks/types.js.map +1 -0
  291. package/dist/core/tools/tasks.d.ts +14 -0
  292. package/dist/core/tools/tasks.d.ts.map +1 -0
  293. package/dist/core/tools/tasks.js +40 -0
  294. package/dist/core/tools/tasks.js.map +1 -0
  295. package/dist/core/tools/tool-definition-wrapper.d.ts +5 -8
  296. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  297. package/dist/core/tools/tool-definition-wrapper.js +4 -4
  298. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  299. package/dist/core/tools/truncate.d.ts +14 -0
  300. package/dist/core/tools/truncate.d.ts.map +1 -1
  301. package/dist/core/tools/truncate.js +29 -0
  302. package/dist/core/tools/truncate.js.map +1 -1
  303. package/dist/core/trust-manager.d.ts.map +1 -1
  304. package/dist/core/trust-manager.js +1 -0
  305. package/dist/core/trust-manager.js.map +1 -1
  306. package/dist/core/usage-totals.d.ts +5 -3
  307. package/dist/core/usage-totals.d.ts.map +1 -1
  308. package/dist/core/usage-totals.js +27 -4
  309. package/dist/core/usage-totals.js.map +1 -1
  310. package/dist/core/virtual-models.d.ts +115 -0
  311. package/dist/core/virtual-models.d.ts.map +1 -0
  312. package/dist/core/virtual-models.js +117 -0
  313. package/dist/core/virtual-models.js.map +1 -0
  314. package/dist/extensions/codemode/execute.d.ts +16 -0
  315. package/dist/extensions/codemode/execute.d.ts.map +1 -0
  316. package/dist/extensions/codemode/execute.js +390 -0
  317. package/dist/extensions/codemode/execute.js.map +1 -0
  318. package/dist/extensions/codemode/execute.lazy.d.ts +3 -0
  319. package/dist/extensions/codemode/execute.lazy.d.ts.map +1 -0
  320. package/dist/extensions/codemode/execute.lazy.js +3 -0
  321. package/dist/extensions/codemode/execute.lazy.js.map +1 -0
  322. package/dist/extensions/codemode/index.d.ts +21 -0
  323. package/dist/extensions/codemode/index.d.ts.map +1 -0
  324. package/dist/extensions/codemode/index.js +36 -0
  325. package/dist/extensions/codemode/index.js.map +1 -0
  326. package/dist/extensions/codemode/renderer.d.ts +12 -0
  327. package/dist/extensions/codemode/renderer.d.ts.map +1 -0
  328. package/dist/extensions/codemode/renderer.js +119 -0
  329. package/dist/extensions/codemode/renderer.js.map +1 -0
  330. package/dist/extensions/codemode/search.d.ts +33 -0
  331. package/dist/extensions/codemode/search.d.ts.map +1 -0
  332. package/dist/extensions/codemode/search.js +117 -0
  333. package/dist/extensions/codemode/search.js.map +1 -0
  334. package/dist/extensions/codemode/tool.d.ts +122 -0
  335. package/dist/extensions/codemode/tool.d.ts.map +1 -0
  336. package/dist/extensions/codemode/tool.js +324 -0
  337. package/dist/extensions/codemode/tool.js.map +1 -0
  338. package/dist/extensions/codemode/worker.d.ts +7 -0
  339. package/dist/extensions/codemode/worker.d.ts.map +1 -0
  340. package/dist/extensions/codemode/worker.js +7 -0
  341. package/dist/extensions/codemode/worker.js.map +1 -0
  342. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  343. package/dist/extensions/index.d.ts.map +1 -1
  344. package/dist/extensions/index.js +14 -12
  345. package/dist/extensions/index.js.map +1 -1
  346. package/dist/extensions/llama/provider.d.ts +1 -1
  347. package/dist/extensions/llama/provider.d.ts.map +1 -1
  348. package/dist/extensions/llama/provider.js +65 -13
  349. package/dist/extensions/llama/provider.js.map +1 -1
  350. package/dist/extensions/mcp/cli.d.ts +21 -0
  351. package/dist/extensions/mcp/cli.d.ts.map +1 -0
  352. package/dist/extensions/mcp/cli.js +485 -0
  353. package/dist/extensions/mcp/cli.js.map +1 -0
  354. package/dist/extensions/mcp/cli.lazy.d.ts +3 -0
  355. package/dist/extensions/mcp/cli.lazy.d.ts.map +1 -0
  356. package/dist/extensions/mcp/cli.lazy.js +3 -0
  357. package/dist/extensions/mcp/cli.lazy.js.map +1 -0
  358. package/dist/extensions/mcp/config.d.ts +70 -0
  359. package/dist/extensions/mcp/config.d.ts.map +1 -0
  360. package/dist/extensions/mcp/config.js +146 -0
  361. package/dist/extensions/mcp/config.js.map +1 -0
  362. package/dist/extensions/mcp/index.d.ts +52 -0
  363. package/dist/extensions/mcp/index.d.ts.map +1 -0
  364. package/dist/extensions/mcp/index.js +904 -0
  365. package/dist/extensions/mcp/index.js.map +1 -0
  366. package/dist/extensions/mcp/log.d.ts +16 -0
  367. package/dist/extensions/mcp/log.d.ts.map +1 -0
  368. package/dist/extensions/mcp/log.js +64 -0
  369. package/dist/extensions/mcp/log.js.map +1 -0
  370. package/dist/extensions/mcp/oauth.d.ts +94 -0
  371. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  372. package/dist/extensions/mcp/oauth.js +330 -0
  373. package/dist/extensions/mcp/oauth.js.map +1 -0
  374. package/dist/extensions/mcp/resources.d.ts +43 -0
  375. package/dist/extensions/mcp/resources.d.ts.map +1 -0
  376. package/dist/extensions/mcp/resources.js +262 -0
  377. package/dist/extensions/mcp/resources.js.map +1 -0
  378. package/dist/extensions/mcp/runtime.d.ts +96 -0
  379. package/dist/extensions/mcp/runtime.d.ts.map +1 -0
  380. package/dist/extensions/mcp/runtime.js +372 -0
  381. package/dist/extensions/mcp/runtime.js.map +1 -0
  382. package/dist/extensions/mcp/runtime.lazy.d.ts +3 -0
  383. package/dist/extensions/mcp/runtime.lazy.d.ts.map +1 -0
  384. package/dist/extensions/mcp/runtime.lazy.js +3 -0
  385. package/dist/extensions/mcp/runtime.lazy.js.map +1 -0
  386. package/dist/extensions/mcp/tools.d.ts +83 -0
  387. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  388. package/dist/extensions/mcp/tools.js +233 -0
  389. package/dist/extensions/mcp/tools.js.map +1 -0
  390. package/dist/extensions/mcp/ui.d.ts +60 -0
  391. package/dist/extensions/mcp/ui.d.ts.map +1 -0
  392. package/dist/extensions/mcp/ui.js +166 -0
  393. package/dist/extensions/mcp/ui.js.map +1 -0
  394. package/dist/extensions/question/detail-pane.d.ts +12 -0
  395. package/dist/extensions/question/detail-pane.d.ts.map +1 -0
  396. package/dist/extensions/question/detail-pane.js +42 -0
  397. package/dist/extensions/question/detail-pane.js.map +1 -0
  398. package/dist/extensions/question/dialog.d.ts.map +1 -1
  399. package/dist/extensions/question/dialog.js +175 -105
  400. package/dist/extensions/question/dialog.js.map +1 -1
  401. package/dist/extensions/question/option-window.d.ts +26 -0
  402. package/dist/extensions/question/option-window.d.ts.map +1 -0
  403. package/dist/extensions/question/option-window.js +53 -0
  404. package/dist/extensions/question/option-window.js.map +1 -0
  405. package/dist/extensions/question/render-cache.d.ts +4 -4
  406. package/dist/extensions/question/render-cache.d.ts.map +1 -1
  407. package/dist/extensions/question/render-cache.js +10 -11
  408. package/dist/extensions/question/render-cache.js.map +1 -1
  409. package/dist/extensions/statusline/index.js +2 -2
  410. package/dist/extensions/statusline/index.js.map +1 -1
  411. package/dist/extensions/todo/index.d.ts.map +1 -1
  412. package/dist/extensions/todo/index.js +12 -8
  413. package/dist/extensions/todo/index.js.map +1 -1
  414. package/dist/extensions/todo/view.d.ts +3 -3
  415. package/dist/extensions/todo/view.d.ts.map +1 -1
  416. package/dist/extensions/todo/view.js +7 -6
  417. package/dist/extensions/todo/view.js.map +1 -1
  418. package/dist/extensions/tool-search/index.d.ts +12 -0
  419. package/dist/extensions/tool-search/index.d.ts.map +1 -0
  420. package/dist/extensions/tool-search/index.js +20 -0
  421. package/dist/extensions/tool-search/index.js.map +1 -0
  422. package/dist/extensions/tool-search/tool.d.ts +72 -0
  423. package/dist/extensions/tool-search/tool.d.ts.map +1 -0
  424. package/dist/extensions/tool-search/tool.js +208 -0
  425. package/dist/extensions/tool-search/tool.js.map +1 -0
  426. package/dist/index.d.ts +13 -4
  427. package/dist/index.d.ts.map +1 -1
  428. package/dist/index.js +7 -1
  429. package/dist/index.js.map +1 -1
  430. package/dist/main.d.ts.map +1 -1
  431. package/dist/main.js +10 -0
  432. package/dist/main.js.map +1 -1
  433. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  434. package/dist/modes/interactive/components/config-selector.js +13 -3
  435. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  436. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  437. package/dist/modes/interactive/components/custom-message.js +3 -1
  438. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  439. package/dist/modes/interactive/components/first-time-setup.d.ts +4 -4
  440. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  441. package/dist/modes/interactive/components/first-time-setup.js +8 -2
  442. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  443. package/dist/modes/interactive/components/footer.d.ts +7 -0
  444. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  445. package/dist/modes/interactive/components/footer.js +42 -3
  446. package/dist/modes/interactive/components/footer.js.map +1 -1
  447. package/dist/modes/interactive/components/index.d.ts +1 -1
  448. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  449. package/dist/modes/interactive/components/index.js +1 -1
  450. package/dist/modes/interactive/components/index.js.map +1 -1
  451. package/dist/modes/interactive/components/pi-logo.d.ts +12 -0
  452. package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -0
  453. package/dist/modes/interactive/components/pi-logo.js +25 -0
  454. package/dist/modes/interactive/components/pi-logo.js.map +1 -0
  455. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  456. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  457. package/dist/modes/interactive/components/settings-selector.js +28 -6
  458. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  459. package/dist/modes/interactive/components/status-marker.d.ts +4 -4
  460. package/dist/modes/interactive/components/status-marker.js +4 -4
  461. package/dist/modes/interactive/components/status-marker.js.map +1 -1
  462. package/dist/modes/interactive/components/themed-text.d.ts +17 -0
  463. package/dist/modes/interactive/components/themed-text.d.ts.map +1 -0
  464. package/dist/modes/interactive/components/themed-text.js +28 -0
  465. package/dist/modes/interactive/components/themed-text.js.map +1 -0
  466. package/dist/modes/interactive/interactive-mode.d.ts +2 -4
  467. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  468. package/dist/modes/interactive/interactive-mode.js +221 -173
  469. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  470. package/dist/modes/interactive/tasks/completion-render.d.ts +8 -0
  471. package/dist/modes/interactive/tasks/completion-render.d.ts.map +1 -0
  472. package/dist/{extensions/background → modes/interactive/tasks}/completion-render.js +33 -30
  473. package/dist/modes/interactive/tasks/completion-render.js.map +1 -0
  474. package/dist/modes/interactive/tasks/fallback-view.d.ts +4 -0
  475. package/dist/modes/interactive/tasks/fallback-view.d.ts.map +1 -0
  476. package/dist/modes/interactive/tasks/fallback-view.js +27 -0
  477. package/dist/modes/interactive/tasks/fallback-view.js.map +1 -0
  478. package/dist/modes/interactive/tasks/index.d.ts +12 -0
  479. package/dist/modes/interactive/tasks/index.d.ts.map +1 -0
  480. package/dist/modes/interactive/tasks/index.js +97 -0
  481. package/dist/modes/interactive/tasks/index.js.map +1 -0
  482. package/dist/modes/interactive/tasks/manager.d.ts +67 -0
  483. package/dist/modes/interactive/tasks/manager.d.ts.map +1 -0
  484. package/dist/modes/interactive/tasks/manager.js +380 -0
  485. package/dist/modes/interactive/tasks/manager.js.map +1 -0
  486. package/dist/{extensions/background → modes/interactive/tasks}/render.d.ts +13 -13
  487. package/dist/modes/interactive/tasks/render.d.ts.map +1 -0
  488. package/dist/{extensions/background → modes/interactive/tasks}/render.js +18 -18
  489. package/dist/modes/interactive/tasks/render.js.map +1 -0
  490. package/dist/{extensions/background → modes/interactive/tasks}/task-view.d.ts +7 -7
  491. package/dist/modes/interactive/tasks/task-view.d.ts.map +1 -0
  492. package/dist/{extensions/background → modes/interactive/tasks}/task-view.js +4 -4
  493. package/dist/modes/interactive/tasks/task-view.js.map +1 -0
  494. package/dist/{extensions/background → modes/interactive/tasks}/text.d.ts +1 -1
  495. package/dist/modes/interactive/tasks/text.d.ts.map +1 -0
  496. package/dist/{extensions/background → modes/interactive/tasks}/text.js +1 -1
  497. package/dist/modes/interactive/tasks/text.js.map +1 -0
  498. package/dist/modes/interactive/tasks/viewport.d.ts +15 -0
  499. package/dist/modes/interactive/tasks/viewport.d.ts.map +1 -0
  500. package/dist/modes/interactive/tasks/viewport.js +49 -0
  501. package/dist/modes/interactive/tasks/viewport.js.map +1 -0
  502. package/dist/modes/interactive/theme/dark.json +59 -72
  503. package/dist/modes/interactive/theme/light.json +57 -69
  504. package/dist/modes/interactive/theme/system-theme.d.ts +54 -0
  505. package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -0
  506. package/dist/modes/interactive/theme/system-theme.js +535 -0
  507. package/dist/modes/interactive/theme/system-theme.js.map +1 -0
  508. package/dist/modes/interactive/theme/theme-controller.d.ts +46 -6
  509. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  510. package/dist/modes/interactive/theme/theme-controller.js +125 -47
  511. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  512. package/dist/modes/interactive/theme/theme-json.d.ts +1 -0
  513. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -1
  514. package/dist/modes/interactive/theme/theme-json.js +3 -1
  515. package/dist/modes/interactive/theme/theme-json.js.map +1 -1
  516. package/dist/modes/interactive/theme/theme-schema.json +7 -2
  517. package/dist/modes/interactive/theme/theme.d.ts +70 -39
  518. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  519. package/dist/modes/interactive/theme/theme.js +247 -314
  520. package/dist/modes/interactive/theme/theme.js.map +1 -1
  521. package/dist/modes/interactive/tool-view/chat.d.ts +20 -0
  522. package/dist/modes/interactive/tool-view/chat.d.ts.map +1 -0
  523. package/dist/modes/interactive/tool-view/chat.js +46 -0
  524. package/dist/modes/interactive/tool-view/chat.js.map +1 -0
  525. package/dist/modes/interactive/tool-view/fallback.d.ts +14 -0
  526. package/dist/modes/interactive/tool-view/fallback.d.ts.map +1 -0
  527. package/dist/modes/interactive/tool-view/fallback.js +55 -0
  528. package/dist/modes/interactive/tool-view/fallback.js.map +1 -0
  529. package/dist/modes/interactive/tool-view/style.d.ts +63 -0
  530. package/dist/modes/interactive/tool-view/style.d.ts.map +1 -0
  531. package/dist/modes/interactive/tool-view/style.js +83 -0
  532. package/dist/modes/interactive/tool-view/style.js.map +1 -0
  533. package/dist/modes/interactive/{components → tool-view}/tool-execution.d.ts +17 -24
  534. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -0
  535. package/dist/modes/interactive/{components → tool-view}/tool-execution.js +42 -116
  536. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -0
  537. package/dist/modes/interactive/tui-renderer.d.ts +2 -1
  538. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -1
  539. package/dist/modes/interactive/tui-renderer.js +1 -0
  540. package/dist/modes/interactive/tui-renderer.js.map +1 -1
  541. package/dist/modes/rpc/rpc-client.d.ts +6 -6
  542. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  543. package/dist/modes/rpc/rpc-client.js +12 -8
  544. package/dist/modes/rpc/rpc-client.js.map +1 -1
  545. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  546. package/dist/modes/rpc/rpc-mode.js +7 -9
  547. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  548. package/dist/modes/rpc/rpc-types.d.ts +10 -1
  549. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  550. package/dist/modes/rpc/rpc-types.js.map +1 -1
  551. package/dist/package-manager-cli.d.ts.map +1 -1
  552. package/dist/package-manager-cli.js +6 -2
  553. package/dist/package-manager-cli.js.map +1 -1
  554. package/dist/utils/clipboard-image.d.ts.map +1 -1
  555. package/dist/utils/clipboard-image.js +14 -17
  556. package/dist/utils/clipboard-image.js.map +1 -1
  557. package/dist/utils/clipboard.d.ts +2 -0
  558. package/dist/utils/clipboard.d.ts.map +1 -1
  559. package/dist/utils/clipboard.js +5 -0
  560. package/dist/utils/clipboard.js.map +1 -1
  561. package/dist/utils/paths.d.ts +3 -3
  562. package/dist/utils/paths.d.ts.map +1 -1
  563. package/dist/utils/paths.js +5 -4
  564. package/dist/utils/paths.js.map +1 -1
  565. package/dist/utils/shell.d.ts +1 -3
  566. package/dist/utils/shell.d.ts.map +1 -1
  567. package/dist/utils/shell.js +3 -30
  568. package/dist/utils/shell.js.map +1 -1
  569. package/docs/bundled/README.md +22 -8
  570. package/docs/bundled/extensions/question.md +6 -5
  571. package/docs/bundled/extensions/statusline.md +2 -2
  572. package/docs/bundled/tasks.md +141 -0
  573. package/docs/bundled/tool-presentation.md +41 -31
  574. package/docs/custom-provider.md +44 -0
  575. package/docs/docs.json +10 -6
  576. package/docs/extensions.md +90 -90
  577. package/docs/index.md +2 -1
  578. package/docs/keybindings.md +19 -7
  579. package/docs/llama-cpp.md +12 -1
  580. package/docs/mcp.md +188 -0
  581. package/docs/models.md +35 -0
  582. package/docs/packages.md +4 -0
  583. package/docs/providers.md +6 -0
  584. package/docs/rpc.md +5 -3
  585. package/docs/sdk.md +26 -16
  586. package/docs/security.md +4 -0
  587. package/docs/session-format.md +18 -11
  588. package/docs/settings.md +26 -2
  589. package/docs/themes.md +27 -5
  590. package/docs/tui.md +20 -0
  591. package/docs/usage.md +61 -3
  592. package/docs/virtual-models.md +114 -0
  593. package/docs/windows.md +2 -0
  594. package/examples/README.md +1 -1
  595. package/examples/extensions/README.md +2 -0
  596. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  597. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  598. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  599. package/examples/extensions/custom-provider-gitlab-duo/test.ts +4 -4
  600. package/examples/extensions/debug-provider.ts +90 -0
  601. package/examples/extensions/gondolin/package-lock.json +2 -2
  602. package/examples/extensions/gondolin/package.json +1 -1
  603. package/examples/extensions/jev-router.ts +113 -0
  604. package/examples/extensions/sandbox/package-lock.json +2 -2
  605. package/examples/extensions/sandbox/package.json +1 -1
  606. package/examples/extensions/with-deps/package-lock.json +2 -2
  607. package/examples/extensions/with-deps/package.json +1 -1
  608. package/examples/rpc-client.ts +1 -1
  609. package/examples/rpc-extension-ui.ts +1 -1
  610. package/examples/sdk/14-codemode-mcp.ts +61 -0
  611. package/examples/sdk/README.md +1 -0
  612. package/npm-shrinkwrap.json +409 -423
  613. package/package.json +13 -10
  614. package/dist/bundle/chunks/anthropic-messages-XWFTZP2N.js +0 -6
  615. package/dist/bundle/chunks/azure-openai-responses-HS35BQV6.js +0 -2
  616. package/dist/bundle/chunks/chunk-2IO5GDBS.js +0 -11
  617. package/dist/bundle/chunks/chunk-APQ4ACY3.js +0 -2
  618. package/dist/bundle/chunks/chunk-EDBLK2JQ.js +0 -2
  619. package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
  620. package/dist/bundle/chunks/google-generative-ai-NOVAJBFC.js +0 -2
  621. package/dist/bundle/chunks/google-vertex-4VHCZJV5.js +0 -2
  622. package/dist/bundle/chunks/mistral-conversations-WC6A2WCJ.js +0 -5
  623. package/dist/bundle/chunks/openai-codex-responses-XCDG75W2.js +0 -10
  624. package/dist/bundle/chunks/openai-completions-SHS3CAEL.js +0 -7
  625. package/dist/bundle/chunks/openai-responses-UT6XFKC7.js +0 -2
  626. package/dist/bundle/chunks/virtual-modules-W3OGMIX7.js +0 -2
  627. package/dist/core/background/history.d.ts +0 -4
  628. package/dist/core/background/history.d.ts.map +0 -1
  629. package/dist/core/background/history.js.map +0 -1
  630. package/dist/core/background/output.d.ts.map +0 -1
  631. package/dist/core/background/output.js.map +0 -1
  632. package/dist/core/background/presentation.d.ts +0 -9
  633. package/dist/core/background/presentation.d.ts.map +0 -1
  634. package/dist/core/background/presentation.js.map +0 -1
  635. package/dist/core/background/service.d.ts.map +0 -1
  636. package/dist/core/background/service.js.map +0 -1
  637. package/dist/core/background/session.d.ts +0 -63
  638. package/dist/core/background/session.d.ts.map +0 -1
  639. package/dist/core/background/session.js +0 -222
  640. package/dist/core/background/session.js.map +0 -1
  641. package/dist/core/background/types.d.ts.map +0 -1
  642. package/dist/core/background/types.js.map +0 -1
  643. package/dist/core/model-stream-options.d.ts +0 -6
  644. package/dist/core/model-stream-options.d.ts.map +0 -1
  645. package/dist/core/model-stream-options.js +0 -20
  646. package/dist/core/model-stream-options.js.map +0 -1
  647. package/dist/extensions/background/actions.d.ts +0 -11
  648. package/dist/extensions/background/actions.d.ts.map +0 -1
  649. package/dist/extensions/background/actions.js.map +0 -1
  650. package/dist/extensions/background/completion-render.d.ts +0 -8
  651. package/dist/extensions/background/completion-render.d.ts.map +0 -1
  652. package/dist/extensions/background/completion-render.js.map +0 -1
  653. package/dist/extensions/background/constants.d.ts +0 -22
  654. package/dist/extensions/background/constants.d.ts.map +0 -1
  655. package/dist/extensions/background/constants.js.map +0 -1
  656. package/dist/extensions/background/index.d.ts +0 -7
  657. package/dist/extensions/background/index.d.ts.map +0 -1
  658. package/dist/extensions/background/index.js +0 -109
  659. package/dist/extensions/background/index.js.map +0 -1
  660. package/dist/extensions/background/keybindings.d.ts +0 -10
  661. package/dist/extensions/background/keybindings.d.ts.map +0 -1
  662. package/dist/extensions/background/keybindings.js +0 -14
  663. package/dist/extensions/background/keybindings.js.map +0 -1
  664. package/dist/extensions/background/manager.d.ts +0 -80
  665. package/dist/extensions/background/manager.d.ts.map +0 -1
  666. package/dist/extensions/background/manager.js +0 -673
  667. package/dist/extensions/background/manager.js.map +0 -1
  668. package/dist/extensions/background/render.d.ts.map +0 -1
  669. package/dist/extensions/background/render.js.map +0 -1
  670. package/dist/extensions/background/schema.d.ts.map +0 -1
  671. package/dist/extensions/background/schema.js.map +0 -1
  672. package/dist/extensions/background/task-view.d.ts.map +0 -1
  673. package/dist/extensions/background/task-view.js.map +0 -1
  674. package/dist/extensions/background/text.d.ts.map +0 -1
  675. package/dist/extensions/background/text.js.map +0 -1
  676. package/dist/extensions/background/types.d.ts.map +0 -1
  677. package/dist/extensions/background/types.js.map +0 -1
  678. package/dist/extensions/subagent/activity.d.ts +0 -34
  679. package/dist/extensions/subagent/activity.d.ts.map +0 -1
  680. package/dist/extensions/subagent/activity.js +0 -192
  681. package/dist/extensions/subagent/activity.js.map +0 -1
  682. package/dist/extensions/subagent/agents-command.d.ts +0 -4
  683. package/dist/extensions/subagent/agents-command.d.ts.map +0 -1
  684. package/dist/extensions/subagent/agents-command.js +0 -230
  685. package/dist/extensions/subagent/agents-command.js.map +0 -1
  686. package/dist/extensions/subagent/agents.d.ts +0 -6
  687. package/dist/extensions/subagent/agents.d.ts.map +0 -1
  688. package/dist/extensions/subagent/agents.js +0 -53
  689. package/dist/extensions/subagent/agents.js.map +0 -1
  690. package/dist/extensions/subagent/budget.d.ts +0 -15
  691. package/dist/extensions/subagent/budget.d.ts.map +0 -1
  692. package/dist/extensions/subagent/budget.js +0 -123
  693. package/dist/extensions/subagent/budget.js.map +0 -1
  694. package/dist/extensions/subagent/cancellation.d.ts +0 -29
  695. package/dist/extensions/subagent/cancellation.d.ts.map +0 -1
  696. package/dist/extensions/subagent/cancellation.js +0 -91
  697. package/dist/extensions/subagent/cancellation.js.map +0 -1
  698. package/dist/extensions/subagent/constants.d.ts +0 -25
  699. package/dist/extensions/subagent/constants.d.ts.map +0 -1
  700. package/dist/extensions/subagent/constants.js +0 -50
  701. package/dist/extensions/subagent/constants.js.map +0 -1
  702. package/dist/extensions/subagent/index.d.ts +0 -3
  703. package/dist/extensions/subagent/index.d.ts.map +0 -1
  704. package/dist/extensions/subagent/index.js +0 -151
  705. package/dist/extensions/subagent/index.js.map +0 -1
  706. package/dist/extensions/subagent/model-selection.d.ts +0 -16
  707. package/dist/extensions/subagent/model-selection.d.ts.map +0 -1
  708. package/dist/extensions/subagent/model-selection.js +0 -51
  709. package/dist/extensions/subagent/model-selection.js.map +0 -1
  710. package/dist/extensions/subagent/render.d.ts +0 -24
  711. package/dist/extensions/subagent/render.d.ts.map +0 -1
  712. package/dist/extensions/subagent/render.js +0 -336
  713. package/dist/extensions/subagent/render.js.map +0 -1
  714. package/dist/extensions/subagent/resolve.d.ts +0 -31
  715. package/dist/extensions/subagent/resolve.d.ts.map +0 -1
  716. package/dist/extensions/subagent/resolve.js +0 -111
  717. package/dist/extensions/subagent/resolve.js.map +0 -1
  718. package/dist/extensions/subagent/runner.d.ts +0 -35
  719. package/dist/extensions/subagent/runner.d.ts.map +0 -1
  720. package/dist/extensions/subagent/runner.js +0 -255
  721. package/dist/extensions/subagent/runner.js.map +0 -1
  722. package/dist/extensions/subagent/schema.d.ts +0 -28
  723. package/dist/extensions/subagent/schema.d.ts.map +0 -1
  724. package/dist/extensions/subagent/schema.js +0 -58
  725. package/dist/extensions/subagent/schema.js.map +0 -1
  726. package/dist/extensions/subagent/sdk-runner.d.ts +0 -33
  727. package/dist/extensions/subagent/sdk-runner.d.ts.map +0 -1
  728. package/dist/extensions/subagent/sdk-runner.js +0 -331
  729. package/dist/extensions/subagent/sdk-runner.js.map +0 -1
  730. package/dist/extensions/subagent/settings.d.ts +0 -8
  731. package/dist/extensions/subagent/settings.d.ts.map +0 -1
  732. package/dist/extensions/subagent/settings.js +0 -206
  733. package/dist/extensions/subagent/settings.js.map +0 -1
  734. package/dist/extensions/subagent/state.d.ts +0 -102
  735. package/dist/extensions/subagent/state.d.ts.map +0 -1
  736. package/dist/extensions/subagent/state.js +0 -383
  737. package/dist/extensions/subagent/state.js.map +0 -1
  738. package/dist/extensions/subagent/text.d.ts +0 -6
  739. package/dist/extensions/subagent/text.d.ts.map +0 -1
  740. package/dist/extensions/subagent/text.js +0 -66
  741. package/dist/extensions/subagent/text.js.map +0 -1
  742. package/dist/extensions/subagent/types.d.ts +0 -91
  743. package/dist/extensions/subagent/types.d.ts.map +0 -1
  744. package/dist/extensions/subagent/types.js +0 -2
  745. package/dist/extensions/subagent/types.js.map +0 -1
  746. package/dist/extensions/subagent/ui/agents-dialog.d.ts +0 -4
  747. package/dist/extensions/subagent/ui/agents-dialog.d.ts.map +0 -1
  748. package/dist/extensions/subagent/ui/agents-dialog.js +0 -84
  749. package/dist/extensions/subagent/ui/agents-dialog.js.map +0 -1
  750. package/dist/extensions/subagent/ui/choice-menu.d.ts +0 -39
  751. package/dist/extensions/subagent/ui/choice-menu.d.ts.map +0 -1
  752. package/dist/extensions/subagent/ui/choice-menu.js +0 -93
  753. package/dist/extensions/subagent/ui/choice-menu.js.map +0 -1
  754. package/dist/extensions/subagent/ui/choices.d.ts +0 -36
  755. package/dist/extensions/subagent/ui/choices.d.ts.map +0 -1
  756. package/dist/extensions/subagent/ui/choices.js +0 -54
  757. package/dist/extensions/subagent/ui/choices.js.map +0 -1
  758. package/dist/extensions/subagent/ui/model-list.d.ts +0 -66
  759. package/dist/extensions/subagent/ui/model-list.d.ts.map +0 -1
  760. package/dist/extensions/subagent/ui/model-list.js +0 -235
  761. package/dist/extensions/subagent/ui/model-list.js.map +0 -1
  762. package/dist/extensions/subagent/ui/model-picker.d.ts +0 -47
  763. package/dist/extensions/subagent/ui/model-picker.d.ts.map +0 -1
  764. package/dist/extensions/subagent/ui/model-picker.js +0 -143
  765. package/dist/extensions/subagent/ui/model-picker.js.map +0 -1
  766. package/dist/extensions/subagent/ui/profile-settings-menu.d.ts +0 -41
  767. package/dist/extensions/subagent/ui/profile-settings-menu.d.ts.map +0 -1
  768. package/dist/extensions/subagent/ui/profile-settings-menu.js +0 -98
  769. package/dist/extensions/subagent/ui/profile-settings-menu.js.map +0 -1
  770. package/dist/modes/interactive/components/tool-chrome.d.ts +0 -28
  771. package/dist/modes/interactive/components/tool-chrome.d.ts.map +0 -1
  772. package/dist/modes/interactive/components/tool-chrome.js +0 -84
  773. package/dist/modes/interactive/components/tool-chrome.js.map +0 -1
  774. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  775. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  776. package/dist/modes/interactive/components/tool-group.d.ts +0 -17
  777. package/dist/modes/interactive/components/tool-group.d.ts.map +0 -1
  778. package/dist/modes/interactive/components/tool-group.js +0 -78
  779. package/dist/modes/interactive/components/tool-group.js.map +0 -1
  780. package/dist/modes/interactive/tool-chat.d.ts +0 -21
  781. package/dist/modes/interactive/tool-chat.d.ts.map +0 -1
  782. package/dist/modes/interactive/tool-chat.js +0 -58
  783. package/dist/modes/interactive/tool-chat.js.map +0 -1
  784. package/docs/bundled/extensions/background.md +0 -132
  785. package/docs/bundled/extensions/subagent.md +0 -148
  786. /package/dist/{extensions/background → core/tools/tasks}/types.js +0 -0
@@ -1,3 +1,4 @@
1
+ import { createTasksToolDefinition } from "./tools/tasks.js";
1
2
  /**
2
3
  * AgentSession - Core abstraction for agent lifecycle and session management.
3
4
  *
@@ -14,6 +15,7 @@
14
15
  */
15
16
  import { readFileSync } from "node:fs";
16
17
  import { basename, dirname } from "node:path";
18
+ import { runToolCall, } from "@earendil-works/pi-agent-core";
17
19
  import { contentText, getCurrentSystemMessage, getSystemMessageText, retryDelayMs } from "@earendil-works/pi-ai";
18
20
  import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, isRecoverableLength, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@earendil-works/pi-ai/compat";
19
21
  import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
@@ -22,27 +24,28 @@ import { processImage } from "../utils/image-process.js";
22
24
  import { sleep } from "../utils/sleep.js";
23
25
  import { normalizeToolResultImages } from "../utils/tool-result-images.js";
24
26
  import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
25
- import { BackgroundSession } from "./background/session.js";
26
27
  import { executeBashWithOperations } from "./bash-executor.js";
27
28
  import { generateBugReportSummary } from "./bug-report.js";
28
29
  import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateProjectedContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
29
30
  import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "./defaults.js";
30
31
  import { exportSessionToHtml } from "./export-html/index.js";
31
32
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
32
- import { ExtensionRunner, STALE_EXTENSION_CONTEXT_MESSAGE, wrapRegisteredTools, } from "./extensions/index.js";
33
+ import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
33
34
  import { emitSessionShutdownEvent } from "./extensions/runner.js";
34
35
  import { convertToLlm } from "./messages.js";
35
36
  import { ModelRegistry } from "./model-registry.js";
36
- import { resolveModelStreamOptions } from "./model-stream-options.js";
37
+ import { NestedToolCallRunner } from "./nested-tool-calls.js";
37
38
  import { expandPromptTemplate } from "./prompt-templates.js";
38
39
  import { exportSessionToJsonl } from "./session-export.js";
39
40
  import { getLatestCompactionEntry, SessionManager, } from "./session-manager.js";
40
- import { createSyntheticSourceInfo } from "./source-info.js";
41
+ import { BUILTIN_PATH_PREFIX, createSyntheticSourceInfo, isSyntheticPath } from "./source-info.js";
41
42
  import { buildSystemPrompt, buildSystemPromptSections, diffSystemPromptSections, normalizeBuildSystemPromptOptions, } from "./system-prompt.js";
43
+ import { TaskSession } from "./tasks/session.js";
42
44
  import { createLocalBashOperations } from "./tools/bash.js";
43
45
  import { createAllToolDefinitions } from "./tools/index.js";
44
46
  import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
45
- import { addUsageToTotals, createUsageTotals, getAccountedUsages } from "./usage-totals.js";
47
+ import { addUsageToTotals, combineUsage, createUsageTotals, getAccountedUsages } from "./usage-totals.js";
48
+ import { findLatestResponse, getBranchSelection, getVirtualModelState, isVirtualModel, VIRTUAL_MODEL_STATE_ENTRY, } from "./virtual-models.js";
46
49
  /**
47
50
  * Parse a skill block from message text.
48
51
  * Returns null if the text doesn't contain a skill block.
@@ -58,6 +61,9 @@ export function parseSkillBlock(text) {
58
61
  userMessage: match[4]?.trim() || undefined,
59
62
  };
60
63
  }
64
+ // ============================================================================
65
+ // Types
66
+ // ============================================================================
61
67
  function withoutDeletedHeaders(headers) {
62
68
  return headers
63
69
  ? Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] !== null))
@@ -86,8 +92,6 @@ export class AgentSession {
86
92
  this._pendingNextTurnMessages = [];
87
93
  /** Context-only custom messages queued during a run, flushed once the current turn's tool results are in. */
88
94
  this._pendingCustomMessages = [];
89
- /** Background completions queued for steering, awaiting the persistence that confirms delivery. */
90
- this._queuedBackgroundCompletions = new Map();
91
95
  // Compaction state
92
96
  this._compactionAbortController = undefined;
93
97
  this._autoCompactionAbortController = undefined;
@@ -113,20 +117,30 @@ export class AgentSession {
113
117
  this._extensionMode = "print";
114
118
  // Tool registry for extension getTools/setTools
115
119
  this._toolRegistry = new Map();
120
+ /** Declared tools whose declarations requests leave out, from `prepareLoadout` hooks. */
121
+ this._hiddenDeclarations = new Set();
116
122
  this._toolDefinitions = new Map();
117
123
  this._toolPromptSnippets = new Map();
118
124
  this._toolPromptGuidelines = new Map();
119
125
  /** Internal handler for agent events - shared by subscribe and reconnect */
120
126
  this._handleAgentEvent = async (event) => {
121
- // Preserve host delivery identity before extension message_end transforms.
122
- // Content/details may be replaced, but a persisted replacement is still an ack.
123
- const acknowledgeBackground = event.type === "message_end" ? this._backgroundHost.messageAcknowledgement(event.message) : undefined;
124
- // A queued completion is tracked by identity too, for the same reason.
125
- const queuedBackgroundCompletion = event.type === "message_start" || event.type === "message_end"
126
- ? this._queuedBackgroundCompletions.get(event.message)
127
- : undefined;
128
- if (event.type === "message_start" && queuedBackgroundCompletion)
129
- queuedBackgroundCompletion.drained = true;
127
+ if (event.type === "message_start")
128
+ this._tasksHost.delivery.messageStarted(event.message);
129
+ // Record the calls a tool made through ctx.executeTool() and their usage on its result message.
130
+ if (this._nestedToolCalls) {
131
+ if (event.type === "message_start" && event.message.role === "toolResult") {
132
+ const message = event.message;
133
+ const summary = this._nestedToolCalls.takeRecord(message.toolCallId);
134
+ if (summary?.calls)
135
+ message.nestedCalls = summary.calls;
136
+ if (summary?.usage) {
137
+ message.usage = message.usage ? combineUsage(message.usage, summary.usage) : summary.usage;
138
+ }
139
+ }
140
+ else if (event.type === "agent_end") {
141
+ this._nestedToolCalls.clear();
142
+ }
143
+ }
130
144
  // When a user message starts, check if it's from either queue and remove it BEFORE emitting
131
145
  // This ensures the UI sees the updated queue state
132
146
  if (event.type === "message_start" && event.message.role === "user") {
@@ -154,10 +168,24 @@ export class AgentSession {
154
168
  this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
155
169
  // Handle session persistence
156
170
  if (event.type === "message_end") {
157
- if (this._persistMessage(event.message)) {
158
- acknowledgeBackground?.();
159
- queuedBackgroundCompletion?.resolve();
171
+ let entryId;
172
+ // Check if this is a custom message from extensions
173
+ if (event.message.role === "custom") {
174
+ // Persist as CustomMessageEntry
175
+ entryId = this.sessionManager.appendCustomMessageEntry(event.message.customType, event.message.content, event.message.display, event.message.details);
176
+ }
177
+ else if (event.message.role === "system" ||
178
+ event.message.role === "user" ||
179
+ event.message.role === "assistant" ||
180
+ event.message.role === "toolResult") {
181
+ // Regular LLM message - persist as SessionMessageEntry
182
+ entryId = this.sessionManager.appendMessage(event.message);
160
183
  }
184
+ if (entryId)
185
+ this._entryIdsByMessage.set(event.message, entryId);
186
+ if (entryId)
187
+ this._messagePersisted(event.message);
188
+ // Other message types (bashExecution, compactionSummary, branchSummary) are persisted elsewhere
161
189
  if (event.message.role === "assistant") {
162
190
  const assistantMsg = event.message;
163
191
  this._lastAssistantMessage = assistantMsg;
@@ -186,14 +214,14 @@ export class AgentSession {
186
214
  this._flushPendingCustomMessages();
187
215
  }
188
216
  if (event.type === "agent_end")
189
- this._failDrainedBackgroundCompletions();
217
+ this._tasksHost.delivery.agentEnded();
190
218
  };
191
219
  this.agent = config.agent;
192
220
  this.sessionManager = config.sessionManager;
193
221
  this.settingsManager = config.settingsManager;
194
- this._backgroundHost = new BackgroundSession({
222
+ this._tasksHost = new TaskSession({
195
223
  manager: this.sessionManager,
196
- role: config.executionRole ?? "main",
224
+ backgroundAllowed: config.backgroundAllowed,
197
225
  canDeliver: () => {
198
226
  if (this.model === undefined || this.isCompacting)
199
227
  return false;
@@ -202,7 +230,14 @@ export class AgentSession {
202
230
  // turn, so it still waits for the queues to drain.
203
231
  return this.isStreaming || (this.pendingMessageCount === 0 && !this.agent.hasQueuedMessages());
204
232
  },
205
- deliver: (message) => this._deliverBackgroundCompletion(message),
233
+ deliver: (message, waitForPersistence) => {
234
+ if (this.isStreaming) {
235
+ this.agent.steer(message);
236
+ return waitForPersistence();
237
+ }
238
+ // Completion turns skip before_agent_start, but consume nextTurn context.
239
+ return this._runAgentPrompt([message, ...this._pendingNextTurnMessages]);
240
+ },
206
241
  onEntry: (entry) => this._emit({ type: "entry_appended", entry }),
207
242
  onError: (event, error) => this._extensionRunner?.emitError({ extensionPath: "<background>", event, error }),
208
243
  });
@@ -211,7 +246,7 @@ export class AgentSession {
211
246
  this._customTools = config.customTools ?? [];
212
247
  this._cwd = config.cwd;
213
248
  this._modelRuntime = config.modelRuntime;
214
- this._captureModelContext = config.captureModelContext;
249
+ this._contextSource = config.contextSource;
215
250
  this._cacheWarmer = config.cacheWarmer;
216
251
  if (this._cacheWarmer) {
217
252
  this._cacheWarmer.onWarmed = (entry) => this._emit({ type: "entry_appended", entry });
@@ -229,6 +264,7 @@ export class AgentSession {
229
264
  this._installAgentNextTurnRefresh();
230
265
  this._installAgentRequestProjection();
231
266
  this._installAgentBoundaryHooks();
267
+ this._installHiddenDeclarationsProjection();
232
268
  this._installAgentForcedPromptProjection();
233
269
  this._buildRuntime({
234
270
  activeToolNames: this._initialActiveToolNames,
@@ -237,26 +273,26 @@ export class AgentSession {
237
273
  if (this._initialActiveToolNames === undefined)
238
274
  this._restoreToolsFromTranscript();
239
275
  }
240
- get background() {
241
- return this._backgroundHost.service;
276
+ get tasks() {
277
+ return this._tasksHost.service;
242
278
  }
243
- get quarantinedBackgroundSettlements() {
244
- return this._backgroundHost.quarantinedSettlements;
279
+ get quarantinedTaskSettlements() {
280
+ return this._tasksHost.quarantinedSettlements;
245
281
  }
246
282
  /** Pause delivery across asynchronous lifecycle/preflight gaps. Nestable. */
247
- pauseBackgroundNotifications() {
248
- return this._backgroundHost.pause();
283
+ pauseTaskNotifications() {
284
+ return this._tasksHost.delivery.pause();
249
285
  }
250
286
  /** Explicit retry after a host delivery failure; never spins on a timer by itself. */
251
- retryBackgroundNotifications() {
252
- this._backgroundHost.retry();
287
+ retryTaskNotifications() {
288
+ this._tasksHost.delivery.retry();
253
289
  }
254
290
  /**
255
291
  * Run a lifecycle operation with delivery paused across its asynchronous gaps.
256
292
  * Lifecycle methods are thin shells over upstream bodies so those keep upstream's shape.
257
293
  */
258
- async _withBackgroundPaused(operation) {
259
- const resumeBackground = this.pauseBackgroundNotifications();
294
+ async _withTasksPaused(operation) {
295
+ const resumeBackground = this.pauseTaskNotifications();
260
296
  try {
261
297
  return await operation();
262
298
  }
@@ -272,6 +308,14 @@ export class AgentSession {
272
308
  const model = this.model;
273
309
  if (!model)
274
310
  throw new Error("No model selected");
311
+ const requestOptions = {
312
+ sessionId: this.agent.sessionId ?? this.sessionManager.getSessionId(),
313
+ transport: this.agent.transport,
314
+ thinkingBudgets: structuredClone(this.agent.thinkingBudgets),
315
+ maxRetryDelayMs: this.agent.maxRetryDelayMs,
316
+ onPayload: this.agent.onPayload,
317
+ onResponse: this.agent.onResponse,
318
+ };
275
319
  const snapshot = {
276
320
  capturedAt: Date.now(),
277
321
  sessionId: this.sessionManager.getSessionId(),
@@ -284,22 +328,15 @@ export class AgentSession {
284
328
  parameters: structuredClone(parameters),
285
329
  ...(constrainedSampling === undefined ? {} : { constrainedSampling: structuredClone(constrainedSampling) }),
286
330
  })),
287
- streamOptions: resolveModelStreamOptions(model, this.settingsManager, this._extensionRunner, {
288
- sessionId: this.agent.sessionId ?? this.sessionManager.getSessionId(),
289
- transport: this.agent.transport,
290
- thinkingBudgets: structuredClone(this.agent.thinkingBudgets),
291
- maxRetryDelayMs: this.agent.maxRetryDelayMs,
292
- onPayload: this.agent.onPayload,
293
- onResponse: this.agent.onResponse,
294
- }),
331
+ streamOptions: this._contextSource?.resolveStreamOptions(model, requestOptions) ?? requestOptions,
295
332
  };
296
333
  const currentSystemPrompt = this.systemPrompt;
297
334
  // The canonical projection is what the next request converts; the inspection cache may lag it.
298
335
  const messages = structuredClone(this.sessionManager.buildSessionProjection().messages);
299
336
  const convert = this.agent.convertToLlm;
300
337
  const transform = this.agent.transformContext;
301
- const prepared = this._captureModelContext
302
- ? await this._captureModelContext(messages)
338
+ const prepared = this._contextSource
339
+ ? await this._contextSource.prepareMessages(messages)
303
340
  : await convert(transform ? await transform(messages) : messages);
304
341
  // The prepared transcript declares the prompt the provider received, including a forced
305
342
  // prompt projected for the last request; before the first request there is none yet.
@@ -339,28 +376,71 @@ export class AgentSession {
339
376
  }
340
377
  throw new Error(formatNoApiKeyFoundMessage(model.provider));
341
378
  }
342
- async _getSummarizationRequestAuth(model, signal) {
379
+ async _getSummarizationRequestAuth(selectedModel, signal) {
380
+ // Route a virtual model first: summaries size their input and output from the model they get.
381
+ const { model, thinkingLevel } = isVirtualModel(selectedModel)
382
+ ? await this._modelRuntime.resolveModel(selectedModel, convertToLlm(this.messages), {
383
+ reason: "direct",
384
+ thinkingLevel: this.thinkingLevel,
385
+ signal,
386
+ })
387
+ : { model: selectedModel, thinkingLevel: this.thinkingLevel };
343
388
  if (this.agent.streamFunction === streamSimple) {
344
- return this._getRequiredRequestAuth(model, signal);
389
+ return { ...(await this._getRequiredRequestAuth(model, signal)), thinkingLevel };
345
390
  }
346
391
  try {
347
392
  const result = await this._modelRuntime.getAuth(model, { signal });
348
393
  if (!result)
349
- return { model };
394
+ return { model, thinkingLevel };
350
395
  const requestModel = result.auth.baseUrl ? { ...model, baseUrl: result.auth.baseUrl } : model;
351
396
  return {
352
397
  model: requestModel,
353
398
  apiKey: result.auth.apiKey,
354
399
  headers: withoutDeletedHeaders(result.auth.headers),
355
400
  env: result.env,
401
+ thinkingLevel,
356
402
  };
357
403
  }
358
404
  catch (error) {
359
405
  if (signal?.aborted)
360
406
  throw error;
361
- return { model };
407
+ return { model, thinkingLevel };
362
408
  }
363
409
  }
410
+ /**
411
+ * The model whose limits apply to `message`, or undefined when the message came from another
412
+ * model. Under a virtual selection, that is the physical model that produced it.
413
+ */
414
+ _modelForMessage(message) {
415
+ const model = this.model;
416
+ if (model && isVirtualModel(model))
417
+ return this._modelRuntime.getPhysicalModel(message.provider, message.model);
418
+ return model?.provider === message.provider && model.id === message.model ? model : undefined;
419
+ }
420
+ /**
421
+ * Record the selection on the current branch when the branch implies another one, so a resume
422
+ * restores it. Tree navigation can leave the latest `model_change` on another branch; responses
423
+ * cannot record a virtual selection because they name physical models. Responses do record a
424
+ * physical selection unless the branch holds a virtual one; checking a physical selection against
425
+ * responses would record it on every prompt while `prepareRequest` redirects to another model.
426
+ */
427
+ _recordSelection() {
428
+ const model = this.model;
429
+ if (!model)
430
+ return;
431
+ const getModel = (provider, modelId) => this._modelRuntime.getModel(provider, modelId);
432
+ const recorded = getBranchSelection(this.sessionManager.getBranch(), getModel);
433
+ if (!recorded || (recorded.provider === model.provider && recorded.modelId === model.id))
434
+ return;
435
+ const recordedModel = getModel(recorded.provider, recorded.modelId);
436
+ if (!isVirtualModel(model) && !(recordedModel && isVirtualModel(recordedModel)))
437
+ return;
438
+ this.sessionManager.appendModelChange(model.provider, model.id);
439
+ }
440
+ /** The model whose limits apply to the conversation. */
441
+ _limitsModel() {
442
+ return this.routedModel?.model ?? this.model;
443
+ }
364
444
  /**
365
445
  * Install tool hooks once on the Agent instance.
366
446
  *
@@ -370,65 +450,112 @@ export class AgentSession {
370
450
  * happens here instead of in wrappers.
371
451
  */
372
452
  _installAgentToolHooks() {
373
- this.agent.beforeToolCall = async ({ toolCall, args }) => {
374
- const runner = this._extensionRunner;
375
- if (!runner.hasHandlers("tool_call")) {
376
- return undefined;
377
- }
378
- try {
379
- return await runner.emitToolCall({
380
- type: "tool_call",
381
- toolName: toolCall.name,
382
- toolCallId: toolCall.id,
383
- input: args,
384
- });
385
- }
386
- catch (err) {
387
- if (err instanceof Error) {
388
- throw err;
389
- }
390
- throw new Error(`Extension failed, blocking execution: ${String(err)}`);
391
- }
392
- };
393
- this.agent.afterToolCall = async ({ toolCall, args, result, isError }) => {
394
- const runner = this._extensionRunner;
395
- const hookResult = runner.hasHandlers("tool_result")
396
- ? await runner.emitToolResult({
397
- type: "tool_result",
398
- toolName: toolCall.name,
399
- toolCallId: toolCall.id,
400
- input: args,
401
- content: result.content,
402
- details: result.details,
403
- isError,
404
- usage: result.usage,
405
- })
406
- : undefined;
407
- const content = hookResult?.content ?? result.content ?? [];
408
- // Runs after the extension hook so images injected or replaced by extensions are normalized too.
409
- const resizeOptions = this.model?.inputLimits?.images?.resize;
410
- const normalizedContent = await normalizeToolResultImages(content, {
411
- autoResizeImages: this.settingsManager.getImageAutoResize(),
412
- ...(resizeOptions ? { resizeOptions } : {}),
453
+ this.agent.beforeToolCall = (context) => this._beforeToolCall(context);
454
+ this.agent.afterToolCall = (context) => this._afterToolCall(context);
455
+ }
456
+ /** `tool_call` handlers. `parentToolCallId` is set for calls another tool made. */
457
+ async _beforeToolCall({ toolCall, args }, parentToolCallId) {
458
+ const runner = this._extensionRunner;
459
+ if (!runner.hasHandlers("tool_call")) {
460
+ return undefined;
461
+ }
462
+ try {
463
+ return await runner.emitToolCall({
464
+ type: "tool_call",
465
+ toolName: toolCall.name,
466
+ toolCallId: toolCall.id,
467
+ ...(parentToolCallId ? { parentToolCallId } : {}),
468
+ input: args,
413
469
  });
414
- if (!hookResult && normalizedContent === content) {
415
- return undefined;
470
+ }
471
+ catch (err) {
472
+ if (err instanceof Error) {
473
+ throw err;
416
474
  }
417
- return {
418
- content: normalizedContent,
419
- details: hookResult?.details,
420
- isError: hookResult?.isError ?? isError,
421
- usage: hookResult?.usage,
422
- };
475
+ throw new Error(`Extension failed, blocking execution: ${String(err)}`);
476
+ }
477
+ }
478
+ /** `tool_result` handlers and image normalization. `parentToolCallId` is set for calls another tool made. */
479
+ async _afterToolCall({ toolCall, args, result, isError }, parentToolCallId) {
480
+ const runner = this._extensionRunner;
481
+ const hookResult = runner.hasHandlers("tool_result")
482
+ ? await runner.emitToolResult({
483
+ type: "tool_result",
484
+ toolName: toolCall.name,
485
+ toolCallId: toolCall.id,
486
+ ...(parentToolCallId ? { parentToolCallId } : {}),
487
+ input: args,
488
+ content: result.content,
489
+ details: result.details,
490
+ ...(result.structuredContent === undefined ? {} : { structuredContent: result.structuredContent }),
491
+ isError,
492
+ usage: result.usage,
493
+ })
494
+ : undefined;
495
+ const content = hookResult?.content ?? result.content ?? [];
496
+ // Runs after the extension hook so images injected or replaced by extensions are normalized too.
497
+ const resizeOptions = this._limitsModel()?.inputLimits?.images?.resize;
498
+ const normalizedContent = await normalizeToolResultImages(content, {
499
+ autoResizeImages: this.settingsManager.getImageAutoResize(),
500
+ ...(resizeOptions ? { resizeOptions } : {}),
501
+ });
502
+ if (!hookResult && normalizedContent === content) {
503
+ return undefined;
504
+ }
505
+ // The hook result already dropped structured content that replaced content no longer matches.
506
+ return {
507
+ content: normalizedContent,
508
+ details: hookResult?.details,
509
+ structuredContent: hookResult ? hookResult.structuredContent : result.structuredContent,
510
+ isError: hookResult?.isError ?? isError,
511
+ usage: hookResult?.usage,
423
512
  };
424
513
  }
514
+ /**
515
+ * Run a call that the tool call `parentToolCallId` made through `ctx.executeTool()`. It goes
516
+ * through the agent's tool pipeline with the session's hooks, against the callable tools.
517
+ */
518
+ async _executeNestedToolCall(parentToolCallId, name, args, options) {
519
+ this._nestedToolCalls ??= new NestedToolCallRunner({
520
+ getTools: () => this._getCallableTools(),
521
+ isSequential: () => this.agent.toolExecution === "sequential",
522
+ runToolCall: (toolCall, parentId, signal, onUpdate) => {
523
+ const assistantMessage = this._findLastAssistantMessage();
524
+ if (!assistantMessage) {
525
+ return Promise.resolve({
526
+ toolCall,
527
+ result: { content: [{ type: "text", text: "No assistant message issued this call" }], details: {} },
528
+ isError: true,
529
+ });
530
+ }
531
+ return runToolCall(toolCall, {
532
+ tools: this._getCallableTools(),
533
+ assistantMessage,
534
+ context: { messages: this.agent.state.messages, tools: this.agent.state.tools },
535
+ beforeToolCall: (context) => this._beforeToolCall(context, parentId),
536
+ afterToolCall: (context) => this._afterToolCall(context, parentId),
537
+ signal,
538
+ onUpdate,
539
+ });
540
+ },
541
+ emit: async (event) => {
542
+ await this._extensionRunner.emit(event);
543
+ this._emit(event);
544
+ },
545
+ });
546
+ return this._nestedToolCalls.execute(parentToolCallId, name, args, options);
547
+ }
548
+ /** Whether `projection`, the current session projection, exceeds the compaction threshold of `model`. */
549
+ _exceedsCompactionThreshold(model, projection) {
550
+ if (model.contextWindow <= 0)
551
+ return false;
552
+ return shouldCompact(estimateProjectedContextTokens(projection, this.sessionManager.getBranch()).tokens, model.contextWindow, this.settingsManager.getCompactionSettings(model));
553
+ }
425
554
  async _compactBeforeNextAssistantResponse(context) {
426
- const model = this.model;
427
- const settings = this.settingsManager.getCompactionSettings(model);
428
555
  const projection = this.sessionManager.buildSessionProjection();
429
- if (!model ||
430
- model.contextWindow <= 0 ||
431
- !shouldCompact(estimateProjectedContextTokens(projection, this.sessionManager.getBranch()).tokens, model.contextWindow, settings)) {
556
+ // A virtual selection is checked in prepareRequest, against the model the request is routed to.
557
+ const model = this.model;
558
+ if (!model || isVirtualModel(model) || !this._exceedsCompactionThreshold(model, projection)) {
432
559
  return { ...context, messages: projection.messages };
433
560
  }
434
561
  await this._runAutoCompaction("threshold", false);
@@ -437,24 +564,55 @@ export class AgentSession {
437
564
  _installAgentRequestProjection() {
438
565
  const previousPrepareRequest = this.agent.prepareRequest;
439
566
  this.agent.prepareRequest = async (request, signal) => {
440
- const canonicalContext = {
441
- ...request.context,
442
- messages: this.sessionManager.buildSessionProjection().messages,
443
- // Messages declare the provider-visible loadout; context.tools keeps executable implementations.
444
- tools: this.agent.state.tools.slice(),
445
- };
446
- const previous = await previousPrepareRequest?.({
447
- ...request,
448
- context: canonicalContext,
449
- model: this.agent.state.model,
450
- thinkingLevel: this.agent.state.thinkingLevel,
451
- }, signal);
452
- return {
453
- ...previous,
454
- context: previous?.context ?? canonicalContext,
455
- model: previous?.model ?? this.agent.state.model,
456
- thinkingLevel: previous?.thinkingLevel ?? this.agent.state.thinkingLevel,
567
+ const failed = this._failedResponse;
568
+ this._failedResponse = undefined;
569
+ const prepare = async () => {
570
+ const projection = this.sessionManager.buildSessionProjection();
571
+ const canonicalContext = {
572
+ ...request.context,
573
+ messages: projection.messages,
574
+ // Messages declare the provider-visible loadout; context.tools keeps executable implementations.
575
+ tools: this.agent.state.tools.slice(),
576
+ };
577
+ const previous = await previousPrepareRequest?.({
578
+ ...request,
579
+ context: canonicalContext,
580
+ model: this.agent.state.model,
581
+ thinkingLevel: this.agent.state.thinkingLevel,
582
+ }, signal);
583
+ return { previous, context: previous?.context ?? canonicalContext, projection };
457
584
  };
585
+ let { previous, context, projection } = await prepare();
586
+ const model = previous?.model ?? this.agent.state.model;
587
+ const thinkingLevel = previous?.thinkingLevel ?? this.agent.state.thinkingLevel;
588
+ if (!isVirtualModel(model))
589
+ return { ...previous, context, model, thinkingLevel };
590
+ // The selection stays in agent state; only this request uses the routed model. A routing
591
+ // failure rejects, which ends the run with an error response. Only messages the user wrote
592
+ // start a turn; extension messages can follow them, e.g. from before_agent_start.
593
+ const lastResponse = context.messages.findLastIndex((message) => message.role === "assistant");
594
+ const userTurn = context.messages.slice(lastResponse + 1).some((message) => message.role === "user");
595
+ const state = getVirtualModelState(this.sessionManager.getBranch(), model.provider, model.id);
596
+ const route = await this._modelRuntime.resolveModel(model, convertToLlm(context.messages), {
597
+ reason: failed ? "retry" : userTurn ? "user" : "continuation",
598
+ thinkingLevel,
599
+ signal,
600
+ failed,
601
+ state,
602
+ });
603
+ if (route.state !== undefined && route.state !== state) {
604
+ const data = { provider: model.provider, modelId: model.id, state: route.state };
605
+ const entry = this.sessionManager.getEntry(this.sessionManager.appendCustomEntry(VIRTUAL_MODEL_STATE_ENTRY, data));
606
+ if (entry)
607
+ this._emit({ type: "entry_appended", entry });
608
+ }
609
+ // The route stands: the router already decided this request. The state entry does not change
610
+ // the projection.
611
+ if (this._exceedsCompactionThreshold(route.model, projection)) {
612
+ await this._runAutoCompaction("threshold", false);
613
+ ({ previous, context } = await prepare());
614
+ }
615
+ return { ...previous, context, model: route.model, thinkingLevel: route.thinkingLevel };
458
616
  };
459
617
  }
460
618
  async _dispatchTurnEndBoundary(message, toolResults) {
@@ -510,10 +668,7 @@ export class AgentSession {
510
668
  ? async (_turn, signal) => await this.agent.prepareNextTurn?.(signal)
511
669
  : undefined);
512
670
  this.agent.prepareNextTurnWithContext = async (turn, signal) => {
513
- const context = await this._compactBeforeNextAssistantResponse({
514
- ...turn.context,
515
- messages: this.sessionManager.buildSessionProjection().messages,
516
- });
671
+ const context = await this._compactBeforeNextAssistantResponse(turn.context);
517
672
  const previousSnapshot = await previousPrepareNextTurnWithContext?.({ ...turn, context }, signal);
518
673
  const nextContext = previousSnapshot?.context ?? context;
519
674
  const runOptions = this._runSystemPromptOptions ?? this._baseSystemPromptOptions;
@@ -661,7 +816,7 @@ export class AgentSession {
661
816
  * so a deferred prompt never races a delivery for the same idle gap.
662
817
  */
663
818
  async _emitAgentSettled() {
664
- return this._withBackgroundPaused(() => this._emitAgentSettledBody());
819
+ return this._withTasksPaused(() => this._emitAgentSettledBody());
665
820
  }
666
821
  async _emitAgentSettledBody() {
667
822
  this._cacheWarmer?.onAgentSettled();
@@ -688,31 +843,16 @@ export class AgentSession {
688
843
  this._resolveIdleWaitIfIdle();
689
844
  }
690
845
  /**
691
- * Persist model/custom messages and consume queued context only after the append succeeds.
692
- * Returns the persisted entry ID, which boundary events and recovery omissions resolve later.
846
+ * Called after a message's session entry is appended. Queued `nextTurn` context is consumed
847
+ * only here, so a failed append leaves it queued, and Background delivery is acknowledged.
693
848
  */
694
- _persistMessage(message) {
695
- let entryId;
849
+ _messagePersisted(message) {
696
850
  if (message.role === "custom") {
697
- entryId = this.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, message.details);
698
851
  const pendingIndex = this._pendingNextTurnMessages.indexOf(message);
699
852
  if (pendingIndex !== -1)
700
853
  this._pendingNextTurnMessages.splice(pendingIndex, 1);
701
854
  }
702
- else if (message.role === "system" ||
703
- message.role === "user" ||
704
- message.role === "assistant" ||
705
- message.role === "toolResult") {
706
- entryId = this.sessionManager.appendMessage(message);
707
- }
708
- else {
709
- // Bash execution, compaction and branch summaries are persisted by their owners.
710
- return undefined;
711
- }
712
- this._entryIdsByMessage.set(message, entryId);
713
- if (message.role === "toolResult")
714
- this._backgroundHost.acknowledgeWaitResult(message.details);
715
- return entryId;
855
+ this._tasksHost.delivery.messagePersisted(message);
716
856
  }
717
857
  _willRetryAfterAgentEnd(event) {
718
858
  if (this._agentRunAbortRequested)
@@ -909,10 +1049,7 @@ export class AgentSession {
909
1049
  * Call this when completely done with the session.
910
1050
  */
911
1051
  dispose() {
912
- this._backgroundHost.dispose();
913
- for (const queued of [...this._queuedBackgroundCompletions.values()]) {
914
- queued.reject(new Error("the session was disposed"));
915
- }
1052
+ this._tasksHost.dispose();
916
1053
  try {
917
1054
  this.abortRetry();
918
1055
  this.abortCompaction();
@@ -923,7 +1060,7 @@ export class AgentSession {
923
1060
  catch {
924
1061
  // Dispose must succeed even if an abort hook throws.
925
1062
  }
926
- this._extensionRunner.invalidate(STALE_EXTENSION_CONTEXT_MESSAGE);
1063
+ this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
927
1064
  this._disconnectFromAgent();
928
1065
  this._eventListeners = [];
929
1066
  if (this._cacheWarmer) {
@@ -960,6 +1097,14 @@ export class AgentSession {
960
1097
  get thinkingLevel() {
961
1098
  return this.agent.state.thinkingLevel;
962
1099
  }
1100
+ /** Under a virtual selection, the physical model and thinking level of the latest successful response. */
1101
+ get routedModel() {
1102
+ if (!this.model || !isVirtualModel(this.model))
1103
+ return undefined;
1104
+ const latest = findLatestResponse(this.agent.state.messages);
1105
+ const model = latest && this._modelRuntime.getPhysicalModel(latest.provider, latest.model);
1106
+ return model && { model, thinkingLevel: latest?.thinkingLevel };
1107
+ }
963
1108
  /** Whether the session is currently processing an agent run or post-run continuation. */
964
1109
  get isStreaming() {
965
1110
  return this._isAgentRunActive;
@@ -977,12 +1122,16 @@ export class AgentSession {
977
1122
  return this._retryAttempt;
978
1123
  }
979
1124
  /**
980
- * Get the names of currently active tools.
981
- * Returns the names of tools currently set on the agent.
1125
+ * Get the names of currently active tools, which are the tools declared to the model.
1126
+ * Tools with `codemode` or `deferred` exposure are callable from other tools without being active.
982
1127
  */
983
1128
  getActiveToolNames() {
984
1129
  return this.agent.state.tools.map((t) => t.name);
985
1130
  }
1131
+ /** Get the names of the tools that tools can call through `ctx.executeTool()`. */
1132
+ getCallableToolNames() {
1133
+ return this._getCallableTools().map((t) => t.name);
1134
+ }
986
1135
  /**
987
1136
  * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.
988
1137
  */
@@ -992,6 +1141,9 @@ export class AgentSession {
992
1141
  description: definition.description,
993
1142
  parameters: definition.parameters,
994
1143
  promptGuidelines: definition.promptGuidelines,
1144
+ exposure: this._getToolExposure(definition.name),
1145
+ ...(definition.namespace ? { namespace: definition.namespace } : {}),
1146
+ ...(definition.annotations ? { annotations: { ...definition.annotations } } : {}),
995
1147
  sourceInfo,
996
1148
  }));
997
1149
  }
@@ -1000,22 +1152,79 @@ export class AgentSession {
1000
1152
  }
1001
1153
  /**
1002
1154
  * Set active tools by name.
1003
- * Only tools in the registry can be enabled. Unknown tool names are ignored.
1155
+ * Only tools in the registry can be enabled. Unknown and hidden tool names are ignored.
1004
1156
  * Also rebuilds the system prompt to reflect the new tool set.
1005
1157
  * Changes take effect on the next agent turn.
1006
1158
  */
1007
1159
  setActiveToolsByName(toolNames) {
1008
- const tools = [];
1009
- const validToolNames = [];
1010
- for (const name of toolNames) {
1160
+ const tools = this._applyToolLoadout(toolNames);
1161
+ this._rebuildSystemPrompt(tools.map((tool) => tool.name));
1162
+ }
1163
+ _getToolExposure(name) {
1164
+ return this._toolDefinitions.get(name)?.definition.exposure ?? "direct";
1165
+ }
1166
+ /**
1167
+ * Tools callable through `ctx.executeTool()`: the active `direct` tools and every registered
1168
+ * `codemode` or `deferred` tool.
1169
+ */
1170
+ _getCallableTools(active = new Set(this.getActiveToolNames())) {
1171
+ return [...this._toolRegistry.values()].filter((tool) => {
1172
+ const exposure = this._getToolExposure(tool.name);
1173
+ return exposure === "codemode" || exposure === "deferred" || (exposure === "direct" && active.has(tool.name));
1174
+ });
1175
+ }
1176
+ /**
1177
+ * Set the agent's tools for the given active tool names and return them. The active tools are
1178
+ * the registered, non-hidden ones; they are declared to the model. Active tools with a
1179
+ * `prepareLoadout` hook can change the declared descriptions and hide declarations from
1180
+ * requests (see {@link _installHiddenDeclarationsProjection}).
1181
+ */
1182
+ _applyToolLoadout(toolNames) {
1183
+ const tools = [...new Set(toolNames)].flatMap((name) => {
1011
1184
  const tool = this._toolRegistry.get(name);
1012
- if (tool) {
1013
- tools.push(tool);
1014
- validToolNames.push(name);
1185
+ return tool && this._getToolExposure(name) !== "hidden" ? [tool] : [];
1186
+ });
1187
+ const hooks = tools.flatMap((tool) => {
1188
+ const entry = this._toolDefinitions.get(tool.name);
1189
+ return entry?.definition.prepareLoadout ? [entry] : [];
1190
+ });
1191
+ const hidden = new Set();
1192
+ let declared = tools;
1193
+ if (hooks.length > 0) {
1194
+ const loadout = {
1195
+ declared: tools,
1196
+ callable: this._getCallableTools(new Set(tools.map((tool) => tool.name))),
1197
+ registered: [...this._toolRegistry.values()],
1198
+ getExposure: (name) => this._getToolExposure(name),
1199
+ getNamespace: (name) => this._toolDefinitions.get(name)?.definition.namespace,
1200
+ };
1201
+ const descriptions = new Map();
1202
+ for (const { definition, sourceInfo } of hooks) {
1203
+ try {
1204
+ const changes = definition.prepareLoadout?.(loadout);
1205
+ for (const [name, description] of Object.entries(changes?.descriptions ?? {})) {
1206
+ descriptions.set(name, description);
1207
+ }
1208
+ for (const name of changes?.hiddenDeclarations ?? [])
1209
+ hidden.add(name);
1210
+ }
1211
+ catch (error) {
1212
+ this._extensionRunner.emitError({
1213
+ extensionPath: sourceInfo.path,
1214
+ event: "prepare_loadout",
1215
+ error: error instanceof Error ? error.message : String(error),
1216
+ stack: error instanceof Error ? error.stack : undefined,
1217
+ });
1218
+ }
1015
1219
  }
1220
+ declared = tools.map((tool) => {
1221
+ const description = descriptions.get(tool.name);
1222
+ return description === undefined ? tool : { ...tool, description };
1223
+ });
1016
1224
  }
1017
- this.agent.state.tools = tools;
1018
- this._rebuildSystemPrompt(validToolNames);
1225
+ this._hiddenDeclarations = hidden;
1226
+ this.agent.state.tools = declared;
1227
+ return declared;
1019
1228
  }
1020
1229
  /** Whether compaction or branch summarization is currently running */
1021
1230
  get isCompacting() {
@@ -1116,11 +1325,7 @@ export class AgentSession {
1116
1325
  * {@link _installAgentForcedPromptProjection}.
1117
1326
  */
1118
1327
  _preparePromptAndToolLoadout(options, messages = this.agent.state.messages) {
1119
- options.selectedTools = [...new Set(options.selectedTools)].filter((name) => this._toolRegistry.has(name));
1120
- this.agent.state.tools = options.selectedTools.flatMap((name) => {
1121
- const tool = this._toolRegistry.get(name);
1122
- return tool ? [tool] : [];
1123
- });
1328
+ options.selectedTools = this._applyToolLoadout(options.selectedTools).map((tool) => tool.name);
1124
1329
  const sections = diffSystemPromptSections(getCurrentSystemMessage(messages)?.sections ?? {}, buildSystemPromptSections(options));
1125
1330
  return sections ? { role: "system", content: "", sections, timestamp: Date.now() } : undefined;
1126
1331
  }
@@ -1134,6 +1339,32 @@ export class AgentSession {
1134
1339
  * collapse into one head holding the forced text and the current tools. Runs after the
1135
1340
  * `context` extension handlers.
1136
1341
  */
1342
+ /**
1343
+ * Remove the declarations that `prepareLoadout` hooks hide from every request. The whole
1344
+ * transcript is filtered with the current set, so the projected declarations stay consistent
1345
+ * across requests and only change when the loadout does.
1346
+ */
1347
+ _installHiddenDeclarationsProjection() {
1348
+ const previousTransformContext = this.agent.transformContext;
1349
+ this.agent.transformContext = async (messages, signal) => {
1350
+ const transformed = previousTransformContext ? await previousTransformContext(messages, signal) : messages;
1351
+ const hidden = this._hiddenDeclarations;
1352
+ if (hidden.size === 0)
1353
+ return transformed;
1354
+ return transformed.map((message) => {
1355
+ if (message.role !== "system" || (!message.toolsAdded && !message.toolsRemoved))
1356
+ return message;
1357
+ const { toolsAdded, toolsRemoved, ...rest } = message;
1358
+ const added = toolsAdded?.filter((tool) => !hidden.has(tool.name)) ?? [];
1359
+ const removed = toolsRemoved?.filter((tool) => !hidden.has(tool.name)) ?? [];
1360
+ return {
1361
+ ...rest,
1362
+ ...(added.length > 0 ? { toolsAdded: added } : {}),
1363
+ ...(removed.length > 0 ? { toolsRemoved: removed } : {}),
1364
+ };
1365
+ });
1366
+ };
1367
+ }
1137
1368
  _installAgentForcedPromptProjection() {
1138
1369
  const previousTransformContext = this.agent.transformContext;
1139
1370
  this.agent.transformContext = async (messages, signal) => {
@@ -1151,25 +1382,25 @@ export class AgentSession {
1151
1382
  return [head, ...transformed.filter((message) => message.role !== "system")];
1152
1383
  };
1153
1384
  }
1154
- /** Restore the active tool loadout declared by the session transcript, if it declares one. */
1385
+ /**
1386
+ * Restore the active tool loadout declared by the session transcript, if it declares one.
1387
+ * Tools reachable only from other tools are never declared, but they do not depend on the active
1388
+ * set, so the transcript's declarations are the whole loadout.
1389
+ */
1155
1390
  _restoreToolsFromTranscript() {
1156
1391
  const current = getCurrentSystemMessage(this.sessionManager.buildSessionContext().messages);
1157
1392
  if (!current)
1158
1393
  return;
1159
- const toolNames = (current.toolsAdded ?? [])
1160
- .map((tool) => tool.name)
1161
- .filter((name) => this._toolRegistry.has(name));
1162
- this.agent.state.tools = toolNames.flatMap((name) => {
1163
- const registered = this._toolRegistry.get(name);
1164
- return registered ? [registered] : [];
1165
- });
1166
- this._rebuildSystemPrompt(toolNames);
1394
+ this.setActiveToolsByName((current.toolsAdded ?? []).map((tool) => tool.name));
1167
1395
  }
1168
1396
  // =========================================================================
1169
1397
  // Prompting
1170
1398
  // =========================================================================
1171
1399
  async _runAgentPrompt(messages) {
1172
1400
  this._agentRunAbortRequested = false;
1401
+ // Compaction before the prompt may have scheduled a retry; the new prompt replaces it.
1402
+ this._failedResponse = undefined;
1403
+ this._recordSelection();
1173
1404
  this._isAgentRunActive = true;
1174
1405
  try {
1175
1406
  await this.agent.prompt(messages);
@@ -1190,61 +1421,13 @@ export class AgentSession {
1190
1421
  finally {
1191
1422
  if (this._agentRunAbortRequested)
1192
1423
  this._finishCancelledRetry();
1424
+ this._failedResponse = undefined;
1193
1425
  this._runSystemPromptOptions = undefined;
1194
1426
  this._flushPendingBashMessages();
1195
1427
  this._flushPendingCustomMessages();
1196
1428
  await this._emitAgentSettled();
1197
1429
  }
1198
1430
  }
1199
- /**
1200
- * Deliver a background completion through the same queueing path as interactive input:
1201
- * steering into an active run lands the result right after the current tool batch, and an
1202
- * idle session starts its own turn. The promise settles only once the message is persisted,
1203
- * or once it can no longer be persisted, so the caller never releases its claim for a
1204
- * message the transcript does not contain.
1205
- */
1206
- _deliverBackgroundCompletion(message) {
1207
- if (!this.isStreaming) {
1208
- // Completion turns skip before_agent_start, but consume nextTurn context.
1209
- const asides = this._pendingNextTurnMessages.slice();
1210
- return this._runAgentPrompt(asides.length ? [message, ...asides] : message);
1211
- }
1212
- return new Promise((resolve, reject) => {
1213
- const queued = {
1214
- drained: false,
1215
- resolve: () => {
1216
- if (this._queuedBackgroundCompletions.get(message) !== queued)
1217
- return;
1218
- this._queuedBackgroundCompletions.delete(message);
1219
- resolve();
1220
- },
1221
- reject: (reason) => {
1222
- if (this._queuedBackgroundCompletions.get(message) !== queued)
1223
- return;
1224
- this._queuedBackgroundCompletions.delete(message);
1225
- reject(reason);
1226
- },
1227
- };
1228
- this._queuedBackgroundCompletions.set(message, queued);
1229
- try {
1230
- this.agent.steer(message);
1231
- }
1232
- catch (error) {
1233
- queued.reject(error);
1234
- }
1235
- });
1236
- }
1237
- /**
1238
- * Fail deliveries the owning run emitted but never persisted. A completion still sitting in
1239
- * the steering queue when its run ends stays claimed: the next run delivers it, so failing
1240
- * it here would persist the same message twice.
1241
- */
1242
- _failDrainedBackgroundCompletions() {
1243
- for (const queued of [...this._queuedBackgroundCompletions.values()]) {
1244
- if (queued.drained)
1245
- queued.reject(new Error("the completion message was not persisted"));
1246
- }
1247
- }
1248
1431
  async _handlePostAgentRun() {
1249
1432
  const message = this._lastAssistantMessage;
1250
1433
  const toolResults = this._lastAssistantToolResults;
@@ -1259,6 +1442,7 @@ export class AgentSession {
1259
1442
  if (this._isRetryableError(message) && (await this._prepareRetry(message))) {
1260
1443
  if (this._agentRunAbortRequested)
1261
1444
  this._finishCancelledRetry();
1445
+ this._failedResponse = message;
1262
1446
  return !this._agentRunAbortRequested;
1263
1447
  }
1264
1448
  if (this._agentRunAbortRequested) {
@@ -1326,7 +1510,7 @@ export class AgentSession {
1326
1510
  for (const image of images) {
1327
1511
  const processed = await processImage(Buffer.from(image.data, "base64"), image.mimeType, {
1328
1512
  autoResizeImages: this.settingsManager.getImageAutoResize(),
1329
- resizeOptions: this.model?.inputLimits?.images?.resize,
1513
+ resizeOptions: this._limitsModel()?.inputLimits?.images?.resize,
1330
1514
  });
1331
1515
  if (!processed.ok) {
1332
1516
  hints.push(processed.message);
@@ -1352,7 +1536,7 @@ export class AgentSession {
1352
1536
  return;
1353
1537
  }
1354
1538
  // A user-initiated prompt is the recovery point for failed completion deliveries.
1355
- this.retryBackgroundNotifications();
1539
+ this.retryTaskNotifications();
1356
1540
  const expandPromptTemplates = options?.expandPromptTemplates ?? true;
1357
1541
  const preflightResult = options?.preflightResult;
1358
1542
  let messages;
@@ -1364,20 +1548,20 @@ export class AgentSession {
1364
1548
  const handled = await this._tryExecuteExtensionCommand(text);
1365
1549
  if (handled) {
1366
1550
  // Extension command executed, no prompt to send
1367
- preflightResult?.(true);
1551
+ preflightResult?.("handled");
1368
1552
  return;
1369
1553
  }
1370
1554
  }
1371
1555
  // Observer commands above may stay open indefinitely; only real model input owns
1372
1556
  // the preflight pause, released once the user message is established.
1373
- resumeBackground = this.pauseBackgroundNotifications();
1557
+ resumeBackground = this.pauseTaskNotifications();
1374
1558
  if (this._compactionAbortController !== undefined) {
1375
1559
  throw new Error("Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.");
1376
1560
  }
1377
1561
  // Emit input event for extension interception (before skill/template expansion)
1378
1562
  const processedInput = await this._runInputHandlers(text, options?.images, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
1379
1563
  if (!processedInput) {
1380
- preflightResult?.(true);
1564
+ preflightResult?.("handled");
1381
1565
  return;
1382
1566
  }
1383
1567
  const { text: currentText, images: currentImages } = processedInput;
@@ -1398,7 +1582,7 @@ export class AgentSession {
1398
1582
  else {
1399
1583
  await this._queueSteer(expandedText, currentImages);
1400
1584
  }
1401
- preflightResult?.(true);
1585
+ preflightResult?.("queued");
1402
1586
  return;
1403
1587
  }
1404
1588
  // Flush any pending bash and custom messages before the new prompt
@@ -1447,8 +1631,7 @@ export class AgentSession {
1447
1631
  content: userContent,
1448
1632
  timestamp: Date.now(),
1449
1633
  });
1450
- // Inject any pending "nextTurn" messages as context alongside the user message.
1451
- // They stay queued until _persistMessage() confirms the append.
1634
+ // Inject any pending "nextTurn" messages as context alongside the user message
1452
1635
  for (const msg of this._pendingNextTurnMessages) {
1453
1636
  messages.push(msg);
1454
1637
  }
@@ -1468,18 +1651,12 @@ export class AgentSession {
1468
1651
  if (updateMessage)
1469
1652
  messages.unshift(updateMessage);
1470
1653
  }
1471
- catch (error) {
1472
- preflightResult?.(false);
1473
- throw error;
1474
- }
1475
1654
  finally {
1476
- // Delivery is timer-scheduled, so a completion cannot start before the run below does.
1477
1655
  resumeBackground?.();
1478
1656
  }
1479
- if (!messages) {
1657
+ if (!messages)
1480
1658
  return;
1481
- }
1482
- preflightResult?.(true);
1659
+ preflightResult?.("started");
1483
1660
  await this._runAgentPrompt(messages);
1484
1661
  }
1485
1662
  /**
@@ -1545,7 +1722,7 @@ export class AgentSession {
1545
1722
  }
1546
1723
  const processedInput = await this._runInputHandlers(text, images, source, this.isStreaming ? behavior : undefined);
1547
1724
  if (!processedInput)
1548
- return;
1725
+ return "handled";
1549
1726
  let expandedText = this._expandSkillCommand(processedInput.text);
1550
1727
  expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1551
1728
  if (behavior === "steer") {
@@ -1554,6 +1731,7 @@ export class AgentSession {
1554
1731
  else {
1555
1732
  await this._queueFollowUp(expandedText, processedInput.images);
1556
1733
  }
1734
+ return "queued";
1557
1735
  }
1558
1736
  /**
1559
1737
  * Queue a steering message while the agent is running.
@@ -1565,7 +1743,7 @@ export class AgentSession {
1565
1743
  * @throws Error if text is an extension command
1566
1744
  */
1567
1745
  async steer(text, images, options) {
1568
- await this._queueUserInput(text, images, "steer", options?.source ?? "interactive");
1746
+ return this._queueUserInput(text, images, "steer", options?.source ?? "interactive");
1569
1747
  }
1570
1748
  /**
1571
1749
  * Queue a follow-up message to be processed after the agent finishes.
@@ -1576,7 +1754,7 @@ export class AgentSession {
1576
1754
  * @throws Error if text is an extension command
1577
1755
  */
1578
1756
  async followUp(text, images, options) {
1579
- await this._queueUserInput(text, images, "followUp", options?.source ?? "interactive");
1757
+ return this._queueUserInput(text, images, "followUp", options?.source ?? "interactive");
1580
1758
  }
1581
1759
  /**
1582
1760
  * Internal: Queue a steering message (already expanded, no extension command check).
@@ -1670,9 +1848,9 @@ export class AgentSession {
1670
1848
  }
1671
1849
  }
1672
1850
  _appendCustomMessage(appMessage) {
1673
- this._persistMessage(appMessage);
1851
+ this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details);
1852
+ this._messagePersisted(appMessage);
1674
1853
  this._refreshFinalizedContext();
1675
- this._backgroundHost.messageAcknowledgement(appMessage)?.();
1676
1854
  this._emit({ type: "message_start", message: appMessage });
1677
1855
  this._emit({ type: "message_end", message: appMessage });
1678
1856
  }
@@ -1737,10 +1915,7 @@ export class AgentSession {
1737
1915
  this._steeringMessages = [];
1738
1916
  this._followUpMessages = [];
1739
1917
  this.agent.clearAllQueues();
1740
- // Clearing the queues drops queued completions; fail them so their claims retry.
1741
- for (const queued of [...this._queuedBackgroundCompletions.values()]) {
1742
- queued.reject(new Error("the completion message was dequeued before delivery"));
1743
- }
1918
+ this._tasksHost.delivery.queueCleared();
1744
1919
  this._emitQueueUpdate();
1745
1920
  return { steering, followUp };
1746
1921
  }
@@ -1997,8 +2172,10 @@ export class AgentSession {
1997
2172
  // Compaction
1998
2173
  // =========================================================================
1999
2174
  /** Generate Pi's built-in compaction summary for manual and automatic compaction. */
2000
- async _runDefaultCompaction(preparation, requestModel, apiKey, headers, customInstructions, signal, env, reason) {
2001
- return compact(preparation, requestModel, apiKey, headers, customInstructions, signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }), undefined);
2175
+ async _runDefaultCompaction(preparation, model, customInstructions, signal, reason) {
2176
+ // Resolve the request only when Pi summarizes itself: routing may call models or fail.
2177
+ const request = await this._getSummarizationRequestAuth(model, signal);
2178
+ return compact(preparation, request.model, request.apiKey, request.headers, customInstructions, signal, request.thinkingLevel, this.agent.streamFunction, request.env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }), undefined);
2002
2179
  }
2003
2180
  _clearManualCompactionState() {
2004
2181
  this._compactionAbortController = undefined;
@@ -2020,7 +2197,7 @@ export class AgentSession {
2020
2197
  * @param customInstructions Optional instructions for the compaction summary
2021
2198
  */
2022
2199
  async compact(customInstructions) {
2023
- return this._withBackgroundPaused(() => this._compactBody(customInstructions));
2200
+ return this._withTasksPaused(() => this._compactBody(customInstructions));
2024
2201
  }
2025
2202
  async _compactBody(customInstructions) {
2026
2203
  await this.abort();
@@ -2033,8 +2210,7 @@ export class AgentSession {
2033
2210
  if (!model) {
2034
2211
  throw new Error(formatNoModelSelectedMessage());
2035
2212
  }
2036
- const settings = this.settingsManager.getCompactionSettings(model);
2037
- const { model: requestModel, apiKey, headers, env, } = await this._getSummarizationRequestAuth(model, this._compactionAbortController.signal);
2213
+ const settings = this.settingsManager.getCompactionSettings(this.routedModel?.model ?? model);
2038
2214
  const pathEntries = this.sessionManager.getBranch();
2039
2215
  const preparation = prepareCompaction(pathEntries, settings);
2040
2216
  if (!preparation) {
@@ -2080,7 +2256,7 @@ export class AgentSession {
2080
2256
  }
2081
2257
  else {
2082
2258
  // Shared default summary generator, also used by automatic compaction.
2083
- const result = await this._runDefaultCompaction(preparation, requestModel, apiKey, headers, customInstructions, this._compactionAbortController.signal, env, "manual");
2259
+ const result = await this._runDefaultCompaction(preparation, model, customInstructions, this._compactionAbortController.signal, "manual");
2084
2260
  summary = result.summary;
2085
2261
  firstKeptEntryId = result.firstKeptEntryId;
2086
2262
  tokensBefore = result.tokensBefore;
@@ -2185,18 +2361,20 @@ export class AgentSession {
2185
2361
  * @returns Whether the post-run loop should call `agent.continue()` for overflow recovery or queued messages
2186
2362
  */
2187
2363
  async _checkCompaction(assistantMessage, skipAbortedCheck = true, toolResults = []) {
2188
- const settings = this.settingsManager.getCompactionSettings(this.model);
2364
+ const settings = this.settingsManager.getCompactionSettings(this._modelForMessage(assistantMessage) ?? this.model);
2189
2365
  if (!settings.enabled)
2190
2366
  return false;
2191
2367
  // Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
2192
2368
  if (skipAbortedCheck && assistantMessage.stopReason === "aborted")
2193
2369
  return false;
2194
- const contextWindow = this.model?.contextWindow ?? 0;
2195
2370
  // Skip overflow check if the message came from a different model.
2196
2371
  // This handles the case where user switched from a smaller-context model (e.g. opus)
2197
2372
  // to a larger-context model (e.g. codex) - the overflow error from the old model
2198
- // shouldn't trigger compaction for the new model.
2199
- const sameModel = this.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;
2373
+ // shouldn't trigger compaction for the new model. Under a virtual selection, the
2374
+ // physical model that produced the message supplies the limits.
2375
+ const messageModel = this._modelForMessage(assistantMessage);
2376
+ const sameModel = messageModel !== undefined;
2377
+ const contextWindow = (messageModel ?? this.model)?.contextWindow ?? 0;
2200
2378
  // Skip compaction checks if this assistant message is older than the latest
2201
2379
  // compaction boundary. This prevents a stale pre-compaction usage/error
2202
2380
  // from retriggering compaction on the first prompt after compaction.
@@ -2228,7 +2406,7 @@ export class AgentSession {
2228
2406
  const contextOverflow = sameModel &&
2229
2407
  ((explicitOverflow && assistantRetainedForExplicitRecovery) ||
2230
2408
  (assistantUsageMatchesProjection && isContextOverflow(assistantMessage, contextWindow)));
2231
- const recoverableLength = sameModel && assistantIsProjected && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0);
2409
+ const recoverableLength = sameModel && assistantIsProjected && isRecoverableLength(assistantMessage, messageModel.maxTokens);
2232
2410
  if (contextOverflow || recoverableLength) {
2233
2411
  const willRetry = assistantMessage.stopReason !== "stop";
2234
2412
  // Case 2: the response completed successfully. Compact, but do not retry because
@@ -2260,7 +2438,10 @@ export class AgentSession {
2260
2438
  // Persistently omit the selected final attempt before post-run recovery compaction.
2261
2439
  this._overflowRecoveryAttempted = true;
2262
2440
  this._omitRecoveryAttempt(assistantMessage, toolResults);
2263
- return await this._runAutoCompaction("overflow", willRetry);
2441
+ const retry = await this._runAutoCompaction("overflow", willRetry);
2442
+ if (retry)
2443
+ this._failedResponse = assistantMessage;
2444
+ return retry;
2264
2445
  }
2265
2446
  // Case 3: threshold compaction without retry.
2266
2447
  // For error messages or all-zero usage messages, estimate from the last valid response.
@@ -2310,11 +2491,11 @@ export class AgentSession {
2310
2491
  * @returns Whether the post-run loop should call `agent.continue()`
2311
2492
  */
2312
2493
  async _runAutoCompaction(reason, willRetry) {
2313
- return this._withBackgroundPaused(() => this._runAutoCompactionBody(reason, willRetry));
2494
+ return this._withTasksPaused(() => this._runAutoCompactionBody(reason, willRetry));
2314
2495
  }
2315
2496
  async _runAutoCompactionBody(reason, willRetry) {
2316
2497
  const model = this.model;
2317
- const settings = this.settingsManager.getCompactionSettings(model);
2498
+ const settings = this.settingsManager.getCompactionSettings(this.routedModel?.model ?? model);
2318
2499
  let abortController;
2319
2500
  let started = false;
2320
2501
  let fromExtension = false;
@@ -2333,8 +2514,6 @@ export class AgentSession {
2333
2514
  started = true;
2334
2515
  this._emit({ type: "compaction_start", reason });
2335
2516
  abortController.signal.throwIfAborted();
2336
- const { model: requestModel, apiKey, headers, env, } = await this._getSummarizationRequestAuth(model, abortController.signal);
2337
- abortController.signal.throwIfAborted();
2338
2517
  let extensionCompaction;
2339
2518
  if (this._extensionRunner.hasHandlers("session_before_compact")) {
2340
2519
  const extensionResult = (await this._extensionRunner.emit({
@@ -2371,7 +2550,7 @@ export class AgentSession {
2371
2550
  }
2372
2551
  else {
2373
2552
  // Shared default summary generator, also used by manual compaction.
2374
- const compactResult = await this._runDefaultCompaction(preparation, requestModel, apiKey, headers, undefined, abortController.signal, env, reason);
2553
+ const compactResult = await this._runDefaultCompaction(preparation, model, undefined, abortController.signal, reason);
2375
2554
  summary = compactResult.summary;
2376
2555
  firstKeptEntryId = compactResult.firstKeptEntryId;
2377
2556
  tokensBefore = compactResult.tokensBefore;
@@ -2454,11 +2633,12 @@ export class AgentSession {
2454
2633
  return this.settingsManager.getCompactionEnabled();
2455
2634
  }
2456
2635
  async bindExtensions(bindings) {
2457
- return this._withBackgroundPaused(() => this._bindExtensionsBody(bindings));
2636
+ return this._withTasksPaused(() => this._bindExtensionsBody(bindings));
2458
2637
  }
2459
2638
  async _bindExtensionsBody(bindings) {
2460
- if (bindings.backgroundEnabled !== undefined) {
2461
- this._backgroundHost.setEnabled(bindings.backgroundEnabled);
2639
+ if (bindings.tasksEnabled !== undefined) {
2640
+ this._tasksHost.setEnabled(bindings.tasksEnabled);
2641
+ this._refreshToolRegistry();
2462
2642
  }
2463
2643
  if (bindings.uiContext !== undefined) {
2464
2644
  this._extensionUIContext = bindings.uiContext;
@@ -2480,6 +2660,7 @@ export class AgentSession {
2480
2660
  }
2481
2661
  this._applyExtensionBindings(this._extensionRunner);
2482
2662
  await this._extensionRunner.emit(this._sessionStartEvent);
2663
+ this._extensionRunner.reportUnhandledMcpServers();
2483
2664
  await this.extendResourcesFromExtensions(this._sessionStartEvent.reason === "reload" ? "reload" : "startup");
2484
2665
  }
2485
2666
  async extendResourcesFromExtensions(reason) {
@@ -2501,7 +2682,7 @@ export class AgentSession {
2501
2682
  buildExtensionResourcePaths(entries) {
2502
2683
  return entries.map((entry) => {
2503
2684
  const source = this.getExtensionSourceLabel(entry.extensionPath);
2504
- const baseDir = entry.extensionPath.startsWith("<") ? undefined : dirname(entry.extensionPath);
2685
+ const baseDir = isSyntheticPath(entry.extensionPath) ? undefined : dirname(entry.extensionPath);
2505
2686
  return {
2506
2687
  path: entry.path,
2507
2688
  metadata: {
@@ -2514,7 +2695,7 @@ export class AgentSession {
2514
2695
  });
2515
2696
  }
2516
2697
  getExtensionSourceLabel(extensionPath) {
2517
- if (extensionPath.startsWith("<")) {
2698
+ if (isSyntheticPath(extensionPath)) {
2518
2699
  return `extension:${extensionPath.replace(/[<>]/g, "")}`;
2519
2700
  }
2520
2701
  const base = basename(extensionPath);
@@ -2599,6 +2780,7 @@ export class AgentSession {
2599
2780
  },
2600
2781
  getActiveTools: () => this.getActiveToolNames(),
2601
2782
  getAllTools: () => this.getAllTools(),
2783
+ getSettings: () => this.settingsManager.getSettings(),
2602
2784
  setActiveTools: (toolNames) => this.setActiveToolsByName(toolNames),
2603
2785
  refreshTools: () => this._refreshToolRegistry(),
2604
2786
  getCommands,
@@ -2611,7 +2793,9 @@ export class AgentSession {
2611
2793
  getThinkingLevel: () => this.thinkingLevel,
2612
2794
  setThinkingLevel: (level) => this.setThinkingLevel(level),
2613
2795
  }, {
2614
- getBackground: () => this.background,
2796
+ getTasks: () => this.tasks,
2797
+ getExtensionSettings: (namespace) => this.settingsManager.getExtensionSettings(namespace),
2798
+ setExtensionSettings: (namespace, value) => this.settingsManager.setExtensionSettings(namespace, value),
2615
2799
  getModel: () => this.model,
2616
2800
  getScopedModels: () => this._scopedModels,
2617
2801
  isIdle: () => this.isIdle,
@@ -2644,6 +2828,8 @@ export class AgentSession {
2644
2828
  },
2645
2829
  getSystemPrompt: () => this.systemPrompt,
2646
2830
  getSystemPromptOptions: () => this._baseSystemPromptOptions,
2831
+ executeTool: (callerId, name, args, options) => this._executeNestedToolCall(callerId, name, args, options),
2832
+ getCallableTools: () => this._getCallableTools(),
2647
2833
  }, {
2648
2834
  registerProvider: (name, config) => {
2649
2835
  this._modelRuntime.registerProvider(name, config);
@@ -2657,10 +2843,20 @@ export class AgentSession {
2657
2843
  this._modelRuntime.unregisterProvider(name);
2658
2844
  this._refreshCurrentModelFromRegistry();
2659
2845
  },
2846
+ registerVirtualModel: (definition) => {
2847
+ this._modelRuntime.registerVirtualModel(definition);
2848
+ this._refreshCurrentModelFromRegistry();
2849
+ },
2850
+ unregisterVirtualModel: (provider, id) => {
2851
+ this._modelRuntime.unregisterVirtualModel(provider, id);
2852
+ this._refreshCurrentModelFromRegistry();
2853
+ },
2660
2854
  });
2661
2855
  }
2662
2856
  _refreshToolRegistry(options) {
2663
- const previousRegistryNames = new Set(this._toolRegistry.keys());
2857
+ // Tools that were already activated on registration. A tool whose exposure changes to
2858
+ // `direct` or `model-only` (for example from `hidden`) is activated like a new tool.
2859
+ const previousActivatedOnRegistration = new Set([...this._toolRegistry.keys()].filter((name) => this._isActivatedOnRegistration(name)));
2664
2860
  const previousActiveToolNames = this.getActiveToolNames();
2665
2861
  const allowedToolNames = this._allowedToolNames;
2666
2862
  const excludedToolNames = this._excludedToolNames;
@@ -2679,7 +2875,7 @@ export class AgentSession {
2679
2875
  name,
2680
2876
  {
2681
2877
  definition,
2682
- sourceInfo: createSyntheticSourceInfo(`<builtin:${name}>`, { source: "builtin" }),
2878
+ sourceInfo: createSyntheticSourceInfo(`${BUILTIN_PATH_PREFIX}${name}`, { source: "builtin" }),
2683
2879
  },
2684
2880
  ]));
2685
2881
  for (const tool of allCustomTools) {
@@ -2707,7 +2903,9 @@ export class AgentSession {
2707
2903
  .filter((definition) => isAllowedTool(definition.name))
2708
2904
  .map((definition) => ({
2709
2905
  definition,
2710
- sourceInfo: createSyntheticSourceInfo(`<builtin:${definition.name}>`, { source: "builtin" }),
2906
+ sourceInfo: createSyntheticSourceInfo(`${BUILTIN_PATH_PREFIX}${definition.name}`, {
2907
+ source: "builtin",
2908
+ }),
2711
2909
  })), runner);
2712
2910
  const toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));
2713
2911
  for (const tool of wrappedExtensionTools) {
@@ -2717,25 +2915,41 @@ export class AgentSession {
2717
2915
  const nextActiveToolNames = (options?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]).filter((name) => isAllowedTool(name));
2718
2916
  if (allowedToolNames) {
2719
2917
  for (const toolName of this._toolRegistry.keys()) {
2720
- if (allowedToolNames.has(toolName)) {
2918
+ // Naming a tool activates it even when it is not active by default.
2919
+ if (allowedToolNames.has(toolName) && this._isDeclarable(toolName)) {
2721
2920
  nextActiveToolNames.push(toolName);
2722
2921
  }
2723
2922
  }
2724
2923
  }
2725
2924
  else if (options?.includeAllExtensionTools) {
2726
2925
  for (const tool of wrappedExtensionTools) {
2727
- nextActiveToolNames.push(tool.name);
2926
+ if (this._isActivatedOnRegistration(tool.name))
2927
+ nextActiveToolNames.push(tool.name);
2728
2928
  }
2729
2929
  }
2730
2930
  else if (!options?.activeToolNames) {
2731
2931
  for (const toolName of this._toolRegistry.keys()) {
2732
- if (!previousRegistryNames.has(toolName)) {
2932
+ if (!previousActivatedOnRegistration.has(toolName) && this._isActivatedOnRegistration(toolName)) {
2733
2933
  nextActiveToolNames.push(toolName);
2734
2934
  }
2735
2935
  }
2736
2936
  }
2937
+ if (this.tasks.enabled &&
2938
+ this._initialActiveToolNames?.length !== 0 &&
2939
+ this._toolRegistry.has("tasks") &&
2940
+ isAllowedTool("tasks"))
2941
+ nextActiveToolNames.push("tasks");
2737
2942
  this.setActiveToolsByName([...new Set(nextActiveToolNames)]);
2738
2943
  }
2944
+ /** Whether activating the tool declares it to the model. */
2945
+ _isDeclarable(name) {
2946
+ const exposure = this._getToolExposure(name);
2947
+ return exposure === "direct" || exposure === "model-only";
2948
+ }
2949
+ /** Whether registering the tool activates it, which declares it to the model. */
2950
+ _isActivatedOnRegistration(name) {
2951
+ return this._isDeclarable(name) && this._toolDefinitions.get(name)?.definition.defaultActive !== false;
2952
+ }
2739
2953
  _buildRuntime(options) {
2740
2954
  const autoResizeImages = this.settingsManager.getImageAutoResize();
2741
2955
  const shellCommandPrefix = this.settingsManager.getShellCommandPrefix();
@@ -2750,6 +2964,7 @@ export class AgentSession {
2750
2964
  bash: { commandPrefix: shellCommandPrefix, shellPath },
2751
2965
  });
2752
2966
  this._baseToolDefinitions = new Map(Object.entries(baseToolDefinitions).map(([name, tool]) => [name, tool]));
2967
+ this._baseToolDefinitions.set("tasks", createTasksToolDefinition((callId, taskId) => this._tasksHost.delivery.prepareWait(callId, taskId)));
2753
2968
  const extensionsResult = this._resourceLoader.getExtensions();
2754
2969
  if (options.flagValues) {
2755
2970
  for (const [name, value] of options.flagValues) {
@@ -2772,26 +2987,26 @@ export class AgentSession {
2772
2987
  });
2773
2988
  }
2774
2989
  async reload(options) {
2775
- return this._withBackgroundPaused(() => this._reloadBody(options));
2990
+ return this._withTasksPaused(() => this._reloadBody(options));
2776
2991
  }
2777
2992
  async _reloadBody(options) {
2778
2993
  const oldRunner = this._extensionRunner;
2779
2994
  const previousFlagValues = oldRunner.getFlagValues();
2780
- this.background.close();
2781
- await Promise.all([this.background.shutdown(), this.abort()]);
2995
+ this.tasks.close();
2996
+ await Promise.all([this.tasks.shutdown(), this.abort()]);
2782
2997
  await emitSessionShutdownEvent(oldRunner, { type: "session_shutdown", reason: "reload" });
2783
2998
  oldRunner.invalidate();
2784
2999
  await this.settingsManager.reload();
2785
3000
  this.syncQueueModesFromSettings();
2786
3001
  resetApiProviders();
2787
3002
  await this._resourceLoader.reload();
2788
- this._backgroundHost.replaceService();
3003
+ this._tasksHost.replaceService();
2789
3004
  this._buildRuntime({
2790
3005
  activeToolNames: this.getActiveToolNames(),
2791
3006
  flagValues: previousFlagValues,
2792
3007
  includeAllExtensionTools: true,
2793
3008
  });
2794
- const hasBindings = this.background.enabled ||
3009
+ const hasBindings = this.tasks.enabled ||
2795
3010
  this._extensionUIContext ||
2796
3011
  this._extensionCommandContextActions ||
2797
3012
  this._extensionShutdownHandler ||
@@ -2799,6 +3014,7 @@ export class AgentSession {
2799
3014
  if (hasBindings) {
2800
3015
  await options?.beforeSessionStart?.();
2801
3016
  await this._extensionRunner.emit({ type: "session_start", reason: "reload" });
3017
+ this._extensionRunner.reportUnhandledMcpServers();
2802
3018
  await this.extendResourcesFromExtensions("reload");
2803
3019
  }
2804
3020
  }
@@ -2811,7 +3027,7 @@ export class AgentSession {
2811
3027
  */
2812
3028
  _isRetryableError(message) {
2813
3029
  // Context overflow is handled by compaction, not retry.
2814
- if (isContextOverflow(message, this.model?.contextWindow ?? 0))
3030
+ if (isContextOverflow(message, (this._modelForMessage(message) ?? this.model)?.contextWindow ?? 0))
2815
3031
  return false;
2816
3032
  return isRetryableAssistantError(message);
2817
3033
  }
@@ -3066,7 +3282,7 @@ export class AgentSession {
3066
3282
  replaceInstructions,
3067
3283
  label,
3068
3284
  };
3069
- const resumeBackground = this.pauseBackgroundNotifications();
3285
+ const resumeBackground = this.pauseTaskNotifications();
3070
3286
  // Set up abort controller for summarization
3071
3287
  this._branchSummaryAbortController = new AbortController();
3072
3288
  try {
@@ -3102,15 +3318,11 @@ export class AgentSession {
3102
3318
  let summaryDetails;
3103
3319
  let summaryUsage;
3104
3320
  if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
3105
- const model = this.model;
3106
- const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(model);
3321
+ const signal = this._branchSummaryAbortController.signal;
3107
3322
  const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
3108
3323
  const result = await generateBranchSummary(entriesToSummarize, {
3109
- model: requestModel,
3110
- apiKey,
3111
- headers,
3112
- env,
3113
- signal: this._branchSummaryAbortController.signal,
3324
+ ...(await this._getSummarizationRequestAuth(this.model, signal)),
3325
+ signal,
3114
3326
  customInstructions,
3115
3327
  replaceInstructions,
3116
3328
  reserveTokens: branchSummarySettings.reserveTokens,
@@ -3153,7 +3365,7 @@ export class AgentSession {
3153
3365
  // Non-user message: leaf = selected node
3154
3366
  newLeafId = targetId;
3155
3367
  }
3156
- await this.background.cancelOutsideBranch(new Set(newLeafId === null ? [] : this.sessionManager.getBranch(newLeafId).map((entry) => entry.id)));
3368
+ await this.tasks.cancelOutsideBranch(new Set(newLeafId === null ? [] : this.sessionManager.getBranch(newLeafId).map((entry) => entry.id)));
3157
3369
  // Switch leaf (with or without summary)
3158
3370
  // Summary is attached at the navigation target position (newLeafId), not the old branch
3159
3371
  let summaryEntry;
@@ -3178,7 +3390,7 @@ export class AgentSession {
3178
3390
  if (label && !summaryText) {
3179
3391
  this.sessionManager.appendLabelChange(targetId, label);
3180
3392
  }
3181
- this._backgroundHost.restoreHistory();
3393
+ this._tasksHost.restoreHistory();
3182
3394
  // Update finalized context from the canonical session projection.
3183
3395
  this._refreshFinalizedContext();
3184
3396
  this._restoreToolsFromTranscript();
@@ -3271,7 +3483,7 @@ export class AgentSession {
3271
3483
  };
3272
3484
  }
3273
3485
  getContextUsage() {
3274
- const model = this.model;
3486
+ const model = this._limitsModel();
3275
3487
  if (!model)
3276
3488
  return undefined;
3277
3489
  const contextWindow = model.contextWindow ?? 0;
@@ -3343,16 +3555,11 @@ export class AgentSession {
3343
3555
  if (!model) {
3344
3556
  throw new Error("No model selected");
3345
3557
  }
3346
- const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(model);
3347
3558
  return generateBugReportSummary({
3559
+ ...(await this._getSummarizationRequestAuth(model, options.signal)),
3348
3560
  messages: this.messages,
3349
3561
  hint: options.hint,
3350
- model: requestModel,
3351
- apiKey,
3352
- headers,
3353
- env,
3354
3562
  signal: options.signal,
3355
- thinkingLevel: this.thinkingLevel,
3356
3563
  streamFn: this.agent.streamFunction,
3357
3564
  retry: this.settingsManager.getRetrySettings(),
3358
3565
  sessionId: this.sessionId,