@astralyn/pi 1.0.5 → 1.1.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 (285) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/bundle/chunks/{anthropic-messages-YIOJIMVL.js → anthropic-messages-3K3DWVY6.js} +1 -1
  3. package/dist/bundle/chunks/anthropic.js +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-LDW4FGAQ.js → azure-openai-responses-CH74HGP4.js} +1 -1
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  6. package/dist/bundle/chunks/{chunk-UCXU7KLO.js → chunk-3MMB5I7J.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-GIG5IHES.js → chunk-5KJH3GGH.js} +1 -1
  8. package/dist/bundle/chunks/chunk-6VYRLG5F.js +2 -0
  9. package/dist/bundle/chunks/{chunk-HDHRZ7GT.js → chunk-C2ARIVS3.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-IE3Z7ESB.js → chunk-D3XW5X3Z.js} +371 -246
  11. package/dist/bundle/chunks/{chunk-IFELM7MW.js → chunk-EJEOEBSJ.js} +1 -1
  12. package/dist/bundle/chunks/chunk-H35KWBT5.js +11 -0
  13. package/dist/bundle/chunks/chunk-KAC2YPTW.js +2 -0
  14. package/dist/bundle/chunks/chunk-MAC4N3BW.js +2 -0
  15. package/dist/bundle/chunks/chunk-QLU3LESZ.js +2 -0
  16. package/dist/bundle/chunks/{chunk-A6ALEEY5.js → chunk-TEAAYBTS.js} +1 -1
  17. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-XO45ZT3V.js +2 -0
  18. package/dist/bundle/chunks/codemode-worker.js +2 -2
  19. package/dist/bundle/chunks/github-copilot.js +1 -1
  20. package/dist/bundle/chunks/{google-generative-ai-S5A5IBU4.js → google-generative-ai-VVO64ZRQ.js} +1 -1
  21. package/dist/bundle/chunks/{google-vertex-UBRQFDB4.js → google-vertex-LKS5NUHA.js} +1 -1
  22. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  23. package/dist/bundle/chunks/{llama-cpp-classify-R7DQLTQN.js → llama-cpp-classify-H3IZDR5O.js} +2 -2
  24. package/dist/bundle/chunks/{mistral-conversations-A2N5FSOV.js → mistral-conversations-NJUOG4ET.js} +2 -2
  25. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  26. package/dist/bundle/chunks/{openai-codex-responses-Q6JHCWLE.js → openai-codex-responses-TZWBTTYM.js} +2 -2
  27. package/dist/bundle/chunks/openai-codex.js +1 -1
  28. package/dist/bundle/chunks/{openai-completions-H4VMO7AU.js → openai-completions-7HTTU6FH.js} +1 -1
  29. package/dist/bundle/chunks/openai-decisions-776H4VDZ.js +5 -0
  30. package/dist/bundle/chunks/{openai-responses-G4PGNM2H.js → openai-responses-7A6BAQ5X.js} +1 -1
  31. package/dist/bundle/chunks/{openrouter-images-YP3YVB54.js → openrouter-images-TDLJV5N4.js} +1 -1
  32. package/dist/bundle/chunks/{pi-messages-HZZ7GEEW.js → pi-messages-ZXNERWJG.js} +1 -1
  33. package/dist/bundle/chunks/typesafe-system-one-2DQLG4R2.js +2 -0
  34. package/dist/bundle/chunks/{virtual-modules-46MSJGKO.js → virtual-modules-2NHGQRS6.js} +1 -1
  35. package/dist/bundle/cli.js +1 -1
  36. package/dist/bundle/index.js +1 -1
  37. package/dist/bundle/rpc-entry.js +1 -1
  38. package/dist/cli/args.d.ts +1 -1
  39. package/dist/cli/args.d.ts.map +1 -1
  40. package/dist/cli/args.js +13 -1
  41. package/dist/cli/args.js.map +1 -1
  42. package/dist/core/agent-session.d.ts +12 -6
  43. package/dist/core/agent-session.d.ts.map +1 -1
  44. package/dist/core/agent-session.js +146 -174
  45. package/dist/core/agent-session.js.map +1 -1
  46. package/dist/core/bash-executor.d.ts.map +1 -1
  47. package/dist/core/bash-executor.js +40 -45
  48. package/dist/core/bash-executor.js.map +1 -1
  49. package/dist/core/context-snapshot.d.ts +4 -1
  50. package/dist/core/context-snapshot.d.ts.map +1 -1
  51. package/dist/core/context-snapshot.js +45 -0
  52. package/dist/core/context-snapshot.js.map +1 -1
  53. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  54. package/dist/core/export-html/tool-renderer.js +2 -0
  55. package/dist/core/export-html/tool-renderer.js.map +1 -1
  56. package/dist/core/extensions/types.d.ts +11 -0
  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/model-runtime.d.ts.map +1 -1
  60. package/dist/core/model-runtime.js +2 -1
  61. package/dist/core/model-runtime.js.map +1 -1
  62. package/dist/core/nested-tool-calls.d.ts +1 -0
  63. package/dist/core/nested-tool-calls.d.ts.map +1 -1
  64. package/dist/core/nested-tool-calls.js +1 -0
  65. package/dist/core/nested-tool-calls.js.map +1 -1
  66. package/dist/core/sdk.d.ts +4 -0
  67. package/dist/core/sdk.d.ts.map +1 -1
  68. package/dist/core/sdk.js +17 -5
  69. package/dist/core/sdk.js.map +1 -1
  70. package/dist/core/settings-manager.d.ts +13 -0
  71. package/dist/core/settings-manager.d.ts.map +1 -1
  72. package/dist/core/settings-manager.js +37 -13
  73. package/dist/core/settings-manager.js.map +1 -1
  74. package/dist/core/tasks/session.d.ts +9 -0
  75. package/dist/core/tasks/session.d.ts.map +1 -1
  76. package/dist/core/tasks/session.js +21 -0
  77. package/dist/core/tasks/session.js.map +1 -1
  78. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  79. package/dist/core/tools/renderers/bash.js +8 -3
  80. package/dist/core/tools/renderers/bash.js.map +1 -1
  81. package/dist/core/tools/renderers/edit.js +1 -1
  82. package/dist/core/tools/renderers/edit.js.map +1 -1
  83. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  84. package/dist/extensions/codemode/execute.js +63 -7
  85. package/dist/extensions/codemode/execute.js.map +1 -1
  86. package/dist/extensions/codemode/tool.js +2 -2
  87. package/dist/extensions/codemode/tool.js.map +1 -1
  88. package/dist/extensions/index.js +2 -2
  89. package/dist/extensions/index.js.map +1 -1
  90. package/dist/extensions/llama/provider.d.ts.map +1 -1
  91. package/dist/extensions/llama/provider.js +34 -11
  92. package/dist/extensions/llama/provider.js.map +1 -1
  93. package/dist/extensions/mcp/cli.js +17 -23
  94. package/dist/extensions/mcp/cli.js.map +1 -1
  95. package/dist/extensions/mcp/index.d.ts.map +1 -1
  96. package/dist/extensions/mcp/index.js +165 -64
  97. package/dist/extensions/mcp/index.js.map +1 -1
  98. package/dist/extensions/mcp/oauth.d.ts +5 -3
  99. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  100. package/dist/extensions/mcp/oauth.js +36 -10
  101. package/dist/extensions/mcp/oauth.js.map +1 -1
  102. package/dist/extensions/mcp/ui.d.ts +3 -3
  103. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  104. package/dist/extensions/mcp/ui.js +10 -2
  105. package/dist/extensions/mcp/ui.js.map +1 -1
  106. package/dist/extensions/search/code-search.d.ts +29 -0
  107. package/dist/extensions/search/code-search.d.ts.map +1 -0
  108. package/dist/extensions/search/code-search.js +120 -0
  109. package/dist/extensions/search/code-search.js.map +1 -0
  110. package/dist/extensions/search/command.d.ts +5 -0
  111. package/dist/extensions/search/command.d.ts.map +1 -0
  112. package/dist/extensions/search/command.js +69 -0
  113. package/dist/extensions/search/command.js.map +1 -0
  114. package/dist/extensions/search/credential.d.ts +25 -0
  115. package/dist/extensions/search/credential.d.ts.map +1 -0
  116. package/dist/extensions/search/credential.js +117 -0
  117. package/dist/extensions/search/credential.js.map +1 -0
  118. package/dist/extensions/search/devin.d.ts +34 -0
  119. package/dist/extensions/search/devin.d.ts.map +1 -0
  120. package/dist/extensions/search/devin.js +210 -0
  121. package/dist/extensions/search/devin.js.map +1 -0
  122. package/dist/extensions/search/index.d.ts +5 -0
  123. package/dist/extensions/search/index.d.ts.map +1 -0
  124. package/dist/extensions/search/index.js +110 -0
  125. package/dist/extensions/search/index.js.map +1 -0
  126. package/dist/extensions/search/panel.d.ts +53 -0
  127. package/dist/extensions/search/panel.d.ts.map +1 -0
  128. package/dist/extensions/search/panel.js +157 -0
  129. package/dist/extensions/search/panel.js.map +1 -0
  130. package/dist/extensions/search/prompt.d.ts +14 -0
  131. package/dist/extensions/search/prompt.d.ts.map +1 -0
  132. package/dist/extensions/search/prompt.js +221 -0
  133. package/dist/extensions/search/prompt.js.map +1 -0
  134. package/dist/extensions/search/render.d.ts +28 -0
  135. package/dist/extensions/search/render.d.ts.map +1 -0
  136. package/dist/extensions/search/render.js +86 -0
  137. package/dist/extensions/search/render.js.map +1 -0
  138. package/dist/extensions/search/workspace.d.ts +38 -0
  139. package/dist/extensions/search/workspace.d.ts.map +1 -0
  140. package/dist/extensions/search/workspace.js +245 -0
  141. package/dist/extensions/search/workspace.js.map +1 -0
  142. package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
  143. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  144. package/dist/modes/interactive/components/bash-execution.js +14 -14
  145. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  146. package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
  147. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  148. package/dist/modes/interactive/components/branch-summary-message.js +5 -2
  149. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  150. package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -1
  151. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  152. package/dist/modes/interactive/components/compaction-summary-message.js +5 -2
  153. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  154. package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
  155. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  156. package/dist/modes/interactive/components/custom-entry.js +7 -2
  157. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  158. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  159. package/dist/modes/interactive/components/custom-message.js +1 -0
  160. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  161. package/dist/modes/interactive/components/settings-selector.js +1 -1
  162. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  163. package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
  164. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  165. package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
  166. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  167. package/dist/modes/interactive/interactive-mode.d.ts +2 -0
  168. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  169. package/dist/modes/interactive/interactive-mode.js +52 -59
  170. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  171. package/dist/modes/interactive/program-status-reporter.d.ts +34 -0
  172. package/dist/modes/interactive/program-status-reporter.d.ts.map +1 -0
  173. package/dist/modes/interactive/program-status-reporter.js +107 -0
  174. package/dist/modes/interactive/program-status-reporter.js.map +1 -0
  175. package/dist/modes/interactive/tasks/host-hooks.d.ts +14 -0
  176. package/dist/modes/interactive/tasks/host-hooks.d.ts.map +1 -0
  177. package/dist/modes/interactive/tasks/host-hooks.js +31 -0
  178. package/dist/modes/interactive/tasks/host-hooks.js.map +1 -0
  179. package/dist/modes/interactive/tool-view/tool-execution.d.ts +5 -0
  180. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
  181. package/dist/modes/interactive/tool-view/tool-execution.js +7 -0
  182. package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
  183. package/dist/package-manager-cli.d.ts.map +1 -1
  184. package/dist/package-manager-cli.js +24 -0
  185. package/dist/package-manager-cli.js.map +1 -1
  186. package/dist/utils/ansi.d.ts +8 -0
  187. package/dist/utils/ansi.d.ts.map +1 -1
  188. package/dist/utils/ansi.js +30 -11
  189. package/dist/utils/ansi.js.map +1 -1
  190. package/dist/utils/clipboard.d.ts.map +1 -1
  191. package/dist/utils/clipboard.js +12 -11
  192. package/dist/utils/clipboard.js.map +1 -1
  193. package/dist/utils/image-resize-core.d.ts +12 -0
  194. package/dist/utils/image-resize-core.d.ts.map +1 -1
  195. package/dist/utils/image-resize-core.js +5 -0
  196. package/dist/utils/image-resize-core.js.map +1 -1
  197. package/dist/utils/image-resize-worker.js +3 -2
  198. package/dist/utils/image-resize-worker.js.map +1 -1
  199. package/dist/utils/image-resize.d.ts.map +1 -1
  200. package/dist/utils/image-resize.js +9 -10
  201. package/dist/utils/image-resize.js.map +1 -1
  202. package/docs/bundled/README.md +1 -1
  203. package/docs/bundled/extensions/provider.md +1 -1
  204. package/docs/bundled/extensions/question.md +1 -1
  205. package/docs/bundled/extensions/search.md +50 -0
  206. package/docs/bundled/extensions/statusline.md +15 -41
  207. package/docs/codemode.md +23 -3
  208. package/docs/docs.json +0 -4
  209. package/docs/environment-variables.md +1 -0
  210. package/docs/extensions.md +5 -1
  211. package/docs/json.md +2 -2
  212. package/docs/llama-cpp.md +8 -1
  213. package/docs/models.md +4 -1
  214. package/docs/providers.md +17 -0
  215. package/docs/rpc.md +6 -3
  216. package/docs/session-format.md +1 -0
  217. package/docs/settings.md +3 -3
  218. package/docs/terminal-setup.md +14 -0
  219. package/docs/usage.md +5 -3
  220. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  221. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  222. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  223. package/examples/extensions/gondolin/package-lock.json +2 -2
  224. package/examples/extensions/gondolin/package.json +1 -1
  225. package/examples/extensions/sandbox/package-lock.json +2 -2
  226. package/examples/extensions/sandbox/package.json +1 -1
  227. package/examples/extensions/with-deps/package-lock.json +2 -2
  228. package/examples/extensions/with-deps/package.json +1 -1
  229. package/npm-shrinkwrap.json +54 -54
  230. package/package.json +13 -11
  231. package/dist/bundle/chunks/chunk-57XI7YJH.js +0 -2
  232. package/dist/bundle/chunks/chunk-JI4WGISU.js +0 -2
  233. package/dist/bundle/chunks/chunk-TCQ4HHQD.js +0 -2
  234. package/dist/bundle/chunks/chunk-TXJO4AJ7.js +0 -11
  235. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-OWU5SM6J.js +0 -2
  236. package/dist/bundle/chunks/typesafe-system-one-KYKKNU3E.js +0 -2
  237. package/dist/extensions/web-search/auth.d.ts +0 -12
  238. package/dist/extensions/web-search/auth.d.ts.map +0 -1
  239. package/dist/extensions/web-search/auth.js +0 -90
  240. package/dist/extensions/web-search/auth.js.map +0 -1
  241. package/dist/extensions/web-search/constants.d.ts +0 -13
  242. package/dist/extensions/web-search/constants.d.ts.map +0 -1
  243. package/dist/extensions/web-search/constants.js +0 -26
  244. package/dist/extensions/web-search/constants.js.map +0 -1
  245. package/dist/extensions/web-search/execute.d.ts +0 -9
  246. package/dist/extensions/web-search/execute.d.ts.map +0 -1
  247. package/dist/extensions/web-search/execute.js +0 -96
  248. package/dist/extensions/web-search/execute.js.map +0 -1
  249. package/dist/extensions/web-search/format.d.ts +0 -21
  250. package/dist/extensions/web-search/format.d.ts.map +0 -1
  251. package/dist/extensions/web-search/format.js +0 -117
  252. package/dist/extensions/web-search/format.js.map +0 -1
  253. package/dist/extensions/web-search/index.d.ts +0 -6
  254. package/dist/extensions/web-search/index.d.ts.map +0 -1
  255. package/dist/extensions/web-search/index.js +0 -50
  256. package/dist/extensions/web-search/index.js.map +0 -1
  257. package/dist/extensions/web-search/providers/deepseek.d.ts +0 -13
  258. package/dist/extensions/web-search/providers/deepseek.d.ts.map +0 -1
  259. package/dist/extensions/web-search/providers/deepseek.js +0 -110
  260. package/dist/extensions/web-search/providers/deepseek.js.map +0 -1
  261. package/dist/extensions/web-search/providers/http.d.ts +0 -4
  262. package/dist/extensions/web-search/providers/http.d.ts.map +0 -1
  263. package/dist/extensions/web-search/providers/http.js +0 -42
  264. package/dist/extensions/web-search/providers/http.js.map +0 -1
  265. package/dist/extensions/web-search/providers/minimax.d.ts +0 -12
  266. package/dist/extensions/web-search/providers/minimax.d.ts.map +0 -1
  267. package/dist/extensions/web-search/providers/minimax.js +0 -61
  268. package/dist/extensions/web-search/providers/minimax.js.map +0 -1
  269. package/dist/extensions/web-search/render.d.ts +0 -15
  270. package/dist/extensions/web-search/render.d.ts.map +0 -1
  271. package/dist/extensions/web-search/render.js +0 -142
  272. package/dist/extensions/web-search/render.js.map +0 -1
  273. package/dist/extensions/web-search/results.d.ts +0 -35
  274. package/dist/extensions/web-search/results.d.ts.map +0 -1
  275. package/dist/extensions/web-search/results.js +0 -167
  276. package/dist/extensions/web-search/results.js.map +0 -1
  277. package/dist/extensions/web-search/schema.d.ts +0 -10
  278. package/dist/extensions/web-search/schema.d.ts.map +0 -1
  279. package/dist/extensions/web-search/schema.js +0 -36
  280. package/dist/extensions/web-search/schema.js.map +0 -1
  281. package/dist/extensions/web-search/types.d.ts +0 -51
  282. package/dist/extensions/web-search/types.d.ts.map +0 -1
  283. package/dist/extensions/web-search/types.js +0 -5
  284. package/dist/extensions/web-search/types.js.map +0 -1
  285. package/docs/bundled/extensions/web-search.md +0 -46
