@astralyn/pi 0.99.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (569) hide show
  1. package/CHANGELOG.md +58 -3
  2. package/dist/bundle/chunks/anthropic-messages-YET4T7BO.js +6 -0
  3. package/dist/bundle/chunks/anthropic.js +2 -2
  4. package/dist/bundle/chunks/azure-openai-responses-SBLL5YN3.js +2 -0
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +3 -3
  6. package/dist/bundle/chunks/chunk-4TT2QGFL.js +2 -0
  7. package/dist/bundle/chunks/chunk-GIG5IHES.js +2 -0
  8. package/dist/bundle/chunks/{chunk-VW2P3X6P.js → chunk-H2N2THAO.js} +436 -668
  9. package/dist/bundle/chunks/{chunk-A576H74Y.js → chunk-IZ3S3GDX.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-ABVRAYXT.js → chunk-NY3CWK44.js} +2 -2
  11. package/dist/bundle/chunks/chunk-SVJ7OGEB.js +2 -0
  12. package/dist/bundle/chunks/chunk-TRHTWM3C.js +2 -0
  13. package/dist/bundle/chunks/{chunk-DEWXBB6W.js → chunk-V66VGGOM.js} +1 -1
  14. package/dist/bundle/chunks/chunk-XDYM2567.js +20 -0
  15. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-ZYSAFXXL.js → cloudflare-workers-ai-system-one-QI46LUZ6.js} +1 -1
  16. package/dist/bundle/chunks/codemode-worker.js +90 -10
  17. package/dist/bundle/chunks/github-copilot.js +1 -1
  18. package/dist/bundle/chunks/{google-generative-ai-SDNQVVXA.js → google-generative-ai-YTZCSHQN.js} +1 -1
  19. package/dist/bundle/chunks/{google-vertex-LZXOLBIO.js → google-vertex-OTFZJJXQ.js} +1 -1
  20. package/dist/bundle/chunks/{llama-cpp-classify-7IYGGPND.js → llama-cpp-classify-R7DQLTQN.js} +1 -1
  21. package/dist/bundle/chunks/{mistral-conversations-VYKPSSAM.js → mistral-conversations-ELH4V4TY.js} +1 -1
  22. package/dist/bundle/chunks/node-USQQ7C6M.js +16 -0
  23. package/dist/bundle/chunks/openai-chatgpt.js +2 -2
  24. package/dist/bundle/chunks/{openai-codex-responses-HZ4VUDXD.js → openai-codex-responses-OLVTU4UA.js} +1 -1
  25. package/dist/bundle/chunks/openai-codex.js +1 -1
  26. package/dist/bundle/chunks/openai-completions-53M2KJ67.js +7 -0
  27. package/dist/bundle/chunks/openai-responses-4ABDEL4Z.js +3 -0
  28. package/dist/bundle/chunks/{openrouter-images-5524IQHX.js → openrouter-images-YP3YVB54.js} +1 -1
  29. package/dist/bundle/chunks/openrouter.js +1 -1
  30. package/dist/bundle/chunks/radius.js +1 -1
  31. package/dist/bundle/chunks/{typesafe-system-one-Z2CDLKEY.js → typesafe-system-one-RREJAKWB.js} +1 -1
  32. package/dist/bundle/chunks/virtual-modules-YFKU7JZF.js +2 -0
  33. package/dist/bundle/cli.js +1 -1
  34. package/dist/bundle/index.js +1 -1
  35. package/dist/bundle/rpc-entry.js +1 -1
  36. package/dist/cli/args.d.ts.map +1 -1
  37. package/dist/cli/args.js +5 -2
  38. package/dist/cli/args.js.map +1 -1
  39. package/dist/config.d.ts +5 -8
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +19 -13
  42. package/dist/config.js.map +1 -1
  43. package/dist/core/agent-session.d.ts +21 -1
  44. package/dist/core/agent-session.d.ts.map +1 -1
  45. package/dist/core/agent-session.js +65 -12
  46. package/dist/core/agent-session.js.map +1 -1
  47. package/dist/core/export-html/tool-renderer.d.ts +3 -3
  48. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  49. package/dist/core/export-html/tool-renderer.js +3 -3
  50. package/dist/core/export-html/tool-renderer.js.map +1 -1
  51. package/dist/core/extensions/index.d.ts +2 -2
  52. package/dist/core/extensions/index.d.ts.map +1 -1
  53. package/dist/core/extensions/index.js.map +1 -1
  54. package/dist/core/extensions/loader.d.ts.map +1 -1
  55. package/dist/core/extensions/loader.js +18 -1
  56. package/dist/core/extensions/loader.js.map +1 -1
  57. package/dist/core/extensions/runner.d.ts +3 -1
  58. package/dist/core/extensions/runner.d.ts.map +1 -1
  59. package/dist/core/extensions/runner.js +6 -0
  60. package/dist/core/extensions/runner.js.map +1 -1
  61. package/dist/core/extensions/types.d.ts +15 -1
  62. package/dist/core/extensions/types.d.ts.map +1 -1
  63. package/dist/core/extensions/types.js.map +1 -1
  64. package/dist/core/keybindings.d.ts +51 -11
  65. package/dist/core/keybindings.d.ts.map +1 -1
  66. package/dist/core/keybindings.js +11 -3
  67. package/dist/core/keybindings.js.map +1 -1
  68. package/dist/core/mcp-servers.d.ts +40 -7
  69. package/dist/core/mcp-servers.d.ts.map +1 -1
  70. package/dist/core/mcp-servers.js +63 -11
  71. package/dist/core/mcp-servers.js.map +1 -1
  72. package/dist/core/model-config.d.ts +36 -0
  73. package/dist/core/model-config.d.ts.map +1 -1
  74. package/dist/core/model-config.js +14 -2
  75. package/dist/core/model-config.js.map +1 -1
  76. package/dist/core/model-registry.d.ts +3 -1
  77. package/dist/core/model-registry.d.ts.map +1 -1
  78. package/dist/core/model-registry.js +4 -0
  79. package/dist/core/model-registry.js.map +1 -1
  80. package/dist/core/model-resolver.js +1 -1
  81. package/dist/core/model-resolver.js.map +1 -1
  82. package/dist/core/model-runtime.d.ts +6 -0
  83. package/dist/core/model-runtime.d.ts.map +1 -1
  84. package/dist/core/model-runtime.js +22 -18
  85. package/dist/core/model-runtime.js.map +1 -1
  86. package/dist/core/provider-composer.d.ts +2 -1
  87. package/dist/core/provider-composer.d.ts.map +1 -1
  88. package/dist/core/provider-composer.js +13 -0
  89. package/dist/core/provider-composer.js.map +1 -1
  90. package/dist/core/radius.d.ts +2 -0
  91. package/dist/core/radius.d.ts.map +1 -1
  92. package/dist/core/radius.js +2 -0
  93. package/dist/core/radius.js.map +1 -1
  94. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  95. package/dist/core/remote-catalog-provider.js +4 -9
  96. package/dist/core/remote-catalog-provider.js.map +1 -1
  97. package/dist/core/sdk.d.ts.map +1 -1
  98. package/dist/core/sdk.js +1 -0
  99. package/dist/core/sdk.js.map +1 -1
  100. package/dist/core/settings-manager.d.ts +7 -5
  101. package/dist/core/settings-manager.d.ts.map +1 -1
  102. package/dist/core/settings-manager.js +2 -1
  103. package/dist/core/settings-manager.js.map +1 -1
  104. package/dist/core/system-prompt.js +1 -1
  105. package/dist/core/system-prompt.js.map +1 -1
  106. package/dist/core/tasks/format.d.ts +7 -0
  107. package/dist/core/tasks/format.d.ts.map +1 -0
  108. package/dist/core/tasks/format.js +14 -0
  109. package/dist/core/tasks/format.js.map +1 -0
  110. package/dist/core/tasks/history.d.ts.map +1 -1
  111. package/dist/core/tasks/history.js +0 -19
  112. package/dist/core/tasks/history.js.map +1 -1
  113. package/dist/core/tasks/output.d.ts +8 -0
  114. package/dist/core/tasks/output.d.ts.map +1 -1
  115. package/dist/core/tasks/output.js +19 -0
  116. package/dist/core/tasks/output.js.map +1 -1
  117. package/dist/core/tasks/presentation.d.ts +1 -3
  118. package/dist/core/tasks/presentation.d.ts.map +1 -1
  119. package/dist/core/tasks/presentation.js +79 -166
  120. package/dist/core/tasks/presentation.js.map +1 -1
  121. package/dist/core/tasks/runtime.d.ts +16 -9
  122. package/dist/core/tasks/runtime.d.ts.map +1 -1
  123. package/dist/core/tasks/runtime.js +89 -106
  124. package/dist/core/tasks/runtime.js.map +1 -1
  125. package/dist/core/tasks/session.d.ts.map +1 -1
  126. package/dist/core/tasks/session.js +13 -4
  127. package/dist/core/tasks/session.js.map +1 -1
  128. package/dist/core/tasks/store.d.ts +20 -6
  129. package/dist/core/tasks/store.d.ts.map +1 -1
  130. package/dist/core/tasks/store.js +45 -18
  131. package/dist/core/tasks/store.js.map +1 -1
  132. package/dist/core/tasks/types.d.ts +14 -54
  133. package/dist/core/tasks/types.d.ts.map +1 -1
  134. package/dist/core/tasks/types.js +1 -5
  135. package/dist/core/tasks/types.js.map +1 -1
  136. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  137. package/dist/core/tools/renderers/bash.js +11 -34
  138. package/dist/core/tools/renderers/bash.js.map +1 -1
  139. package/dist/core/tools/renderers/index.d.ts +2 -2
  140. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  141. package/dist/core/tools/renderers/index.js.map +1 -1
  142. package/dist/core/tools/shell-execution.d.ts +0 -1
  143. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  144. package/dist/core/tools/shell-execution.js +3 -10
  145. package/dist/core/tools/shell-execution.js.map +1 -1
  146. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  147. package/dist/core/tools/shell-tool.js +2 -4
  148. package/dist/core/tools/shell-tool.js.map +1 -1
  149. package/dist/core/tools/tasks/actions.d.ts +1 -1
  150. package/dist/core/tools/tasks/actions.d.ts.map +1 -1
  151. package/dist/core/tools/tasks/actions.js +26 -12
  152. package/dist/core/tools/tasks/actions.js.map +1 -1
  153. package/dist/core/tools/tasks/constants.d.ts +2 -6
  154. package/dist/core/tools/tasks/constants.d.ts.map +1 -1
  155. package/dist/core/tools/tasks/constants.js +2 -6
  156. package/dist/core/tools/tasks/constants.js.map +1 -1
  157. package/dist/core/tools/tasks/schema.d.ts +1 -1
  158. package/dist/core/tools/tasks/schema.d.ts.map +1 -1
  159. package/dist/core/tools/tasks/schema.js +8 -7
  160. package/dist/core/tools/tasks/schema.js.map +1 -1
  161. package/dist/core/tools/tasks/types.d.ts +8 -38
  162. package/dist/core/tools/tasks/types.d.ts.map +1 -1
  163. package/dist/core/tools/tasks/types.js +6 -11
  164. package/dist/core/tools/tasks/types.js.map +1 -1
  165. package/dist/core/virtual-models.d.ts +2 -0
  166. package/dist/core/virtual-models.d.ts.map +1 -1
  167. package/dist/core/virtual-models.js +19 -12
  168. package/dist/core/virtual-models.js.map +1 -1
  169. package/dist/extensions/btw/agent.d.ts +17 -8
  170. package/dist/extensions/btw/agent.d.ts.map +1 -1
  171. package/dist/extensions/btw/agent.js +74 -76
  172. package/dist/extensions/btw/agent.js.map +1 -1
  173. package/dist/extensions/btw/controller.d.ts +0 -1
  174. package/dist/extensions/btw/controller.d.ts.map +1 -1
  175. package/dist/extensions/btw/controller.js +26 -33
  176. package/dist/extensions/btw/controller.js.map +1 -1
  177. package/dist/extensions/btw/panel.d.ts +13 -14
  178. package/dist/extensions/btw/panel.d.ts.map +1 -1
  179. package/dist/extensions/btw/panel.js +38 -29
  180. package/dist/extensions/btw/panel.js.map +1 -1
  181. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  182. package/dist/extensions/codemode/execute.js +197 -51
  183. package/dist/extensions/codemode/execute.js.map +1 -1
  184. package/dist/extensions/codemode/renderer.d.ts.map +1 -1
  185. package/dist/extensions/codemode/renderer.js +43 -25
  186. package/dist/extensions/codemode/renderer.js.map +1 -1
  187. package/dist/extensions/codemode/tool.d.ts +12 -11
  188. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  189. package/dist/extensions/codemode/tool.js +73 -129
  190. package/dist/extensions/codemode/tool.js.map +1 -1
  191. package/dist/extensions/codemode/worker.d.ts +1 -1
  192. package/dist/extensions/codemode/worker.js +1 -1
  193. package/dist/extensions/codemode/worker.js.map +1 -1
  194. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  195. package/dist/extensions/index.d.ts.map +1 -1
  196. package/dist/extensions/index.js +0 -2
  197. package/dist/extensions/index.js.map +1 -1
  198. package/dist/extensions/mcp/cli.d.ts.map +1 -1
  199. package/dist/extensions/mcp/cli.js +23 -5
  200. package/dist/extensions/mcp/cli.js.map +1 -1
  201. package/dist/extensions/mcp/config.d.ts +19 -5
  202. package/dist/extensions/mcp/config.d.ts.map +1 -1
  203. package/dist/extensions/mcp/config.js +60 -12
  204. package/dist/extensions/mcp/config.js.map +1 -1
  205. package/dist/extensions/mcp/index.d.ts +36 -9
  206. package/dist/extensions/mcp/index.d.ts.map +1 -1
  207. package/dist/extensions/mcp/index.js +309 -100
  208. package/dist/extensions/mcp/index.js.map +1 -1
  209. package/dist/extensions/mcp/oauth.d.ts +14 -8
  210. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  211. package/dist/extensions/mcp/oauth.js +105 -36
  212. package/dist/extensions/mcp/oauth.js.map +1 -1
  213. package/dist/extensions/mcp/runtime.d.ts +2 -0
  214. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  215. package/dist/extensions/mcp/runtime.js +17 -9
  216. package/dist/extensions/mcp/runtime.js.map +1 -1
  217. package/dist/extensions/mcp/tools.d.ts +8 -5
  218. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  219. package/dist/extensions/mcp/tools.js +50 -26
  220. package/dist/extensions/mcp/tools.js.map +1 -1
  221. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  222. package/dist/extensions/mcp/ui.js +7 -1
  223. package/dist/extensions/mcp/ui.js.map +1 -1
  224. package/dist/extensions/provider/catalog.d.ts +8 -1
  225. package/dist/extensions/provider/catalog.d.ts.map +1 -1
  226. package/dist/extensions/provider/catalog.js +31 -0
  227. package/dist/extensions/provider/catalog.js.map +1 -1
  228. package/dist/extensions/provider/connection.d.ts +4 -1
  229. package/dist/extensions/provider/connection.d.ts.map +1 -1
  230. package/dist/extensions/provider/connection.js +1 -5
  231. package/dist/extensions/provider/connection.js.map +1 -1
  232. package/dist/extensions/provider/editing.d.ts +36 -0
  233. package/dist/extensions/provider/editing.d.ts.map +1 -0
  234. package/dist/extensions/provider/editing.js +99 -0
  235. package/dist/extensions/provider/editing.js.map +1 -0
  236. package/dist/extensions/provider/json-fields.d.ts +5 -0
  237. package/dist/extensions/provider/json-fields.d.ts.map +1 -0
  238. package/dist/extensions/provider/json-fields.js +31 -0
  239. package/dist/extensions/provider/json-fields.js.map +1 -0
  240. package/dist/extensions/provider/store.d.ts +1 -4
  241. package/dist/extensions/provider/store.d.ts.map +1 -1
  242. package/dist/extensions/provider/store.js +2 -30
  243. package/dist/extensions/provider/store.js.map +1 -1
  244. package/dist/extensions/provider/ui/builtin-data.d.ts +0 -2
  245. package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
  246. package/dist/extensions/provider/ui/builtin-data.js +14 -79
  247. package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
  248. package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
  249. package/dist/extensions/provider/ui/compat.js +6 -9
  250. package/dist/extensions/provider/ui/compat.js.map +1 -1
  251. package/dist/extensions/provider/ui/controls.d.ts +48 -0
  252. package/dist/extensions/provider/ui/controls.d.ts.map +1 -0
  253. package/dist/extensions/provider/ui/controls.js +108 -0
  254. package/dist/extensions/provider/ui/controls.js.map +1 -0
  255. package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
  256. package/dist/extensions/provider/ui/dictionary.js +6 -9
  257. package/dist/extensions/provider/ui/dictionary.js.map +1 -1
  258. package/dist/extensions/provider/ui/editor.d.ts +3 -3
  259. package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
  260. package/dist/extensions/provider/ui/editor.js +35 -140
  261. package/dist/extensions/provider/ui/editor.js.map +1 -1
  262. package/dist/extensions/provider/ui/fetch-models.d.ts +0 -3
  263. package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
  264. package/dist/extensions/provider/ui/fetch-models.js +49 -44
  265. package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
  266. package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
  267. package/dist/extensions/provider/ui/model-fields.js +11 -14
  268. package/dist/extensions/provider/ui/model-fields.js.map +1 -1
  269. package/dist/extensions/provider/ui/model-options.d.ts +4 -34
  270. package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
  271. package/dist/extensions/provider/ui/model-options.js +90 -271
  272. package/dist/extensions/provider/ui/model-options.js.map +1 -1
  273. package/dist/extensions/provider/ui/pane.d.ts +4 -18
  274. package/dist/extensions/provider/ui/pane.d.ts.map +1 -1
  275. package/dist/extensions/provider/ui/pane.js.map +1 -1
  276. package/dist/extensions/provider/ui/provider-fields.d.ts +2 -19
  277. package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
  278. package/dist/extensions/provider/ui/provider-fields.js +58 -171
  279. package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
  280. package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -1
  281. package/dist/extensions/provider/ui/thinking-map.js +6 -9
  282. package/dist/extensions/provider/ui/thinking-map.js.map +1 -1
  283. package/dist/extensions/question/detail-pane.d.ts +7 -2
  284. package/dist/extensions/question/detail-pane.d.ts.map +1 -1
  285. package/dist/extensions/question/detail-pane.js +16 -5
  286. package/dist/extensions/question/detail-pane.js.map +1 -1
  287. package/dist/extensions/question/dialog-view.d.ts +41 -0
  288. package/dist/extensions/question/dialog-view.d.ts.map +1 -0
  289. package/dist/extensions/question/dialog-view.js +329 -0
  290. package/dist/extensions/question/dialog-view.js.map +1 -0
  291. package/dist/extensions/question/dialog.d.ts +3 -3
  292. package/dist/extensions/question/dialog.d.ts.map +1 -1
  293. package/dist/extensions/question/dialog.js +220 -634
  294. package/dist/extensions/question/dialog.js.map +1 -1
  295. package/dist/extensions/question/index.d.ts.map +1 -1
  296. package/dist/extensions/question/index.js +2 -3
  297. package/dist/extensions/question/index.js.map +1 -1
  298. package/dist/extensions/question/render.d.ts.map +1 -1
  299. package/dist/extensions/question/render.js +22 -32
  300. package/dist/extensions/question/render.js.map +1 -1
  301. package/dist/extensions/question/results.d.ts.map +1 -1
  302. package/dist/extensions/question/results.js +56 -12
  303. package/dist/extensions/question/results.js.map +1 -1
  304. package/dist/extensions/question/schema.d.ts +21 -6
  305. package/dist/extensions/question/schema.d.ts.map +1 -1
  306. package/dist/extensions/question/schema.js.map +1 -1
  307. package/dist/extensions/question/state.d.ts +9 -7
  308. package/dist/extensions/question/state.d.ts.map +1 -1
  309. package/dist/extensions/question/state.js +63 -54
  310. package/dist/extensions/question/state.js.map +1 -1
  311. package/dist/extensions/question/types.d.ts +41 -18
  312. package/dist/extensions/question/types.d.ts.map +1 -1
  313. package/dist/extensions/question/types.js.map +1 -1
  314. package/dist/extensions/statusline/index.d.ts +4 -0
  315. package/dist/extensions/statusline/index.d.ts.map +1 -1
  316. package/dist/extensions/statusline/index.js +18 -355
  317. package/dist/extensions/statusline/index.js.map +1 -1
  318. package/dist/extensions/statusline/render.d.ts +19 -0
  319. package/dist/extensions/statusline/render.d.ts.map +1 -0
  320. package/dist/extensions/statusline/render.js +163 -0
  321. package/dist/extensions/statusline/render.js.map +1 -0
  322. package/dist/extensions/statusline/usage.d.ts +12 -0
  323. package/dist/extensions/statusline/usage.d.ts.map +1 -0
  324. package/dist/extensions/statusline/usage.js +36 -0
  325. package/dist/extensions/statusline/usage.js.map +1 -0
  326. package/dist/extensions/tool-search/tool.d.ts +5 -4
  327. package/dist/extensions/tool-search/tool.d.ts.map +1 -1
  328. package/dist/extensions/tool-search/tool.js +7 -28
  329. package/dist/extensions/tool-search/tool.js.map +1 -1
  330. package/dist/extensions/web-search/execute.d.ts +1 -5
  331. package/dist/extensions/web-search/execute.d.ts.map +1 -1
  332. package/dist/extensions/web-search/execute.js +4 -9
  333. package/dist/extensions/web-search/execute.js.map +1 -1
  334. package/dist/extensions/web-search/format.d.ts +12 -3
  335. package/dist/extensions/web-search/format.d.ts.map +1 -1
  336. package/dist/extensions/web-search/format.js +33 -25
  337. package/dist/extensions/web-search/format.js.map +1 -1
  338. package/dist/extensions/web-search/index.d.ts.map +1 -1
  339. package/dist/extensions/web-search/index.js +6 -29
  340. package/dist/extensions/web-search/index.js.map +1 -1
  341. package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
  342. package/dist/extensions/web-search/providers/deepseek.js +0 -1
  343. package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
  344. package/dist/extensions/web-search/providers/http.d.ts +1 -1
  345. package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
  346. package/dist/extensions/web-search/providers/http.js.map +1 -1
  347. package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
  348. package/dist/extensions/web-search/providers/minimax.js +0 -1
  349. package/dist/extensions/web-search/providers/minimax.js.map +1 -1
  350. package/dist/extensions/web-search/render.d.ts +7 -2
  351. package/dist/extensions/web-search/render.d.ts.map +1 -1
  352. package/dist/extensions/web-search/render.js +32 -4
  353. package/dist/extensions/web-search/render.js.map +1 -1
  354. package/dist/extensions/web-search/results.d.ts.map +1 -1
  355. package/dist/extensions/web-search/results.js +3 -8
  356. package/dist/extensions/web-search/results.js.map +1 -1
  357. package/dist/extensions/web-search/types.d.ts +4 -2
  358. package/dist/extensions/web-search/types.d.ts.map +1 -1
  359. package/dist/extensions/web-search/types.js.map +1 -1
  360. package/dist/index.d.ts +3 -5
  361. package/dist/index.d.ts.map +1 -1
  362. package/dist/index.js +0 -1
  363. package/dist/index.js.map +1 -1
  364. package/dist/main.d.ts.map +1 -1
  365. package/dist/main.js +6 -0
  366. package/dist/main.js.map +1 -1
  367. package/dist/modes/interactive/components/armin.d.ts +3 -0
  368. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  369. package/dist/modes/interactive/components/armin.js +7 -5
  370. package/dist/modes/interactive/components/armin.js.map +1 -1
  371. package/dist/modes/interactive/components/auth-url.d.ts +14 -0
  372. package/dist/modes/interactive/components/auth-url.d.ts.map +1 -0
  373. package/dist/modes/interactive/components/auth-url.js +34 -0
  374. package/dist/modes/interactive/components/auth-url.js.map +1 -0
  375. package/dist/modes/interactive/components/easter-egg-3d.d.ts +104 -0
  376. package/dist/modes/interactive/components/easter-egg-3d.d.ts.map +1 -0
  377. package/dist/modes/interactive/components/easter-egg-3d.js +1123 -0
  378. package/dist/modes/interactive/components/easter-egg-3d.js.map +1 -0
  379. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts +6 -0
  380. package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts.map +1 -0
  381. package/dist/modes/interactive/components/easter-egg-3d.lazy.js +24 -0
  382. package/dist/modes/interactive/components/easter-egg-3d.lazy.js.map +1 -0
  383. package/dist/modes/interactive/components/index.d.ts +0 -1
  384. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  385. package/dist/modes/interactive/components/index.js +0 -1
  386. package/dist/modes/interactive/components/index.js.map +1 -1
  387. package/dist/modes/interactive/components/login-dialog.d.ts +2 -0
  388. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/login-dialog.js +9 -5
  390. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  391. package/dist/modes/interactive/components/oauth-selector.d.ts +8 -2
  392. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  393. package/dist/modes/interactive/components/oauth-selector.js +24 -21
  394. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  395. package/dist/modes/interactive/components/pi-logo.d.ts +7 -0
  396. package/dist/modes/interactive/components/pi-logo.d.ts.map +1 -1
  397. package/dist/modes/interactive/components/pi-logo.js +13 -1
  398. package/dist/modes/interactive/components/pi-logo.js.map +1 -1
  399. package/dist/modes/interactive/components/radius-login-selector.d.ts +15 -0
  400. package/dist/modes/interactive/components/radius-login-selector.d.ts.map +1 -0
  401. package/dist/modes/interactive/components/radius-login-selector.js +83 -0
  402. package/dist/modes/interactive/components/radius-login-selector.js.map +1 -0
  403. package/dist/modes/interactive/components/settings-selector.d.ts +3 -3
  404. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  405. package/dist/modes/interactive/components/settings-selector.js +5 -5
  406. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  407. package/dist/modes/interactive/components/status-marker.d.ts +0 -2
  408. package/dist/modes/interactive/components/status-marker.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/status-marker.js +0 -4
  410. package/dist/modes/interactive/components/status-marker.js.map +1 -1
  411. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/user-message.js +5 -4
  413. package/dist/modes/interactive/components/user-message.js.map +1 -1
  414. package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
  415. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/visual-truncate.js +36 -6
  417. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  418. package/dist/modes/interactive/interactive-mode.d.ts +12 -2
  419. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  420. package/dist/modes/interactive/interactive-mode.js +180 -55
  421. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  422. package/dist/modes/interactive/tasks/completion-render.d.ts +1 -1
  423. package/dist/modes/interactive/tasks/completion-render.d.ts.map +1 -1
  424. package/dist/modes/interactive/tasks/completion-render.js +28 -82
  425. package/dist/modes/interactive/tasks/completion-render.js.map +1 -1
  426. package/dist/modes/interactive/tasks/index.d.ts.map +1 -1
  427. package/dist/modes/interactive/tasks/index.js +18 -13
  428. package/dist/modes/interactive/tasks/index.js.map +1 -1
  429. package/dist/modes/interactive/tasks/inspector.d.ts +35 -0
  430. package/dist/modes/interactive/tasks/inspector.d.ts.map +1 -0
  431. package/dist/modes/interactive/tasks/inspector.js +93 -0
  432. package/dist/modes/interactive/tasks/inspector.js.map +1 -0
  433. package/dist/modes/interactive/tasks/layout.d.ts +40 -0
  434. package/dist/modes/interactive/tasks/layout.d.ts.map +1 -0
  435. package/dist/modes/interactive/tasks/layout.js +212 -0
  436. package/dist/modes/interactive/tasks/layout.js.map +1 -0
  437. package/dist/modes/interactive/tasks/list.d.ts +21 -0
  438. package/dist/modes/interactive/tasks/list.d.ts.map +1 -0
  439. package/dist/modes/interactive/tasks/list.js +96 -0
  440. package/dist/modes/interactive/tasks/list.js.map +1 -0
  441. package/dist/modes/interactive/tasks/manager.d.ts +29 -36
  442. package/dist/modes/interactive/tasks/manager.d.ts.map +1 -1
  443. package/dist/modes/interactive/tasks/manager.js +315 -315
  444. package/dist/modes/interactive/tasks/manager.js.map +1 -1
  445. package/dist/modes/interactive/tasks/model.d.ts +21 -0
  446. package/dist/modes/interactive/tasks/model.d.ts.map +1 -0
  447. package/dist/modes/interactive/tasks/model.js +41 -0
  448. package/dist/modes/interactive/tasks/model.js.map +1 -0
  449. package/dist/modes/interactive/tasks/render.d.ts +5 -19
  450. package/dist/modes/interactive/tasks/render.d.ts.map +1 -1
  451. package/dist/modes/interactive/tasks/render.js +18 -102
  452. package/dist/modes/interactive/tasks/render.js.map +1 -1
  453. package/dist/modes/interactive/tasks/task-view.d.ts +8 -48
  454. package/dist/modes/interactive/tasks/task-view.d.ts.map +1 -1
  455. package/dist/modes/interactive/tasks/task-view.js +11 -51
  456. package/dist/modes/interactive/tasks/task-view.js.map +1 -1
  457. package/dist/modes/interactive/tasks/text.d.ts +1 -7
  458. package/dist/modes/interactive/tasks/text.d.ts.map +1 -1
  459. package/dist/modes/interactive/tasks/text.js +6 -29
  460. package/dist/modes/interactive/tasks/text.js.map +1 -1
  461. package/dist/modes/interactive/tasks/viewport.d.ts +2 -0
  462. package/dist/modes/interactive/tasks/viewport.d.ts.map +1 -1
  463. package/dist/modes/interactive/tasks/viewport.js +17 -7
  464. package/dist/modes/interactive/tasks/viewport.js.map +1 -1
  465. package/dist/modes/interactive/tasks/views.d.ts +9 -0
  466. package/dist/modes/interactive/tasks/views.d.ts.map +1 -0
  467. package/dist/modes/interactive/tasks/views.js +42 -0
  468. package/dist/modes/interactive/tasks/views.js.map +1 -0
  469. package/dist/modes/interactive/theme/system-theme.d.ts +2 -1
  470. package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -1
  471. package/dist/modes/interactive/theme/system-theme.js +16 -5
  472. package/dist/modes/interactive/theme/system-theme.js.map +1 -1
  473. package/dist/modes/interactive/tool-view/tool-execution.d.ts +4 -19
  474. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
  475. package/dist/modes/interactive/tool-view/tool-execution.js +23 -67
  476. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
  477. package/dist/utils/image-convert.d.ts +12 -0
  478. package/dist/utils/image-convert.d.ts.map +1 -1
  479. package/dist/utils/image-convert.js +45 -6
  480. package/dist/utils/image-convert.js.map +1 -1
  481. package/docs/bundled/README.md +0 -1
  482. package/docs/bundled/extensions/question.md +2 -2
  483. package/docs/bundled/extensions/statusline.md +24 -15
  484. package/docs/bundled/tasks.md +34 -48
  485. package/docs/codemode.md +207 -0
  486. package/docs/docs.json +4 -4
  487. package/docs/environment-variables.md +1 -1
  488. package/docs/extensions.md +11 -9
  489. package/docs/keybindings.md +14 -7
  490. package/docs/mcp.md +164 -82
  491. package/docs/models.md +51 -3
  492. package/docs/providers.md +8 -0
  493. package/docs/sdk.md +2 -2
  494. package/docs/session-format.md +12 -22
  495. package/docs/settings.md +4 -2
  496. package/docs/tui.md +1 -1
  497. package/docs/usage.md +6 -16
  498. package/examples/README.md +1 -1
  499. package/examples/extensions/README.md +1 -2
  500. package/examples/extensions/built-in-tool-renderer.ts +16 -40
  501. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  502. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  503. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  504. package/examples/extensions/gondolin/package-lock.json +2 -2
  505. package/examples/extensions/gondolin/package.json +1 -1
  506. package/examples/extensions/minimal-mode.ts +24 -96
  507. package/examples/extensions/sandbox/package-lock.json +2 -2
  508. package/examples/extensions/sandbox/package.json +1 -1
  509. package/examples/extensions/with-deps/package-lock.json +2 -2
  510. package/examples/extensions/with-deps/package.json +1 -1
  511. package/examples/sdk/14-codemode-mcp.ts +2 -2
  512. package/npm-shrinkwrap.json +73 -62
  513. package/package.json +11 -10
  514. package/dist/bundle/chunks/anthropic-messages-KIXY7EDT.js +0 -6
  515. package/dist/bundle/chunks/azure-openai-responses-RPBERDXD.js +0 -2
  516. package/dist/bundle/chunks/chunk-CLLDCO64.js +0 -2
  517. package/dist/bundle/chunks/chunk-PJVFYVHE.js +0 -42
  518. package/dist/bundle/chunks/chunk-UUSTLCVC.js +0 -2
  519. package/dist/bundle/chunks/chunk-VWCWZD6E.js +0 -2
  520. package/dist/bundle/chunks/node-CXWYTK2I.js +0 -16
  521. package/dist/bundle/chunks/openai-completions-SKDGF6OE.js +0 -7
  522. package/dist/bundle/chunks/openai-responses-FPML4SSG.js +0 -3
  523. package/dist/bundle/chunks/virtual-modules-TQRORWJQ.js +0 -2
  524. package/dist/core/tasks/view-data.d.ts +0 -8
  525. package/dist/core/tasks/view-data.d.ts.map +0 -1
  526. package/dist/core/tasks/view-data.js +0 -61
  527. package/dist/core/tasks/view-data.js.map +0 -1
  528. package/dist/core/tasks/view.d.ts +0 -30
  529. package/dist/core/tasks/view.d.ts.map +0 -1
  530. package/dist/core/tasks/view.js +0 -50
  531. package/dist/core/tasks/view.js.map +0 -1
  532. package/dist/core/tools/renderers/shell-task.d.ts +0 -4
  533. package/dist/core/tools/renderers/shell-task.d.ts.map +0 -1
  534. package/dist/core/tools/renderers/shell-task.js +0 -35
  535. package/dist/core/tools/renderers/shell-task.js.map +0 -1
  536. package/dist/extensions/todo/constants.d.ts +0 -16
  537. package/dist/extensions/todo/constants.d.ts.map +0 -1
  538. package/dist/extensions/todo/constants.js +0 -30
  539. package/dist/extensions/todo/constants.js.map +0 -1
  540. package/dist/extensions/todo/index.d.ts +0 -3
  541. package/dist/extensions/todo/index.d.ts.map +0 -1
  542. package/dist/extensions/todo/index.js +0 -98
  543. package/dist/extensions/todo/index.js.map +0 -1
  544. package/dist/extensions/todo/schema.d.ts +0 -60
  545. package/dist/extensions/todo/schema.d.ts.map +0 -1
  546. package/dist/extensions/todo/schema.js +0 -56
  547. package/dist/extensions/todo/schema.js.map +0 -1
  548. package/dist/extensions/todo/state.d.ts +0 -34
  549. package/dist/extensions/todo/state.d.ts.map +0 -1
  550. package/dist/extensions/todo/state.js +0 -425
  551. package/dist/extensions/todo/state.js.map +0 -1
  552. package/dist/extensions/todo/view.d.ts +0 -36
  553. package/dist/extensions/todo/view.d.ts.map +0 -1
  554. package/dist/extensions/todo/view.js +0 -580
  555. package/dist/extensions/todo/view.js.map +0 -1
  556. package/dist/extensions/todo/widget.d.ts +0 -15
  557. package/dist/extensions/todo/widget.d.ts.map +0 -1
  558. package/dist/extensions/todo/widget.js +0 -50
  559. package/dist/extensions/todo/widget.js.map +0 -1
  560. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  561. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  562. package/dist/modes/interactive/components/daxnuts.js +0 -138
  563. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  564. package/dist/modes/interactive/tasks/fallback-view.d.ts +0 -4
  565. package/dist/modes/interactive/tasks/fallback-view.d.ts.map +0 -1
  566. package/dist/modes/interactive/tasks/fallback-view.js +0 -27
  567. package/dist/modes/interactive/tasks/fallback-view.js.map +0 -1
  568. package/docs/bundled/extensions/todo.md +0 -104
  569. package/examples/extensions/todo.ts +0 -297
