@averyyy/pi-coding-agent 0.84.2-piclient.3 → 0.84.4-piclient.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 (323) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +13 -8
  3. package/dist/bundle/chunks/anthropic-messages-JWX2WP65.js +45 -0
  4. package/dist/bundle/chunks/anthropic.js +75 -0
  5. package/dist/bundle/chunks/azure-openai-responses-B2RCCN5N.js +2 -0
  6. package/dist/bundle/chunks/bedrock-converse-stream.js +74 -0
  7. package/dist/bundle/chunks/chunk-2KVJKXS2.js +50 -0
  8. package/dist/bundle/chunks/chunk-4L3WN2XY.js +2 -0
  9. package/dist/bundle/chunks/chunk-6CYCI3EJ.js +12 -0
  10. package/dist/bundle/chunks/chunk-6R7UI4IY.js +2 -0
  11. package/dist/bundle/chunks/chunk-AP7VCR6I.js +1633 -0
  12. package/dist/bundle/chunks/chunk-AXIIZGTV.js +2 -0
  13. package/dist/bundle/chunks/chunk-DRQDKNXA.js +2 -0
  14. package/dist/bundle/chunks/chunk-GMWCTUPB.js +2 -0
  15. package/dist/bundle/chunks/chunk-JUUC5AZY.js +2 -0
  16. package/dist/bundle/chunks/chunk-L2ZPNLYD.js +2 -0
  17. package/dist/bundle/chunks/chunk-LRBSW3NQ.js +11 -0
  18. package/dist/bundle/chunks/chunk-MNAIPA3J.js +2 -0
  19. package/dist/bundle/chunks/chunk-NUHFSC37.js +25 -0
  20. package/dist/bundle/chunks/chunk-PGXDEOVV.js +2 -0
  21. package/dist/bundle/chunks/chunk-PJACZCIR.js +2 -0
  22. package/dist/bundle/chunks/chunk-PRRNXB7S.js +2 -0
  23. package/dist/bundle/chunks/chunk-TEPMHNKQ.js +2 -0
  24. package/dist/bundle/chunks/chunk-TRDNDS6A.js +4 -0
  25. package/dist/bundle/chunks/chunk-UAQELI3K.js +2 -0
  26. package/dist/bundle/chunks/chunk-XDUWOHPL.js +6 -0
  27. package/dist/bundle/chunks/chunk-XNGRGP62.js +2 -0
  28. package/dist/bundle/chunks/github-copilot.js +2 -0
  29. package/dist/bundle/chunks/google-generative-ai-YMUPJBKR.js +2 -0
  30. package/dist/bundle/chunks/google-vertex-MPWMV4OF.js +2 -0
  31. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +13 -0
  32. package/dist/bundle/chunks/image-resize-worker.js +2 -0
  33. package/dist/bundle/chunks/kimi-coding.js +2 -0
  34. package/dist/bundle/chunks/lib-HGQMNYVT.js +9 -0
  35. package/dist/bundle/chunks/mistral-conversations-Q3AWZJAZ.js +5 -0
  36. package/dist/bundle/chunks/multipart-parser-SQ6GDJL7.js +3 -0
  37. package/dist/bundle/chunks/openai-codex-responses-MJHX7NXI.js +8 -0
  38. package/dist/bundle/chunks/openai-codex.js +75 -0
  39. package/dist/bundle/chunks/openai-completions-ERMU2SS7.js +7 -0
  40. package/dist/bundle/chunks/openai-responses-CP4VKB27.js +2 -0
  41. package/dist/bundle/chunks/openrouter-images-N4XVVFSD.js +2 -0
  42. package/dist/bundle/chunks/openrouter.js +75 -0
  43. package/dist/bundle/chunks/pi-messages-TPFH44NP.js +8 -0
  44. package/dist/bundle/chunks/radius.js +75 -0
  45. package/dist/bundle/chunks/src-UK77SYZE.js +4 -0
  46. package/dist/bundle/chunks/xai.js +2 -0
  47. package/dist/bundle/cli.js +3 -0
  48. package/dist/bundle/client.js +2 -0
  49. package/dist/bundle/index.js +2 -0
  50. package/dist/bundle/rpc-entry.js +3 -0
  51. package/dist/cli/args.d.ts +1 -0
  52. package/dist/cli/args.d.ts.map +1 -1
  53. package/dist/cli/args.js +29 -9
  54. package/dist/cli/args.js.map +1 -1
  55. package/dist/cli/file-processor.d.ts.map +1 -1
  56. package/dist/cli/file-processor.js +2 -1
  57. package/dist/cli/file-processor.js.map +1 -1
  58. package/dist/cli/startup-ui.d.ts.map +1 -1
  59. package/dist/cli/startup-ui.js +2 -1
  60. package/dist/cli/startup-ui.js.map +1 -1
  61. package/dist/config.d.ts +4 -3
  62. package/dist/config.d.ts.map +1 -1
  63. package/dist/config.js +22 -14
  64. package/dist/config.js.map +1 -1
  65. package/dist/core/agent-session.d.ts +27 -9
  66. package/dist/core/agent-session.d.ts.map +1 -1
  67. package/dist/core/agent-session.js +150 -58
  68. package/dist/core/agent-session.js.map +1 -1
  69. package/dist/core/auth-storage.d.ts.map +1 -1
  70. package/dist/core/auth-storage.js +6 -7
  71. package/dist/core/auth-storage.js.map +1 -1
  72. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  73. package/dist/core/compaction/branch-summarization.js +8 -1
  74. package/dist/core/compaction/branch-summarization.js.map +1 -1
  75. package/dist/core/compaction/compaction.d.ts +9 -4
  76. package/dist/core/compaction/compaction.d.ts.map +1 -1
  77. package/dist/core/compaction/compaction.js +42 -22
  78. package/dist/core/compaction/compaction.js.map +1 -1
  79. package/dist/core/defaults.d.ts +1 -0
  80. package/dist/core/defaults.d.ts.map +1 -1
  81. package/dist/core/defaults.js +9 -0
  82. package/dist/core/defaults.js.map +1 -1
  83. package/dist/core/exec.d.ts.map +1 -1
  84. package/dist/core/exec.js +3 -1
  85. package/dist/core/exec.js.map +1 -1
  86. package/dist/core/extensions/index.d.ts +2 -2
  87. package/dist/core/extensions/index.d.ts.map +1 -1
  88. package/dist/core/extensions/index.js +1 -1
  89. package/dist/core/extensions/index.js.map +1 -1
  90. package/dist/core/extensions/loader.d.ts.map +1 -1
  91. package/dist/core/extensions/loader.js +115 -48
  92. package/dist/core/extensions/loader.js.map +1 -1
  93. package/dist/core/extensions/runner.d.ts +5 -0
  94. package/dist/core/extensions/runner.d.ts.map +1 -1
  95. package/dist/core/extensions/runner.js +45 -1
  96. package/dist/core/extensions/runner.js.map +1 -1
  97. package/dist/core/extensions/types.d.ts +56 -10
  98. package/dist/core/extensions/types.d.ts.map +1 -1
  99. package/dist/core/extensions/types.js +3 -0
  100. package/dist/core/extensions/types.js.map +1 -1
  101. package/dist/core/footer-data-provider.d.ts +1 -1
  102. package/dist/core/footer-data-provider.d.ts.map +1 -1
  103. package/dist/core/footer-data-provider.js +1 -1
  104. package/dist/core/footer-data-provider.js.map +1 -1
  105. package/dist/core/index.d.ts +1 -0
  106. package/dist/core/index.d.ts.map +1 -1
  107. package/dist/core/index.js +1 -0
  108. package/dist/core/index.js.map +1 -1
  109. package/dist/core/keybindings.d.ts +20 -19
  110. package/dist/core/keybindings.d.ts.map +1 -1
  111. package/dist/core/keybindings.js +26 -5
  112. package/dist/core/keybindings.js.map +1 -1
  113. package/dist/core/model-config.d.ts +5 -0
  114. package/dist/core/model-config.d.ts.map +1 -1
  115. package/dist/core/model-config.js +3 -1
  116. package/dist/core/model-config.js.map +1 -1
  117. package/dist/core/model-resolver.d.ts +1 -0
  118. package/dist/core/model-resolver.d.ts.map +1 -1
  119. package/dist/core/model-resolver.js +14 -8
  120. package/dist/core/model-resolver.js.map +1 -1
  121. package/dist/core/models-store.d.ts.map +1 -1
  122. package/dist/core/models-store.js +2 -1
  123. package/dist/core/models-store.js.map +1 -1
  124. package/dist/core/package-manager.d.ts.map +1 -1
  125. package/dist/core/package-manager.js +22 -14
  126. package/dist/core/package-manager.js.map +1 -1
  127. package/dist/core/pi-client-cli-adapter.d.ts +11 -0
  128. package/dist/core/pi-client-cli-adapter.d.ts.map +1 -0
  129. package/dist/core/pi-client-cli-adapter.js +91 -0
  130. package/dist/core/pi-client-cli-adapter.js.map +1 -0
  131. package/dist/core/pi-manifest.d.ts.map +1 -1
  132. package/dist/core/pi-manifest.js +2 -1
  133. package/dist/core/pi-manifest.js.map +1 -1
  134. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  135. package/dist/core/remote-catalog-provider.js +2 -1
  136. package/dist/core/remote-catalog-provider.js.map +1 -1
  137. package/dist/core/resource-loader.d.ts.map +1 -1
  138. package/dist/core/resource-loader.js +3 -2
  139. package/dist/core/resource-loader.js.map +1 -1
  140. package/dist/core/sdk.d.ts +2 -2
  141. package/dist/core/sdk.d.ts.map +1 -1
  142. package/dist/core/sdk.js +10 -3
  143. package/dist/core/sdk.js.map +1 -1
  144. package/dist/core/session-export.d.ts +4 -0
  145. package/dist/core/session-export.d.ts.map +1 -0
  146. package/dist/core/session-export.js +32 -0
  147. package/dist/core/session-export.js.map +1 -0
  148. package/dist/core/session-manager.d.ts.map +1 -1
  149. package/dist/core/session-manager.js +6 -3
  150. package/dist/core/session-manager.js.map +1 -1
  151. package/dist/core/settings-diagnostics.d.ts +9 -0
  152. package/dist/core/settings-diagnostics.d.ts.map +1 -0
  153. package/dist/core/settings-diagnostics.js +21 -0
  154. package/dist/core/settings-diagnostics.js.map +1 -0
  155. package/dist/core/settings-manager.d.ts +17 -1
  156. package/dist/core/settings-manager.d.ts.map +1 -1
  157. package/dist/core/settings-manager.js +69 -10
  158. package/dist/core/settings-manager.js.map +1 -1
  159. package/dist/core/skills.d.ts.map +1 -1
  160. package/dist/core/skills.js +51 -33
  161. package/dist/core/skills.js.map +1 -1
  162. package/dist/core/slash-commands.d.ts.map +1 -1
  163. package/dist/core/slash-commands.js +2 -1
  164. package/dist/core/slash-commands.js.map +1 -1
  165. package/dist/core/system-prompt.d.ts.map +1 -1
  166. package/dist/core/system-prompt.js +11 -2
  167. package/dist/core/system-prompt.js.map +1 -1
  168. package/dist/core/tools/bash.d.ts +13 -1
  169. package/dist/core/tools/bash.d.ts.map +1 -1
  170. package/dist/core/tools/bash.js +30 -14
  171. package/dist/core/tools/bash.js.map +1 -1
  172. package/dist/core/tools/edit-diff.d.ts +0 -5
  173. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  174. package/dist/core/tools/edit-diff.js +2 -5
  175. package/dist/core/tools/edit-diff.js.map +1 -1
  176. package/dist/core/tools/edit.d.ts.map +1 -1
  177. package/dist/core/tools/edit.js +20 -4
  178. package/dist/core/tools/edit.js.map +1 -1
  179. package/dist/core/tools/index.d.ts +4 -1
  180. package/dist/core/tools/index.d.ts.map +1 -1
  181. package/dist/core/tools/index.js +18 -1
  182. package/dist/core/tools/index.js.map +1 -1
  183. package/dist/core/tools/powershell.d.ts +16 -0
  184. package/dist/core/tools/powershell.d.ts.map +1 -0
  185. package/dist/core/tools/powershell.js +39 -0
  186. package/dist/core/tools/powershell.js.map +1 -0
  187. package/dist/core/trust-manager.d.ts.map +1 -1
  188. package/dist/core/trust-manager.js +2 -1
  189. package/dist/core/trust-manager.js.map +1 -1
  190. package/dist/extensions/llama/client.d.ts +6 -0
  191. package/dist/extensions/llama/client.d.ts.map +1 -1
  192. package/dist/extensions/llama/client.js +7 -0
  193. package/dist/extensions/llama/client.js.map +1 -1
  194. package/dist/extensions/llama/index.d.ts.map +1 -1
  195. package/dist/extensions/llama/index.js +2 -0
  196. package/dist/extensions/llama/index.js.map +1 -1
  197. package/dist/extensions/llama/provider.d.ts +3 -1
  198. package/dist/extensions/llama/provider.d.ts.map +1 -1
  199. package/dist/extensions/llama/provider.js +29 -4
  200. package/dist/extensions/llama/provider.js.map +1 -1
  201. package/dist/index.d.ts +4 -3
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +4 -3
  204. package/dist/index.js.map +1 -1
  205. package/dist/main.d.ts +4 -0
  206. package/dist/main.d.ts.map +1 -1
  207. package/dist/main.js +22 -15
  208. package/dist/main.js.map +1 -1
  209. package/dist/migrations.d.ts.map +1 -1
  210. package/dist/migrations.js +4 -3
  211. package/dist/migrations.js.map +1 -1
  212. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  213. package/dist/modes/interactive/components/bash-execution.js +2 -1
  214. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  215. package/dist/modes/interactive/components/model-selector.d.ts +9 -3
  216. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/model-selector.js +56 -12
  218. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  219. package/dist/modes/interactive/components/settings-selector.d.ts +9 -2
  220. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  221. package/dist/modes/interactive/components/settings-selector.js +128 -56
  222. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  223. package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
  224. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
  225. package/dist/modes/interactive/components/settings-submenu.js +165 -0
  226. package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
  227. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  228. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  229. package/dist/modes/interactive/components/thinking-selector.js +74 -17
  230. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  231. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  232. package/dist/modes/interactive/external-editor.js +2 -1
  233. package/dist/modes/interactive/external-editor.js.map +1 -1
  234. package/dist/modes/interactive/interactive-mode.d.ts +17 -12
  235. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  236. package/dist/modes/interactive/interactive-mode.js +244 -250
  237. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  238. package/dist/modes/interactive/session-share.d.ts +16 -0
  239. package/dist/modes/interactive/session-share.d.ts.map +1 -0
  240. package/dist/modes/interactive/session-share.js +188 -0
  241. package/dist/modes/interactive/session-share.js.map +1 -0
  242. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  243. package/dist/modes/interactive/theme/theme.js +4 -3
  244. package/dist/modes/interactive/theme/theme.js.map +1 -1
  245. package/dist/modes/json-event.d.ts +16 -13
  246. package/dist/modes/json-event.d.ts.map +1 -1
  247. package/dist/modes/json-event.js +20 -6
  248. package/dist/modes/json-event.js.map +1 -1
  249. package/dist/modes/rpc/rpc-client.d.ts +7 -0
  250. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  251. package/dist/modes/rpc/rpc-client.js +7 -0
  252. package/dist/modes/rpc/rpc-client.js.map +1 -1
  253. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  254. package/dist/modes/rpc/rpc-mode.js +3 -0
  255. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  256. package/dist/modes/rpc/rpc-types.d.ts +12 -0
  257. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  258. package/dist/modes/rpc/rpc-types.js.map +1 -1
  259. package/dist/package-manager-cli.d.ts +1 -0
  260. package/dist/package-manager-cli.d.ts.map +1 -1
  261. package/dist/package-manager-cli.js +186 -2
  262. package/dist/package-manager-cli.js.map +1 -1
  263. package/dist/utils/child-process.d.ts.map +1 -1
  264. package/dist/utils/child-process.js +8 -3
  265. package/dist/utils/child-process.js.map +1 -1
  266. package/dist/utils/frontmatter.d.ts.map +1 -1
  267. package/dist/utils/frontmatter.js +2 -1
  268. package/dist/utils/frontmatter.js.map +1 -1
  269. package/dist/utils/management-http.d.ts +5 -3
  270. package/dist/utils/management-http.d.ts.map +1 -1
  271. package/dist/utils/management-http.js +14 -10
  272. package/dist/utils/management-http.js.map +1 -1
  273. package/dist/utils/shell.d.ts +3 -0
  274. package/dist/utils/shell.d.ts.map +1 -1
  275. package/dist/utils/shell.js +27 -11
  276. package/dist/utils/shell.js.map +1 -1
  277. package/dist/utils/syntax-highlight.d.ts +1 -0
  278. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  279. package/dist/utils/syntax-highlight.js +60 -1
  280. package/dist/utils/syntax-highlight.js.map +1 -1
  281. package/dist/utils/text.d.ts +8 -0
  282. package/dist/utils/text.d.ts.map +1 -0
  283. package/dist/utils/text.js +9 -0
  284. package/dist/utils/text.js.map +1 -0
  285. package/dist/utils/version-check.d.ts.map +1 -1
  286. package/dist/utils/version-check.js +2 -1
  287. package/dist/utils/version-check.js.map +1 -1
  288. package/docs/compaction.md +17 -0
  289. package/docs/custom-provider.md +12 -9
  290. package/docs/environment-variables.md +11 -8
  291. package/docs/extensions.md +35 -7
  292. package/docs/json.md +7 -2
  293. package/docs/keybindings.md +9 -9
  294. package/docs/llama-cpp.md +2 -0
  295. package/docs/models.md +8 -2
  296. package/docs/packages.md +2 -2
  297. package/docs/quickstart.md +1 -1
  298. package/docs/rpc.md +32 -3
  299. package/docs/sdk.md +7 -2
  300. package/docs/settings.md +23 -7
  301. package/docs/skills.md +4 -3
  302. package/docs/terminal-setup.md +23 -9
  303. package/docs/usage.md +10 -5
  304. package/docs/windows.md +24 -2
  305. package/examples/extensions/border-status-editor.ts +1 -1
  306. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  307. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  308. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  309. package/examples/extensions/git-checkpoint.ts +2 -2
  310. package/examples/extensions/gondolin/package-lock.json +2 -2
  311. package/examples/extensions/gondolin/package.json +1 -1
  312. package/examples/extensions/notify.ts +3 -1
  313. package/examples/extensions/sandbox/package-lock.json +2 -2
  314. package/examples/extensions/sandbox/package.json +1 -1
  315. package/examples/extensions/subagent/README.md +1 -1
  316. package/examples/extensions/subagent/index.ts +6 -1
  317. package/examples/extensions/titlebar-spinner.ts +1 -1
  318. package/examples/extensions/with-deps/package-lock.json +2 -2
  319. package/examples/extensions/with-deps/package.json +1 -1
  320. package/examples/rpc-extension-ui.ts +1 -1
  321. package/examples/sdk/06-extensions.ts +1 -1
  322. package/examples/sdk/README.md +1 -1
  323. package/package.json +12 -14