@@ -16,7 +16,7 @@ import { createTasksToolDefinition } from "./tools/tasks.js";
16
16
  import { readFileSync } from "node:fs";
17
17
  import { basename, dirname } from "node:path";
18
18
  import { runToolCall, } from "@earendil-works/pi-agent-core";
19
- import { contentText, getCurrentSystemMessage, getSystemMessageText, retryDelayMs } from "@earendil-works/pi-ai";
19
+ import { contentText, getCurrentSystemMessage, retryDelayMs } from "@earendil-works/pi-ai";
20
20
  import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, isRecoverableLength, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@earendil-works/pi-ai/compat";
21
21
  import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
22
22
  import { stripFrontmatter } from "../utils/frontmatter.js";
@@ -27,6 +27,7 @@ import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth
27
27
  import { executeBashWithOperations } from "./bash-executor.js";
28
28
  import { generateBugReportSummary } from "./bug-report.js";
29
29
  import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateProjectedContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
30
+ import { captureContextSnapshot } from "./context-snapshot.js";
30
31
  import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "./defaults.js";
31
32
  import { exportSessionToHtml } from "./export-html/index.js";
32
33
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
@@ -39,7 +40,7 @@ import { NestedToolCallRunner } from "./nested-tool-calls.js";
39
40
  import { expandPromptTemplate } from "./prompt-templates.js";
