@sheason/pi-coding-agent 0.74.1-sheason.0 → 0.78.0-sheason.0.6.0-alpha.2

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 (516) hide show
  1. package/CHANGELOG.md +256 -4
  2. package/README.md +16 -8
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/cli/args.d.ts +7 -2
  6. package/dist/cli/args.d.ts.map +1 -1
  7. package/dist/cli/args.js +49 -1
  8. package/dist/cli/args.js.map +1 -1
  9. package/dist/cli/config-selector.d.ts +2 -2
  10. package/dist/cli/config-selector.d.ts.map +1 -1
  11. package/dist/cli/config-selector.js +1 -1
  12. package/dist/cli/config-selector.js.map +1 -1
  13. package/dist/cli/file-processor.d.ts.map +1 -1
  14. package/dist/cli/file-processor.js +2 -3
  15. package/dist/cli/file-processor.js.map +1 -1
  16. package/dist/cli/initial-message.d.ts +1 -1
  17. package/dist/cli/initial-message.d.ts.map +1 -1
  18. package/dist/cli/initial-message.js.map +1 -1
  19. package/dist/cli/list-models.d.ts +1 -1
  20. package/dist/cli/list-models.d.ts.map +1 -1
  21. package/dist/cli/list-models.js.map +1 -1
  22. package/dist/cli/session-picker.d.ts +1 -1
  23. package/dist/cli/session-picker.d.ts.map +1 -1
  24. package/dist/cli/session-picker.js.map +1 -1
  25. package/dist/cli.d.ts.map +1 -1
  26. package/dist/cli.js +4 -6
  27. package/dist/cli.js.map +1 -1
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +61 -32
  30. package/dist/config.js.map +1 -1
  31. package/dist/core/agent-session-proxy.d.ts +268 -0
  32. package/dist/core/agent-session-proxy.d.ts.map +1 -0
  33. package/dist/core/agent-session-proxy.js +2 -0
  34. package/dist/core/agent-session-proxy.js.map +1 -0
  35. package/dist/core/agent-session-runtime.d.ts +10 -10
  36. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  37. package/dist/core/agent-session-runtime.js +14 -14
  38. package/dist/core/agent-session-runtime.js.map +1 -1
  39. package/dist/core/agent-session-services.d.ts +8 -7
  40. package/dist/core/agent-session-services.d.ts.map +1 -1
  41. package/dist/core/agent-session-services.js +4 -2
  42. package/dist/core/agent-session-services.js.map +1 -1
  43. package/dist/core/agent-session.d.ts +60 -27
  44. package/dist/core/agent-session.d.ts.map +1 -1
  45. package/dist/core/agent-session.js +303 -177
  46. package/dist/core/agent-session.js.map +1 -1
  47. package/dist/core/auth-guidance.d.ts.map +1 -1
  48. package/dist/core/auth-guidance.js.map +1 -1
  49. package/dist/core/auth-storage.d.ts +1 -1
  50. package/dist/core/auth-storage.d.ts.map +1 -1
  51. package/dist/core/auth-storage.js +3 -2
  52. package/dist/core/auth-storage.js.map +1 -1
  53. package/dist/core/bash-executor.d.ts +1 -1
  54. package/dist/core/bash-executor.d.ts.map +1 -1
  55. package/dist/core/bash-executor.js.map +1 -1
  56. package/dist/core/compaction/branch-summarization.d.ts +3 -3
  57. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  58. package/dist/core/compaction/branch-summarization.js.map +1 -1
  59. package/dist/core/compaction/compaction.d.ts +5 -5
  60. package/dist/core/compaction/compaction.d.ts.map +1 -1
  61. package/dist/core/compaction/compaction.js +41 -37
  62. package/dist/core/compaction/compaction.js.map +1 -1
  63. package/dist/core/compaction/index.d.ts +3 -3
  64. package/dist/core/compaction/index.d.ts.map +1 -1
  65. package/dist/core/compaction/index.js.map +1 -1
  66. package/dist/core/exec.d.ts.map +1 -1
  67. package/dist/core/exec.js.map +1 -1
  68. package/dist/core/export-html/index.d.ts +1 -1
  69. package/dist/core/export-html/index.d.ts.map +1 -1
  70. package/dist/core/export-html/index.js +8 -6
  71. package/dist/core/export-html/index.js.map +1 -1
  72. package/dist/core/export-html/template.js +23 -6
  73. package/dist/core/export-html/tool-renderer.d.ts +2 -2
  74. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  75. package/dist/core/export-html/tool-renderer.js.map +1 -1
  76. package/dist/core/extensions/index.d.ts +8 -8
  77. package/dist/core/extensions/index.d.ts.map +1 -1
  78. package/dist/core/extensions/index.js.map +1 -1
  79. package/dist/core/extensions/loader.d.ts +2 -2
  80. package/dist/core/extensions/loader.d.ts.map +1 -1
  81. package/dist/core/extensions/loader.js +17 -34
  82. package/dist/core/extensions/loader.js.map +1 -1
  83. package/dist/core/extensions/runner.d.ts +12 -7
  84. package/dist/core/extensions/runner.d.ts.map +1 -1
  85. package/dist/core/extensions/runner.js +36 -2
  86. package/dist/core/extensions/runner.js.map +1 -1
  87. package/dist/core/extensions/types.d.ts +26 -24
  88. package/dist/core/extensions/types.d.ts.map +1 -1
  89. package/dist/core/extensions/types.js.map +1 -1
  90. package/dist/core/extensions/wrapper.d.ts +2 -2
  91. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  92. package/dist/core/extensions/wrapper.js.map +1 -1
  93. package/dist/core/footer-data-provider.d.ts +3 -1
  94. package/dist/core/footer-data-provider.d.ts.map +1 -1
  95. package/dist/core/footer-data-provider.js +4 -0
  96. package/dist/core/footer-data-provider.js.map +1 -1
  97. package/dist/core/http-dispatcher.d.ts +21 -0
  98. package/dist/core/http-dispatcher.d.ts.map +1 -0
  99. package/dist/core/http-dispatcher.js +48 -0
  100. package/dist/core/http-dispatcher.js.map +1 -0
  101. package/dist/core/index.d.ts +8 -8
  102. package/dist/core/index.d.ts.map +1 -1
  103. package/dist/core/index.js.map +1 -1
  104. package/dist/core/keybindings.d.ts.map +1 -1
  105. package/dist/core/keybindings.js.map +1 -1
  106. package/dist/core/local-agent-session-proxy.d.ts +82 -0
  107. package/dist/core/local-agent-session-proxy.d.ts.map +1 -0
  108. package/dist/core/local-agent-session-proxy.js +531 -0
  109. package/dist/core/local-agent-session-proxy.js.map +1 -0
  110. package/dist/core/messages.d.ts +0 -9
  111. package/dist/core/messages.d.ts.map +1 -1
  112. package/dist/core/messages.js +0 -10
  113. package/dist/core/messages.js.map +1 -1
  114. package/dist/core/model-registry.d.ts +4 -4
  115. package/dist/core/model-registry.d.ts.map +1 -1
  116. package/dist/core/model-registry.js +72 -16
  117. package/dist/core/model-registry.js.map +1 -1
  118. package/dist/core/model-resolver.d.ts +1 -1
  119. package/dist/core/model-resolver.d.ts.map +1 -1
  120. package/dist/core/model-resolver.js +1 -1
  121. package/dist/core/model-resolver.js.map +1 -1
  122. package/dist/core/output-guard.d.ts +1 -0
  123. package/dist/core/output-guard.d.ts.map +1 -1
  124. package/dist/core/output-guard.js +52 -22
  125. package/dist/core/output-guard.js.map +1 -1
  126. package/dist/core/package-manager.d.ts +7 -1
  127. package/dist/core/package-manager.d.ts.map +1 -1
  128. package/dist/core/package-manager.js +129 -64
  129. package/dist/core/package-manager.js.map +1 -1
  130. package/dist/core/prompt-templates.d.ts +1 -1
  131. package/dist/core/prompt-templates.d.ts.map +1 -1
  132. package/dist/core/prompt-templates.js +12 -24
  133. package/dist/core/prompt-templates.js.map +1 -1
  134. package/dist/core/provider-display-names.d.ts.map +1 -1
  135. package/dist/core/provider-display-names.js +0 -1
  136. package/dist/core/provider-display-names.js.map +1 -1
  137. package/dist/core/resolve-config-value.d.ts +9 -1
  138. package/dist/core/resolve-config-value.d.ts.map +1 -1
  139. package/dist/core/resolve-config-value.js +134 -11
  140. package/dist/core/resolve-config-value.js.map +1 -1
  141. package/dist/core/resource-loader.d.ts +13 -10
  142. package/dist/core/resource-loader.d.ts.map +1 -1
  143. package/dist/core/resource-loader.js +41 -33
  144. package/dist/core/resource-loader.js.map +1 -1
  145. package/dist/core/sdk.d.ts +15 -13
  146. package/dist/core/sdk.d.ts.map +1 -1
  147. package/dist/core/sdk.js +24 -17
  148. package/dist/core/sdk.js.map +1 -1
  149. package/dist/core/session-manager.d.ts +20 -10
  150. package/dist/core/session-manager.d.ts.map +1 -1
  151. package/dist/core/session-manager.js +201 -106
  152. package/dist/core/session-manager.js.map +1 -1
  153. package/dist/core/settings-manager.d.ts +5 -0
  154. package/dist/core/settings-manager.d.ts.map +1 -1
  155. package/dist/core/settings-manager.js +31 -13
  156. package/dist/core/settings-manager.js.map +1 -1
  157. package/dist/core/skills.d.ts +2 -2
  158. package/dist/core/skills.d.ts.map +1 -1
  159. package/dist/core/skills.js +10 -27
  160. package/dist/core/skills.js.map +1 -1
  161. package/dist/core/slash-commands.d.ts +1 -1
  162. package/dist/core/slash-commands.d.ts.map +1 -1
  163. package/dist/core/slash-commands.js.map +1 -1
  164. package/dist/core/source-info.d.ts +1 -1
  165. package/dist/core/source-info.d.ts.map +1 -1
  166. package/dist/core/source-info.js.map +1 -1
  167. package/dist/core/system-prompt.d.ts +1 -1
  168. package/dist/core/system-prompt.d.ts.map +1 -1
  169. package/dist/core/system-prompt.js +16 -9
  170. package/dist/core/system-prompt.js.map +1 -1
  171. package/dist/core/telemetry.d.ts +1 -1
  172. package/dist/core/telemetry.d.ts.map +1 -1
  173. package/dist/core/telemetry.js.map +1 -1
  174. package/dist/core/tools/bash.d.ts +2 -2
  175. package/dist/core/tools/bash.d.ts.map +1 -1
  176. package/dist/core/tools/bash.js +55 -54
  177. package/dist/core/tools/bash.js.map +1 -1
  178. package/dist/core/tools/edit-diff.d.ts +3 -1
  179. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  180. package/dist/core/tools/edit-diff.js +8 -1
  181. package/dist/core/tools/edit-diff.js.map +1 -1
  182. package/dist/core/tools/edit.d.ts +5 -3
  183. package/dist/core/tools/edit.d.ts.map +1 -1
  184. package/dist/core/tools/edit.js +51 -91
  185. package/dist/core/tools/edit.js.map +1 -1
  186. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  187. package/dist/core/tools/file-mutation-queue.js +27 -12
  188. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  189. package/dist/core/tools/find.d.ts +2 -2
  190. package/dist/core/tools/find.d.ts.map +1 -1
  191. package/dist/core/tools/find.js +2 -3
  192. package/dist/core/tools/find.js.map +1 -1
  193. package/dist/core/tools/grep.d.ts +2 -2
  194. package/dist/core/tools/grep.d.ts.map +1 -1
  195. package/dist/core/tools/grep.js +3 -3
  196. package/dist/core/tools/grep.js.map +1 -1
  197. package/dist/core/tools/index.d.ts +17 -17
  198. package/dist/core/tools/index.d.ts.map +1 -1
  199. package/dist/core/tools/index.js.map +1 -1
  200. package/dist/core/tools/ls.d.ts +2 -2
  201. package/dist/core/tools/ls.d.ts.map +1 -1
  202. package/dist/core/tools/ls.js +10 -12
  203. package/dist/core/tools/ls.js.map +1 -1
  204. package/dist/core/tools/output-accumulator.d.ts +3 -1
  205. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  206. package/dist/core/tools/output-accumulator.js +9 -3
  207. package/dist/core/tools/output-accumulator.js.map +1 -1
  208. package/dist/core/tools/path-utils.d.ts +2 -0
  209. package/dist/core/tools/path-utils.d.ts.map +1 -1
  210. package/dist/core/tools/path-utils.js +39 -21
  211. package/dist/core/tools/path-utils.js.map +1 -1
  212. package/dist/core/tools/read.d.ts +2 -2
  213. package/dist/core/tools/read.d.ts.map +1 -1
  214. package/dist/core/tools/read.js +15 -15
  215. package/dist/core/tools/read.js.map +1 -1
  216. package/dist/core/tools/render-utils.d.ts +5 -2
  217. package/dist/core/tools/render-utils.d.ts.map +1 -1
  218. package/dist/core/tools/render-utils.js +17 -1
  219. package/dist/core/tools/render-utils.js.map +1 -1
  220. package/dist/core/tools/tool-definition-wrapper.d.ts +1 -1
  221. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  222. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  223. package/dist/core/tools/truncate.d.ts.map +1 -1
  224. package/dist/core/tools/truncate.js +12 -2
  225. package/dist/core/tools/truncate.js.map +1 -1
  226. package/dist/core/tools/write.d.ts +1 -1
  227. package/dist/core/tools/write.d.ts.map +1 -1
  228. package/dist/core/tools/write.js +25 -41
  229. package/dist/core/tools/write.js.map +1 -1
  230. package/dist/d-pi-worker.d.ts +12 -0
  231. package/dist/d-pi-worker.d.ts.map +1 -0
  232. package/dist/d-pi-worker.js +9 -0
  233. package/dist/d-pi-worker.js.map +1 -0
  234. package/dist/index.d.ts +30 -28
  235. package/dist/index.d.ts.map +1 -1
  236. package/dist/index.js +5 -3
  237. package/dist/index.js.map +1 -1
  238. package/dist/main.d.ts +1 -1
  239. package/dist/main.d.ts.map +1 -1
  240. package/dist/main.js +100 -39
  241. package/dist/main.js.map +1 -1
  242. package/dist/migrations.d.ts.map +1 -1
  243. package/dist/migrations.js +118 -1
  244. package/dist/migrations.js.map +1 -1
  245. package/dist/modes/connect/auth-headers.d.ts +2 -0
  246. package/dist/modes/connect/auth-headers.d.ts.map +1 -0
  247. package/dist/modes/connect/auth-headers.js +2 -0
  248. package/dist/modes/connect/auth-headers.js.map +1 -0
  249. package/dist/modes/connect/client-extension-sync.d.ts +13 -0
  250. package/dist/modes/connect/client-extension-sync.d.ts.map +1 -0
  251. package/dist/modes/connect/client-extension-sync.js +51 -0
  252. package/dist/modes/connect/client-extension-sync.js.map +1 -0
  253. package/dist/modes/connect/connect-mode.d.ts +6 -0
  254. package/dist/modes/connect/connect-mode.d.ts.map +1 -0
  255. package/dist/modes/connect/connect-mode.js +29 -0
  256. package/dist/modes/connect/connect-mode.js.map +1 -0
  257. package/dist/modes/connect/remote-agent-session-proxy.d.ts +81 -0
  258. package/dist/modes/connect/remote-agent-session-proxy.d.ts.map +1 -0
  259. package/dist/modes/connect/remote-agent-session-proxy.js +326 -0
  260. package/dist/modes/connect/remote-agent-session-proxy.js.map +1 -0
  261. package/dist/modes/connect/sse-client.d.ts +18 -0
  262. package/dist/modes/connect/sse-client.d.ts.map +1 -0
  263. package/dist/modes/connect/sse-client.js +90 -0
  264. package/dist/modes/connect/sse-client.js.map +1 -0
  265. package/dist/modes/index.d.ts +5 -5
  266. package/dist/modes/index.d.ts.map +1 -1
  267. package/dist/modes/index.js.map +1 -1
  268. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  269. package/dist/modes/interactive/components/armin.js.map +1 -1
  270. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  271. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  272. package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
  273. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  274. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  275. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  276. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  277. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  278. package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
  279. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  280. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  281. package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
  282. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  283. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  284. package/dist/modes/interactive/components/config-selector.d.ts +4 -4
  285. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  286. package/dist/modes/interactive/components/config-selector.js +8 -5
  287. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  288. package/dist/modes/interactive/components/countdown-timer.d.ts +2 -2
  289. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  290. package/dist/modes/interactive/components/countdown-timer.js +2 -2
  291. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  292. package/dist/modes/interactive/components/custom-editor.d.ts +1 -1
  293. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  294. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  295. package/dist/modes/interactive/components/custom-message.d.ts +2 -2
  296. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  297. package/dist/modes/interactive/components/custom-message.js +0 -1
  298. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  299. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  300. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  301. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  302. package/dist/modes/interactive/components/diff.js.map +1 -1
  303. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  304. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  305. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  306. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  307. package/dist/modes/interactive/components/extension-editor.d.ts +1 -1
  308. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  309. package/dist/modes/interactive/components/extension-editor.js +14 -6
  310. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  311. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  312. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  313. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  314. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  315. package/dist/modes/interactive/components/footer.d.ts +15 -4
  316. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  317. package/dist/modes/interactive/components/footer.js +126 -8
  318. package/dist/modes/interactive/components/footer.js.map +1 -1
  319. package/dist/modes/interactive/components/index.d.ts +31 -31
  320. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  321. package/dist/modes/interactive/components/index.js.map +1 -1
  322. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  323. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  324. package/dist/modes/interactive/components/login-dialog.d.ts +7 -1
  325. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/login-dialog.js +28 -5
  327. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  328. package/dist/modes/interactive/components/model-selector.d.ts +2 -2
  329. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  330. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  331. package/dist/modes/interactive/components/oauth-selector.d.ts +1 -1
  332. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  333. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  334. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  336. package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
  337. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  338. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  339. package/dist/modes/interactive/components/session-selector.d.ts +3 -3
  340. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  341. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  342. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  343. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  344. package/dist/modes/interactive/components/settings-selector.js +15 -0
  345. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  346. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  347. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  348. package/dist/modes/interactive/components/skill-invocation-message.d.ts +1 -1
  349. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  350. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  351. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  352. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  353. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  354. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  355. package/dist/modes/interactive/components/tool-execution.d.ts +1 -1
  356. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  357. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  358. package/dist/modes/interactive/components/tree-selector.d.ts +1 -1
  359. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  360. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  361. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  362. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  363. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/user-message.js.map +1 -1
  365. package/dist/modes/interactive/interactive-mode.d.ts +53 -7
  366. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  367. package/dist/modes/interactive/interactive-mode.js +1247 -205
  368. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  369. package/dist/modes/interactive/theme/dark.json +5 -4
  370. package/dist/modes/interactive/theme/light.json +5 -4
  371. package/dist/modes/interactive/theme/theme.d.ts +22 -3
  372. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  373. package/dist/modes/interactive/theme/theme.js +130 -69
  374. package/dist/modes/interactive/theme/theme.js.map +1 -1
  375. package/dist/modes/print-mode.d.ts +1 -1
  376. package/dist/modes/print-mode.d.ts.map +1 -1
  377. package/dist/modes/print-mode.js.map +1 -1
  378. package/dist/modes/rpc/rpc-client.d.ts +8 -5
  379. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  380. package/dist/modes/rpc/rpc-client.js +65 -8
  381. package/dist/modes/rpc/rpc-client.js.map +1 -1
  382. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  383. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  384. package/dist/modes/rpc/rpc-mode.js +18 -4
  385. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  386. package/dist/modes/rpc/rpc-types.d.ts +5 -4
  387. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  388. package/dist/modes/rpc/rpc-types.js.map +1 -1
  389. package/dist/modes/serve/api-handlers.d.ts +4 -0
  390. package/dist/modes/serve/api-handlers.d.ts.map +1 -0
  391. package/dist/modes/serve/api-handlers.js +324 -0
  392. package/dist/modes/serve/api-handlers.js.map +1 -0
  393. package/dist/modes/serve/http-server.d.ts +14 -0
  394. package/dist/modes/serve/http-server.d.ts.map +1 -0
  395. package/dist/modes/serve/http-server.js +94 -0
  396. package/dist/modes/serve/http-server.js.map +1 -0
  397. package/dist/modes/serve/serve-mode.d.ts +10 -0
  398. package/dist/modes/serve/serve-mode.d.ts.map +1 -0
  399. package/dist/modes/serve/serve-mode.js +217 -0
  400. package/dist/modes/serve/serve-mode.js.map +1 -0
  401. package/dist/package-manager-cli.d.ts.map +1 -1
  402. package/dist/package-manager-cli.js +62 -7
  403. package/dist/package-manager-cli.js.map +1 -1
  404. package/dist/utils/ansi.d.ts.map +1 -1
  405. package/dist/utils/ansi.js +47 -72
  406. package/dist/utils/ansi.js.map +1 -1
  407. package/dist/utils/changelog.d.ts +1 -1
  408. package/dist/utils/changelog.d.ts.map +1 -1
  409. package/dist/utils/changelog.js.map +1 -1
  410. package/dist/utils/child-process.d.ts +5 -2
  411. package/dist/utils/child-process.d.ts.map +1 -1
  412. package/dist/utils/child-process.js +9 -7
  413. package/dist/utils/child-process.js.map +1 -1
  414. package/dist/utils/clipboard-image.d.ts.map +1 -1
  415. package/dist/utils/clipboard-image.js.map +1 -1
  416. package/dist/utils/clipboard-native.d.ts +3 -1
  417. package/dist/utils/clipboard-native.d.ts.map +1 -1
  418. package/dist/utils/clipboard-native.js +14 -8
  419. package/dist/utils/clipboard-native.js.map +1 -1
  420. package/dist/utils/clipboard.d.ts.map +1 -1
  421. package/dist/utils/clipboard.js.map +1 -1
  422. package/dist/utils/deprecation.d.ts +4 -0
  423. package/dist/utils/deprecation.d.ts.map +1 -0
  424. package/dist/utils/deprecation.js +13 -0
  425. package/dist/utils/deprecation.js.map +1 -0
  426. package/dist/utils/exif-orientation.d.ts +1 -1
  427. package/dist/utils/exif-orientation.d.ts.map +1 -1
  428. package/dist/utils/exif-orientation.js.map +1 -1
  429. package/dist/utils/html.d.ts +7 -0
  430. package/dist/utils/html.d.ts.map +1 -0
  431. package/dist/utils/html.js +40 -0
  432. package/dist/utils/html.js.map +1 -0
  433. package/dist/utils/image-convert.d.ts.map +1 -1
  434. package/dist/utils/image-convert.js.map +1 -1
  435. package/dist/utils/image-resize-core.d.ts +30 -0
  436. package/dist/utils/image-resize-core.d.ts.map +1 -0
  437. package/dist/utils/image-resize-core.js +124 -0
  438. package/dist/utils/image-resize-core.js.map +1 -0
  439. package/dist/utils/image-resize-worker.d.ts +2 -0
  440. package/dist/utils/image-resize-worker.d.ts.map +1 -0
  441. package/dist/utils/image-resize-worker.js +31 -0
  442. package/dist/utils/image-resize-worker.js.map +1 -0
  443. package/dist/utils/image-resize.d.ts +7 -27
  444. package/dist/utils/image-resize.d.ts.map +1 -1
  445. package/dist/utils/image-resize.js +75 -131
  446. package/dist/utils/image-resize.js.map +1 -1
  447. package/dist/utils/json.d.ts +3 -0
  448. package/dist/utils/json.d.ts.map +1 -0
  449. package/dist/utils/json.js +7 -0
  450. package/dist/utils/json.js.map +1 -0
  451. package/dist/utils/paths.d.ts +16 -1
  452. package/dist/utils/paths.d.ts.map +1 -1
  453. package/dist/utils/paths.js +49 -7
  454. package/dist/utils/paths.js.map +1 -1
  455. package/dist/utils/shell.d.ts.map +1 -1
  456. package/dist/utils/shell.js +6 -1
  457. package/dist/utils/shell.js.map +1 -1
  458. package/dist/utils/syntax-highlight.d.ts +12 -0
  459. package/dist/utils/syntax-highlight.d.ts.map +1 -0
  460. package/dist/utils/syntax-highlight.js +118 -0
  461. package/dist/utils/syntax-highlight.js.map +1 -0
  462. package/dist/utils/tools-manager.d.ts.map +1 -1
  463. package/dist/utils/tools-manager.js +4 -1
  464. package/dist/utils/tools-manager.js.map +1 -1
  465. package/dist/utils/version-check.d.ts +2 -1
  466. package/dist/utils/version-check.d.ts.map +1 -1
  467. package/dist/utils/version-check.js +9 -4
  468. package/dist/utils/version-check.js.map +1 -1
  469. package/dist/utils/windows-self-update.d.ts +3 -0
  470. package/dist/utils/windows-self-update.d.ts.map +1 -0
  471. package/dist/utils/windows-self-update.js +77 -0
  472. package/dist/utils/windows-self-update.js.map +1 -0
  473. package/docs/custom-provider.md +111 -21
  474. package/docs/development.md +1 -1
  475. package/docs/extensions.md +13 -7
  476. package/docs/index.md +13 -3
  477. package/docs/models.md +32 -13
  478. package/docs/packages.md +9 -6
  479. package/docs/providers.md +13 -5
  480. package/docs/quickstart.md +24 -1
  481. package/docs/rpc.md +2 -1
  482. package/docs/sdk.md +8 -0
  483. package/docs/session-format.md +1 -1
  484. package/docs/sessions.md +8 -0
  485. package/docs/settings.md +8 -6
  486. package/docs/skills.md +3 -4
  487. package/docs/terminal-setup.md +8 -0
  488. package/docs/termux.md +3 -3
  489. package/docs/tui.md +2 -2
  490. package/docs/usage.md +13 -2
  491. package/examples/extensions/README.md +1 -0
  492. package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
  493. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  494. package/examples/extensions/custom-provider-anthropic/package.json +2 -2
  495. package/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
  496. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  497. package/examples/extensions/custom-provider-gitlab-duo/test.ts +1 -1
  498. package/examples/extensions/doom-overlay/doom-component.ts +2 -2
  499. package/examples/extensions/doom-overlay/index.ts +3 -3
  500. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  501. package/examples/extensions/input-transform-streaming.ts +39 -0
  502. package/examples/extensions/overlay-qa-tests.ts +97 -66
  503. package/examples/extensions/overlay-test.ts +7 -4
  504. package/examples/extensions/plan-mode/index.ts +1 -1
  505. package/examples/extensions/sandbox/package-lock.json +2 -2
  506. package/examples/extensions/sandbox/package.json +2 -2
  507. package/examples/extensions/subagent/README.md +3 -0
  508. package/examples/extensions/subagent/index.ts +42 -20
  509. package/examples/extensions/with-deps/package-lock.json +2 -2
  510. package/examples/extensions/with-deps/package.json +3 -3
  511. package/npm-shrinkwrap.json +1790 -0
  512. package/package.json +39 -32
  513. package/dist/utils/uuid.d.ts +0 -2
  514. package/dist/utils/uuid.d.ts.map +0 -1
  515. package/dist/utils/uuid.js +0 -40
  516. package/dist/utils/uuid.js.map +0 -1