@@ -10,8 +10,15 @@ export interface BtwTurn {
10
10
  elapsedMs: number;
11
11
  firstAnswerMs?: number;
12
12
  }
13
+ export interface BtwConversationState {
14
+ busy: boolean;
15
+ turns: readonly BtwTurn[];
16
+ usage: Usage;
17
+ latestCacheHitPercent: number | undefined;
18
+ blockedTools: number;
19
+ }
13
20
  /** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */
14
- export declare class BtwAgent {
21
+ export declare class BtwAgent implements BtwConversationState {
15
22
  readonly turns: BtwTurn[];
16
23
  readonly usage: Usage;
17
24
  latestCacheHitPercent: number | undefined;
@@ -20,16 +27,18 @@ export declare class BtwAgent {
20
27
  private readonly unsubscribe;
21
28
  private readonly onChange;
22
29
  private readonly inputBudget;
23
- private running;
30
+ private active?;
24
31
  private disposed;
25
- private steps;
26
- private completedAnswer;
27
- private responseChars;
28
32
  constructor(snapshot: ContextSnapshot, runtime: Pick<Models, "streamSimple">, onChange: () => void);
29
33
  get busy(): boolean;
30
- /** A rejected submission stays in the editor and never enters either agent's queue. */
31
- validate(text: string): string | undefined;
32
- ask(text: string): Promise<void>;
34
+ private validate;
35
+ /** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */
36
+ startQuestion(text: string): {
37
+ error: string;
38
+ } | {
39
+ completion: Promise<void>;
40
+ };
41
+ private runQuestion;
33
42
  cancel(): void;
34
43
  dispose(): void;
35
44
  private fits;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA6B,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAYtE,MAAM,WAAW,OAAO;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAiBD,+FAA+F;AAC/F,qBAAa,QAAQ;IACpB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAM;IAC/B,QAAQ,CAAC,KAAK,QAAgB;IAC9B,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,SAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,aAAa,CAAK;gBAEd,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IA0DlG,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAapC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCtC,MAAM,IAAI,IAAI;IAQd,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,WAAW;IA2CnB,OAAO,CAAC,YAAY;CAiBpB"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA6B,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAYtE,MAAM,WAAW,OAAO;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC;CACrB;AAwBD,+FAA+F;AAC/F,qBAAa,QAAS,YAAW,oBAAoB;IACpD,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAM;IAC/B,QAAQ,CAAC,KAAK,QAAgB;IAC9B,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,SAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAC,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IAyDlG,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,OAAO,CAAC,QAAQ;IAahB,oGAAoG;IACpG,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE;YAqBhE,WAAW;IAsBzB,MAAM,IAAI,IAAI;IAOd,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,WAAW;IA8CnB,OAAO,CAAC,YAAY;CAkBpB"}
@@ -22,11 +22,7 @@ export class BtwAgent {
22
22
  this.turns = [];
23
23
  this.usage = emptyUsage();
24
24
  this.blockedTools = 0;
25
- this.running = false;
26
25
  this.disposed = false;
27
- this.steps = 0;
28
- this.completedAnswer = "";
29
- this.responseChars = 0;
30
26
  this.onChange = onChange;
31
27
  const outputReserve = Math.min(MAX_OUTPUT_RESERVE_TOKENS, snapshot.model.maxTokens, Math.max(1024, Math.floor(snapshot.model.contextWindow / 8)));
32
28
  // Leave room for the answer and estimation error; never trim the inherited prefix.
@@ -59,21 +55,19 @@ export class BtwAgent {
59
55
  runtime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),
60
56
  beforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),
61
57
  finishTurn: ({ message, toolResults, context }) => {
58
+ const question = this.active;
62
59
  // Error and aborted responses are hard exits; the step budget only counts answered turns.
63
- if (message.stopReason === "error" || message.stopReason === "aborted")
60
+ if (!question || this.disposed || message.stopReason === "error" || message.stopReason === "aborted")
64
61
  return undefined;
65
- this.steps++;
62
+ question.steps++;
66
63
  if (!toolResults.length)
67
64
  return undefined;
68
- if (this.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {
69
- const turn = this.turns.at(-1);
70
- if (turn) {
71
- turn.status = "error";
72
- turn.notice =
73
- this.steps >= MAX_MODEL_STEPS
74
- ? "Stopped after repeated tool requests. BTW can only answer from its snapshot."
75
- : "Context limit reached. Reopen /btw for a new conversation.";
76
- }
65
+ if (question.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {
66
+ question.turn.status = "error";
67
+ question.turn.notice =
68
+ question.steps >= MAX_MODEL_STEPS
69
+ ? "Stopped after repeated tool requests. BTW can only answer from its snapshot."
70
+ : "Context limit reached. Reopen /btw for a new conversation.";
77
71
  return { action: "end" };
78
72
  }
79
73
  return undefined;
@@ -82,9 +76,8 @@ export class BtwAgent {
82
76
  this.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));
83
77
  }
84
78
  get busy() {
85
- return this.running;
79
+ return this.active !== undefined;
86
80
  }
87
- /** A rejected submission stays in the editor and never enters either agent's queue. */
88
81
  validate(text) {
89
82
  if (this.disposed)
90
83
  return "This BTW conversation is closed.";
@@ -100,26 +93,32 @@ export class BtwAgent {
100
93
  }
101
94
  return undefined;
102
95
  }
103
- async ask(text) {
96
+ /** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */
97
+ startQuestion(text) {
104
98
  const error = this.validate(text);
105
99
  if (error)
106
- throw new Error(error);
107
- this.running = true;
108
- this.steps = 0;
109
- this.completedAnswer = "";
110
- this.responseChars = 0;
111
- const turn = {
112
- question: text,
113
- answer: "",
114
- thinking: "",
115
- status: "streaming",
116
- startedAt: Date.now(),
117
- elapsedMs: 0,
100
+ return { error };
101
+ const question = {
102
+ turn: {
103
+ question: text,
104
+ answer: "",
105
+ thinking: "",
106
+ status: "streaming",
107
+ startedAt: Date.now(),
108
+ elapsedMs: 0,
109
+ },
110
+ steps: 0,
111
+ completedAnswer: "",
112
+ responseChars: 0,
118
113
  };
119
- this.turns.push(turn);
120
- this.onChange();
114
+ this.active = question;
115
+ this.turns.push(question.turn);
116
+ return { completion: this.runQuestion(question) };
117
+ }
118
+ async runQuestion({ turn }) {
121
119
  try {
122
- await this.agent.prompt(text);
120
+ this.onChange();
121
+ await this.agent.prompt(turn.question);
123
122
  if (turn.status === "streaming") {
124
123
  turn.status = "done";
125
124
  if (!turn.answer)
@@ -134,7 +133,8 @@ export class BtwAgent {
134
133
  turn.notice = displayText(error instanceof Error ? error.message : String(error));
135
134
  }
136
135
  finally {
137
- this.running = false;
136
+ // Cancellation remains busy until the native Agent has fully settled.
137
+ this.active = undefined;
138
138
  turn.elapsedMs = Date.now() - turn.startedAt;
139
139
  if (this.disposed)
140
140
  this.agent.reset();
@@ -143,11 +143,9 @@ export class BtwAgent {
143
143
  }
144
144
  }
145
145
  cancel() {
146
- if (!this.busy || this.disposed)
146
+ if (!this.active || this.disposed)
147
147
  return;
148
- const turn = this.turns.at(-1);
149
- if (turn)
150
- turn.status = "cancelling";
148
+ this.active.turn.status = "cancelling";
151
149
  this.agent.abort();
152
150
  this.onChange();
153
151
  }
@@ -170,46 +168,46 @@ export class BtwAgent {
170
168
  })).tokens < this.inputBudget);
171
169
  }
172
170
  handleEvent(event) {
173
- if (this.disposed)
171
+ const question = this.active;
172
+ if (this.disposed ||
173
+ !question ||
174
+ (event.type !== "message_update" && event.type !== "message_end") ||
175
+ event.message.role !== "assistant")
174
176
  return;
175
- const turn = this.turns.at(-1);
176
- if (!turn)
177
- return;
178
- if ((event.type === "message_update" || event.type === "message_end") && event.message.role === "assistant") {
179
- const message = event.message;
180
- this.updateAnswer(turn, message);
181
- if (event.type === "message_end") {
182
- this.completedAnswer = turn.answer;
183
- this.responseChars += message.content.reduce((sum, part) => sum +
184
- (part.type === "text"
185
- ? part.text.length
186
- : part.type === "thinking"
187
- ? part.thinking.length
188
- : JSON.stringify(part.arguments).length), 0);
189
- this.blockedTools += message.content.filter((part) => part.type === "toolCall").length;
190
- const usage = message.usage;
191
- const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
192
- this.latestCacheHitPercent =
193
- (usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0
194
- ? (usage.cacheRead / promptTokens) * 100
195
- : undefined;
196
- for (const key of ["input", "output", "cacheRead", "cacheWrite", "totalTokens"])
197
- this.usage[key] += usage[key];
198
- for (const key of ["input", "output", "cacheRead", "cacheWrite", "total"])
199
- this.usage.cost[key] += usage.cost[key];
200
- if (message.stopReason === "error" || message.stopReason === "aborted") {
201
- turn.status = message.stopReason === "aborted" ? "cancelled" : "error";
202
- turn.notice ??=
203
- message.stopReason === "aborted"
204
- ? "Stopped. You can ask another question."
205
- : displayText(message.errorMessage ?? "The request failed.");
206
- }
177
+ const { turn } = question;
178
+ const message = event.message;
179
+ this.updateAnswer(question, message);
180
+ if (event.type === "message_end") {
181
+ question.completedAnswer = turn.answer;
182
+ question.responseChars += message.content.reduce((sum, part) => sum +
183
+ (part.type === "text"
184
+ ? part.text.length
185
+ : part.type === "thinking"
186
+ ? part.thinking.length
187
+ : JSON.stringify(part.arguments).length), 0);
188
+ this.blockedTools += message.content.filter((part) => part.type === "toolCall").length;
189
+ const usage = message.usage;
190
+ const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
191
+ this.latestCacheHitPercent =
192
+ (usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0
193
+ ? (usage.cacheRead / promptTokens) * 100
194
+ : undefined;
195
+ for (const key of ["input", "output", "cacheRead", "cacheWrite", "totalTokens"])
196
+ this.usage[key] += usage[key];
197
+ for (const key of ["input", "output", "cacheRead", "cacheWrite", "total"])
198
+ this.usage.cost[key] += usage.cost[key];
199
+ if (message.stopReason === "error" || message.stopReason === "aborted") {
200
+ turn.status = message.stopReason === "aborted" ? "cancelled" : "error";
201
+ turn.notice ??=
202
+ message.stopReason === "aborted"
203
+ ? "Stopped. You can ask another question."
204
+ : displayText(message.errorMessage ?? "The request failed.");
207
205
  }
208
- turn.elapsedMs = Date.now() - turn.startedAt;
209
- this.onChange();
210
206
  }
207
+ this.onChange();
211
208
  }
212
- updateAnswer(turn, message) {
209
+ updateAnswer(question, message) {
210
+ const { turn } = question;
213
211
  const text = message.content
214
212
  .filter((part) => part.type === "text")
215
213
  .map((part) => part.text)
@@ -220,9 +218,9 @@ export class BtwAgent {
220
218
  .join("");
221
219
  if (text && turn.firstAnswerMs === undefined)
222
220
  turn.firstAnswerMs = Date.now() - turn.startedAt;
223
- turn.answer = displayText([this.completedAnswer, text].filter(Boolean).join("\n\n"));
221
+ turn.answer = displayText([question.completedAnswer, text].filter(Boolean).join("\n\n"));
224
222
  turn.thinking = thinking.slice(-2000);
225
- if (this.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {
223
+ if (question.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {
226
224
  turn.notice = "Stopped at the BTW response size limit. You can ask a shorter follow-up.";
227
225
  this.agent.abort();
228
226
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tAgent,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentTool,\n\ttype AgentTurnDecision,\n} from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, Message, Models, Usage } from \"@earendil-works/pi-ai\";\nimport { normalizeContext } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport type { ContextSnapshot } from \"../../core/extensions/index.ts\";\nimport {\n\tMAX_DISPLAY_CHARS,\n\tMAX_MODEL_STEPS,\n\tMAX_OUTPUT_RESERVE_TOKENS,\n\tMAX_QUESTION_CHARS,\n\tMAX_QUESTIONS,\n\tMAX_RESPONSE_CHARS,\n\tTOOL_DENIAL,\n} from \"./constants.ts\";\nimport { createBtwMessages } from \"./snapshot.ts\";\n\nexport interface BtwTurn {\n\tquestion: string;\n\tanswer: string;\n\tthinking: string;\n\tstatus: \"streaming\" | \"cancelling\" | \"done\" | \"cancelled\" | \"error\";\n\tnotice?: string;\n\tstartedAt: number;\n\telapsedMs: number;\n\tfirstAnswerMs?: number;\n}\n\nfunction emptyUsage(): Usage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction displayText(text: string): string {\n\treturn text.length <= MAX_DISPLAY_CHARS ? text : `${text.slice(0, MAX_DISPLAY_CHARS)}\\n\\n[Display truncated]`;\n}\n\n/** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */\nexport class BtwAgent {\n\treadonly turns: BtwTurn[] = [];\n\treadonly usage = emptyUsage();\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools = 0;\n\tprivate readonly agent: Agent;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly onChange: () => void;\n\tprivate readonly inputBudget: number;\n\tprivate running = false;\n\tprivate disposed = false;\n\tprivate steps = 0;\n\tprivate completedAnswer = \"\";\n\tprivate responseChars = 0;\n\n\tconstructor(snapshot: ContextSnapshot, runtime: Pick<Models, \"streamSimple\">, onChange: () => void) {\n\t\tthis.onChange = onChange;\n\t\tconst outputReserve = Math.min(\n\t\t\tMAX_OUTPUT_RESERVE_TOKENS,\n\t\t\tsnapshot.model.maxTokens,\n\t\t\tMath.max(1024, Math.floor(snapshot.model.contextWindow / 8)),\n\t\t);\n\t\t// Leave room for the answer and estimation error; never trim the inherited prefix.\n\t\tthis.inputBudget = snapshot.model.contextWindow - outputReserve - 4096;\n\t\tconst tools: AgentTool[] = snapshot.tools.map((tool) => ({\n\t\t\t...structuredClone(tool),\n\t\t\tlabel: tool.name,\n\t\t\texecute: async () => {\n\t\t\t\t// Defense in depth: these objects never receive an original execute function.\n\t\t\t\tthrow new Error(TOOL_DENIAL);\n\t\t\t},\n\t\t}));\n\t\tthis.agent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tmodel: snapshot.model,\n\t\t\t\tthinkingLevel: snapshot.thinkingLevel,\n\t\t\t\tsystemPrompt: snapshot.systemPrompt,\n\t\t\t\ttools,\n\t\t\t\tmessages: createBtwMessages(snapshot),\n\t\t\t},\n\t\t\tsessionId: snapshot.streamOptions.sessionId ?? snapshot.sessionId,\n\t\t\ttransport: snapshot.streamOptions.transport,\n\t\t\tthinkingBudgets: snapshot.streamOptions.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: snapshot.streamOptions.maxRetryDelayMs,\n\t\t\tonPayload: snapshot.streamOptions.onPayload,\n\t\t\tonResponse: snapshot.streamOptions.onResponse,\n\t\t\tstreamFn: (model, context, options) =>\n\t\t\t\t// Keep the parent's generation settings as well as its message prefix.\n\t\t\t\t// The model's native output ceiling and our response-size guard still bound output.\n\t\t\t\truntime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),\n\t\t\tbeforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),\n\t\t\tfinishTurn: ({ message, toolResults, context }): AgentTurnDecision | undefined => {\n\t\t\t\t// Error and aborted responses are hard exits; the step budget only counts answered turns.\n\t\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") return undefined;\n\t\t\t\tthis.steps++;\n\t\t\t\tif (!toolResults.length) return undefined;\n\t\t\t\tif (this.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {\n\t\t\t\t\tconst turn = this.turns.at(-1);\n\t\t\t\t\tif (turn) {\n\t\t\t\t\t\tturn.status = \"error\";\n\t\t\t\t\t\tturn.notice =\n\t\t\t\t\t\t\tthis.steps >= MAX_MODEL_STEPS\n\t\t\t\t\t\t\t\t? \"Stopped after repeated tool requests. BTW can only answer from its snapshot.\"\n\t\t\t\t\t\t\t\t: \"Context limit reached. Reopen /btw for a new conversation.\";\n\t\t\t\t\t}\n\t\t\t\t\treturn { action: \"end\" };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t});\n\t\tthis.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.running;\n\t}\n\n\t/** A rejected submission stays in the editor and never enters either agent's queue. */\n\tvalidate(text: string): string | undefined {\n\t\tif (this.disposed) return \"This BTW conversation is closed.\";\n\t\tif (this.busy) return \"BTW is still answering. Your question is kept in the editor.\";\n\t\tif (this.turns.length >= MAX_QUESTIONS) return \"BTW conversation limit reached. Reopen /btw to start a new one.\";\n\t\tif (text.length > MAX_QUESTION_CHARS)\n\t\t\treturn `BTW questions are limited to ${MAX_QUESTION_CHARS.toLocaleString()} characters.`;\n\t\tconst question: AgentMessage = { role: \"user\", content: text, timestamp: Date.now() };\n\t\tif (!this.fits([...this.agent.state.messages, question])) {\n\t\t\treturn \"Not enough context space for this BTW question. Compact the main conversation, then reopen /btw.\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tasync ask(text: string): Promise<void> {\n\t\tconst error = this.validate(text);\n\t\tif (error) throw new Error(error);\n\t\tthis.running = true;\n\t\tthis.steps = 0;\n\t\tthis.completedAnswer = \"\";\n\t\tthis.responseChars = 0;\n\t\tconst turn: BtwTurn = {\n\t\t\tquestion: text,\n\t\t\tanswer: \"\",\n\t\t\tthinking: \"\",\n\t\t\tstatus: \"streaming\",\n\t\t\tstartedAt: Date.now(),\n\t\t\telapsedMs: 0,\n\t\t};\n\t\tthis.turns.push(turn);\n\t\tthis.onChange();\n\t\ttry {\n\t\t\tawait this.agent.prompt(text);\n\t\t\tif (turn.status === \"streaming\") {\n\t\t\t\tturn.status = \"done\";\n\t\t\t\tif (!turn.answer) turn.notice = \"The model returned no answer text.\";\n\t\t\t} else if (turn.status === \"cancelling\") {\n\t\t\t\tturn.status = \"cancelled\";\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tturn.status = \"error\";\n\t\t\tturn.notice = displayText(error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\tthis.running = false;\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tif (this.disposed) this.agent.reset();\n\t\t\telse this.onChange();\n\t\t}\n\t}\n\n\tcancel(): void {\n\t\tif (!this.busy || this.disposed) return;\n\t\tconst turn = this.turns.at(-1);\n\t\tif (turn) turn.status = \"cancelling\";\n\t\tthis.agent.abort();\n\t\tthis.onChange();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.unsubscribe();\n\t\tthis.agent.abort();\n\t\tthis.turns.length = 0;\n\t\tif (!this.busy) this.agent.reset();\n\t\t// sessionId is cache affinity shared with main. Never clean up its provider resources here.\n\t}\n\n\tprivate fits(messages: AgentMessage[]): boolean {\n\t\treturn (\n\t\t\testimateContextTokens(\n\t\t\t\tnormalizeContext({\n\t\t\t\t\tsystemPrompt: this.agent.state.systemPrompt,\n\t\t\t\t\ttools: this.agent.state.tools,\n\t\t\t\t\tmessages: messages.filter(\n\t\t\t\t\t\t(message): message is Message =>\n\t\t\t\t\t\t\tmessage.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t).tokens < this.inputBudget\n\t\t);\n\t}\n\n\tprivate handleEvent(event: AgentEvent): void {\n\t\tif (this.disposed) return;\n\t\tconst turn = this.turns.at(-1);\n\t\tif (!turn) return;\n\t\tif ((event.type === \"message_update\" || event.type === \"message_end\") && event.message.role === \"assistant\") {\n\t\t\tconst message = event.message;\n\t\t\tthis.updateAnswer(turn, message);\n\t\t\tif (event.type === \"message_end\") {\n\t\t\t\tthis.completedAnswer = turn.answer;\n\t\t\t\tthis.responseChars += message.content.reduce(\n\t\t\t\t\t(sum, part) =>\n\t\t\t\t\t\tsum +\n\t\t\t\t\t\t(part.type === \"text\"\n\t\t\t\t\t\t\t? part.text.length\n\t\t\t\t\t\t\t: part.type === \"thinking\"\n\t\t\t\t\t\t\t\t? part.thinking.length\n\t\t\t\t\t\t\t\t: JSON.stringify(part.arguments).length),\n\t\t\t\t\t0,\n\t\t\t\t);\n\t\t\t\tthis.blockedTools += message.content.filter((part) => part.type === \"toolCall\").length;\n\t\t\t\tconst usage = message.usage;\n\t\t\t\tconst promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\t\t\t\tthis.latestCacheHitPercent =\n\t\t\t\t\t(usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0\n\t\t\t\t\t\t? (usage.cacheRead / promptTokens) * 100\n\t\t\t\t\t\t: undefined;\n\t\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"totalTokens\"] as const)\n\t\t\t\t\tthis.usage[key] += usage[key];\n\t\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"total\"] as const)\n\t\t\t\t\tthis.usage.cost[key] += usage.cost[key];\n\t\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\t\tturn.status = message.stopReason === \"aborted\" ? \"cancelled\" : \"error\";\n\t\t\t\t\tturn.notice ??=\n\t\t\t\t\t\tmessage.stopReason === \"aborted\"\n\t\t\t\t\t\t\t? \"Stopped. You can ask another question.\"\n\t\t\t\t\t\t\t: displayText(message.errorMessage ?? \"The request failed.\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tthis.onChange();\n\t\t}\n\t}\n\n\tprivate updateAnswer(turn: BtwTurn, message: AssistantMessage): void {\n\t\tconst text = message.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\");\n\t\tconst thinking = message.content\n\t\t\t.filter((part) => part.type === \"thinking\")\n\t\t\t.map((part) => part.thinking)\n\t\t\t.join(\"\");\n\t\tif (text && turn.firstAnswerMs === undefined) turn.firstAnswerMs = Date.now() - turn.startedAt;\n\t\tturn.answer = displayText([this.completedAnswer, text].filter(Boolean).join(\"\\n\\n\"));\n\t\tturn.thinking = thinking.slice(-2000);\n\t\tif (this.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {\n\t\t\tturn.notice = \"Stopped at the BTW response size limit. You can ask a shorter follow-up.\";\n\t\t\tthis.agent.abort();\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tAgent,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentTool,\n\ttype AgentTurnDecision,\n} from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, Message, Models, Usage } from \"@earendil-works/pi-ai\";\nimport { normalizeContext } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport type { ContextSnapshot } from \"../../core/extensions/index.ts\";\nimport {\n\tMAX_DISPLAY_CHARS,\n\tMAX_MODEL_STEPS,\n\tMAX_OUTPUT_RESERVE_TOKENS,\n\tMAX_QUESTION_CHARS,\n\tMAX_QUESTIONS,\n\tMAX_RESPONSE_CHARS,\n\tTOOL_DENIAL,\n} from \"./constants.ts\";\nimport { createBtwMessages } from \"./snapshot.ts\";\n\nexport interface BtwTurn {\n\tquestion: string;\n\tanswer: string;\n\tthinking: string;\n\tstatus: \"streaming\" | \"cancelling\" | \"done\" | \"cancelled\" | \"error\";\n\tnotice?: string;\n\tstartedAt: number;\n\telapsedMs: number;\n\tfirstAnswerMs?: number;\n}\n\nexport interface BtwConversationState {\n\tbusy: boolean;\n\tturns: readonly BtwTurn[];\n\tusage: Usage;\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools: number;\n}\n\ninterface ActiveQuestion {\n\tturn: BtwTurn;\n\tsteps: number;\n\tcompletedAnswer: string;\n\tresponseChars: number;\n}\n\nfunction emptyUsage(): Usage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction displayText(text: string): string {\n\treturn text.length <= MAX_DISPLAY_CHARS ? text : `${text.slice(0, MAX_DISPLAY_CHARS)}\\n\\n[Display truncated]`;\n}\n\n/** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */\nexport class BtwAgent implements BtwConversationState {\n\treadonly turns: BtwTurn[] = [];\n\treadonly usage = emptyUsage();\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools = 0;\n\tprivate readonly agent: Agent;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly onChange: () => void;\n\tprivate readonly inputBudget: number;\n\tprivate active?: ActiveQuestion;\n\tprivate disposed = false;\n\n\tconstructor(snapshot: ContextSnapshot, runtime: Pick<Models, \"streamSimple\">, onChange: () => void) {\n\t\tthis.onChange = onChange;\n\t\tconst outputReserve = Math.min(\n\t\t\tMAX_OUTPUT_RESERVE_TOKENS,\n\t\t\tsnapshot.model.maxTokens,\n\t\t\tMath.max(1024, Math.floor(snapshot.model.contextWindow / 8)),\n\t\t);\n\t\t// Leave room for the answer and estimation error; never trim the inherited prefix.\n\t\tthis.inputBudget = snapshot.model.contextWindow - outputReserve - 4096;\n\t\tconst tools: AgentTool[] = snapshot.tools.map((tool) => ({\n\t\t\t...structuredClone(tool),\n\t\t\tlabel: tool.name,\n\t\t\texecute: async () => {\n\t\t\t\t// Defense in depth: these objects never receive an original execute function.\n\t\t\t\tthrow new Error(TOOL_DENIAL);\n\t\t\t},\n\t\t}));\n\t\tthis.agent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tmodel: snapshot.model,\n\t\t\t\tthinkingLevel: snapshot.thinkingLevel,\n\t\t\t\tsystemPrompt: snapshot.systemPrompt,\n\t\t\t\ttools,\n\t\t\t\tmessages: createBtwMessages(snapshot),\n\t\t\t},\n\t\t\tsessionId: snapshot.streamOptions.sessionId ?? snapshot.sessionId,\n\t\t\ttransport: snapshot.streamOptions.transport,\n\t\t\tthinkingBudgets: snapshot.streamOptions.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: snapshot.streamOptions.maxRetryDelayMs,\n\t\t\tonPayload: snapshot.streamOptions.onPayload,\n\t\t\tonResponse: snapshot.streamOptions.onResponse,\n\t\t\tstreamFn: (model, context, options) =>\n\t\t\t\t// Keep the parent's generation settings as well as its message prefix.\n\t\t\t\t// The model's native output ceiling and our response-size guard still bound output.\n\t\t\t\truntime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),\n\t\t\tbeforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),\n\t\t\tfinishTurn: ({ message, toolResults, context }): AgentTurnDecision | undefined => {\n\t\t\t\tconst question = this.active;\n\t\t\t\t// Error and aborted responses are hard exits; the step budget only counts answered turns.\n\t\t\t\tif (!question || this.disposed || message.stopReason === \"error\" || message.stopReason === \"aborted\")\n\t\t\t\t\treturn undefined;\n\t\t\t\tquestion.steps++;\n\t\t\t\tif (!toolResults.length) return undefined;\n\t\t\t\tif (question.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {\n\t\t\t\t\tquestion.turn.status = \"error\";\n\t\t\t\t\tquestion.turn.notice =\n\t\t\t\t\t\tquestion.steps >= MAX_MODEL_STEPS\n\t\t\t\t\t\t\t? \"Stopped after repeated tool requests. BTW can only answer from its snapshot.\"\n\t\t\t\t\t\t\t: \"Context limit reached. Reopen /btw for a new conversation.\";\n\t\t\t\t\treturn { action: \"end\" };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t});\n\t\tthis.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.active !== undefined;\n\t}\n\n\tprivate validate(text: string): string | undefined {\n\t\tif (this.disposed) return \"This BTW conversation is closed.\";\n\t\tif (this.busy) return \"BTW is still answering. Your question is kept in the editor.\";\n\t\tif (this.turns.length >= MAX_QUESTIONS) return \"BTW conversation limit reached. Reopen /btw to start a new one.\";\n\t\tif (text.length > MAX_QUESTION_CHARS)\n\t\t\treturn `BTW questions are limited to ${MAX_QUESTION_CHARS.toLocaleString()} characters.`;\n\t\tconst question: AgentMessage = { role: \"user\", content: text, timestamp: Date.now() };\n\t\tif (!this.fits([...this.agent.state.messages, question])) {\n\t\t\treturn \"Not enough context space for this BTW question. Compact the main conversation, then reopen /btw.\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */\n\tstartQuestion(text: string): { error: string } | { completion: Promise<void> } {\n\t\tconst error = this.validate(text);\n\t\tif (error) return { error };\n\t\tconst question: ActiveQuestion = {\n\t\t\tturn: {\n\t\t\t\tquestion: text,\n\t\t\t\tanswer: \"\",\n\t\t\t\tthinking: \"\",\n\t\t\t\tstatus: \"streaming\",\n\t\t\t\tstartedAt: Date.now(),\n\t\t\t\telapsedMs: 0,\n\t\t\t},\n\t\t\tsteps: 0,\n\t\t\tcompletedAnswer: \"\",\n\t\t\tresponseChars: 0,\n\t\t};\n\t\tthis.active = question;\n\t\tthis.turns.push(question.turn);\n\t\treturn { completion: this.runQuestion(question) };\n\t}\n\n\tprivate async runQuestion({ turn }: ActiveQuestion): Promise<void> {\n\t\ttry {\n\t\t\tthis.onChange();\n\t\t\tawait this.agent.prompt(turn.question);\n\t\t\tif (turn.status === \"streaming\") {\n\t\t\t\tturn.status = \"done\";\n\t\t\t\tif (!turn.answer) turn.notice = \"The model returned no answer text.\";\n\t\t\t} else if (turn.status === \"cancelling\") {\n\t\t\t\tturn.status = \"cancelled\";\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tturn.status = \"error\";\n\t\t\tturn.notice = displayText(error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\t// Cancellation remains busy until the native Agent has fully settled.\n\t\t\tthis.active = undefined;\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tif (this.disposed) this.agent.reset();\n\t\t\telse this.onChange();\n\t\t}\n\t}\n\n\tcancel(): void {\n\t\tif (!this.active || this.disposed) return;\n\t\tthis.active.turn.status = \"cancelling\";\n\t\tthis.agent.abort();\n\t\tthis.onChange();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.unsubscribe();\n\t\tthis.agent.abort();\n\t\tthis.turns.length = 0;\n\t\tif (!this.busy) this.agent.reset();\n\t\t// sessionId is cache affinity shared with main. Never clean up its provider resources here.\n\t}\n\n\tprivate fits(messages: AgentMessage[]): boolean {\n\t\treturn (\n\t\t\testimateContextTokens(\n\t\t\t\tnormalizeContext({\n\t\t\t\t\tsystemPrompt: this.agent.state.systemPrompt,\n\t\t\t\t\ttools: this.agent.state.tools,\n\t\t\t\t\tmessages: messages.filter(\n\t\t\t\t\t\t(message): message is Message =>\n\t\t\t\t\t\t\tmessage.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t).tokens < this.inputBudget\n\t\t);\n\t}\n\n\tprivate handleEvent(event: AgentEvent): void {\n\t\tconst question = this.active;\n\t\tif (\n\t\t\tthis.disposed ||\n\t\t\t!question ||\n\t\t\t(event.type !== \"message_update\" && event.type !== \"message_end\") ||\n\t\t\tevent.message.role !== \"assistant\"\n\t\t)\n\t\t\treturn;\n\t\tconst { turn } = question;\n\t\tconst message = event.message;\n\t\tthis.updateAnswer(question, message);\n\t\tif (event.type === \"message_end\") {\n\t\t\tquestion.completedAnswer = turn.answer;\n\t\t\tquestion.responseChars += message.content.reduce(\n\t\t\t\t(sum, part) =>\n\t\t\t\t\tsum +\n\t\t\t\t\t(part.type === \"text\"\n\t\t\t\t\t\t? part.text.length\n\t\t\t\t\t\t: part.type === \"thinking\"\n\t\t\t\t\t\t\t? part.thinking.length\n\t\t\t\t\t\t\t: JSON.stringify(part.arguments).length),\n\t\t\t\t0,\n\t\t\t);\n\t\t\tthis.blockedTools += message.content.filter((part) => part.type === \"toolCall\").length;\n\t\t\tconst usage = message.usage;\n\t\t\tconst promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\t\t\tthis.latestCacheHitPercent =\n\t\t\t\t(usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0\n\t\t\t\t\t? (usage.cacheRead / promptTokens) * 100\n\t\t\t\t\t: undefined;\n\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"totalTokens\"] as const)\n\t\t\t\tthis.usage[key] += usage[key];\n\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"total\"] as const)\n\t\t\t\tthis.usage.cost[key] += usage.cost[key];\n\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\tturn.status = message.stopReason === \"aborted\" ? \"cancelled\" : \"error\";\n\t\t\t\tturn.notice ??=\n\t\t\t\t\tmessage.stopReason === \"aborted\"\n\t\t\t\t\t\t? \"Stopped. You can ask another question.\"\n\t\t\t\t\t\t: displayText(message.errorMessage ?? \"The request failed.\");\n\t\t\t}\n\t\t}\n\t\tthis.onChange();\n\t}\n\n\tprivate updateAnswer(question: ActiveQuestion, message: AssistantMessage): void {\n\t\tconst { turn } = question;\n\t\tconst text = message.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\");\n\t\tconst thinking = message.content\n\t\t\t.filter((part) => part.type === \"thinking\")\n\t\t\t.map((part) => part.thinking)\n\t\t\t.join(\"\");\n\t\tif (text && turn.firstAnswerMs === undefined) turn.firstAnswerMs = Date.now() - turn.startedAt;\n\t\tturn.answer = displayText([question.completedAnswer, text].filter(Boolean).join(\"\\n\\n\"));\n\t\tturn.thinking = thinking.slice(-2000);\n\t\tif (question.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {\n\t\t\tturn.notice = \"Stopped at the BTW response size limit. You can ask a shorter follow-up.\";\n\t\t\tthis.agent.abort();\n\t\t}\n\t}\n}\n"]}
@@ -10,7 +10,6 @@ export declare class BtwController {
10
10
  } | undefined;
11
11
  close(): void;
12
12
  private submit;
13
- private refresh;
14
13
  private handleKey;
15
14
  }
16
15
  //# sourceMappingURL=controller.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/controller.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAa1F,4FAA4F;AAC5F,qBAAa,aAAa;IACzB,OAAO,CAAC,OAAO,CAAC,CAAe;IAEzB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyDlE,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IAU9G,KAAK,IAAI,IAAI;IAYb,OAAO,CAAC,MAAM;IAmBd,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,SAAS;CA+BjB"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/controller.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAY1F,4FAA4F;AAC5F,qBAAa,aAAa;IACzB,OAAO,CAAC,OAAO,CAAC,CAAe;IAEzB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwDlE,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IAU9G,KAAK,IAAI,IAAI;IAYb,OAAO,CAAC,MAAM;IAmBd,OAAO,CAAC,SAAS;CAgCjB"}
@@ -15,7 +15,7 @@ export class BtwController {
15
15
  ctx.ui.setEditorText("");
16
16
  const conversation = {
17
17
  ctx,
18
- state: { phase: "opening", busy: false, turns: [], blockedTools: 0 },
18
+ state: { phase: "opening" },
19
19
  };
20
20
  this.current = conversation;
21
21
  try {
@@ -30,29 +30,30 @@ export class BtwController {
30
30
  const snapshot = await pendingSnapshot;
31
31
  if (this.current !== conversation)
32
32
  return;
33
- conversation.agent = new BtwAgent(snapshot, ctx.modelRuntime, () => this.refresh(conversation));
33
+ const usesSubscription = ctx.modelRegistry.isUsingOAuth(snapshot.model);
34
34
  conversation.state = {
35
35
  phase: "ready",
36
36
  capturedAt: snapshot.capturedAt,
37
37
  model: `${snapshot.model.provider}/${snapshot.model.id}`,
38
- busy: false,
39
- turns: conversation.agent.turns,
40
- usage: conversation.agent.usage,
41
- usesSubscription: ctx.modelRegistry.isUsingOAuth(snapshot.model),
42
- blockedTools: 0,
38
+ usesSubscription,
39
+ conversation: new BtwAgent(snapshot, ctx.modelRuntime, () => {
40
+ if (this.current === conversation)
41
+ conversation.panel?.changed();
42
+ }),
43
43
  };
44
- this.refresh(conversation);
44
+ conversation.panel?.changed();
45
45
  if (question.trim()) {
46
- const result = this.submit(question.trim());
47
- if (result?.editorText && !ctx.ui.getEditorText())
46
+ const result = this.submit(conversation, question.trim());
47
+ if (result.editorText && !ctx.ui.getEditorText())
48
48
  ctx.ui.setEditorText(result.editorText);
49
49
  }
50
50
  }
51
51
  catch (error) {
52
52
  if (this.current !== conversation)
53
53
  return;
54
- conversation.state.phase = "error";
55
- conversation.state.error = error instanceof Error ? error.message : String(error);
54
+ if (conversation.state.phase === "ready")
55
+ conversation.state.conversation.dispose();
56
+ conversation.state = { phase: "error", error: error instanceof Error ? error.message : String(error) };
56
57
  conversation.panel?.changed();
57
58
  if (question && !ctx.ui.getEditorText())
58
59
  ctx.ui.setEditorText(question);
@@ -66,7 +67,7 @@ export class BtwController {
66
67
  }
67
68
  if (!this.current || event.kind !== "prompt")
68
69
  return undefined;
69
- return this.submit(event.text);
70
+ return this.submit(this.current, event.text);
70
71
  }
71
72
  close() {
72
73
  const conversation = this.current;
@@ -75,23 +76,23 @@ export class BtwController {
75
76
  this.current = undefined;
76
77
  conversation.unsubscribeKeys?.();
77
78
  conversation.panel?.dispose();
78
- conversation.agent?.dispose();
79
+ if (conversation.state.phase === "ready")
80
+ conversation.state.conversation.dispose();
79
81
  conversation.ctx.ui.setWidget(BTW_WIDGET, undefined);
80
82
  // The open panel owns the editor draft; never hand it back to the main conversation.
81
83
  conversation.ctx.ui.setEditorText("");
82
84
  }
83
- submit(text) {
84
- const conversation = this.current;
85
- if (!conversation)
86
- return undefined;
87
- const error = conversation.agent?.validate(text) ??
88
- (conversation.agent ? undefined : "BTW is not ready. Reopen /btw if context preparation failed.");
89
- if (error) {
90
- conversation.ctx.ui.notify(error, "warning");
85
+ submit(conversation, text) {
86
+ const { state } = conversation;
87
+ const result = state.phase === "ready"
88
+ ? state.conversation.startQuestion(text)
89
+ : { error: "BTW is not ready. Reopen /btw if context preparation failed." };
90
+ if ("error" in result) {
91
+ conversation.ctx.ui.notify(result.error, "warning");
91
92
  return { handled: true, editorText: text };
92
93
  }
93
94
  conversation.panel?.followTail();
94
- void conversation.agent.ask(text).catch((error) => {
95
+ void result.completion.catch((error) => {
95
96
  if (this.current !== conversation)
96
97
  return;
97
98
  conversation.ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
@@ -100,14 +101,6 @@ export class BtwController {
100
101
  });
101
102
  return { handled: true };
102
103
  }
103
- refresh(conversation) {
104
- if (this.current !== conversation)
105
- return;
106
- conversation.state.busy = conversation.agent?.busy ?? false;
107
- conversation.state.blockedTools = conversation.agent?.blockedTools ?? 0;
108
- conversation.state.latestCacheHitPercent = conversation.agent?.latestCacheHitPercent;
109
- conversation.panel?.changed();
110
- }
111
104
  handleKey(conversation, data) {
112
105
  if (this.current !== conversation)
113
106
  return undefined;
@@ -117,8 +110,8 @@ export class BtwController {
117
110
  return { consume: true };
118
111
  }
119
112
  if (keys.matches(data, "app.btw.cancel")) {
120
- if (conversation.agent?.busy)
121
- conversation.agent.cancel();
113
+ if (conversation.state.phase === "ready" && conversation.state.conversation.busy)
114
+ conversation.state.conversation.cancel();
122
115
  else
123
116
  this.close();
124
117
  return { consume: true };
@@ -1 +1 @@
1
- {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/extensions/btw/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import \"./keybindings.ts\";\nimport { getKeybindings } from \"@earendil-works/pi-tui\";\nimport type { EditorSubmitEvent, ExtensionContext } from \"../../core/extensions/index.ts\";\nimport { BtwAgent } from \"./agent.ts\";\nimport { BTW_WIDGET } from \"./constants.ts\";\nimport { BtwPanel, type BtwPanelState } from \"./panel.ts\";\n\ninterface Conversation {\n\tctx: ExtensionContext;\n\tstate: BtwPanelState;\n\tpanel?: BtwPanel;\n\tagent?: BtwAgent;\n\tunsubscribeKeys?: () => void;\n}\n\n/** A conversation object's identity guards all callbacks across close/reopen and reload. */\nexport class BtwController {\n\tprivate current?: Conversation;\n\n\tasync open(question: string, ctx: ExtensionContext): Promise<void> {\n\t\tconst editorHost = ctx.ui.editorHost;\n\t\tif (!editorHost) {\n\t\t\tctx.ui.notify(\"/btw is available in interactive mode.\", \"warning\");\n\t\t\treturn;\n\t\t}\n\t\tthis.close();\n\t\tctx.ui.setEditorText(\"\");\n\t\tconst conversation: Conversation = {\n\t\t\tctx,\n\t\t\tstate: { phase: \"opening\", busy: false, turns: [], blockedTools: 0 },\n\t\t};\n\t\tthis.current = conversation;\n\t\ttry {\n\t\t\t// Calling now fixes source state before UI setup or asynchronous preparation.\n\t\t\tconst pendingSnapshot = ctx.getContextSnapshot();\n\t\t\tctx.ui.setWidget(\n\t\t\t\tBTW_WIDGET,\n\t\t\t\t(tui) => {\n\t\t\t\t\tconst panel = new BtwPanel(\n\t\t\t\t\t\ttui,\n\t\t\t\t\t\t() => ctx.ui.theme,\n\t\t\t\t\t\t() => conversation.state,\n\t\t\t\t\t);\n\t\t\t\t\tconversation.panel = panel;\n\t\t\t\t\treturn panel;\n\t\t\t\t},\n\t\t\t\t{ placement: \"aboveEditor\" },\n\t\t\t);\n\t\t\tconversation.unsubscribeKeys = editorHost.onInput((data) => this.handleKey(conversation, data));\n\t\t\tconst snapshot = await pendingSnapshot;\n\t\t\tif (this.current !== conversation) return;\n\t\t\tconversation.agent = new BtwAgent(snapshot, ctx.modelRuntime, () => this.refresh(conversation));\n\t\t\tconversation.state = {\n\t\t\t\tphase: \"ready\",\n\t\t\t\tcapturedAt: snapshot.capturedAt,\n\t\t\t\tmodel: `${snapshot.model.provider}/${snapshot.model.id}`,\n\t\t\t\tbusy: false,\n\t\t\t\tturns: conversation.agent.turns,\n\t\t\t\tusage: conversation.agent.usage,\n\t\t\t\tusesSubscription: ctx.modelRegistry.isUsingOAuth(snapshot.model),\n\t\t\t\tblockedTools: 0,\n\t\t\t};\n\t\t\tthis.refresh(conversation);\n\t\t\tif (question.trim()) {\n\t\t\t\tconst result = this.submit(question.trim());\n\t\t\t\tif (result?.editorText && !ctx.ui.getEditorText()) ctx.ui.setEditorText(result.editorText);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (this.current !== conversation) return;\n\t\t\tconversation.state.phase = \"error\";\n\t\t\tconversation.state.error = error instanceof Error ? error.message : String(error);\n\t\t\tconversation.panel?.changed();\n\t\t\tif (question && !ctx.ui.getEditorText()) ctx.ui.setEditorText(question);\n\t\t}\n\t}\n\n\tintercept(event: EditorSubmitEvent, ctx: ExtensionContext): { handled: true; editorText?: string } | undefined {\n\t\tconst command = /^\\/btw(?:\\s+([\\s\\S]*))?$/.exec(event.text);\n\t\tif (command) {\n\t\t\tvoid this.open(command[1] ?? \"\", ctx);\n\t\t\treturn { handled: true };\n\t\t}\n\t\tif (!this.current || event.kind !== \"prompt\") return undefined;\n\t\treturn this.submit(event.text);\n\t}\n\n\tclose(): void {\n\t\tconst conversation = this.current;\n\t\tif (!conversation) return;\n\t\tthis.current = undefined;\n\t\tconversation.unsubscribeKeys?.();\n\t\tconversation.panel?.dispose();\n\t\tconversation.agent?.dispose();\n\t\tconversation.ctx.ui.setWidget(BTW_WIDGET, undefined);\n\t\t// The open panel owns the editor draft; never hand it back to the main conversation.\n\t\tconversation.ctx.ui.setEditorText(\"\");\n\t}\n\n\tprivate submit(text: string): { handled: true; editorText?: string } | undefined {\n\t\tconst conversation = this.current;\n\t\tif (!conversation) return undefined;\n\t\tconst error =\n\t\t\tconversation.agent?.validate(text) ??\n\t\t\t(conversation.agent ? undefined : \"BTW is not ready. Reopen /btw if context preparation failed.\");\n\t\tif (error) {\n\t\t\tconversation.ctx.ui.notify(error, \"warning\");\n\t\t\treturn { handled: true, editorText: text };\n\t\t}\n\t\tconversation.panel?.followTail();\n\t\tvoid conversation.agent!.ask(text).catch((error: unknown) => {\n\t\t\tif (this.current !== conversation) return;\n\t\t\tconversation.ctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\tif (!conversation.ctx.ui.getEditorText()) conversation.ctx.ui.setEditorText(text);\n\t\t});\n\t\treturn { handled: true };\n\t}\n\n\tprivate refresh(conversation: Conversation): void {\n\t\tif (this.current !== conversation) return;\n\t\tconversation.state.busy = conversation.agent?.busy ?? false;\n\t\tconversation.state.blockedTools = conversation.agent?.blockedTools ?? 0;\n\t\tconversation.state.latestCacheHitPercent = conversation.agent?.latestCacheHitPercent;\n\t\tconversation.panel?.changed();\n\t}\n\n\tprivate handleKey(conversation: Conversation, data: string): { consume: true } | undefined {\n\t\tif (this.current !== conversation) return undefined;\n\t\tconst keys = getKeybindings();\n\t\tif (keys.matches(data, \"app.btw.close\")) {\n\t\t\tthis.close();\n\t\t\treturn { consume: true };\n\t\t}\n\t\tif (keys.matches(data, \"app.btw.cancel\")) {\n\t\t\tif (conversation.agent?.busy) conversation.agent.cancel();\n\t\t\telse this.close();\n\t\t\treturn { consume: true };\n\t\t}\n\t\t// Main prompt history never belongs in this editor mode, including explicit\n\t\t// history bindings. Autocomplete/dialog input is excluded by the host scope.\n\t\tif (keys.matches(data, \"tui.editor.historyPrevious\") || keys.matches(data, \"tui.editor.historyNext\")) {\n\t\t\treturn { consume: true };\n\t\t}\n\t\tconst direction = keys.matches(data, \"app.btw.scrollUp\") ? -1 : keys.matches(data, \"app.btw.scrollDown\") ? 1 : 0;\n\t\tconst cursorUp = keys.matches(data, \"tui.editor.cursorUp\");\n\t\tconst cursorDown = keys.matches(data, \"tui.editor.cursorDown\");\n\t\tif (!conversation.ctx.ui.getEditorText()) {\n\t\t\tif (direction) conversation.panel?.scroll(direction);\n\t\t\tif (direction || cursorUp || cursorDown) return { consume: true };\n\t\t} else if (cursorUp || cursorDown) {\n\t\t\tconst cursor = conversation.ctx.ui.editorHost?.getCursor();\n\t\t\t// The native editor browses history on Up at the start of the draft.\n\t\t\t// Let it keep normal movement within multiline and wrapped drafts.\n\t\t\tif (!cursor || (cursorUp && cursor.line === 0 && cursor.col === 0)) return { consume: true };\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/extensions/btw/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import \"./keybindings.ts\";\nimport { getKeybindings } from \"@earendil-works/pi-tui\";\nimport type { EditorSubmitEvent, ExtensionContext } from \"../../core/extensions/index.ts\";\nimport { BtwAgent } from \"./agent.ts\";\nimport { BTW_WIDGET } from \"./constants.ts\";\nimport { BtwPanel, type BtwPanelState } from \"./panel.ts\";\n\ninterface Conversation {\n\tctx: ExtensionContext;\n\tstate: BtwPanelState<BtwAgent>;\n\tpanel?: BtwPanel;\n\tunsubscribeKeys?: () => void;\n}\n\n/** A conversation object's identity guards all callbacks across close/reopen and reload. */\nexport class BtwController {\n\tprivate current?: Conversation;\n\n\tasync open(question: string, ctx: ExtensionContext): Promise<void> {\n\t\tconst editorHost = ctx.ui.editorHost;\n\t\tif (!editorHost) {\n\t\t\tctx.ui.notify(\"/btw is available in interactive mode.\", \"warning\");\n\t\t\treturn;\n\t\t}\n\t\tthis.close();\n\t\tctx.ui.setEditorText(\"\");\n\t\tconst conversation: Conversation = {\n\t\t\tctx,\n\t\t\tstate: { phase: \"opening\" },\n\t\t};\n\t\tthis.current = conversation;\n\t\ttry {\n\t\t\t// Calling now fixes source state before UI setup or asynchronous preparation.\n\t\t\tconst pendingSnapshot = ctx.getContextSnapshot();\n\t\t\tctx.ui.setWidget(\n\t\t\t\tBTW_WIDGET,\n\t\t\t\t(tui) => {\n\t\t\t\t\tconst panel = new BtwPanel(\n\t\t\t\t\t\ttui,\n\t\t\t\t\t\t() => ctx.ui.theme,\n\t\t\t\t\t\t() => conversation.state,\n\t\t\t\t\t);\n\t\t\t\t\tconversation.panel = panel;\n\t\t\t\t\treturn panel;\n\t\t\t\t},\n\t\t\t\t{ placement: \"aboveEditor\" },\n\t\t\t);\n\t\t\tconversation.unsubscribeKeys = editorHost.onInput((data) => this.handleKey(conversation, data));\n\t\t\tconst snapshot = await pendingSnapshot;\n\t\t\tif (this.current !== conversation) return;\n\t\t\tconst usesSubscription = ctx.modelRegistry.isUsingOAuth(snapshot.model);\n\t\t\tconversation.state = {\n\t\t\t\tphase: \"ready\",\n\t\t\t\tcapturedAt: snapshot.capturedAt,\n\t\t\t\tmodel: `${snapshot.model.provider}/${snapshot.model.id}`,\n\t\t\t\tusesSubscription,\n\t\t\t\tconversation: new BtwAgent(snapshot, ctx.modelRuntime, () => {\n\t\t\t\t\tif (this.current === conversation) conversation.panel?.changed();\n\t\t\t\t}),\n\t\t\t};\n\t\t\tconversation.panel?.changed();\n\t\t\tif (question.trim()) {\n\t\t\t\tconst result = this.submit(conversation, question.trim());\n\t\t\t\tif (result.editorText && !ctx.ui.getEditorText()) ctx.ui.setEditorText(result.editorText);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (this.current !== conversation) return;\n\t\t\tif (conversation.state.phase === \"ready\") conversation.state.conversation.dispose();\n\t\t\tconversation.state = { phase: \"error\", error: error instanceof Error ? error.message : String(error) };\n\t\t\tconversation.panel?.changed();\n\t\t\tif (question && !ctx.ui.getEditorText()) ctx.ui.setEditorText(question);\n\t\t}\n\t}\n\n\tintercept(event: EditorSubmitEvent, ctx: ExtensionContext): { handled: true; editorText?: string } | undefined {\n\t\tconst command = /^\\/btw(?:\\s+([\\s\\S]*))?$/.exec(event.text);\n\t\tif (command) {\n\t\t\tvoid this.open(command[1] ?? \"\", ctx);\n\t\t\treturn { handled: true };\n\t\t}\n\t\tif (!this.current || event.kind !== \"prompt\") return undefined;\n\t\treturn this.submit(this.current, event.text);\n\t}\n\n\tclose(): void {\n\t\tconst conversation = this.current;\n\t\tif (!conversation) return;\n\t\tthis.current = undefined;\n\t\tconversation.unsubscribeKeys?.();\n\t\tconversation.panel?.dispose();\n\t\tif (conversation.state.phase === \"ready\") conversation.state.conversation.dispose();\n\t\tconversation.ctx.ui.setWidget(BTW_WIDGET, undefined);\n\t\t// The open panel owns the editor draft; never hand it back to the main conversation.\n\t\tconversation.ctx.ui.setEditorText(\"\");\n\t}\n\n\tprivate submit(conversation: Conversation, text: string): { handled: true; editorText?: string } {\n\t\tconst { state } = conversation;\n\t\tconst result =\n\t\t\tstate.phase === \"ready\"\n\t\t\t\t? state.conversation.startQuestion(text)\n\t\t\t\t: { error: \"BTW is not ready. Reopen /btw if context preparation failed.\" };\n\t\tif (\"error\" in result) {\n\t\t\tconversation.ctx.ui.notify(result.error, \"warning\");\n\t\t\treturn { handled: true, editorText: text };\n\t\t}\n\t\tconversation.panel?.followTail();\n\t\tvoid result.completion.catch((error: unknown) => {\n\t\t\tif (this.current !== conversation) return;\n\t\t\tconversation.ctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\tif (!conversation.ctx.ui.getEditorText()) conversation.ctx.ui.setEditorText(text);\n\t\t});\n\t\treturn { handled: true };\n\t}\n\n\tprivate handleKey(conversation: Conversation, data: string): { consume: true } | undefined {\n\t\tif (this.current !== conversation) return undefined;\n\t\tconst keys = getKeybindings();\n\t\tif (keys.matches(data, \"app.btw.close\")) {\n\t\t\tthis.close();\n\t\t\treturn { consume: true };\n\t\t}\n\t\tif (keys.matches(data, \"app.btw.cancel\")) {\n\t\t\tif (conversation.state.phase === \"ready\" && conversation.state.conversation.busy)\n\t\t\t\tconversation.state.conversation.cancel();\n\t\t\telse this.close();\n\t\t\treturn { consume: true };\n\t\t}\n\t\t// Main prompt history never belongs in this editor mode, including explicit\n\t\t// history bindings. Autocomplete/dialog input is excluded by the host scope.\n\t\tif (keys.matches(data, \"tui.editor.historyPrevious\") || keys.matches(data, \"tui.editor.historyNext\")) {\n\t\t\treturn { consume: true };\n\t\t}\n\t\tconst direction = keys.matches(data, \"app.btw.scrollUp\") ? -1 : keys.matches(data, \"app.btw.scrollDown\") ? 1 : 0;\n\t\tconst cursorUp = keys.matches(data, \"tui.editor.cursorUp\");\n\t\tconst cursorDown = keys.matches(data, \"tui.editor.cursorDown\");\n\t\tif (!conversation.ctx.ui.getEditorText()) {\n\t\t\tif (direction) conversation.panel?.scroll(direction);\n\t\t\tif (direction || cursorUp || cursorDown) return { consume: true };\n\t\t} else if (cursorUp || cursorDown) {\n\t\t\tconst cursor = conversation.ctx.ui.editorHost?.getCursor();\n\t\t\t// The native editor browses history on Up at the start of the draft.\n\t\t\t// Let it keep normal movement within multiline and wrapped drafts.\n\t\t\tif (!cursor || (cursorUp && cursor.line === 0 && cursor.col === 0)) return { consume: true };\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
@@ -1,20 +1,19 @@
1
1
  import "./keybindings.ts";
2
- import type { Usage } from "@earendil-works/pi-ai";
3
2
  import { type Component, type TUI } from "@earendil-works/pi-tui";
4
3
  import { type Theme } from "../../modes/interactive/theme/theme.ts";
5
- import type { BtwTurn } from "./agent.ts";
6
- export interface BtwPanelState {
7
- phase: "opening" | "ready" | "error";
8
- error?: string;
9
- capturedAt?: number;
10
- model?: string;
11
- busy: boolean;
12
- turns: readonly BtwTurn[];
13
- usage?: Usage;
14
- latestCacheHitPercent?: number;
15
- usesSubscription?: boolean;
16
- blockedTools: number;
17
- }
4
+ import type { BtwConversationState } from "./agent.ts";
5
+ export type BtwPanelState<Conversation extends BtwConversationState = Readonly<BtwConversationState>> = {
6
+ phase: "opening";
7
+ } | {
8
+ phase: "error";
9
+ error: string;
10
+ } | {
11
+ phase: "ready";
12
+ capturedAt: number;
13
+ model: string;
14
+ usesSubscription: boolean;
15
+ conversation: Conversation;
16
+ };
18
17
  /** A bounded, scrollable widget above the normal editor. It never takes keyboard focus. */
19
18
  export declare class BtwPanel implements Component {
20
19
  private readonly tui;
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/panel.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACN,KAAK,SAAS,EAGd,KAAK,GAAG,EAIR,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;CACrB;AAUD,2FAA2F;AAC3F,qBAAa,QAAS,YAAW,SAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0C;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAC,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAS;gBAEb,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa;IAM9G,UAAU,IAAI,IAAI;IAIlB,OAAO,IAAI,IAAI;IAef,UAAU,IAAI,IAAI;IAKlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAQ9B,OAAO,IAAI,IAAI;IAOf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAoC/B,OAAO,CAAC,IAAI;IAmDZ,OAAO,CAAC,MAAM;IAkCd,OAAO,CAAC,MAAM;CAQd"}
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/panel.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EACN,KAAK,SAAS,EAGd,KAAK,GAAG,EAIR,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,KAAK,EAAE,oBAAoB,EAAW,MAAM,YAAY,CAAC;AAEhE,MAAM,MAAM,aAAa,CAAC,YAAY,SAAS,oBAAoB,GAAG,QAAQ,CAAC,oBAAoB,CAAC,IACjG;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GACpB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IACA,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,YAAY,CAAC;CAC1B,CAAC;AAUL,2FAA2F;AAC3F,qBAAa,QAAS,YAAW,SAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0C;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4D;IACpF,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAC,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAS;gBAEb,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa;IAM9G,UAAU,IAAI,IAAI;IAIlB,OAAO,IAAI,IAAI;IAiBf,UAAU,IAAI,IAAI;IAKlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAQ9B,OAAO,IAAI,IAAI;IAOf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAqC/B,OAAO,CAAC,IAAI;IAwDZ,OAAO,CAAC,MAAM;IAoCd,OAAO,CAAC,MAAM;CAQd"}