@astralyn/pi 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/dist/bundle/chunks/anthropic-messages-MSB6JBS2.js +6 -0
  3. package/dist/bundle/chunks/{azure-openai-responses-CH74HGP4.js → azure-openai-responses-ATZ757I2.js} +1 -1
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +14 -11
  5. package/dist/bundle/chunks/{chunk-H35KWBT5.js → chunk-4XZYHGVN.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-MAC4N3BW.js → chunk-7UBIBLPN.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-KAC2YPTW.js → chunk-J75WV3FL.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-EJEOEBSJ.js → chunk-KSCGI7JW.js} +2 -2
  9. package/dist/bundle/chunks/chunk-LUYFHZ6W.js +11 -0
  10. package/dist/bundle/chunks/{chunk-TEAAYBTS.js → chunk-NM2KGRFS.js} +1 -1
  11. package/dist/bundle/chunks/chunk-Q74S7ILH.js +2 -0
  12. package/dist/bundle/chunks/{chunk-QLU3LESZ.js → chunk-QDDSFJ35.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-D3XW5X3Z.js → chunk-R2KES7LS.js} +175 -244
  14. package/dist/bundle/chunks/{chunk-5B3S5DVL.js → chunk-SA2AQYEI.js} +5 -2
  15. package/dist/bundle/chunks/{chunk-C2ARIVS3.js → chunk-YHRHHXFG.js} +1 -1
  16. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-XO45ZT3V.js → cloudflare-workers-ai-system-one-HGOVFZDC.js} +1 -1
  17. package/dist/bundle/chunks/codemode-worker.js +17 -9
  18. package/dist/bundle/chunks/github-copilot.js +1 -1
  19. package/dist/bundle/chunks/{google-generative-ai-VVO64ZRQ.js → google-generative-ai-QRLQ4MCJ.js} +1 -1
  20. package/dist/bundle/chunks/{google-vertex-LKS5NUHA.js → google-vertex-L3T6EGTL.js} +1 -1
  21. package/dist/bundle/chunks/mistral-conversations-6E6SS3WF.js +5 -0
  22. package/dist/bundle/chunks/openai-codex-responses-4GUO76XJ.js +10 -0
  23. package/dist/bundle/chunks/{openai-completions-7HTTU6FH.js → openai-completions-O4TKZCIM.js} +1 -1
  24. package/dist/bundle/chunks/{openai-decisions-776H4VDZ.js → openai-decisions-TVCDIPZX.js} +1 -1
  25. package/dist/bundle/chunks/openai-responses-VBQKJFNO.js +3 -0
  26. package/dist/bundle/chunks/{pi-messages-ZXNERWJG.js → pi-messages-3POWZ43C.js} +1 -1
  27. package/dist/bundle/chunks/{typesafe-system-one-2DQLG4R2.js → typesafe-system-one-LWPJYTJP.js} +1 -1
  28. package/dist/bundle/chunks/{virtual-modules-2NHGQRS6.js → virtual-modules-TG53AOL4.js} +1 -1
  29. package/dist/bundle/cli.js +1 -1
  30. package/dist/bundle/index.js +1 -1
  31. package/dist/bundle/rpc-entry.js +1 -1
  32. package/dist/cli/credential-print.d.ts.map +1 -1
  33. package/dist/cli/credential-print.js +4 -4
  34. package/dist/cli/credential-print.js.map +1 -1
  35. package/dist/core/agent-session.d.ts +18 -3
  36. package/dist/core/agent-session.d.ts.map +1 -1
  37. package/dist/core/agent-session.js +98 -62
  38. package/dist/core/agent-session.js.map +1 -1
  39. package/dist/core/auth-storage.d.ts.map +1 -1
  40. package/dist/core/auth-storage.js +20 -13
  41. package/dist/core/auth-storage.js.map +1 -1
  42. package/dist/core/bug-report.d.ts +9 -1
  43. package/dist/core/bug-report.d.ts.map +1 -1
  44. package/dist/core/compaction/utils.d.ts +6 -0
  45. package/dist/core/compaction/utils.d.ts.map +1 -1
  46. package/dist/core/compaction/utils.js +7 -8
  47. package/dist/core/compaction/utils.js.map +1 -1
  48. package/dist/core/export-html/template.js +21 -16
  49. package/dist/core/extensions/index.d.ts +1 -1
  50. package/dist/core/extensions/index.d.ts.map +1 -1
  51. package/dist/core/extensions/index.js.map +1 -1
  52. package/dist/core/extensions/runner.d.ts +4 -2
  53. package/dist/core/extensions/runner.d.ts.map +1 -1
  54. package/dist/core/extensions/runner.js +2 -3
  55. package/dist/core/extensions/runner.js.map +1 -1
  56. package/dist/core/extensions/types.d.ts +31 -7
  57. package/dist/core/extensions/types.d.ts.map +1 -1
  58. package/dist/core/extensions/types.js.map +1 -1
  59. package/dist/core/key-id-schema.d.ts +6 -0
  60. package/dist/core/key-id-schema.d.ts.map +1 -0
  61. package/dist/core/key-id-schema.js +16 -0
  62. package/dist/core/key-id-schema.js.map +1 -0
  63. package/dist/core/keybinding-registry.d.ts +4 -3
  64. package/dist/core/keybinding-registry.d.ts.map +1 -1
  65. package/dist/core/keybinding-registry.js +4 -3
  66. package/dist/core/keybinding-registry.js.map +1 -1
  67. package/dist/core/keybindings-schema.d.ts +4 -0
  68. package/dist/core/keybindings-schema.d.ts.map +1 -0
  69. package/dist/core/keybindings-schema.js +16 -0
  70. package/dist/core/keybindings-schema.js.map +1 -0
  71. package/dist/core/keybindings.d.ts +258 -81
  72. package/dist/core/keybindings.d.ts.map +1 -1
  73. package/dist/core/keybindings.js +27 -24
  74. package/dist/core/keybindings.js.map +1 -1
  75. package/dist/core/model-config.d.ts +729 -180
  76. package/dist/core/model-config.d.ts.map +1 -1
  77. package/dist/core/model-config.js +18 -179
  78. package/dist/core/model-config.js.map +1 -1
  79. package/dist/core/model-resolver.d.ts +56 -43
  80. package/dist/core/model-resolver.d.ts.map +1 -1
  81. package/dist/core/model-resolver.js +247 -352
  82. package/dist/core/model-resolver.js.map +1 -1
  83. package/dist/core/model-runtime.d.ts.map +1 -1
  84. package/dist/core/model-runtime.js +11 -6
  85. package/dist/core/model-runtime.js.map +1 -1
  86. package/dist/core/package-manager.d.ts.map +1 -1
  87. package/dist/core/package-manager.js +3 -3
  88. package/dist/core/package-manager.js.map +1 -1
  89. package/dist/core/project-trust.d.ts.map +1 -1
  90. package/dist/core/project-trust.js +2 -1
  91. package/dist/core/project-trust.js.map +1 -1
  92. package/dist/core/prompt-templates.d.ts.map +1 -1
  93. package/dist/core/prompt-templates.js +7 -2
  94. package/dist/core/prompt-templates.js.map +1 -1
  95. package/dist/core/remote-catalog-provider.d.ts +12 -1
  96. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  97. package/dist/core/remote-catalog-provider.js +82 -24
  98. package/dist/core/remote-catalog-provider.js.map +1 -1
  99. package/dist/core/resource-loader.d.ts.map +1 -1
  100. package/dist/core/resource-loader.js +7 -2
  101. package/dist/core/resource-loader.js.map +1 -1
  102. package/dist/core/settings-defaults.d.ts +66 -0
  103. package/dist/core/settings-defaults.d.ts.map +1 -0
  104. package/dist/core/settings-defaults.js +67 -0
  105. package/dist/core/settings-defaults.js.map +1 -0
  106. package/dist/core/settings-manager.d.ts +6 -149
  107. package/dist/core/settings-manager.d.ts.map +1 -1
  108. package/dist/core/settings-manager.js +59 -44
  109. package/dist/core/settings-manager.js.map +1 -1
  110. package/dist/core/settings-schema.d.ts +233 -0
  111. package/dist/core/settings-schema.d.ts.map +1 -0
  112. package/dist/core/settings-schema.js +298 -0
  113. package/dist/core/settings-schema.js.map +1 -0
  114. package/dist/core/slash-commands.js +1 -1
  115. package/dist/core/slash-commands.js.map +1 -1
  116. package/dist/core/tools/render-utils.d.ts +20 -0
  117. package/dist/core/tools/render-utils.d.ts.map +1 -1
  118. package/dist/core/tools/render-utils.js +67 -0
  119. package/dist/core/tools/render-utils.js.map +1 -1
  120. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  121. package/dist/core/tools/renderers/bash.js +21 -50
  122. package/dist/core/tools/renderers/bash.js.map +1 -1
  123. package/dist/core/tools/renderers/read.d.ts.map +1 -1
  124. package/dist/core/tools/renderers/read.js +7 -11
  125. package/dist/core/tools/renderers/read.js.map +1 -1
  126. package/dist/extensions/btw/keybindings.d.ts +2 -2
  127. package/dist/extensions/btw/keybindings.d.ts.map +1 -1
  128. package/dist/extensions/btw/keybindings.js.map +1 -1
  129. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  130. package/dist/extensions/codemode/execute.js +76 -45
  131. package/dist/extensions/codemode/execute.js.map +1 -1
  132. package/dist/extensions/codemode/index.d.ts.map +1 -1
  133. package/dist/extensions/codemode/index.js +3 -7
  134. package/dist/extensions/codemode/index.js.map +1 -1
  135. package/dist/extensions/codemode/renderer.d.ts +2 -2
  136. package/dist/extensions/codemode/renderer.d.ts.map +1 -1
  137. package/dist/extensions/codemode/renderer.js +9 -3
  138. package/dist/extensions/codemode/renderer.js.map +1 -1
  139. package/dist/extensions/codemode/tool.d.ts +6 -12
  140. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  141. package/dist/extensions/codemode/tool.js +44 -32
  142. package/dist/extensions/codemode/tool.js.map +1 -1
  143. package/dist/extensions/list-keybindings.d.ts +2 -2
  144. package/dist/extensions/list-keybindings.d.ts.map +1 -1
  145. package/dist/extensions/list-keybindings.js.map +1 -1
  146. package/dist/extensions/mcp/cli.js +5 -8
  147. package/dist/extensions/mcp/cli.js.map +1 -1
  148. package/dist/extensions/mcp/index.d.ts.map +1 -1
  149. package/dist/extensions/mcp/index.js +25 -34
  150. package/dist/extensions/mcp/index.js.map +1 -1
  151. package/dist/extensions/mcp/resources.d.ts +0 -6
  152. package/dist/extensions/mcp/resources.d.ts.map +1 -1
  153. package/dist/extensions/mcp/resources.js +1 -1
  154. package/dist/extensions/mcp/resources.js.map +1 -1
  155. package/dist/extensions/mcp/runtime.d.ts +3 -6
  156. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  157. package/dist/extensions/mcp/runtime.js +4 -39
  158. package/dist/extensions/mcp/runtime.js.map +1 -1
  159. package/dist/extensions/mcp/tools.d.ts +2 -3
  160. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  161. package/dist/extensions/mcp/tools.js +62 -6
  162. package/dist/extensions/mcp/tools.js.map +1 -1
  163. package/dist/extensions/provider/keybindings.d.ts +2 -2
  164. package/dist/extensions/provider/keybindings.d.ts.map +1 -1
  165. package/dist/extensions/provider/keybindings.js.map +1 -1
  166. package/dist/extensions/search/code-search.d.ts +0 -2
  167. package/dist/extensions/search/code-search.d.ts.map +1 -1
  168. package/dist/extensions/search/code-search.js +2 -2
  169. package/dist/extensions/search/code-search.js.map +1 -1
  170. package/dist/extensions/search/command.js +2 -2
  171. package/dist/extensions/search/command.js.map +1 -1
  172. package/dist/extensions/search/index.d.ts.map +1 -1
  173. package/dist/extensions/search/index.js +14 -11
  174. package/dist/extensions/search/index.js.map +1 -1
  175. package/dist/extensions/search/workspace.d.ts +11 -10
  176. package/dist/extensions/search/workspace.d.ts.map +1 -1
  177. package/dist/extensions/search/workspace.js +259 -141
  178. package/dist/extensions/search/workspace.js.map +1 -1
  179. package/dist/extensions/tool-search/index.d.ts.map +1 -1
  180. package/dist/extensions/tool-search/index.js +1 -6
  181. package/dist/extensions/tool-search/index.js.map +1 -1
  182. package/dist/extensions/tool-search/tool.d.ts +0 -2
  183. package/dist/extensions/tool-search/tool.d.ts.map +1 -1
  184. package/dist/extensions/tool-search/tool.js +2 -4
  185. package/dist/extensions/tool-search/tool.js.map +1 -1
  186. package/dist/index.d.ts +2 -1
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +1 -0
  189. package/dist/index.js.map +1 -1
  190. package/dist/main.d.ts.map +1 -1
  191. package/dist/main.js +4 -3
  192. package/dist/main.js.map +1 -1
  193. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  194. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/settings-selector.js +13 -2
  196. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  197. package/dist/modes/interactive/components/status-indicator.d.ts +1 -1
  198. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  199. package/dist/modes/interactive/components/status-indicator.js +2 -2
  200. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  201. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/tree-selector.js +2 -9
  203. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  204. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  205. package/dist/modes/interactive/interactive-mode.js +20 -8
  206. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  207. package/dist/modes/interactive/session-share.d.ts.map +1 -1
  208. package/dist/modes/interactive/session-share.js +9 -2
  209. package/dist/modes/interactive/session-share.js.map +1 -1
  210. package/dist/modes/interactive/tasks/layout.d.ts +2 -0
  211. package/dist/modes/interactive/tasks/layout.d.ts.map +1 -1
  212. package/dist/modes/interactive/tasks/layout.js +32 -6
  213. package/dist/modes/interactive/tasks/layout.js.map +1 -1
  214. package/dist/modes/interactive/tasks/manager.d.ts.map +1 -1
  215. package/dist/modes/interactive/tasks/manager.js +20 -2
  216. package/dist/modes/interactive/tasks/manager.js.map +1 -1
  217. package/dist/modes/interactive/theme/dark.json +1 -1
  218. package/dist/modes/interactive/theme/light.json +1 -1
  219. package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
  220. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
  221. package/dist/modes/interactive/theme/theme-schema.js +105 -0
  222. package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
  223. package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
  224. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
  225. package/dist/modes/interactive/theme/theme-tokens.js +94 -0
  226. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
  227. package/dist/modes/interactive/theme/theme.d.ts +13 -16
  228. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  229. package/dist/modes/interactive/theme/theme.js +23 -31
  230. package/dist/modes/interactive/theme/theme.js.map +1 -1
  231. package/dist/modes/print-mode.d.ts.map +1 -1
  232. package/dist/modes/print-mode.js +4 -0
  233. package/dist/modes/print-mode.js.map +1 -1
  234. package/dist/utils/clipboard.d.ts.map +1 -1
  235. package/dist/utils/clipboard.js +6 -1
  236. package/dist/utils/clipboard.js.map +1 -1
  237. package/docs/bundled/extensions/search.md +2 -1
  238. package/docs/bundled/tasks.md +1 -1
  239. package/docs/codemode.md +2 -1
  240. package/docs/compaction.md +2 -2
  241. package/docs/development.md +0 -13
  242. package/docs/docs.json +12 -0
  243. package/docs/environment-variables.md +2 -3
  244. package/docs/extensions.md +11 -5
  245. package/docs/keybindings.md +1 -0
  246. package/docs/llama-cpp.md +1 -1
  247. package/docs/mcp.md +1 -1
  248. package/docs/models.md +1 -0
  249. package/docs/nvidia-rtx-llama-cpp.md +96 -0
  250. package/docs/providers.md +17 -1
  251. package/docs/sdk.md +0 -27
  252. package/docs/sessions.md +1 -1
  253. package/docs/settings.md +4 -3
  254. package/docs/themes.md +4 -2
  255. package/docs/tui.md +1 -1
  256. package/docs/usage.md +7 -5
  257. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  258. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  259. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  260. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  261. package/examples/extensions/gondolin/package-lock.json +2 -2
  262. package/examples/extensions/gondolin/package.json +1 -1
  263. package/examples/extensions/minimal-mode.ts +4 -5
  264. package/examples/extensions/overlay-test.ts +2 -2
  265. package/examples/extensions/plan-mode/index.ts +6 -2
  266. package/examples/extensions/sandbox/package-lock.json +2 -2
  267. package/examples/extensions/sandbox/package.json +1 -1
  268. package/examples/extensions/with-deps/package-lock.json +2 -2
  269. package/examples/extensions/with-deps/package.json +1 -1
  270. package/npm-shrinkwrap.json +151 -199
  271. package/package.json +8 -20
  272. package/schemas/keybindings.schema.json +453 -0
  273. package/schemas/models.schema.json +1157 -0
  274. package/schemas/settings.schema.json +800 -0
  275. package/schemas/theme.schema.json +365 -0
  276. package/dist/bundle/chunks/anthropic-messages-3K3DWVY6.js +0 -6
  277. package/dist/bundle/chunks/chunk-3MMB5I7J.js +0 -11
  278. package/dist/bundle/chunks/mistral-conversations-NJUOG4ET.js +0 -5
  279. package/dist/bundle/chunks/openai-codex-responses-TZWBTTYM.js +0 -10
  280. package/dist/bundle/chunks/openai-responses-7A6BAQ5X.js +0 -3
  281. package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
  282. package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
  283. package/dist/modes/interactive/theme/theme-json.js +0 -132
  284. package/dist/modes/interactive/theme/theme-json.js.map +0 -1
  285. package/dist/modes/interactive/theme/theme-schema.json +0 -361
  286. package/examples/plugins/pi-example-plugin/README.md +0 -38
  287. package/examples/plugins/pi-example-plugin/package.json +0 -10
  288. package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
  289. package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
  290. package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