@@ -13,10 +13,11 @@
13
13
  * Modes use this class and add their own I/O layer on top.
14
14
  */
15
15
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
16
- import { basename, dirname, resolve } from "node:path";
17
- import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, resetApiProviders, } from "@sheason/pi-ai";
16
+ import { basename, dirname } from "node:path";
17
+ import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, modelsAreEqual, resetApiProviders, streamSimple, } from "@sheason/pi-ai";
18
18
  import { theme } from "../modes/interactive/theme/theme.js";
19
19
  import { stripFrontmatter } from "../utils/frontmatter.js";
20
+ import { resolvePath } from "../utils/paths.js";
20
21
  import { sleep } from "../utils/sleep.js";
21
22
  import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
22
23
  import { executeBashWithOperations } from "./bash-executor.js";
@@ -64,7 +65,6 @@ export class AgentSession {
64
65
  // Event subscription state
65
66
  _unsubscribeAgent;
66
67
  _eventListeners = [];
67
- _agentEventQueue = Promise.resolve();
68
68
  /** Tracks pending steering messages for UI display. Removed when delivered. */
69
69
  _steeringMessages = [];
70
70
  /** Tracks pending follow-up messages for UI display. Removed when delivered. */
@@ -80,14 +80,14 @@ export class AgentSession {
80
80
  // Retry state
81
81
  _retryAbortController = undefined;
82
82
  _retryAttempt = 0;
83
- _retryPromise = undefined;
84
- _retryResolve = undefined;
85
83
  // Bash execution state
86
84
  _bashAbortController = undefined;
87
85
  _pendingBashMessages = [];
88
86
  // Extension system
89
87
  _extensionRunner;
90
88
  _turnIndex = 0;
89
+ /** Timestamp when the current agent run started, for per-turn TPS calculation */
90
+ _agentStartTime = undefined;
91
91
  _resourceLoader;
92
92
  _customTools;
93
93
  _baseToolDefinitions = new Map();
@@ -95,10 +95,12 @@ export class AgentSession {
95
95
  _extensionRunnerRef;
96
96
  _initialActiveToolNames;
97
97
  _allowedToolNames;
98
+ _excludedToolNames;
98
99
  _baseToolsOverride;
99
100
  _sessionStartEvent;
100
101
  _extensionUIContext;
101
102
  _extensionCommandContextActions;
103
+ _extensionAbortHandler;
102
104
  _extensionShutdownHandler;
103
105
  _extensionErrorListener;
104
106
  _extensionErrorUnsubscriber;
@@ -124,6 +126,7 @@ export class AgentSession {
124
126
  this._extensionRunnerRef = config.extensionRunnerRef;
125
127
  this._initialActiveToolNames = config.initialActiveToolNames;
126
128
  this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
129
+ this._excludedToolNames = config.excludedToolNames ? new Set(config.excludedToolNames) : undefined;
127
130
  this._baseToolsOverride = config.baseToolsOverride;
128
131
  this._sessionStartEvent = config.sessionStartEvent ?? { type: "session_start", reason: "startup" };
129
132
  // Always subscribe to agent events for internal handling
@@ -158,6 +161,13 @@ export class AgentSession {
158
161
  }
159
162
  throw new Error(formatNoApiKeyFoundMessage(model.provider));
160
163
  }
164
+ async _getCompactionRequestAuth(model) {
165
+ if (this.agent.streamFn === streamSimple) {
166
+ return this._getRequiredRequestAuth(model);
167
+ }
168
+ const result = await this._modelRegistry.getApiKeyAndHeaders(model);
169
+ return result.ok ? { apiKey: result.apiKey, headers: result.headers } : {};
170
+ }
161
171
  /**
162
172
  * Install tool hooks once on the Agent instance.
163
173
  *
@@ -172,7 +182,6 @@ export class AgentSession {
172
182
  if (!runner.hasHandlers("tool_call")) {
173
183
  return undefined;
174
184
  }
175
- await this._agentEventQueue;
176
185
  try {
177
186
  return await runner.emitToolCall({
178
187
  type: "tool_call",
@@ -228,72 +237,81 @@ export class AgentSession {
228
237
  followUp: [...this._followUpMessages],
229
238
  });
230
239
  }
240
+ /** Emit a state_update event with the current token/context/model snapshot */
241
+ _emitStateUpdate() {
242
+ const model = this.model;
243
+ const state = this.state;
244
+ // Compute cumulative token usage
245
+ let totalInput = 0;
246
+ let totalOutput = 0;
247
+ let totalCacheRead = 0;
248
+ let totalCacheWrite = 0;
249
+ let totalCost = 0;
250
+ for (const entry of this.sessionManager.getEntries()) {
251
+ if (entry.type === "message" && entry.message.role === "assistant") {
252
+ totalInput += entry.message.usage.input;
253
+ totalOutput += entry.message.usage.output;
254
+ totalCacheRead += entry.message.usage.cacheRead;
255
+ totalCacheWrite += entry.message.usage.cacheWrite;
256
+ totalCost += entry.message.usage.cost.total;
257
+ }
258
+ }
259
+ const usingSubscription = model ? this.modelRegistry.isUsingOAuth(model) : false;
260
+ const rawContextUsage = this.getContextUsage();
261
+ const snapshot = {
262
+ model: model?.id ?? "",
263
+ thinkingLevel: state.thinkingLevel,
264
+ // Note: isStreaming and isCompacting are NOT included here.
265
+ // They are managed by agent_start/agent_end and compaction_start/compaction_end events
266
+ // to avoid race conditions where a late state_update overwrites the correct state.
267
+ tokenUsage: {
268
+ input: totalInput,
269
+ output: totalOutput,
270
+ cacheRead: totalCacheRead,
271
+ cacheWrite: totalCacheWrite,
272
+ cost: totalCost,
273
+ usingSubscription,
274
+ },
275
+ contextUsage: rawContextUsage
276
+ ? {
277
+ tokens: rawContextUsage.tokens,
278
+ contextWindow: rawContextUsage.contextWindow,
279
+ percent: rawContextUsage.percent,
280
+ }
281
+ : { tokens: null, contextWindow: model?.contextWindow ?? 0, percent: null },
282
+ modelInfo: model
283
+ ? { id: model.id, provider: model.provider, reasoning: model.reasoning, contextWindow: model.contextWindow }
284
+ : { id: "", provider: "", reasoning: false, contextWindow: 0 },
285
+ autoCompactEnabled: this.autoCompactionEnabled,
286
+ cwd: this.sessionManager.getCwd(),
287
+ availableProviderCount: this.modelRegistry.getAvailable().length,
288
+ };
289
+ this._emit({ type: "state_update", snapshot });
290
+ }
231
291
  // Track last assistant message for auto-compaction check
232
292
  _lastAssistantMessage = undefined;
233
293
  /** Internal handler for agent events - shared by subscribe and reconnect */
234
- _handleAgentEvent = (event) => {
235
- // Create retry promise synchronously before queueing async processing.
236
- // Agent.emit() calls this handler synchronously, and prompt() calls waitForRetry()
237
- // as soon as agent.prompt() resolves. If _retryPromise is created only inside
238
- // _processAgentEvent, slow earlier queued events can delay agent_end processing
239
- // and waitForRetry() can miss the in-flight retry.
240
- this._createRetryPromiseForAgentEnd(event);
241
- this._agentEventQueue = this._agentEventQueue.then(() => this._processAgentEvent(event), () => this._processAgentEvent(event));
242
- // Keep queue alive if an event handler fails
243
- this._agentEventQueue.catch(() => { });
244
- };
245
- _createRetryPromiseForAgentEnd(event) {
246
- if (event.type !== "agent_end" || this._retryPromise) {
247
- return;
248
- }
249
- const settings = this.settingsManager.getRetrySettings();
250
- if (!settings.enabled) {
251
- return;
252
- }
253
- const lastAssistant = this._findLastAssistantInMessages(event.messages);
254
- if (!lastAssistant || !this._isRetryableError(lastAssistant)) {
255
- return;
256
- }
257
- this._retryPromise = new Promise((resolve) => {
258
- this._retryResolve = resolve;
259
- });
260
- }
261
- _findLastAssistantInMessages(messages) {
262
- for (let i = messages.length - 1; i >= 0; i--) {
263
- const message = messages[i];
264
- if (message.role === "assistant") {
265
- return message;
266
- }
267
- }
268
- return undefined;
269
- }
270
- async _processAgentEvent(event) {
271
- // When a user message starts, check if it's from either queue and remove it BEFORE emitting
272
- // This ensures the UI sees the updated queue state
273
- if (event.type === "message_start" && event.message.role === "user") {
274
- this._overflowRecoveryAttempted = false;
275
- const messageText = this._getUserMessageText(event.message);
294
+ _handleAgentEvent = async (event) => {
295
+ // When a queued message starts, remove it BEFORE emitting so the UI sees the updated queue state.
296
+ if (event.type === "message_start" && (event.message.role === "user" || event.message.role === "custom")) {
297
+ if (event.message.role === "user") {
298
+ this._overflowRecoveryAttempted = false;
299
+ }
300
+ const messageText = event.message.role === "user"
301
+ ? this._getUserMessageText(event.message)
302
+ : this._getCustomMessageText(event.message);
276
303
  if (messageText) {
277
- // Check steering queue first
278
- const steeringIndex = this._steeringMessages.indexOf(messageText);
279
- if (steeringIndex !== -1) {
280
- this._steeringMessages.splice(steeringIndex, 1);
281
- this._emitQueueUpdate();
282
- }
283
- else {
284
- // Check follow-up queue
285
- const followUpIndex = this._followUpMessages.indexOf(messageText);
286
- if (followUpIndex !== -1) {
287
- this._followUpMessages.splice(followUpIndex, 1);
288
- this._emitQueueUpdate();
289
- }
290
- }
304
+ this._removeQueuedMessageText(messageText);
291
305
  }
292
306
  }
307
+ // Track agent start time for per-turn TPS calculation
308
+ if (event.type === "agent_start") {
309
+ this._agentStartTime = Date.now();
310
+ }
293
311
  // Emit to extensions first
294
312
  await this._emitExtensionEvent(event);
295
313
  // Notify all listeners
296
- this._emit(event);
314
+ this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
297
315
  // Handle session persistence
298
316
  if (event.type === "message_end") {
299
317
  // Check if this is a custom message from extensions
@@ -325,40 +343,87 @@ export class AgentSession {
325
343
  });
326
344
  this._retryAttempt = 0;
327
345
  }
346
+ // Push state update (token usage changed)
347
+ this._emitStateUpdate();
328
348
  }
329
349
  }
330
- // Check auto-retry and auto-compaction after agent completes
331
- if (event.type === "agent_end" && this._lastAssistantMessage) {
332
- const msg = this._lastAssistantMessage;
333
- this._lastAssistantMessage = undefined;
334
- // Check for retryable errors first (overloaded, rate limit, server errors)
335
- if (this._isRetryableError(msg)) {
336
- const didRetry = await this._handleRetryableError(msg);
337
- if (didRetry)
338
- return; // Retry was initiated, don't proceed to compaction
350
+ else if (event.type === "agent_end") {
351
+ // Push state update (streaming ended)
352
+ this._emitStateUpdate();
353
+ // Emit per-turn stats
354
+ if (this._agentStartTime !== undefined) {
355
+ const duration = (Date.now() - this._agentStartTime) / 1000;
356
+ this._agentStartTime = undefined;
357
+ // Sum token usage from all assistant messages in this agent run
358
+ let turnInput = 0;
359
+ let turnOutput = 0;
360
+ let turnCacheRead = 0;
361
+ let turnCacheWrite = 0;
362
+ for (const msg of event.messages) {
363
+ if (msg.role === "assistant") {
364
+ const usage = msg.usage;
365
+ turnInput += usage.input;
366
+ turnOutput += usage.output;
367
+ turnCacheRead += usage.cacheRead;
368
+ turnCacheWrite += usage.cacheWrite;
369
+ }
370
+ }
371
+ const total = turnInput + turnOutput + turnCacheRead + turnCacheWrite;
372
+ const tps = duration > 0 ? turnOutput / duration : 0;
373
+ this._emit({
374
+ type: "turn_stats",
375
+ tps,
376
+ output: turnOutput,
377
+ input: turnInput,
378
+ cacheRead: turnCacheRead,
379
+ cacheWrite: turnCacheWrite,
380
+ total,
381
+ duration,
382
+ });
339
383
  }
340
- this._resolveRetry();
341
- await this._checkCompaction(msg);
342
384
  }
343
- }
344
- /** Resolve the pending retry promise */
345
- _resolveRetry() {
346
- if (this._retryResolve) {
347
- this._retryResolve();
348
- this._retryResolve = undefined;
349
- this._retryPromise = undefined;
385
+ };
386
+ _willRetryAfterAgentEnd(event) {
387
+ const settings = this.settingsManager.getRetrySettings();
388
+ if (!settings.enabled || this._retryAttempt >= settings.maxRetries) {
389
+ return false;
350
390
  }
391
+ for (let i = event.messages.length - 1; i >= 0; i--) {
392
+ const message = event.messages[i];
393
+ if (message.role === "assistant") {
394
+ return this._isRetryableError(message);
395
+ }
396
+ }
397
+ return false;
351
398
  }
352
399
  /** Extract text content from a message */
353
400
  _getUserMessageText(message) {
354
401
  if (message.role !== "user")
355
402
  return "";
356
- const content = message.content;
403
+ return this._getContentText(message.content);
404
+ }
405
+ _getCustomMessageText(message) {
406
+ return this._getContentText(message.content);
407
+ }
408
+ _getContentText(content) {
357
409
  if (typeof content === "string")
358
410
  return content;
359
411
  const textBlocks = content.filter((c) => c.type === "text");
360
412
  return textBlocks.map((c) => c.text).join("");
361
413
  }
414
+ _removeQueuedMessageText(messageText) {
415
+ const steeringIndex = this._steeringMessages.indexOf(messageText);
416
+ if (steeringIndex !== -1) {
417
+ this._steeringMessages.splice(steeringIndex, 1);
418
+ this._emitQueueUpdate();
419
+ return;
420
+ }
421
+ const followUpIndex = this._followUpMessages.indexOf(messageText);
422
+ if (followUpIndex !== -1) {
423
+ this._followUpMessages.splice(followUpIndex, 1);
424
+ this._emitQueueUpdate();
425
+ }
426
+ }
362
427
  /** Find the last assistant message in agent state (including aborted ones) */
363
428
  _findLastAssistantMessage() {
364
429
  const messages = this.agent.state.messages;
@@ -372,7 +437,7 @@ export class AgentSession {
372
437
  }
373
438
  _replaceMessageInPlace(target, replacement) {
374
439
  // Agent-core stores the finalized message object in its state before emitting message_end.
375
- // SessionManager persistence happens later in _processAgentEvent() with event.message.
440
+ // SessionManager persistence happens later in _handleAgentEvent() with event.message.
376
441
  // Mutating this object in place keeps agent state, later turn/agent events, listeners,
377
442
  // and the eventual SessionManager.appendMessage(event.message) persistence in sync.
378
443
  if (target === replacement) {
@@ -506,6 +571,16 @@ export class AgentSession {
506
571
  * Call this when completely done with the session.
507
572
  */
508
573
  dispose() {
574
+ try {
575
+ this.abortRetry();
576
+ this.abortCompaction();
577
+ this.abortBranchSummary();
578
+ this.abortBash();
579
+ this.agent.abort();
580
+ }
581
+ catch {
582
+ // Dispose must succeed even if an abort hook throws.
583
+ }
509
584
  this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
510
585
  this._disconnectFromAgent();
511
586
  this._eventListeners = [];
@@ -546,13 +621,14 @@ export class AgentSession {
546
621
  return this.agent.state.tools.map((t) => t.name);
547
622
  }
548
623
  /**
549
- * Get all configured tools with name, description, parameter schema, and source metadata.
624
+ * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.
550
625
  */
551
626
  getAllTools() {
552
627
  return Array.from(this._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({
553
628
  name: definition.name,
554
629
  description: definition.description,
555
630
  parameters: definition.parameters,
631
+ promptGuidelines: definition.promptGuidelines,
556
632
  sourceInfo,
557
633
  }));
558
634
  }
@@ -678,6 +754,42 @@ export class AgentSession {
678
754
  // =========================================================================
679
755
  // Prompting
680
756
  // =========================================================================
757
+ async _runAgentPrompt(messages) {
758
+ try {
759
+ await this.agent.prompt(messages);
760
+ while (await this._handlePostAgentRun()) {
761
+ await this.agent.continue();
762
+ }
763
+ }
764
+ finally {
765
+ this._flushPendingBashMessages();
766
+ }
767
+ }
768
+ async _handlePostAgentRun() {
769
+ const msg = this._lastAssistantMessage;
770
+ this._lastAssistantMessage = undefined;
771
+ if (!msg) {
772
+ return false;
773
+ }
774
+ if (this._isRetryableError(msg) && (await this._prepareRetry(msg))) {
775
+ return true;
776
+ }
777
+ if (msg.stopReason === "error" && this._retryAttempt > 0) {
778
+ this._emit({
779
+ type: "auto_retry_end",
780
+ success: false,
781
+ attempt: this._retryAttempt,
782
+ finalError: msg.errorMessage,
783
+ });
784
+ this._retryAttempt = 0;
785
+ }
786
+ if (await this._checkCompaction(msg)) {
787
+ return true;
788
+ }
789
+ // The agent loop drains both queues before emitting agent_end. Any messages
790
+ // here were queued by agent_end extension handlers and need a continuation.
791
+ return this.agent.hasQueuedMessages();
792
+ }
681
793
  /**
682
794
  * Send a prompt to the agent.
683
795
  * - Handles extension commands (registered via pi.registerCommand) immediately, even during streaming
@@ -706,7 +818,7 @@ export class AgentSession {
706
818
  let currentText = text;
707
819
  let currentImages = options?.images;
708
820
  if (this._extensionRunner.hasHandlers("input")) {
709
- const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive");
821
+ const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
710
822
  if (inputResult.action === "handled") {
711
823
  preflightResult?.(true);
712
824
  return;
@@ -753,8 +865,16 @@ export class AgentSession {
753
865
  }
754
866
  // Check if we need to compact before sending (catches aborted responses)
755
867
  const lastAssistant = this._findLastAssistantMessage();
756
- if (lastAssistant) {
757
- await this._checkCompaction(lastAssistant, false);
868
+ if (lastAssistant && (await this._checkCompaction(lastAssistant, false))) {
869
+ try {
870
+ await this.agent.continue();
871
+ while (await this._handlePostAgentRun()) {
872
+ await this.agent.continue();
873
+ }
874
+ }
875
+ finally {
876
+ this._flushPendingBashMessages();
877
+ }
758
878
  }
759
879
  // Build messages array (custom message if any, then user message)
760
880
  messages = [];
@@ -805,8 +925,7 @@ export class AgentSession {
805
925
  return;
806
926
  }
807
927
  preflightResult?.(true);
808
- await this.agent.prompt(messages);
809
- await this.waitForRetry();
928
+ await this._runAgentPrompt(messages);
810
929
  }
811
930
  /**
812
931
  * Try to execute an extension command. Returns true if command was found and executed.
@@ -968,15 +1087,20 @@ export class AgentSession {
968
1087
  this._pendingNextTurnMessages.push(appMessage);
969
1088
  }
970
1089
  else if (this.isStreaming) {
1090
+ const queuedText = this._getCustomMessageText(appMessage);
971
1091
  if (options?.deliverAs === "followUp") {
1092
+ this._followUpMessages.push(queuedText);
1093
+ this._emitQueueUpdate();
972
1094
  this.agent.followUp(appMessage);
973
1095
  }
974
1096
  else {
1097
+ this._steeringMessages.push(queuedText);
1098
+ this._emitQueueUpdate();
975
1099
  this.agent.steer(appMessage);
976
1100
  }
977
1101
  }
978
1102
  else if (options?.triggerTurn) {
979
- await this.agent.prompt(appMessage);
1103
+ await this._runAgentPrompt(appMessage);
980
1104
  }
981
1105
  else {
982
1106
  this.agent.state.messages.push(appMessage);
@@ -1077,7 +1201,7 @@ export class AgentSession {
1077
1201
  * Validates that auth is configured, saves to session and settings.
1078
1202
  * @throws Error if no auth is configured for the model
1079
1203
  */
1080
- async setModel(model, options = {}) {
1204
+ async setModel(model) {
1081
1205
  if (!this._modelRegistry.hasConfiguredAuth(model)) {
1082
1206
  throw new Error(`No API key for ${model.provider}/${model.id}`);
1083
1207
  }
@@ -1085,12 +1209,11 @@ export class AgentSession {
1085
1209
  const thinkingLevel = this._getThinkingLevelForModelSwitch();
1086
1210
  this.agent.state.model = model;
1087
1211
  this.sessionManager.appendModelChange(model.provider, model.id);
1088
- if (options.persistDefault !== false) {
1089
- this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
1090
- }
1212
+ this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
1091
1213
  // Re-clamp thinking level for new model's capabilities
1092
1214
  this.setThinkingLevel(thinkingLevel);
1093
1215
  await this._emitModelSelect(model, previousModel, "set");
1216
+ this._emitStateUpdate();
1094
1217
  }
1095
1218
  /**
1096
1219
  * Cycle to next/previous model.
@@ -1126,6 +1249,7 @@ export class AgentSession {
1126
1249
  // setThinkingLevel clamps to model capabilities.
1127
1250
  this.setThinkingLevel(thinkingLevel);
1128
1251
  await this._emitModelSelect(next.model, currentModel, "cycle");
1252
+ this._emitStateUpdate();
1129
1253
  return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
1130
1254
  }
1131
1255
  async _cycleAvailableModel(direction) {
@@ -1146,6 +1270,7 @@ export class AgentSession {
1146
1270
  // Re-clamp thinking level for new model's capabilities
1147
1271
  this.setThinkingLevel(thinkingLevel);
1148
1272
  await this._emitModelSelect(nextModel, currentModel, "cycle");
1273
+ this._emitStateUpdate();
1149
1274
  return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };
1150
1275
  }
1151
1276
  // =========================================================================
@@ -1174,6 +1299,7 @@ export class AgentSession {
1174
1299
  level: effectiveLevel,
1175
1300
  previousLevel,
1176
1301
  });
1302
+ this._emitStateUpdate();
1177
1303
  }
1178
1304
  }
1179
1305
  /**
@@ -1227,6 +1353,7 @@ export class AgentSession {
1227
1353
  setSteeringMode(mode) {
1228
1354
  this.agent.steeringMode = mode;
1229
1355
  this.settingsManager.setSteeringMode(mode);
1356
+ this._emitStateUpdate();
1230
1357
  }
1231
1358
  /**
1232
1359
  * Set follow-up message mode.
@@ -1235,6 +1362,7 @@ export class AgentSession {
1235
1362
  setFollowUpMode(mode) {
1236
1363
  this.agent.followUpMode = mode;
1237
1364
  this.settingsManager.setFollowUpMode(mode);
1365
+ this._emitStateUpdate();
1238
1366
  }
1239
1367
  // =========================================================================
1240
1368
  // Compaction
@@ -1253,7 +1381,7 @@ export class AgentSession {
1253
1381
  if (!this.model) {
1254
1382
  throw new Error(formatNoModelSelectedMessage());
1255
1383
  }
1256
- const { apiKey, headers } = await this._getRequiredRequestAuth(this.model);
1384
+ const { apiKey, headers } = await this._getCompactionRequestAuth(this.model);
1257
1385
  const pathEntries = this.sessionManager.getBranch();
1258
1386
  const settings = this.settingsManager.getCompactionSettings();
1259
1387
  const preparation = prepareCompaction(pathEntries, settings);
@@ -1296,7 +1424,7 @@ export class AgentSession {
1296
1424
  }
1297
1425
  else {
1298
1426
  // Generate compaction result
1299
- const result = await compact(preparation, this.model, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel);
1427
+ const result = await compact(preparation, this.model, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFn);
1300
1428
  summary = result.summary;
1301
1429
  firstKeptEntryId = result.firstKeptEntryId;
1302
1430
  tokensBefore = result.tokensBefore;
@@ -1309,6 +1437,8 @@ export class AgentSession {
1309
1437
  const newEntries = this.sessionManager.getEntries();
1310
1438
  const sessionContext = this.sessionManager.buildSessionContext();
1311
1439
  this.agent.state.messages = sessionContext.messages;
1440
+ // Prune old entries from memory and disk to prevent unbounded growth
1441
+ this.sessionManager.pruneAfterCompaction();
1312
1442
  // Get the saved compaction entry for the extension event
1313
1443
  const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary);
1314
1444
  if (this._extensionRunner && savedCompactionEntry) {
@@ -1331,6 +1461,7 @@ export class AgentSession {
1331
1461
  aborted: false,
1332
1462
  willRetry: false,
1333
1463
  });
1464
+ this._emitStateUpdate();
1334
1465
  return compactionResult;
1335
1466
  }
1336
1467
  catch (error) {
@@ -1344,6 +1475,7 @@ export class AgentSession {
1344
1475
  willRetry: false,
1345
1476
  errorMessage: aborted ? undefined : `Compaction failed: ${message}`,
1346
1477
  });
1478
+ this._emitStateUpdate();
1347
1479
  throw error;
1348
1480
  }
1349
1481
  finally {
@@ -1378,10 +1510,10 @@ export class AgentSession {
1378
1510
  async _checkCompaction(assistantMessage, skipAbortedCheck = true) {
1379
1511
  const settings = this.settingsManager.getCompactionSettings();
1380
1512
  if (!settings.enabled)
1381
- return;
1513
+ return false;
1382
1514
  // Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
1383
1515
  if (skipAbortedCheck && assistantMessage.stopReason === "aborted")
1384
- return;
1516
+ return false;
1385
1517
  const contextWindow = this.model?.contextWindow ?? 0;
1386
1518
  // Skip overflow check if the message came from a different model.
1387
1519
  // This handles the case where user switched from a smaller-context model (e.g. opus)
@@ -1394,7 +1526,7 @@ export class AgentSession {
1394
1526
  const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
1395
1527
  const assistantIsFromBeforeCompaction = compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();
1396
1528
  if (assistantIsFromBeforeCompaction) {
1397
- return;
1529
+ return false;
1398
1530
  }
1399
1531
  // Case 1: Overflow - LLM returned context overflow error
1400
1532
  if (sameModel && isContextOverflow(assistantMessage, contextWindow)) {
@@ -1407,7 +1539,8 @@ export class AgentSession {
1407
1539
  willRetry: false,
1408
1540
  errorMessage: "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.",
1409
1541
  });
1410
- return;
1542
+ this._emitStateUpdate();
1543
+ return false;
1411
1544
  }
1412
1545
  this._overflowRecoveryAttempted = true;
1413
1546
  // Remove the error message from agent state (it IS saved to session for history,
@@ -1416,8 +1549,7 @@ export class AgentSession {
1416
1549
  if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
1417
1550
  this.agent.state.messages = messages.slice(0, -1);
1418
1551
  }
1419
- await this._runAutoCompaction("overflow", true);
1420
- return;
1552
+ return await this._runAutoCompaction("overflow", true);
1421
1553
  }
1422
1554
  // Case 2: Threshold - context is getting large
1423
1555
  // For error messages (no usage data), estimate from last successful response.
@@ -1427,7 +1559,7 @@ export class AgentSession {
1427
1559
  const messages = this.agent.state.messages;
1428
1560
  const estimate = estimateContextTokens(messages);
1429
1561
  if (estimate.lastUsageIndex === null)
1430
- return; // No usage data at all
1562
+ return false; // No usage data at all
1431
1563
  // Verify the usage source is post-compaction. Kept pre-compaction messages
1432
1564
  // have stale usage reflecting the old (larger) context and would falsely
1433
1565
  // trigger compaction right after one just finished.
@@ -1435,7 +1567,7 @@ export class AgentSession {
1435
1567
  if (compactionEntry &&
1436
1568
  usageMsg.role === "assistant" &&
1437
1569
  usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
1438
- return;
1570
+ return false;
1439
1571
  }
1440
1572
  contextTokens = estimate.tokens;
1441
1573
  }
@@ -1443,8 +1575,9 @@ export class AgentSession {
1443
1575
  contextTokens = calculateContextTokens(assistantMessage.usage);
1444
1576
  }
1445
1577
  if (shouldCompact(contextTokens, contextWindow, settings)) {
1446
- await this._runAutoCompaction("threshold", false);
1578
+ return await this._runAutoCompaction("threshold", false);
1447
1579
  }
1580
+ return false;
1448
1581
  }
1449
1582
  /**
1450
1583
  * Internal: Run auto-compaction with events.
@@ -1462,20 +1595,30 @@ export class AgentSession {
1462
1595
  aborted: false,
1463
1596
  willRetry: false,
1464
1597
  });
1465
- return;
1598
+ this._emitStateUpdate();
1599
+ return false;
1466
1600
  }
1467
- const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
1468
- if (!authResult.ok || !authResult.apiKey) {
1469
- this._emit({
1470
- type: "compaction_end",
1471
- reason,
1472
- result: undefined,
1473
- aborted: false,
1474
- willRetry: false,
1475
- });
1476
- return;
1601
+ let apiKey;
1602
+ let headers;
1603
+ if (this.agent.streamFn === streamSimple) {
1604
+ const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
1605
+ if (!authResult.ok || !authResult.apiKey) {
1606
+ this._emit({
1607
+ type: "compaction_end",
1608
+ reason,
1609
+ result: undefined,
1610
+ aborted: false,
1611
+ willRetry: false,
1612
+ });
1613
+ this._emitStateUpdate();
1614
+ return false;
1615
+ }
1616
+ apiKey = authResult.apiKey;
1617
+ headers = authResult.headers;
1618
+ }
1619
+ else {
1620
+ ({ apiKey, headers } = await this._getCompactionRequestAuth(this.model));
1477
1621
  }
1478
- const { apiKey, headers } = authResult;
1479
1622
  const pathEntries = this.sessionManager.getBranch();
1480
1623
  const preparation = prepareCompaction(pathEntries, settings);
1481
1624
  if (!preparation) {
@@ -1486,7 +1629,8 @@ export class AgentSession {
1486
1629
  aborted: false,
1487
1630
  willRetry: false,
1488
1631
  });
1489
- return;
1632
+ this._emitStateUpdate();
1633
+ return false;
1490
1634
  }
1491
1635
  let extensionCompaction;
1492
1636
  let fromExtension = false;
@@ -1506,7 +1650,8 @@ export class AgentSession {
1506
1650
  aborted: true,
1507
1651
  willRetry: false,
1508
1652
  });
1509
- return;
1653
+ this._emitStateUpdate();
1654
+ return false;
1510
1655
  }
1511
1656
  if (extensionResult?.compaction) {
1512
1657
  extensionCompaction = extensionResult.compaction;
@@ -1526,7 +1671,7 @@ export class AgentSession {
1526
1671
  }
1527
1672
  else {
1528
1673
  // Generate compaction result
1529
- const compactResult = await compact(preparation, this.model, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel);
1674
+ const compactResult = await compact(preparation, this.model, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFn);
1530
1675
  summary = compactResult.summary;
1531
1676
  firstKeptEntryId = compactResult.firstKeptEntryId;
1532
1677
  tokensBefore = compactResult.tokensBefore;
@@ -1540,12 +1685,14 @@ export class AgentSession {
1540
1685
  aborted: true,
1541
1686
  willRetry: false,
1542
1687
  });
1543
- return;
1688
+ return false;
1544
1689
  }
1545
1690
  this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
1546
1691
  const newEntries = this.sessionManager.getEntries();
1547
1692
  const sessionContext = this.sessionManager.buildSessionContext();
1548
1693
  this.agent.state.messages = sessionContext.messages;
1694
+ // Prune old entries from memory and disk to prevent unbounded growth
1695
+ this.sessionManager.pruneAfterCompaction();
1549
1696
  // Get the saved compaction entry for the extension event
1550
1697
  const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary);
1551
1698
  if (this._extensionRunner && savedCompactionEntry) {
@@ -1562,23 +1709,18 @@ export class AgentSession {
1562
1709
  details,
1563
1710
  };
1564
1711
  this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
1712
+ this._emitStateUpdate();
1565
1713
  if (willRetry) {
1566
1714
  const messages = this.agent.state.messages;
1567
1715
  const lastMsg = messages[messages.length - 1];
1568
1716
  if (lastMsg?.role === "assistant" && lastMsg.stopReason === "error") {
1569
1717
  this.agent.state.messages = messages.slice(0, -1);
1570
1718
  }
1571
- setTimeout(() => {
1572
- this.agent.continue().catch(() => { });
1573
- }, 100);
1574
- }
1575
- else if (this.agent.hasQueuedMessages()) {
1576
- // Auto-compaction can complete while follow-up/steering/custom messages are waiting.
1577
- // Kick the loop so queued messages are actually delivered.
1578
- setTimeout(() => {
1579
- this.agent.continue().catch(() => { });
1580
- }, 100);
1719
+ return true;
1581
1720
  }
1721
+ // Auto-compaction can complete while follow-up/steering/custom messages are waiting.
1722
+ // Continue once so queued messages are delivered.
1723
+ return this.agent.hasQueuedMessages();
1582
1724
  }
1583
1725
  catch (error) {
1584
1726
  const errorMessage = error instanceof Error ? error.message : "compaction failed";
@@ -1592,6 +1734,8 @@ export class AgentSession {
1592
1734
  ? `Context overflow recovery failed: ${errorMessage}`
1593
1735
  : `Auto-compaction failed: ${errorMessage}`,
1594
1736
  });
1737
+ this._emitStateUpdate();
1738
+ return false;
1595
1739
  }
1596
1740
  finally {
1597
1741
  this._autoCompactionAbortController = undefined;
@@ -1602,6 +1746,7 @@ export class AgentSession {
1602
1746
  */
1603
1747
  setAutoCompactionEnabled(enabled) {
1604
1748
  this.settingsManager.setCompactionEnabled(enabled);
1749
+ this._emitStateUpdate();
1605
1750
  }
1606
1751
  /** Whether auto-compaction is enabled */
1607
1752
  get autoCompactionEnabled() {
@@ -1614,6 +1759,9 @@ export class AgentSession {
1614
1759
  if (bindings.commandContextActions !== undefined) {
1615
1760
  this._extensionCommandContextActions = bindings.commandContextActions;
1616
1761
  }
1762
+ if (bindings.abortHandler !== undefined) {
1763
+ this._extensionAbortHandler = bindings.abortHandler;
1764
+ }
1617
1765
  if (bindings.shutdownHandler !== undefined) {
1618
1766
  this._extensionShutdownHandler = bindings.shutdownHandler;
1619
1767
  }
@@ -1753,7 +1901,13 @@ export class AgentSession {
1753
1901
  getModel: () => this.model,
1754
1902
  isIdle: () => !this.isStreaming,
1755
1903
  getSignal: () => this.agent.signal,
1756
- abort: () => this.abort(),
1904
+ abort: () => {
1905
+ if (this._extensionAbortHandler) {
1906
+ this._extensionAbortHandler();
1907
+ return;
1908
+ }
1909
+ void this.abort();
1910
+ },
1757
1911
  hasPendingMessages: () => this.pendingMessageCount > 0,
1758
1912
  shutdown: () => {
1759
1913
  this._extensionShutdownHandler?.();
@@ -1787,7 +1941,8 @@ export class AgentSession {
1787
1941
  const previousRegistryNames = new Set(this._toolRegistry.keys());
1788
1942
  const previousActiveToolNames = this.getActiveToolNames();
1789
1943
  const allowedToolNames = this._allowedToolNames;
1790
- const isAllowedTool = (name) => !allowedToolNames || allowedToolNames.has(name);
1944
+ const excludedToolNames = this._excludedToolNames;
1945
+ const isAllowedTool = (name) => (!allowedToolNames || allowedToolNames.has(name)) && !excludedToolNames?.has(name);
1791
1946
  const registeredTools = this._extensionRunner.getAllRegisteredTools();
1792
1947
  const allCustomTools = [
1793
1948
  ...registeredTools,
@@ -1917,6 +2072,9 @@ export class AgentSession {
1917
2072
  // =========================================================================
1918
2073
  // Auto-Retry
1919
2074
  // =========================================================================
2075
+ _isNonRetryableProviderLimitError(errorMessage) {
2076
+ return /GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient_quota|out of budget|quota exceeded|billing/i.test(errorMessage);
2077
+ }
1920
2078
  /**
1921
2079
  * Check if an error is retryable (overloaded, rate limit, server errors).
1922
2080
  * Context overflow errors are NOT retryable (handled by compaction instead).
@@ -1929,37 +2087,24 @@ export class AgentSession {
1929
2087
  if (isContextOverflow(message, contextWindow))
1930
2088
  return false;
1931
2089
  const err = message.errorMessage;
2090
+ if (this._isNonRetryableProviderLimitError(err))
2091
+ return false;
1932
2092
  // Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504, service unavailable, network/connection errors (including connection lost), WebSocket transport closes/errors, fetch failed, premature stream endings, HTTP/2 closed before response, terminated, retry delay exceeded
1933
2093
  return /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|stream ended before message_stop|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i.test(err);
1934
2094
  }
1935
2095
  /**
1936
- * Handle retryable errors with exponential backoff.
1937
- * @returns true if retry was initiated, false if max retries exceeded or disabled
2096
+ * Prepare a retryable error for continuation with exponential backoff.
2097
+ * @returns true if the caller should continue the agent, false otherwise
1938
2098
  */
1939
- async _handleRetryableError(message) {
2099
+ async _prepareRetry(message) {
1940
2100
  const settings = this.settingsManager.getRetrySettings();
1941
2101
  if (!settings.enabled) {
1942
- this._resolveRetry();
1943
2102
  return false;
1944
2103
  }
1945
- // Retry promise is created synchronously in _handleAgentEvent for agent_end.
1946
- // Keep a defensive fallback here in case a future refactor bypasses that path.
1947
- if (!this._retryPromise) {
1948
- this._retryPromise = new Promise((resolve) => {
1949
- this._retryResolve = resolve;
1950
- });
1951
- }
1952
2104
  this._retryAttempt++;
1953
2105
  if (this._retryAttempt > settings.maxRetries) {
1954
- // Max retries exceeded, emit final failure and reset
1955
- this._emit({
1956
- type: "auto_retry_end",
1957
- success: false,
1958
- attempt: this._retryAttempt - 1,
1959
- finalError: message.errorMessage,
1960
- });
1961
- this._retryAttempt = 0;
1962
- this._resolveRetry(); // Resolve so waitForRetry() completes
2106
+ // Preserve the completed attempt count so post-run handling can emit the final failure.
2107
+ this._retryAttempt--;
1963
2108
  return false;
1964
2109
  }
1965
2110
  const delayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);
@@ -1984,23 +2129,17 @@ export class AgentSession {
1984
2129
  // Aborted during sleep - emit end event so UI can clean up
1985
2130
  const attempt = this._retryAttempt;
1986
2131
  this._retryAttempt = 0;
1987
- this._retryAbortController = undefined;
1988
2132
  this._emit({
1989
2133
  type: "auto_retry_end",
1990
2134
  success: false,
1991
2135
  attempt,
1992
2136
  finalError: "Retry cancelled",
1993
2137
  });
1994
- this._resolveRetry();
1995
2138
  return false;
1996
2139
  }
1997
- this._retryAbortController = undefined;
1998
- // Retry via continue() - use setTimeout to break out of event handler chain
1999
- setTimeout(() => {
2000
- this.agent.continue().catch(() => {
2001
- // Retry failed - will be caught by next agent_end
2002
- });
2003
- }, 0);
2140
+ finally {
2141
+ this._retryAbortController = undefined;
2142
+ }
2004
2143
  return true;
2005
2144
  }
2006
2145
  /**
@@ -2008,23 +2147,10 @@ export class AgentSession {
2008
2147
  */
2009
2148
  abortRetry() {
2010
2149
  this._retryAbortController?.abort();
2011
- // Note: _retryAttempt is reset in the catch block of _autoRetry
2012
- this._resolveRetry();
2013
- }
2014
- /**
2015
- * Wait for any in-progress retry to complete.
2016
- * Returns immediately if no retry is in progress.
2017
- */
2018
- async waitForRetry() {
2019
- if (!this._retryPromise) {
2020
- return;
2021
- }
2022
- await this._retryPromise;
2023
- await this.agent.waitForIdle();
2024
2150
  }
2025
2151
  /** Whether auto-retry is currently in progress */
2026
2152
  get isRetrying() {
2027
- return this._retryPromise !== undefined;
2153
+ return this._retryAbortController !== undefined;
2028
2154
  }
2029
2155
  /** Whether auto-retry is enabled */
2030
2156
  get autoRetryEnabled() {
@@ -2443,7 +2569,7 @@ export class AgentSession {
2443
2569
  * @returns The resolved output file path.
2444
2570
  */
2445
2571
  exportToJsonl(outputPath) {
2446
- const filePath = resolve(outputPath ?? `session-${new Date().toISOString().replace(/[:.]/g, "-")}.jsonl`);
2572
+ const filePath = resolvePath(outputPath ?? `session-${new Date().toISOString().replace(/[:.]/g, "-")}.jsonl`, process.cwd());
2447
2573
  const dir = dirname(filePath);
2448
2574
  if (!existsSync(dir)) {
2449
2575
  mkdirSync(dir, { recursive: true });