@@ -24,7 +24,7 @@ import { normalizeToolResultImages } from "../utils/tool-result-images.js";
24
24
  import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
25
25
  import { executeBashWithOperations } from "./bash-executor.js";
26
26
  import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
27
- import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
27
+ import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "./defaults.js";
28
28
  import { exportSessionToHtml } from "./export-html/index.js";
29
29
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
30
30
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
@@ -72,8 +72,6 @@ function estimateMessagesTokens(messages) {
72
72
  // ============================================================================
73
73
  // Constants
74
74
  // ============================================================================
75
- /** Standard thinking levels */
76
- const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high"];
77
75
  const INTRA_TURN_COMPACTION_MARKER_TYPE = "pi:intra-turn-compaction";
78
76
  const INTRA_TURN_COMPACTION_MARKER_TEXT = "Continue from the compaction summary above. The previous tool loop was compacted before the next provider request; use the summary's Operational State, file lists, failures, last command, and next steps.";
79
77
  const VALIDATION_HINT_MESSAGE_TYPE = "pi:validation-hint";
@@ -172,6 +170,8 @@ export class AgentSession {
172
170
  _followUpMessages = [];
173
171
  /** Messages queued to be included with the next user prompt as context ("asides"). */
174
172
  _pendingNextTurnMessages = [];
173
+ /** Context-only custom messages queued during a run, flushed once the current turn's tool results are in. */
174
+ _pendingCustomMessages = [];
175
175
  // Compaction state
176
176
  _compactionAbortController = undefined;
177
177
  _autoCompactionAbortController = undefined;
@@ -474,6 +474,11 @@ export class AgentSession {
474
474
  followUp: [...this._followUpMessages],
475
475
  });
476
476
  }