@@ -140,6 +140,10 @@ export class AgentSession {
140
140
  this._handleAgentEvent = async (event) => {
141
141
  if (event.type === "message_start")
142
142
  this._tasksHost.delivery.messageStarted(event.message);
143
+ // An abort requested while the run was starting, e.g. during before_agent_start, stops it
144
+ // here. agent_start is awaited before the first request.
145
+ if (event.type === "agent_start" && this._agentRunAbortRequested)
146
+ this.agent.abort();
143
147
  // Record the calls a tool made through ctx.executeTool() and their usage on its result message.
144
148
  if (this._nestedToolCalls) {
145
149
  if (event.type === "message_start" && event.message.role === "toolResult") {
@@ -249,8 +253,9 @@ export class AgentSession {
249
253
  this.agent.steer(message);
250
254
  return waitForPersistence();
251
255
  }
252
- // Completion turns skip before_agent_start, but consume nextTurn context.
253
- return this._runAgentPrompt([message, ...this._pendingNextTurnMessages]);
256
+ // An idle delivery starts its own custom-message run, which consumes the
257
+ // pending nextTurn context in _prepareRun.
258
+ return this._startRun({ messageType: "custom", message });
254
259
  },
255
260
  onEntry: (entry) => this._emit({ type: "entry_appended", entry }),
256
261
  onError: (event, error) => this._extensionRunner?.emitError({ extensionPath: "<background>", event, error }),
@@ -290,8 +295,8 @@ export class AgentSession {
290
295
  activeToolNames: this._initialActiveToolNames,
291
296
  includeAllExtensionTools: true,
292
297
  });
293
- if (this._initialActiveToolNames === undefined)
294
- this._restoreToolsFromTranscript();
298
+ if (this._usesDefaultTools)
299
+ this._restoreToolsFromTranscript(this._defaultToolModifiers);
295
300
  }
296
301
  get tasks() {
297
302
  return this._tasksHost.service;
@@ -1130,6 +1135,7 @@ export class AgentSession {
1130
1135
  exposure: this._getToolExposure(definition.name),
1131
1136
  ...(definition.namespace ? { namespace: definition.namespace } : {}),
1132
1137
  ...(definition.annotations ? { annotations: { ...definition.annotations } } : {}),
1138
+ ...(definition.reachesTools ? { reachesTools: definition.reachesTools } : {}),
1133
1139
  sourceInfo,
1134
1140
  }));