40
41
  import { exportSessionToJsonl } from "./session-export.js";
41
42
  import { getLatestCompactionEntry, SessionManager, } from "./session-manager.js";
42
- import { DEFAULT_TOOL_NAMES } from "./settings-manager.js";
43
+ import { applyToolModifiers, DEFAULT_TOOL_NAMES, } from "./settings-manager.js";
43
44
  import { BUILTIN_PATH_PREFIX, createSyntheticSourceInfo, isSyntheticPath } from "./source-info.js";
44
45
  import { buildSystemPrompt, buildSystemPromptSections, diffSystemPromptSections, normalizeBuildSystemPromptOptions, } from "./system-prompt.js";
45
46
  import { TaskSession } from "./tasks/session.js";
@@ -267,6 +268,7 @@ export class AgentSession {
267
268
  this._extensionRunnerRef = config.extensionRunnerRef;
268
269
  this._initialActiveToolNames = config.initialActiveToolNames;
269
270
  this._usesDefaultTools = config.usesDefaultTools ?? false;
271
+ this._defaultToolModifiers = config.defaultToolModifiers ?? [];
270
272
  if (config.allowedToolNames) {
271
273
  this._allowedTools = createToolNameMatcher(config.allowedToolNames);
272
274
  this._allowlistFiltersMcp =
@@ -297,6 +299,10 @@ export class AgentSession {
297
299
  get quarantinedTaskSettlements() {
298
300
  return this._tasksHost.quarantinedSettlements;
299
301
  }
302
+ /** Running tasks that navigating to `targetId` would cancel, so a host can confirm first. */
303
+ tasksStoppedByTreeNavigation(targetId) {
304
+ return this._tasksHost.stoppedByTreeNavigation(targetId);
305
+ }
300
306
  /** Pause delivery across asynchronous lifecycle/preflight gaps. Nestable. */
301
307
  pauseTaskNotifications() {
302
308
  return this._tasksHost.delivery.pause();
@@ -322,48 +328,8 @@ export class AgentSession {
322
328
  return this._modelRuntime;
323
329
  }
324
330
  /** Capture stable state before any asynchronous context preparation. Never includes a partial stream. */
325
- async getContextSnapshot() {
326
- const model = this.model;
327
- if (!model)
328
- throw new Error("No model selected");
329
- const requestOptions = {
330
- sessionId: this.agent.sessionId ?? this.sessionManager.getSessionId(),
331
- transport: this.agent.transport,
332
- thinkingBudgets: structuredClone(this.agent.thinkingBudgets),
333
- maxRetryDelayMs: this.agent.maxRetryDelayMs,
334
- onPayload: this.agent.onPayload,
335
- onResponse: this.agent.onResponse,
336
- };
337
- const snapshot = {
338
- capturedAt: Date.now(),
339
- sessionId: this.sessionManager.getSessionId(),
340
- leafId: this.sessionManager.getLeafId(),
341
- model: structuredClone(model),
342
- thinkingLevel: this.thinkingLevel,
343
- tools: this.agent.state.tools.map(({ name, description, parameters, constrainedSampling }) => ({
344
- name,
345
- description,
346
- parameters: structuredClone(parameters),
347
- ...(constrainedSampling === undefined ? {} : { constrainedSampling: structuredClone(constrainedSampling) }),
348
- })),
349
- streamOptions: this._contextSource?.resolveStreamOptions(model, requestOptions) ?? requestOptions,
350
- };
351
- const currentSystemPrompt = this.systemPrompt;
352
- // The canonical projection is what the next request converts; the inspection cache may lag it.
353
- const messages = structuredClone(this.sessionManager.buildSessionProjection().messages);
354
- const convert = this.agent.convertToLlm;
355
- const transform = this.agent.transformContext;
356
- const prepared = this._contextSource
357
- ? await this._contextSource.prepareMessages(messages)
358
- : await convert(transform ? await transform(messages) : messages);
359
- // The prepared transcript declares the prompt the provider received, including a forced
360
- // prompt projected for the last request; before the first request there is none yet.
361
- const declared = getCurrentSystemMessage(prepared);
362
- return {
363
- ...snapshot,
364
- systemPrompt: declared ? getSystemMessageText(declared) : currentSystemPrompt,
365
- messages: structuredClone(prepared),
366
- };
331
+ getContextSnapshot() {
332
+ return captureContextSnapshot(this, this._contextSource);
367
333
  }
368
334
  async _getRequiredRequestAuth(model, signal) {
369
335
  let result;
@@ -841,8 +807,9 @@ export class AgentSession {
841
807
  this._isAgentRunActive = false;
842
808
  this._isEmittingAgentSettled = true;
843
809
  try {
844
- await this._extensionRunner.emit({ type: "agent_settled" });
845
- this._emit({ type: "agent_settled" });
810
+ const aborted = this._agentRunAbortRequested;
811
+ await this._extensionRunner.emit({ type: "agent_settled", aborted });
812
+ this._emit({ type: "agent_settled", aborted });
846
813
  }
847
814
  finally {
848
815
  this._isEmittingAgentSettled = false;
@@ -1036,6 +1003,7 @@ export class AgentSession {
1036
1003
  toolName: event.toolName,
1037
1004
  result: event.result,
1038
1005
  isError: event.isError,
1006
+ ...(event.durationMs === undefined ? {} : { durationMs: event.durationMs }),
1039
1007
  };
1040
1008
  await this._extensionRunner.emit(extensionEvent);
1041
1009
  }
@@ -1593,131 +1561,147 @@ export class AgentSession {
1593
1561
  * @throws Error if no model selected or no API key available (when not streaming)
1594
1562
  */
1595
1563
  async prompt(text, options) {
1564
+ // A deferred prompt re-enters here after the settled handlers finish.
1565
+ if (this._isEmittingAgentSettled)
1566
+ return this._promptBody(text, options);
1567
+ // A user-initiated prompt is the recovery point for failed completion deliveries.
1568
+ this.retryTaskNotifications();
1569
+ // Extension commands may stay open indefinitely; only model input holds the preflight pause,
1570
+ // released once the prompt is handled, queued, or started.
1571
+ if (this._isExtensionCommandPrompt(text, options))
1572
+ return this._promptBody(text, options);
1573
+ const resumeBackground = this.pauseTaskNotifications();
1574
+ try {
1575
+ await this._promptBody(text, {
1576
+ ...options,
1577
+ preflightResult: (result) => {
1578
+ resumeBackground();
1579
+ options?.preflightResult?.(result);
1580
+ },
1581
+ });
1582
+ }
1583
+ finally {
1584
+ resumeBackground();
1585
+ }
1586
+ }
1587
+ _isExtensionCommandPrompt(text, options) {
1588
+ if (!(options?.expandPromptTemplates ?? true) || !text.startsWith("/"))
1589
+ return false;
1590
+ const spaceIndex = text.indexOf(" ");
1591
+ return (this._extensionRunner.getCommand(spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex)) !== undefined);
1592
+ }
1593
+ async _promptBody(text, options) {
1596
1594
  if (this._isEmittingAgentSettled) {
1597
1595
  this._deferredSettledActions.push(async () => await this.prompt(text, options));
1598
1596
  return;
1599
1597
  }
1600
- // A user-initiated prompt is the recovery point for failed completion deliveries.
1601
- this.retryTaskNotifications();
1602
1598
  const expandPromptTemplates = options?.expandPromptTemplates ?? true;
1603
1599
  const preflightResult = options?.preflightResult;
1604
- let messages;
1605
- let resumeBackground;
1606
- try {
1607
- // Handle extension commands first (execute immediately, even during streaming)
1608
- // Extension commands manage their own LLM interaction via pi.sendMessage()
1609
- if (expandPromptTemplates && text.startsWith("/")) {
1610
- const handled = await this._tryExecuteExtensionCommand(text);
1611
- if (handled) {
1612
- // Extension command executed, no prompt to send
1613
- preflightResult?.("handled");
1614
- return;
1615
- }
1616
- }
1617
- // Observer commands above may stay open indefinitely; only real model input owns
1618
- // the preflight pause, released once the user message is established.
1619
- resumeBackground = this.pauseTaskNotifications();
1620
- if (this._compactionAbortController !== undefined) {
1621
- throw new Error("Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.");
1622
- }
1623
- // Emit input event for extension interception (before skill/template expansion)
1624
- const processedInput = await this._runInputHandlers(text, options?.images, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
1625
- if (!processedInput) {
1600
+ // Handle extension commands first (execute immediately, even during streaming)
1601
+ // Extension commands manage their own LLM interaction via pi.sendMessage()
1602
+ if (expandPromptTemplates && text.startsWith("/")) {
1603
+ const handled = await this._tryExecuteExtensionCommand(text);
1604
+ if (handled) {
1605
+ // Extension command executed, no prompt to send
1626
1606
  preflightResult?.("handled");
1627
1607
  return;
1628
1608
  }
1629
- const { text: currentText, images: currentImages } = processedInput;
1630
- // Expand skill commands (/skill:name args) and prompt templates (/template args)
1631
- let expandedText = currentText;
1632
- if (expandPromptTemplates) {
1633
- expandedText = this._expandSkillCommand(expandedText);
1634
- expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1635
- }
1636
- // If streaming, queue via steer() or followUp() based on option
1637
- if (this.isStreaming) {
1638
- if (!options?.streamingBehavior) {
1639
- throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
1640
- }
1641
- if (options.streamingBehavior === "followUp") {
1642
- await this._queueFollowUp(expandedText, currentImages);
1643
- }
1644
- else {
1645
- await this._queueSteer(expandedText, currentImages);
1646
- }
1647
- preflightResult?.("queued");
1648
- return;
1609
+ }
1610
+ if (this._compactionAbortController !== undefined) {
1611
+ throw new Error("Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.");
1612
+ }
1613
+ // Emit input event for extension interception (before skill/template expansion)
1614
+ const processedInput = await this._runInputHandlers(text, options?.images, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
1615
+ if (!processedInput) {
1616
+ preflightResult?.("handled");
1617
+ return;
1618
+ }
1619
+ const { text: currentText, images: currentImages } = processedInput;
1620
+ // Expand skill commands (/skill:name args) and prompt templates (/template args)
1621
+ let expandedText = currentText;
1622
+ if (expandPromptTemplates) {
1623
+ expandedText = this._expandSkillCommand(expandedText);
1624
+ expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1625
+ }
1626
+ // If streaming, queue via steer() or followUp() based on option
1627
+ if (this.isStreaming) {
1628
+ if (!options?.streamingBehavior) {
1629
+ throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
1649
1630
  }
1650
- // Flush any pending bash and custom messages before the new prompt
1651
- this._flushPendingBashMessages();
1652
- this._flushPendingCustomMessages();
1653
- // Validate model
1654
- if (!this.model) {
1655
- throw new Error(formatNoModelSelectedMessage());
1631
+ if (options.streamingBehavior === "followUp") {
1632
+ await this._queueFollowUp(expandedText, currentImages);
1656
1633
  }
1657
- const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) ||
1658
- (await this._modelRuntime.checkAuth(this.model.provider)) !== undefined;
1659
- if (!hasConfiguredAuth) {
1660
- const isOAuth = this._modelRuntime.isUsingOAuth(this.model.provider);
1661
- if (isOAuth) {
1662
- throw new Error(`Authentication failed for "${this.model.provider}". ` +
1663
- `Credentials may have expired or network is unavailable. ` +
1664
- `Run '/login ${this.model.provider}' to re-authenticate.`);
1665
- }
1666
- throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
1667
- }
1668
- // Check if we need to compact before sending (catches aborted responses).
1669
- // The user's new prompt is sent below, so do not call agent.continue() here.
1670
- const lastAssistant = this._findLastAssistantMessage();
1671
- if (lastAssistant) {
1672
- await this._checkCompaction(lastAssistant, false);
1673
- }
1674
- // Emit before_agent_start before normalizing images so extension-driven model
1675
- // selection determines the resize profile used for the request and history.
1676
- const selectedToolsBefore = this._baseSystemPromptOptions.selectedTools;
1677
- const result = await this._extensionRunner.emitBeforeAgentStart(expandedText, currentImages, this._baseSystemPromptOptions);
1678
- // Handlers may edit event.systemPromptOptions.selectedTools or call setActiveTools(),
1679
- // which updates the live loadout instead. An explicit edit wins; otherwise the live
1680
- // loadout is authoritative, so a setActiveTools() call is not undone here.
1681
- const handlerEditedTools = result.systemPromptOptions.selectedTools.length !== selectedToolsBefore.length ||
1682
- result.systemPromptOptions.selectedTools.some((name, index) => name !== selectedToolsBefore[index]);
1683
- if (!handlerEditedTools)
1684
- result.systemPromptOptions.selectedTools = this.getActiveToolNames();
1685
- const normalized = await this._normalizePromptImages(currentImages);
1686
- const userText = normalized.hints.length > 0 ? `${expandedText}\n\n${normalized.hints.join("\n")}` : expandedText;
1687
- // Build messages only after hooks and image normalization have completed.
1688
- messages = [];
1689
- const userContent = [{ type: "text", text: userText }];
1690
- userContent.push(...normalized.images);
1634
+ else {
1635
+ await this._queueSteer(expandedText, currentImages);
1636
+ }
1637
+ preflightResult?.("queued");
1638
+ return;
1639
+ }
1640
+ // Flush any pending bash and custom messages before the new prompt
1641
+ this._flushPendingBashMessages();
1642
+ this._flushPendingCustomMessages();
1643
+ // Validate model
1644
+ if (!this.model) {
1645
+ throw new Error(formatNoModelSelectedMessage());
1646
+ }
1647
+ const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) ||
1648
+ (await this._modelRuntime.checkAuth(this.model.provider)) !== undefined;
1649
+ if (!hasConfiguredAuth) {
1650
+ const isOAuth = this._modelRuntime.isUsingOAuth(this.model.provider);
1651
+ if (isOAuth) {
1652
+ throw new Error(`Authentication failed for "${this.model.provider}". ` +
1653
+ `Credentials may have expired or network is unavailable. ` +
1654
+ `Run '/login ${this.model.provider}' to re-authenticate.`);
1655
+ }
1656
+ throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
1657
+ }
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
1691
  messages.push({
1692
- role: "user",
1693
- content: userContent,
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,
1694
1698
  timestamp: Date.now(),
1695
1699
  });
1696
- // Inject any pending "nextTurn" messages as context alongside the user message
1697
- for (const msg of this._pendingNextTurnMessages) {
1698
- messages.push(msg);
1699
- }
1700
- for (const msg of result.messages) {
1701
- messages.push({
1702
- role: "custom",
1703
- customType: msg.customType,
1704
- // Untyped extensions can pass null/missing content; normalize at ingestion.
1705
- content: msg.content ?? [],
1706
- display: msg.display,
1707
- details: msg.details,
1708
- timestamp: Date.now(),
1709
- });
1710
- }
1711
- const updateMessage = this._preparePromptAndToolLoadout(result.systemPromptOptions);
1712
- this._runSystemPromptOptions = result.systemPromptOptions;
1713
- if (updateMessage)
1714
- messages.unshift(updateMessage);
1715
- }
1716
- finally {
1717
- resumeBackground?.();
1718
1700
  }
1719
- if (!messages)
1720
- return;
1701
+ const updateMessage = this._preparePromptAndToolLoadout(result.systemPromptOptions);
1702
+ this._runSystemPromptOptions = result.systemPromptOptions;
1703
+ if (updateMessage)
1704
+ messages.unshift(updateMessage);
1721
1705
  preflightResult?.("started");
1722
1706
  await this._runAgentPrompt(messages);
1723
1707
  }
@@ -3059,7 +3043,10 @@ export class AgentSession {
3059
3043
  await Promise.all([this.tasks.shutdown(), this.abort()]);
3060
3044
  await emitSessionShutdownEvent(oldRunner, { type: "session_shutdown", reason: "reload" });
3061
3045
  oldRunner.invalidate();
3062
- const previousDefaultTools = new Set(this._usesDefaultTools ? (this.settingsManager.getDefaultTools() ?? DEFAULT_TOOL_NAMES) : []);
3046
+ const getDefaultTools = () => this._usesDefaultTools
3047
+ ? applyToolModifiers(this.settingsManager.getDefaultTools() ?? DEFAULT_TOOL_NAMES, this._defaultToolModifiers)
3048
+ : [];
3049
+ const previousDefaultTools = new Set(getDefaultTools());
3063
3050
  await this.settingsManager.reload();
3064
3051
  this.syncQueueModesFromSettings();
3065
3052
  resetApiProviders();
@@ -3067,9 +3054,7 @@ export class AgentSession {
3067
3054
  this._tasksHost.replaceService();
3068
3055
  // Activate tools newly added to defaultTools. Removed ones stay active, and tools disabled
3069
3056
  // during the session stay disabled unless the setting newly adds them.
3070
- const addedDefaultTools = this._usesDefaultTools
3071
- ? (this.settingsManager.getDefaultTools() ?? DEFAULT_TOOL_NAMES).filter((name) => !previousDefaultTools.has(name))
3072
- : [];
3057
+ const addedDefaultTools = getDefaultTools().filter((name) => !previousDefaultTools.has(name));
3073
3058
  // Tools the new extensions register later, such as MCP tools, are pending until then.
3074
3059
  for (const name of this.getActiveToolNames())
3075
3060
  this._pendingToolNames.add(name);
@@ -3318,19 +3303,6 @@ export class AgentSession {
3318
3303
  * @param options.label Label to attach to the branch summary entry
3319
3304
  * @returns Result with editorText (if user message) and cancelled status
3320
3305
  */
3321
- /**
3322
- * Running tasks that navigating to `targetId` would cancel, so a host can confirm first.
3323
- * Mirrors navigateTree's destination: selecting a user or custom message moves the leaf to its parent.
3324
- */
3325
- tasksStoppedByTreeNavigation(targetId) {
3326
- const target = this.sessionManager.getEntry(targetId);
3327
- if (!target)
3328
- return [];
3329
- const leafId = (target.type === "message" && target.message.role === "user") || target.type === "custom_message"
3330
- ? target.parentId
3331
- : targetId;
3332
- return this.tasks.activeOutsideBranch(new Set(leafId === null ? [] : this.sessionManager.getBranch(leafId).map((entry) => entry.id)));
3333
- }
3334
3306
  async navigateTree(targetId, options = {}) {
3335
3307
  if (this.isStreaming) {
3336
3308
  throw new Error("Wait for the current response to finish before navigating the session tree.");
@@ -3450,7 +3422,7 @@ export class AgentSession {
3450
3422
  // Non-user message: leaf = selected node
3451
3423
  newLeafId = targetId;
3452
3424
  }
3453
- await this.tasks.cancelOutsideBranch(new Set(newLeafId === null ? [] : this.sessionManager.getBranch(newLeafId).map((entry) => entry.id)));
3425
+ await this._tasksHost.cancelOutsideBranch(newLeafId);
3454
3426
  // Switch leaf (with or without summary)
3455
3427
  // Summary is attached at the navigation target position (newLeafId), not the old branch
3456
3428
  let summaryEntry;