477
+ async _emitSessionCompactFailed(event) {
478
+ if (this._extensionRunner.hasHandlers("session_compact_failed")) {
479
+ await this._extensionRunner.emit({ type: "session_compact_failed", ...event });
480
+ }
481
+ }
477
482
  _getIdleWaitPromise() {
478
483
  if (!this._idleWaitPromise) {
479
484
  this._idleWaitPromise = new Promise((resolve) => {
@@ -564,6 +569,14 @@ export class AgentSession {
564
569
  }
565
570
  }
566
571
  }
572
+ // A turn ends after its assistant message and every tool result has been appended,
573
+ // so this is the first point in the run where a context-only custom message can be
574
+ // inserted without landing between a tool call and its result. Flushing after the
575
+ // extension and listener dispatch above also picks up messages that turn_end
576
+ // handlers queued.
577
+ if (event.type === "turn_end") {
578
+ this._flushPendingCustomMessages();
579
+ }
567
580
  };
568
581
  _willRetryAfterAgentEnd(event) {
569
582
  const settings = this.settingsManager.getRetrySettings();
@@ -992,6 +1005,7 @@ export class AgentSession {
992
1005
  finally {
993
1006
  this._systemPromptOverride = undefined;
994
1007
  this._flushPendingBashMessages();
1008
+ this._flushPendingCustomMessages();
995
1009
  await this._emitAgentSettled();
996
1010
  }
997
1011
  }
@@ -1150,8 +1164,9 @@ export class AgentSession {
1150
1164
  preflightResult?.(true);
1151
1165
  return;
1152
1166
  }
1153
- // Flush any pending bash messages before the new prompt
1167
+ // Flush any pending bash and custom messages before the new prompt
1154
1168
  this._flushPendingBashMessages();
1169
+ this._flushPendingCustomMessages();
1155
1170
  // Validate model
1156
1171
  if (!this.model) {
1157
1172
  throw new Error(formatNoModelSelectedMessage());
@@ -1368,8 +1383,9 @@ export class AgentSession {
1368
1383
  /**
1369
1384
  * Send a custom message to the session. Creates a CustomMessageEntry.
1370
1385
  *
1371
- * Handles three cases:
1386
+ * Handles four cases:
1372
1387
  * - Streaming: queues message, processed when loop pulls from queue
1388
+ * - Streaming + triggerTurn false: appended to state/session once the current turn ends
1373
1389
  * - Not streaming + triggerTurn: appends to state/session, starts new turn
1374
1390
  * - Not streaming + no trigger: appends to state/session, no turn
1375
1391
  *
@@ -1401,11 +1417,34 @@ export class AgentSession {
1401
1417
  else if (options?.triggerTurn) {
1402
1418
  await this._runAgentPrompt(appMessage);
1403
1419
  }
1420
+ else if (this.isStreaming) {
1421
+ // Appending now would put the message between an assistant tool call and its
1422
+ // result, which providers that validate message order reject on replay. Defer
1423
+ // to the end of the turn. Nothing is emitted yet: message events must not
1424
+ // describe messages the session tree does not contain.
1425
+ this._pendingCustomMessages.push(appMessage);
1426
+ }
1404
1427
  else {
1405
- this.agent.state.messages.push(appMessage);
1406
- this.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, message.details);
1407
- this._emit({ type: "message_start", message: appMessage });
1408
- this._emit({ type: "message_end", message: appMessage });
1428
+ this._appendCustomMessage(appMessage);
1429
+ }
1430
+ }
1431
+ _appendCustomMessage(appMessage) {
1432
+ this.agent.state.messages.push(appMessage);
1433
+ this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details);
1434
+ this._emit({ type: "message_start", message: appMessage });
1435
+ this._emit({ type: "message_end", message: appMessage });
1436
+ }
1437
+ /**
1438
+ * Append custom messages queued while the agent was running.
1439
+ * Called once the current turn's tool results are in agent state and session history.
1440
+ */
1441
+ _flushPendingCustomMessages() {
1442
+ if (this._pendingCustomMessages.length === 0)
1443
+ return;
1444
+ const pending = this._pendingCustomMessages;
1445
+ this._pendingCustomMessages = [];
1446
+ for (const appMessage of pending) {
1447
+ this._appendCustomMessage(appMessage);
1409
1448
  }
1410
1449
  }
1411
1450
  /**
@@ -1503,10 +1542,11 @@ export class AgentSession {
1503
1542
  }
1504
1543
  /**
1505
1544
  * Set model directly.
1506
- * Validates that auth is configured, saves to session and settings.
1545
+ * Validates that auth is configured and saves to the session transcript.
1546
+ * Persists to global defaults only when options.persist is true.
1507
1547
  * @throws Error if no auth is configured for the model
1508
1548
  */
1509
- async setModel(model) {
1549
+ async setModel(model, options = {}) {
1510
1550
  if (!(await this._modelRuntime.checkAuth(model.provider))) {
1511
1551
  throw new Error(`No API key for ${model.provider}/${model.id}`);
1512
1552
  }
@@ -1514,27 +1554,46 @@ export class AgentSession {
1514
1554
  await this.abort();
1515
1555
  }
1516
1556
  const previousModel = this.model;
1517
- const thinkingLevel = this._getThinkingLevelForModelSwitch();
1557
+ const thinkingLevel = this._getThinkingLevelForModelSwitch(model);
1518
1558
  this.agent.state.model = model;
1519
1559
  this.sessionManager.appendModelChange(model.provider, model.id);
1520
- this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
1521
- // Re-clamp thinking level for new model's capabilities
1560
+ if (options.persist) {
1561
+ this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
1562
+ this._addPersistedDefaultToNonEmptyScope(model);
1563
+ }
1564
+ // Apply thinking level for the new model.
1565
+ // Per-model thinking level overrides take priority over the global default.
1566
+ // Model persistence does not implicitly rewrite the global thinking default.
1522
1567
  this.setThinkingLevel(thinkingLevel);
1523
1568
  await this._emitModelSelect(model, previousModel, "set");
1524
1569
  }
1570
+ _addPersistedDefaultToNonEmptyScope(model) {
1571
+ if (this._scopedModels.length === 0)
1572
+ return;
1573
+ if (this._scopedModels.some((scoped) => modelsAreEqual(scoped.model, model)))
1574
+ return;
1575
+ this._scopedModels = [...this._scopedModels, { model }];
1576
+ const enabledModels = this.settingsManager.getEnabledModels();
1577
+ if (!enabledModels?.length)
1578
+ return;
1579
+ const modelReference = `${model.provider}/${model.id}`;
1580
+ if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
1581
+ return;
1582
+ this.settingsManager.setEnabledModels([...enabledModels, modelReference]);
1583
+ }
1525
1584
  /**
1526
1585
  * Cycle to next/previous model.
1527
1586
  * Uses scoped models (from --models flag) if available, otherwise all available models.
1528
1587
  * @param direction - "forward" (default) or "backward"
1529
1588
  * @returns The new model info, or undefined if only one model available
1530
1589
  */
1531
- async cycleModel(direction = "forward") {
1590
+ async cycleModel(direction = "forward", options = {}) {
1532
1591
  if (this._scopedModels.length > 0) {
1533
- return this._cycleScopedModel(direction);
1592
+ return this._cycleScopedModel(direction, options);
1534
1593
  }
1535
- return this._cycleAvailableModel(direction);
1594
+ return this._cycleAvailableModel(direction, options);
1536
1595
  }
1537
- async _cycleScopedModel(direction) {
1596
+ async _cycleScopedModel(direction, options) {
1538
1597
  const availableIds = new Set(this._modelRuntime.getAvailableSnapshot().map((model) => `${model.provider}\0${model.id}`));
1539
1598
  const scopedModels = this._scopedModels.filter((scoped) => availableIds.has(`${scoped.model.provider}\0${scoped.model.id}`));
1540
1599
  if (scopedModels.length <= 1)
@@ -1546,20 +1605,24 @@ export class AgentSession {
1546
1605
  const len = scopedModels.length;
1547
1606
  const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
1548
1607
  const next = scopedModels[nextIndex];
1549
- const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
1608
+ const thinkingLevel = this._getThinkingLevelForModelSwitch(next.model, next.thinkingLevel);
1550
1609
  // Apply model
1551
1610
  this.agent.state.model = next.model;
1552
1611
  this.sessionManager.appendModelChange(next.model.provider, next.model.id);
1553
- this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
1554
- // Apply thinking level.
1555
- // - Explicit scoped model thinking level overrides current session level
1556
- // - Undefined scoped model thinking level inherits the current session preference
1612
+ if (options.persist) {
1613
+ this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
1614
+ this._addPersistedDefaultToNonEmptyScope(next.model);
1615
+ }
1616
+ // Apply thinking level for the new model.
1617
+ // - Explicit scoped model thinking level overrides defaults
1618
+ // - Per-model thinking level overrides take priority over the global default
1557
1619
  // setThinkingLevel clamps to model capabilities.
1620
+ // Model persistence does not implicitly rewrite the global thinking default.
1558
1621
  this.setThinkingLevel(thinkingLevel);
1559
1622
  await this._emitModelSelect(next.model, currentModel, "cycle");
1560
1623
  return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
1561
1624
  }
1562
- async _cycleAvailableModel(direction) {
1625
+ async _cycleAvailableModel(direction, options) {
1563
1626
  const availableModels = this._modelRuntime.getAvailableSnapshot();
1564
1627
  if (availableModels.length <= 1)
1565
1628
  return undefined;
@@ -1570,11 +1633,15 @@ export class AgentSession {
1570
1633
  const len = availableModels.length;
1571
1634
  const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
1572
1635
  const nextModel = availableModels[nextIndex];
1573
- const thinkingLevel = this._getThinkingLevelForModelSwitch();
1636
+ const thinkingLevel = this._getThinkingLevelForModelSwitch(nextModel);
1574
1637
  this.agent.state.model = nextModel;
1575
1638
  this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
1576
- this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
1577
- // Re-clamp thinking level for new model's capabilities
1639
+ if (options.persist) {
1640
+ this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
1641
+ this._addPersistedDefaultToNonEmptyScope(nextModel);
1642
+ }
1643
+ // Apply thinking level for the new model.
1644
+ // Model persistence does not implicitly rewrite the global thinking default.
1578
1645
  this.setThinkingLevel(thinkingLevel);
1579
1646
  await this._emitModelSelect(nextModel, currentModel, "cycle");
1580
1647
  return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };
@@ -1585,20 +1652,21 @@ export class AgentSession {
1585
1652
  /**
1586
1653
  * Set thinking level.
1587
1654
  * Clamps to model capabilities based on available thinking levels.
1588
- * Saves to session and settings only if the level actually changes.
1655
+ * Saves the clamped level to the session transcript only if the level actually changes.
1656
+ * Persists the requested level to global defaults only when options.persist is true.
1589
1657
  */
1590
- setThinkingLevel(level) {
1658
+ setThinkingLevel(level, options = {}) {
1591
1659
  const availableLevels = this.getAvailableThinkingLevels();
1592
1660
  const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);
1593
1661
  // Only persist if actually changing
1594
1662
  const previousLevel = this.agent.state.thinkingLevel;
1595
1663
  const isChanging = effectiveLevel !== previousLevel;
1596
1664
  this.agent.state.thinkingLevel = effectiveLevel;
1665
+ if (options.persist) {
1666
+ this.settingsManager.setDefaultThinkingLevel(level);
1667
+ }
1597
1668
  if (isChanging) {
1598
1669
  this.sessionManager.appendThinkingLevelChange(effectiveLevel);
1599
- if (this.supportsThinking() || effectiveLevel !== "off") {
1600
- this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
1601
- }
1602
1670
  this._emit({ type: "thinking_level_changed", level: effectiveLevel });
1603
1671
  void this._extensionRunner.emit({
1604
1672
  type: "thinking_level_select",
@@ -1611,14 +1679,14 @@ export class AgentSession {
1611
1679
  * Cycle to next thinking level.
1612
1680
  * @returns New level, or undefined if model doesn't support thinking
1613
1681
  */
1614
- cycleThinkingLevel() {
1682
+ cycleThinkingLevel(options = {}) {
1615
1683
  if (!this.supportsThinking())
1616
1684
  return undefined;
1617
1685
  const levels = this.getAvailableThinkingLevels();
1618
1686
  const currentIndex = levels.indexOf(this.thinkingLevel);
1619
1687
  const nextIndex = (currentIndex + 1) % levels.length;
1620
1688
  const nextLevel = levels[nextIndex];
1621
- this.setThinkingLevel(nextLevel);
1689
+ this.setThinkingLevel(nextLevel, options);
1622
1690
  return nextLevel;
1623
1691
  }
1624
1692
  /**
@@ -1627,7 +1695,7 @@ export class AgentSession {
1627
1695
  */
1628
1696
  getAvailableThinkingLevels() {
1629
1697
  if (!this.model)
1630
- return THINKING_LEVELS;
1698
+ return [...THINKING_LEVEL_OPTIONS];
1631
1699
  return getSupportedThinkingLevels(this.model);
1632
1700
  }
1633
1701
  /**
@@ -1636,14 +1704,17 @@ export class AgentSession {
1636
1704
  supportsThinking() {
1637
1705
  return !!this.model?.reasoning;
1638
1706
  }
1639
- _getThinkingLevelForModelSwitch(explicitLevel) {
1707
+ _getThinkingLevelForModelSwitch(targetModel, explicitLevel) {
1640
1708
  if (explicitLevel !== undefined) {
1641
1709
  return explicitLevel;
1642
1710
  }
1643
- if (!this.supportsThinking()) {
1644
- return this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
1711
+ if (targetModel) {
1712
+ const perModel = this.settingsManager.getModelThinkingLevel(targetModel.provider, targetModel.id);
1713
+ if (perModel !== undefined) {
1714
+ return perModel;
1715
+ }
1645
1716
  }
1646
- return this.thinkingLevel;
1717
+ return this.settingsManager.getDefaultThinkingLevel() ?? this.thinkingLevel ?? DEFAULT_THINKING_LEVEL;
1647
1718
  }
1648
1719
  _clampThinkingLevel(level, _availableLevels) {
1649
1720
  return this.model ? clampThinkingLevel(this.model, level) : "off";
@@ -1907,20 +1978,24 @@ export class AgentSession {
1907
1978
  // independent of the configured context size or any context-clamped provider request limit.
1908
1979
  // A successful response over the configured window should compact but must not retry: the
1909
1980
  // assistant answer already completed and agent.continue() cannot continue from an assistant.
1981
+ const contextOverflow = sameModel && isContextOverflow(assistantMessage, contextWindow);
1910
1982
  const recoverableLength = sameModel && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0);
1911
- if (sameModel && (isContextOverflow(assistantMessage, contextWindow) || recoverableLength)) {
1983
+ if (contextOverflow || recoverableLength) {
1912
1984
  const willRetry = assistantMessage.stopReason !== "stop";
1913
1985
  if (!willRetry) {
1914
1986
  return await this._runAutoCompaction("overflow", false);
1915
1987
  }
1916
1988
  if (this._overflowRecoveryAttempted) {
1989
+ const errorMessage = contextOverflow
1990
+ ? "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model."
1991
+ : "Truncated response recovery failed after one compact-and-retry attempt.";
1917
1992
  this._emit({
1918
1993
  type: "compaction_end",
1919
1994
  reason: "overflow",
1920
1995
  result: undefined,
1921
1996
  aborted: false,
1922
1997
  willRetry: false,
1923
- errorMessage: "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.",
1998
+ errorMessage,
1924
1999
  });
1925
2000
  return false;
1926
2001
  }
@@ -1950,16 +2025,16 @@ export class AgentSession {
1950
2025
  if (assistantMessage.stopReason === "error" || directContextTokens === 0) {
1951
2026
  const messages = this.agent.state.messages;
1952
2027
  const estimate = estimateContextTokens(messages);
1953
- if (estimate.lastUsageIndex === null)
1954
- return false; // No usage data at all
1955
- // Verify the usage source is post-compaction. Kept pre-compaction messages
1956
- // have stale usage reflecting the old (larger) context and would falsely
1957
- // trigger compaction right after one just finished.
1958
- const usageMsg = messages[estimate.lastUsageIndex];
1959
- if (compactionTimestamp > 0 &&
1960
- usageMsg.role === "assistant" &&
1961
- usageMsg.timestamp <= compactionTimestamp) {
1962
- return false;
2028
+ // When a valid usage entry exists, verify it is post-compaction. Kept
2029
+ // pre-compaction messages have stale usage reflecting the old (larger)
2030
+ // context and would falsely trigger compaction right after one finished.
2031
+ if (estimate.lastUsageIndex !== null) {
2032
+ const usageMsg = messages[estimate.lastUsageIndex];
2033
+ if (compactionTimestamp > 0 &&
2034
+ usageMsg.role === "assistant" &&
2035
+ usageMsg.timestamp <= compactionTimestamp) {
2036
+ return false;
2037
+ }
1963
2038
  }
1964
2039
  contextTokens = estimate.tokens;
1965
2040
  }
@@ -1977,6 +2052,7 @@ export class AgentSession {
1977
2052
  async _runAutoCompaction(reason, willRetry, preparationOverride, preparationOptions) {
1978
2053
  const settings = this.settingsManager.getCompactionSettings();
1979
2054
  let started = false;
2055
+ let fromExtension = false;
1980
2056
  try {
1981
2057
  if (!this.model) {
1982
2058
  return false;
@@ -2016,7 +2092,6 @@ export class AgentSession {
2016
2092
  this._autoCompactionAbortController = new AbortController();
2017
2093
  started = true;
2018
2094
  let extensionCompaction;
2019
- let fromExtension = false;
2020
2095
  if (this._extensionRunner.hasHandlers("session_before_compact")) {
2021
2096
  const extensionResult = (await this._extensionRunner.emit({
2022
2097
  type: "session_before_compact",
@@ -2035,6 +2110,12 @@ export class AgentSession {
2035
2110
  aborted: true,
2036
2111
  willRetry: false,
2037
2112
  });
2113
+ await this._emitSessionCompactFailed({
2114
+ reason,
2115
+ aborted: true,
2116
+ willRetry: false,
2117
+ fromExtension: false,
2118
+ });
2038
2119
  return false;
2039
2120
  }
2040
2121
  if (extensionResult?.compaction) {
@@ -2072,6 +2153,12 @@ export class AgentSession {
2072
2153
  aborted: true,
2073
2154
  willRetry: false,
2074
2155
  });
2156
+ await this._emitSessionCompactFailed({
2157
+ reason,
2158
+ aborted: true,
2159
+ willRetry: false,
2160
+ fromExtension,
2161
+ });
2075
2162
  return false;
2076
2163
  }
2077
2164
  this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
@@ -2128,6 +2215,15 @@ export class AgentSession {
2128
2215
  ? `Context overflow recovery failed: ${errorMessage}`
2129
2216
  : `Auto-compaction failed: ${errorMessage}`,
2130
2217
  });
2218
+ await this._emitSessionCompactFailed({
2219
+ reason,
2220
+ errorMessage: reason === "overflow"
2221
+ ? `Context overflow recovery failed: ${errorMessage}`
2222
+ : `Auto-compaction failed: ${errorMessage}`,
2223
+ aborted: false,
2224
+ willRetry: false,
2225
+ fromExtension,
2226
+ });
2131
2227
  }
2132
2228
  return false;
2133
2229
  }
@@ -2537,11 +2633,9 @@ export class AgentSession {
2537
2633
  // =========================================================================
2538
2634
  // Auto-Retry
2539
2635
  // =========================================================================
2540
- _isNonRetryableProviderLimitError(errorMessage) {
2541
- return /GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient.?balance|balance.?insufficient|insufficient_quota|out of budget|quota exceeded|billing|payment required|402/i.test(errorMessage);
2542
- }
2543
2636
  /**
2544
- * Check if an error is retryable (overloaded, rate limit, server errors).
2637
+ * Check if an error is retryable. Provider error text is retryable by default,
2638
+ * except usage/quota/balance limits and session or context failures.
2545
2639
  * Context overflow errors are NOT retryable (handled by compaction instead).
2546
2640
  */
2547
2641
  _isRetryableError(message) {
@@ -2553,8 +2647,6 @@ export class AgentSession {
2553
2647
  const piServerPhase = getPiServerFailurePhase(message);
2554
2648
  if (piServerPhase && piServerPhase !== "provider_stream")
2555
2649
  return false;
2556
- if (message.errorMessage && this._isNonRetryableProviderLimitError(message.errorMessage))
2557
- return false;
2558
2650
  return isRetryableAssistantError(message);
2559
2651
  }
2560
2652
  /**