1135
1141
  }
@@ -1410,28 +1416,51 @@ export class AgentSession {
1410
1416
  * Restore the active tool loadout declared by the session transcript, if it declares one.
1411
1417
  * Tools reachable only from other tools are never declared, but they do not depend on the active
1412
1418
  * set, so the transcript's declarations are the whole loadout.
1419
+ * @param modifiers `+name`/`-name` entries applied to the restored loadout.
1413
1420
  */
1414
- _restoreToolsFromTranscript() {
1421
+ _restoreToolsFromTranscript(modifiers = []) {
1415
1422
  this._pendingToolNames.clear();
1416
1423
  const current = getCurrentSystemMessage(this.sessionManager.buildSessionContext().messages);
1417
1424
  if (!current)
1418
1425
  return;
1419
- const names = (current.toolsAdded ?? []).map((tool) => tool.name);
1426
+ const names = applyToolModifiers((current.toolsAdded ?? []).map((tool) => tool.name), modifiers);
1420
1427
  this._pendingToolNames = new Set(names.filter((name) => this._isAllowedTool(name)));
1421
1428
  this._setActiveTools(names);
1422
1429
  }
1423
1430
  // =========================================================================
1424
1431
  // Prompting
1425
1432
  // =========================================================================
1426
- async _runAgentPrompt(messages) {
1433
+ /**
1434
+ * Start a run from a user or custom message. The session counts as busy from here on, so
1435
+ * messages sent while before_agent_start handlers run are queued into this run instead of
1436
+ * starting another, and an abort requested meanwhile aborts the run as soon as it exists.
1437
+ * @param onStarted Called once the run's messages are prepared, before the first request.
1438
+ */
1439
+ async _startRun(trigger, onStarted) {
1440
+ this._isAgentRunActive = true;
1427
1441
  this._agentRunAbortRequested = false;
1442
+ let messages;
1443
+ try {
1444
+ messages = await this._prepareRun(trigger);
1445
+ }
1446
+ catch (error) {
1447
+ this._isAgentRunActive = false;
1448
+ this._flushPendingBashMessages();
1449
+ this._flushPendingCustomMessages();
1450
+ this._resolveIdleWaitIfIdle();
1451
+ throw error;
1452
+ }
1453
+ // Messages held while the run was starting go before its starting messages, as they would
1454
+ // have while idle. No run exists yet, so they cannot split a tool call from its result.
1455
+ this._flushPendingBashMessages();
1456
+ this._flushPendingCustomMessages();
1457
+ onStarted?.();
1428
1458
  // Compaction before the prompt may have scheduled a retry; the new prompt replaces it.
1429
1459
  this._failedResponse = undefined;
1430
1460
  this._recordSelection();
1431
1461
  // The run records the loadout in the transcript; restored tools that did not register by now
1432
1462
  // are dropped, so a tool that never registers does not stay pending.
1433
1463
  this._pendingToolNames.clear();
1434
- this._isAgentRunActive = true;
1435
1464
  try {
1436
1465
  await this.agent.prompt(messages);
1437
1466
  while (!this._agentRunAbortRequested) {
@@ -1458,6 +1487,64 @@ export class AgentSession {
1458
1487
  await this._emitAgentSettled();
1459
1488
  }
1460
1489
  }
1490
+ /**
1491
+ * Prepare a run and return its starting messages: compact first when needed, emit
1492
+ * before_agent_start, apply the run's prompt options and tool loadout, and build the starting
1493
+ * message followed by pending nextTurn messages (consumed here) and handler messages, with a
1494
+ * system patch first when the prompt changed.
1495
+ */
1496
+ async _prepareRun(trigger) {
1497
+ // Check if we need to compact before sending (catches aborted responses).
1498
+ // The starting message is sent below, so do not call agent.continue() here.
1499
+ const lastAssistant = this._findLastAssistantMessage();
1500
+ if (lastAssistant) {
1501
+ await this._checkCompaction(lastAssistant, false);
1502
+ }
1503
+ const selectedToolsBefore = this._baseSystemPromptOptions.selectedTools;
1504
+ const result = await this._extensionRunner.emitBeforeAgentStart(trigger, this._baseSystemPromptOptions);
1505
+ // Handlers may edit event.systemPromptOptions.selectedTools or call setActiveTools(),
1506
+ // which updates the live loadout instead. An explicit edit wins; otherwise the live
1507
+ // loadout is authoritative, so a setActiveTools() call is not undone here.
1508
+ const handlerEditedTools = result.systemPromptOptions.selectedTools.length !== selectedToolsBefore.length ||
1509
+ result.systemPromptOptions.selectedTools.some((name, index) => name !== selectedToolsBefore[index]);
1510
+ if (!handlerEditedTools)
1511
+ result.systemPromptOptions.selectedTools = this.getActiveToolNames();
1512
+ const messages = [];
1513
+ if (trigger.messageType === "custom") {
1514
+ messages.push(trigger.message);
1515
+ }
1516
+ else {
1517
+ // Normalize images after before_agent_start so extension-driven model selection
1518
+ // determines the resize profile used for the request and history.
1519
+ const normalized = await this._normalizePromptImages(trigger.images);
1520
+ const text = normalized.hints.length > 0 ? `${trigger.prompt}\n\n${normalized.hints.join("\n")}` : trigger.prompt;
1521
+ messages.push({
1522
+ role: "user",
1523
+ content: [{ type: "text", text }, ...normalized.images],
1524
+ timestamp: Date.now(),
1525
+ });
1526
+ }
1527
+ // Inject any pending "nextTurn" messages as context alongside the starting message. Each
1528
+ // stays queued until _messagePersisted confirms its persistence, so a run that fails
1529
+ // before persisting it carries it into the next attempt.
1530
+ messages.push(...this._pendingNextTurnMessages);
1531
+ for (const msg of result.messages) {
1532
+ messages.push({
1533
+ role: "custom",
1534
+ customType: msg.customType,
1535
+ // Untyped extensions can pass null/missing content; normalize at ingestion.
1536
+ content: msg.content ?? [],
1537
+ display: msg.display,
1538
+ details: msg.details,
1539
+ timestamp: Date.now(),
1540
+ });
1541
+ }
1542
+ const updateMessage = this._preparePromptAndToolLoadout(result.systemPromptOptions);
1543
+ this._runSystemPromptOptions = result.systemPromptOptions;
1544
+ if (updateMessage)
1545
+ messages.unshift(updateMessage);
1546
+ return messages;
1547
+ }
1461
1548
  async _handlePostAgentRun() {
1462
1549
  const message = this._lastAssistantMessage;
1463
1550
  const toolResults = this._lastAssistantToolResults;
@@ -1637,9 +1724,6 @@ export class AgentSession {
1637
1724
  preflightResult?.("queued");
1638
1725
  return;
1639
1726
  }
1640
- // Flush any pending bash and custom messages before the new prompt
1641
- this._flushPendingBashMessages();
1642
- this._flushPendingCustomMessages();
1643
1727
  // Validate model
1644
1728
  if (!this.model) {
1645
1729
  throw new Error(formatNoModelSelectedMessage());
@@ -1655,55 +1739,7 @@ export class AgentSession {
1655
1739
  }
1656
1740
  throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
1657
1741
  }
1658
- // Check if we need to compact before sending (catches aborted responses).
1659
- // The user's new prompt is sent below, so do not call agent.continue() here.
1660
- const lastAssistant = this._findLastAssistantMessage();
1661
- if (lastAssistant) {
1662
- await this._checkCompaction(lastAssistant, false);
1663
- }
1664
- // Emit before_agent_start before normalizing images so extension-driven model
1665
- // selection determines the resize profile used for the request and history.
1666
- const selectedToolsBefore = this._baseSystemPromptOptions.selectedTools;
1667
- const result = await this._extensionRunner.emitBeforeAgentStart(expandedText, currentImages, this._baseSystemPromptOptions);
1668
- // Handlers may edit event.systemPromptOptions.selectedTools or call setActiveTools(),
1669
- // which updates the live loadout instead. An explicit edit wins; otherwise the live
1670
- // loadout is authoritative, so a setActiveTools() call is not undone here.
1671
- const handlerEditedTools = result.systemPromptOptions.selectedTools.length !== selectedToolsBefore.length ||
1672
- result.systemPromptOptions.selectedTools.some((name, index) => name !== selectedToolsBefore[index]);
1673
- if (!handlerEditedTools)
1674
- result.systemPromptOptions.selectedTools = this.getActiveToolNames();
1675
- const normalized = await this._normalizePromptImages(currentImages);
1676
- const userText = normalized.hints.length > 0 ? `${expandedText}\n\n${normalized.hints.join("\n")}` : expandedText;
1677
- // Build messages only after hooks and image normalization have completed.
1678
- const messages = [];
1679
- const userContent = [{ type: "text", text: userText }];
1680
- userContent.push(...normalized.images);
1681
- messages.push({
1682
- role: "user",
1683
- content: userContent,
1684
- timestamp: Date.now(),
1685
- });
1686
- // Inject any pending "nextTurn" messages as context alongside the user message
1687
- for (const msg of this._pendingNextTurnMessages) {
1688
- messages.push(msg);
1689
- }
1690
- for (const msg of result.messages) {
1691
- messages.push({
1692
- role: "custom",
1693
- customType: msg.customType,
1694
- // Untyped extensions can pass null/missing content; normalize at ingestion.
1695
- content: msg.content ?? [],
1696
- display: msg.display,
1697
- details: msg.details,
1698
- timestamp: Date.now(),
1699
- });
1700
- }
1701
- const updateMessage = this._preparePromptAndToolLoadout(result.systemPromptOptions);
1702
- this._runSystemPromptOptions = result.systemPromptOptions;
1703
- if (updateMessage)
1704
- messages.unshift(updateMessage);
1705
- preflightResult?.("started");
1706
- await this._runAgentPrompt(messages);
1742
+ await this._startRun({ messageType: "user", prompt: expandedText, images: currentImages }, () => preflightResult?.("started"));
1707
1743
  }
1708
1744
  /**
1709
1745
  * Try to execute an extension command. Returns true if command was found and executed.
@@ -1877,10 +1913,10 @@ export class AgentSession {
1877
1913
  }
1878
1914
  else if (options?.triggerTurn) {
1879
1915
  if (this._isEmittingAgentSettled) {
1880
- this._deferredSettledActions.push(async () => await this._runAgentPrompt(appMessage));
1916
+ this._deferredSettledActions.push(async () => await this.sendCustomMessage(message, options));
1881
1917
  return;
1882
1918
  }
1883
- await this._runAgentPrompt(appMessage);
1919
+ await this._startRun({ messageType: "custom", message: appMessage });
1884
1920
  }
1885
1921
  else if (this.isStreaming) {
1886
1922
  // Appending now would put the message between an assistant tool call and its