@oh-my-pi/pi-coding-agent 17.0.8 → 17.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 (340) hide show
  1. package/CHANGELOG.md +87 -1
  2. package/README.md +1 -1
  3. package/dist/cli.js +5495 -5021
  4. package/dist/types/async/job-manager.d.ts +37 -1
  5. package/dist/types/cli/args.d.ts +2 -0
  6. package/dist/types/cli/bench-cli.d.ts +41 -0
  7. package/dist/types/commands/bench.d.ts +15 -3
  8. package/dist/types/commands/launch.d.ts +4 -0
  9. package/dist/types/config/__tests__/model-registry.test.d.ts +1 -0
  10. package/dist/types/config/model-registry.d.ts +30 -1
  11. package/dist/types/config/models-config-schema.d.ts +18 -6
  12. package/dist/types/config/models-config.d.ts +14 -5
  13. package/dist/types/config/provider-globals.d.ts +2 -2
  14. package/dist/types/config/service-tier.d.ts +5 -1
  15. package/dist/types/config/settings-schema.d.ts +350 -50
  16. package/dist/types/config/settings.d.ts +7 -0
  17. package/dist/types/dap/client.d.ts +20 -0
  18. package/dist/types/exec/bash-executor.d.ts +38 -0
  19. package/dist/types/exec/direnv.d.ts +33 -0
  20. package/dist/types/export/html/args.d.ts +15 -0
  21. package/dist/types/export/html/index.d.ts +11 -26
  22. package/dist/types/export/html/web-palette.d.ts +55 -116
  23. package/dist/types/extensibility/extensions/loader.d.ts +3 -0
  24. package/dist/types/extensibility/extensions/types.d.ts +17 -2
  25. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -0
  26. package/dist/types/extensibility/legacy-pi-tui-shim.d.ts +10 -0
  27. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +14 -1
  28. package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
  29. package/dist/types/live/controller.d.ts +40 -0
  30. package/dist/types/live/protocol.d.ts +85 -0
  31. package/dist/types/live/protocol.test.d.ts +1 -0
  32. package/dist/types/live/transport.d.ts +48 -0
  33. package/dist/types/live/visualizer.d.ts +33 -0
  34. package/dist/types/lsp/client.d.ts +18 -1
  35. package/dist/types/mcp/config-writer.test.d.ts +1 -0
  36. package/dist/types/mcp/manager.d.ts +6 -2
  37. package/dist/types/mcp/oauth-discovery.d.ts +2 -0
  38. package/dist/types/mcp/render.d.ts +2 -2
  39. package/dist/types/mcp/smithery-auth.d.ts +1 -1
  40. package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
  41. package/dist/types/mcp/tool-bridge.d.ts +7 -3
  42. package/dist/types/mcp/types.d.ts +6 -0
  43. package/dist/types/memory-backend/tool-names.d.ts +2 -0
  44. package/dist/types/modes/components/login-dialog.d.ts +2 -2
  45. package/dist/types/modes/components/oauth-selector.d.ts +8 -0
  46. package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
  47. package/dist/types/modes/components/settings-defs.d.ts +8 -1
  48. package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
  49. package/dist/types/modes/components/tool-execution.d.ts +9 -1
  50. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  51. package/dist/types/modes/controllers/event-controller.d.ts +6 -1
  52. package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
  53. package/dist/types/modes/controllers/mcp-command-controller.d.ts +3 -0
  54. package/dist/types/modes/interactive-mode.d.ts +5 -0
  55. package/dist/types/modes/rpc/rpc-client.d.ts +10 -1
  56. package/dist/types/modes/rpc/rpc-frame.d.ts +16 -0
  57. package/dist/types/modes/rpc/rpc-messages.d.ts +26 -0
  58. package/dist/types/modes/rpc/rpc-types.d.ts +40 -0
  59. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
  60. package/dist/types/modes/setup-wizard/scenes/types.d.ts +9 -1
  61. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
  62. package/dist/types/modes/theme/theme.d.ts +1 -1
  63. package/dist/types/modes/types.d.ts +3 -1
  64. package/dist/types/modes/utils/context-usage.d.ts +12 -2
  65. package/dist/types/plan-mode/plan-files.d.ts +10 -0
  66. package/dist/types/registry/agent-lifecycle.d.ts +21 -9
  67. package/dist/types/registry/agent-registry.d.ts +11 -4
  68. package/dist/types/sdk.d.ts +15 -1
  69. package/dist/types/secrets/index.d.ts +15 -2
  70. package/dist/types/secrets/obfuscator.d.ts +113 -15
  71. package/dist/types/session/acp-permission-gate.d.ts +19 -0
  72. package/dist/types/session/agent-session-events.d.ts +84 -0
  73. package/dist/types/session/agent-session-types.d.ts +314 -0
  74. package/dist/types/session/agent-session.d.ts +120 -750
  75. package/dist/types/session/async-job-delivery.d.ts +28 -0
  76. package/dist/types/session/bash-runner.d.ts +75 -0
  77. package/dist/types/session/blob-store.d.ts +11 -1
  78. package/dist/types/session/blob-store.test.d.ts +1 -0
  79. package/dist/types/session/checkpoint-entries.d.ts +28 -0
  80. package/dist/types/session/eval-runner.d.ts +49 -0
  81. package/dist/types/session/irc-bridge.d.ts +46 -0
  82. package/dist/types/session/messages.d.ts +22 -0
  83. package/dist/types/session/model-controls.d.ts +180 -0
  84. package/dist/types/session/prewalk.d.ts +46 -0
  85. package/dist/types/session/queued-messages.d.ts +22 -0
  86. package/dist/types/session/redis-session-storage.d.ts +1 -0
  87. package/dist/types/session/retry-fallback-chains.d.ts +74 -0
  88. package/dist/types/session/role-models.d.ts +15 -0
  89. package/dist/types/session/session-advisors.d.ts +228 -0
  90. package/dist/types/session/session-entries.d.ts +8 -0
  91. package/dist/types/session/session-handoff.d.ts +70 -0
  92. package/dist/types/session/session-history-format.d.ts +6 -1
  93. package/dist/types/session/session-loader.d.ts +6 -4
  94. package/dist/types/session/session-maintenance.d.ts +246 -0
  95. package/dist/types/session/session-manager.d.ts +41 -0
  96. package/dist/types/session/session-memory.d.ts +56 -0
  97. package/dist/types/session/session-provider-boundary.d.ts +62 -0
  98. package/dist/types/session/session-stats.d.ts +48 -0
  99. package/dist/types/session/session-tools.d.ts +143 -0
  100. package/dist/types/session/session-workspace.d.ts +32 -0
  101. package/dist/types/session/stream-guards.d.ts +44 -0
  102. package/dist/types/session/todo-tracker.d.ts +56 -0
  103. package/dist/types/session/ttsr-coordinator.d.ts +51 -0
  104. package/dist/types/session/turn-recovery.d.ts +225 -0
  105. package/dist/types/system-prompt.d.ts +2 -0
  106. package/dist/types/task/executor.d.ts +4 -1
  107. package/dist/types/task/output-manager.d.ts +3 -1
  108. package/dist/types/task/types.d.ts +14 -0
  109. package/dist/types/tools/approval.d.ts +1 -0
  110. package/dist/types/tools/browser/launch.d.ts +5 -0
  111. package/dist/types/tools/hub/jobs.d.ts +1 -1
  112. package/dist/types/tools/image-gen.d.ts +4 -4
  113. package/dist/types/tools/image-providers.d.ts +38 -0
  114. package/dist/types/tools/index.d.ts +8 -0
  115. package/dist/types/tools/path-utils.d.ts +8 -0
  116. package/dist/types/tools/report-tool-issue.d.ts +24 -9
  117. package/dist/types/tools/todo.d.ts +10 -4
  118. package/dist/types/tools/xdev.d.ts +5 -1
  119. package/dist/types/tts/streaming-player.d.ts +14 -0
  120. package/dist/types/tts/vocalizer.d.ts +5 -0
  121. package/dist/types/utils/jj.d.ts +29 -0
  122. package/dist/types/utils/lang-from-path.d.ts +1 -0
  123. package/dist/types/utils/title-generator.d.ts +30 -0
  124. package/dist/types/vibe/runtime.d.ts +36 -8
  125. package/dist/types/web/search/index.d.ts +1 -1
  126. package/dist/types/web/search/provider.d.ts +15 -5
  127. package/dist/types/web/search/providers/firecrawl.d.ts +9 -0
  128. package/dist/types/web/search/types.d.ts +95 -1
  129. package/package.json +13 -12
  130. package/scripts/generate-share-viewer.ts +4 -6
  131. package/scripts/legacy-pi-virtual-module.ts +1 -1
  132. package/src/advisor/__tests__/advisor.test.ts +643 -0
  133. package/src/advisor/runtime.ts +144 -43
  134. package/src/async/job-manager.ts +90 -2
  135. package/src/cli/args.ts +2 -0
  136. package/src/cli/auth-gateway-cli.ts +18 -3
  137. package/src/cli/bench-cli.ts +395 -29
  138. package/src/cli/flag-tables.ts +3 -0
  139. package/src/cli/gc-cli.ts +2 -2
  140. package/src/cli/grievances-cli.ts +2 -2
  141. package/src/cli/usage-cli.ts +11 -2
  142. package/src/collab/host.ts +3 -2
  143. package/src/commands/bench.ts +18 -4
  144. package/src/commands/launch.ts +4 -0
  145. package/src/config/__tests__/model-registry.test.ts +147 -0
  146. package/src/config/model-registry.ts +50 -2
  147. package/src/config/model-resolver.ts +0 -1
  148. package/src/config/models-config-schema.ts +15 -4
  149. package/src/config/provider-globals.ts +9 -9
  150. package/src/config/service-tier.ts +26 -1
  151. package/src/config/settings-schema.ts +250 -54
  152. package/src/config/settings.ts +81 -2
  153. package/src/dap/client.ts +37 -4
  154. package/src/edit/index.ts +49 -12
  155. package/src/eval/py/executor.ts +103 -33
  156. package/src/exec/bash-executor.ts +89 -6
  157. package/src/exec/direnv.ts +145 -0
  158. package/src/export/html/args.ts +20 -0
  159. package/src/export/html/index.ts +45 -47
  160. package/src/export/html/template.css +19 -1
  161. package/src/export/html/template.html +6 -0
  162. package/src/export/html/template.js +21 -0
  163. package/src/export/html/tool-views.generated.js +31 -31
  164. package/src/export/html/web-palette.ts +116 -132
  165. package/src/export/share.ts +249 -49
  166. package/src/extensibility/extensions/loader.ts +29 -1
  167. package/src/extensibility/extensions/runner.ts +6 -0
  168. package/src/extensibility/extensions/types.ts +33 -2
  169. package/src/extensibility/legacy-pi-coding-agent-shim.ts +1 -0
  170. package/src/extensibility/legacy-pi-tui-shim.ts +10 -0
  171. package/src/extensibility/plugins/legacy-pi-compat.ts +870 -311
  172. package/src/hindsight/state.ts +64 -6
  173. package/src/internal-urls/local-protocol.ts +2 -1
  174. package/src/internal-urls/memory-protocol.ts +2 -2
  175. package/src/internal-urls/registry-helpers.ts +40 -0
  176. package/src/internal-urls/skill-protocol.ts +2 -2
  177. package/src/internal-urls/ssh-protocol.ts +2 -1
  178. package/src/internal-urls/vault-protocol.ts +2 -1
  179. package/src/live/audio-worklet.txt +59 -0
  180. package/src/live/browser-runtime.txt +221 -0
  181. package/src/live/controller.ts +464 -0
  182. package/src/live/prompts/agent-final-message.md +3 -0
  183. package/src/live/prompts/live-instructions.md +23 -0
  184. package/src/live/protocol.test.ts +140 -0
  185. package/src/live/protocol.ts +233 -0
  186. package/src/live/transport.ts +490 -0
  187. package/src/live/visualizer.ts +234 -0
  188. package/src/lsp/client.ts +52 -9
  189. package/src/lsp/clients/biome-client.ts +3 -4
  190. package/src/lsp/index.ts +44 -11
  191. package/src/main.ts +9 -1
  192. package/src/mcp/config-writer.test.ts +43 -0
  193. package/src/mcp/config-writer.ts +109 -82
  194. package/src/mcp/manager.ts +39 -8
  195. package/src/mcp/oauth-discovery.ts +10 -2
  196. package/src/mcp/render.ts +94 -35
  197. package/src/mcp/smithery-auth.test.ts +29 -0
  198. package/src/mcp/smithery-auth.ts +3 -2
  199. package/src/mcp/tool-bridge.ts +107 -11
  200. package/src/mcp/types.ts +7 -0
  201. package/src/memories/index.ts +40 -20
  202. package/src/memory-backend/tool-names.ts +2 -0
  203. package/src/mnemopi/backend.ts +24 -7
  204. package/src/modes/acp/acp-agent.ts +56 -10
  205. package/src/modes/acp/acp-event-mapper.ts +8 -1
  206. package/src/modes/components/agent-hub.ts +27 -10
  207. package/src/modes/components/login-dialog.ts +14 -4
  208. package/src/modes/components/oauth-selector.ts +24 -7
  209. package/src/modes/components/plan-review-overlay.ts +350 -35
  210. package/src/modes/components/settings-defs.ts +28 -3
  211. package/src/modes/components/settings-selector.ts +178 -6
  212. package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
  213. package/src/modes/components/status-line/component.ts +123 -2
  214. package/src/modes/components/tool-execution.test.ts +63 -2
  215. package/src/modes/components/tool-execution.ts +11 -2
  216. package/src/modes/controllers/command-controller.ts +70 -22
  217. package/src/modes/controllers/event-controller.ts +111 -16
  218. package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
  219. package/src/modes/controllers/extension-ui-controller.ts +20 -4
  220. package/src/modes/controllers/live-command-controller.ts +178 -0
  221. package/src/modes/controllers/mcp-command-controller.ts +80 -41
  222. package/src/modes/controllers/omfg-controller.ts +44 -40
  223. package/src/modes/controllers/selector-controller.ts +18 -10
  224. package/src/modes/controllers/session-focus-controller.ts +6 -1
  225. package/src/modes/interactive-mode.ts +160 -38
  226. package/src/modes/rpc/rpc-client.ts +94 -3
  227. package/src/modes/rpc/rpc-frame.ts +164 -4
  228. package/src/modes/rpc/rpc-messages.ts +127 -0
  229. package/src/modes/rpc/rpc-mode.ts +79 -7
  230. package/src/modes/rpc/rpc-types.ts +34 -2
  231. package/src/modes/runtime-init.ts +2 -0
  232. package/src/modes/setup-wizard/scenes/model.ts +5 -7
  233. package/src/modes/setup-wizard/scenes/providers.ts +3 -2
  234. package/src/modes/setup-wizard/scenes/sign-in.ts +8 -2
  235. package/src/modes/setup-wizard/scenes/theme.ts +13 -3
  236. package/src/modes/setup-wizard/scenes/types.ts +9 -1
  237. package/src/modes/setup-wizard/scenes/web-search.ts +23 -10
  238. package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
  239. package/src/modes/theme/theme.ts +1 -1
  240. package/src/modes/types.ts +3 -1
  241. package/src/modes/utils/context-usage.ts +23 -7
  242. package/src/modes/utils/ui-helpers.ts +10 -5
  243. package/src/plan-mode/plan-files.ts +40 -0
  244. package/src/prompts/bench/cache-prefix-chunk.md +1 -0
  245. package/src/prompts/bench/cache-prefix.md +3 -0
  246. package/src/prompts/bench/cache-suffix.md +1 -0
  247. package/src/prompts/goals/guided-goal-system.md +24 -3
  248. package/src/prompts/system/custom-system-prompt.md +1 -1
  249. package/src/prompts/system/project-prompt.md +8 -1
  250. package/src/prompts/system/subagent-async-pending.md +6 -0
  251. package/src/prompts/system/system-prompt.md +1 -1
  252. package/src/prompts/system/workflow-notice.md +48 -40
  253. package/src/prompts/system/xdev-mount-notice.md +4 -0
  254. package/src/prompts/tools/task.md +12 -2
  255. package/src/prompts/tools/todo.md +3 -1
  256. package/src/registry/agent-lifecycle.ts +116 -46
  257. package/src/registry/agent-registry.ts +35 -8
  258. package/src/registry/persisted-agents.ts +26 -2
  259. package/src/sdk.ts +255 -139
  260. package/src/secrets/index.ts +127 -4
  261. package/src/secrets/obfuscator.ts +2328 -105
  262. package/src/session/acp-permission-gate.ts +165 -0
  263. package/src/session/agent-session-error-log.test.ts +1 -1
  264. package/src/session/agent-session-events.ts +66 -0
  265. package/src/session/agent-session-types.ts +334 -0
  266. package/src/session/agent-session.ts +1910 -12213
  267. package/src/session/artifacts.ts +6 -5
  268. package/src/session/async-job-delivery.ts +74 -0
  269. package/src/session/bash-runner.ts +326 -0
  270. package/src/session/blob-store.test.ts +56 -0
  271. package/src/session/blob-store.ts +18 -2
  272. package/src/session/checkpoint-entries.ts +81 -0
  273. package/src/session/eval-runner.ts +212 -0
  274. package/src/session/indexed-session-storage.ts +9 -2
  275. package/src/session/irc-bridge.ts +203 -0
  276. package/src/session/messages.ts +263 -1
  277. package/src/session/model-controls.ts +714 -0
  278. package/src/session/prewalk.ts +252 -0
  279. package/src/session/queued-messages.ts +93 -0
  280. package/src/session/redis-session-storage.ts +51 -11
  281. package/src/session/retry-fallback-chains.ts +455 -0
  282. package/src/session/role-models.ts +85 -0
  283. package/src/session/session-advisors.ts +1679 -0
  284. package/src/session/session-context.test.ts +224 -1
  285. package/src/session/session-context.ts +47 -5
  286. package/src/session/session-entries.ts +8 -0
  287. package/src/session/session-handoff.ts +308 -0
  288. package/src/session/session-history-format.ts +20 -9
  289. package/src/session/session-loader.ts +10 -51
  290. package/src/session/session-maintenance.ts +2983 -0
  291. package/src/session/session-manager.ts +390 -30
  292. package/src/session/session-memory.ts +222 -0
  293. package/src/session/session-provider-boundary.ts +307 -0
  294. package/src/session/session-stats.ts +293 -0
  295. package/src/session/session-tools.ts +943 -0
  296. package/src/session/session-workspace.ts +53 -0
  297. package/src/session/stream-guards.ts +417 -0
  298. package/src/session/todo-tracker.ts +380 -0
  299. package/src/session/ttsr-coordinator.ts +496 -0
  300. package/src/session/turn-recovery.ts +1629 -0
  301. package/src/slash-commands/builtin-registry.ts +92 -11
  302. package/src/slash-commands/helpers/usage-report.ts +25 -4
  303. package/src/system-prompt.ts +41 -17
  304. package/src/task/executor.ts +288 -70
  305. package/src/task/index.ts +148 -111
  306. package/src/task/output-manager.ts +25 -3
  307. package/src/task/persisted-revive.ts +4 -3
  308. package/src/task/structured-subagent.ts +4 -1
  309. package/src/task/types.ts +16 -0
  310. package/src/tools/approval.ts +55 -10
  311. package/src/tools/bash-interactive.ts +26 -0
  312. package/src/tools/bash-skill-urls.ts +28 -2
  313. package/src/tools/bash.ts +339 -123
  314. package/src/tools/browser/launch.ts +9 -1
  315. package/src/tools/browser/tab-supervisor.ts +8 -5
  316. package/src/tools/browser.ts +94 -47
  317. package/src/tools/hub/index.ts +1 -1
  318. package/src/tools/hub/jobs.ts +67 -8
  319. package/src/tools/image-gen.ts +20 -28
  320. package/src/tools/image-providers.ts +50 -0
  321. package/src/tools/index.ts +12 -0
  322. package/src/tools/path-utils.ts +49 -2
  323. package/src/tools/read.ts +156 -88
  324. package/src/tools/renderers.ts +7 -1
  325. package/src/tools/report-tool-issue.ts +79 -28
  326. package/src/tools/todo.ts +101 -11
  327. package/src/tools/vibe.ts +1 -2
  328. package/src/tools/write.ts +51 -1
  329. package/src/tools/xdev.ts +67 -3
  330. package/src/tts/streaming-player.ts +62 -4
  331. package/src/tts/vocalizer.ts +18 -1
  332. package/src/utils/jj.ts +125 -4
  333. package/src/utils/lang-from-path.ts +7 -0
  334. package/src/utils/title-generator.ts +137 -1
  335. package/src/vibe/runtime.ts +852 -72
  336. package/src/web/search/index.ts +3 -6
  337. package/src/web/search/provider.ts +31 -16
  338. package/src/web/search/providers/firecrawl.ts +46 -13
  339. package/src/web/search/providers/xai.ts +7 -1
  340. package/src/web/search/types.ts +8 -1
package/src/task/types.ts CHANGED
@@ -113,6 +113,7 @@ export const taskItemSchema = type({
113
113
  "name?": "string",
114
114
  agent: "string = 'task'",
115
115
  task: "string",
116
+ "model?": "string | string[]",
116
117
  "outputSchema?": outputSchemaInputSchema,
117
118
  "schemaMode?": '"permissive" | "strict"',
118
119
  "+": "delete",
@@ -121,6 +122,7 @@ const taskItemSchemaIsolated = type({
121
122
  "name?": "string",
122
123
  agent: "string = 'task'",
123
124
  task: "string",
125
+ "model?": "string | string[]",
124
126
  "outputSchema?": outputSchemaInputSchema,
125
127
  "schemaMode?": '"permissive" | "strict"',
126
128
  "isolated?": "boolean",
@@ -135,6 +137,8 @@ export interface TaskItem {
135
137
  agent?: string;
136
138
  /** The work; required by the schema. */
137
139
  task?: string;
140
+ /** Explicit model selector or fallback chain for this spawn, including optional reasoning suffixes. */
141
+ model?: string | string[];
138
142
  /** Caller-provided output schema; its presence overrides the selected agent's schema. */
139
143
  outputSchema?: unknown;
140
144
  /** Validation behavior for a caller-provided or inherited output schema. */
@@ -147,6 +151,7 @@ export const taskSchema = type({
147
151
  "name?": "string",
148
152
  agent: "string = 'task'",
149
153
  task: "string",
154
+ "model?": "string | string[]",
150
155
  "outputSchema?": outputSchemaInputSchema,
151
156
  "schemaMode?": '"permissive" | "strict"',
152
157
  "isolated?": "boolean",
@@ -156,6 +161,7 @@ const taskSchemaNoIsolation = type({
156
161
  "name?": "string",
157
162
  agent: "string = 'task'",
158
163
  task: "string",
164
+ "model?": "string | string[]",
159
165
  "outputSchema?": outputSchemaInputSchema,
160
166
  "schemaMode?": '"permissive" | "strict"',
161
167
  "+": "delete",
@@ -200,6 +206,7 @@ function createTaskSchema(options: {
200
206
  "name?": "string",
201
207
  agent,
202
208
  task: "string",
209
+ "model?": "string | string[]",
203
210
  "outputSchema?": outputSchemaInputSchema,
204
211
  "schemaMode?": '"permissive" | "strict"',
205
212
  "isolated?": "boolean",
@@ -215,6 +222,7 @@ function createTaskSchema(options: {
215
222
  "name?": "string",
216
223
  agent,
217
224
  task: "string",
225
+ "model?": "string | string[]",
218
226
  "outputSchema?": outputSchemaInputSchema,
219
227
  "schemaMode?": '"permissive" | "strict"',
220
228
  "+": "delete",
@@ -230,6 +238,7 @@ function createTaskSchema(options: {
230
238
  "name?": "string",
231
239
  agent,
232
240
  task: "string",
241
+ "model?": "string | string[]",
233
242
  "outputSchema?": outputSchemaInputSchema,
234
243
  "schemaMode?": '"permissive" | "strict"',
235
244
  "isolated?": "boolean",
@@ -240,6 +249,7 @@ function createTaskSchema(options: {
240
249
  "name?": "string",
241
250
  agent,
242
251
  task: "string",
252
+ "model?": "string | string[]",
243
253
  "outputSchema?": outputSchemaInputSchema,
244
254
  "schemaMode?": '"permissive" | "strict"',
245
255
  "+": "delete",
@@ -283,6 +293,8 @@ export interface TaskParams {
283
293
  agent?: string;
284
294
  /** The work (flat form). */
285
295
  task?: string;
296
+ /** Explicit model selector or fallback chain for the spawn, including optional reasoning suffixes. */
297
+ model?: string | string[];
286
298
  /** Caller-provided output schema; its presence overrides the selected agent's schema. */
287
299
  outputSchema?: unknown;
288
300
  /** Validation behavior for a caller-provided or inherited output schema. */
@@ -419,6 +431,8 @@ export interface AgentProgress {
419
431
  modelOverride?: string | string[];
420
432
  /** Resolved model display string in the form `<provider>/<id>`, optionally suffixed with `:<thinkingLevel>` when the level was set explicitly. Undefined when the model could not be resolved. */
421
433
  resolvedModel?: string;
434
+ /** True when {@link resolvedModel} is the target of an active retry fallback (not the originally configured model). Lets observer-only UIs (collab guests, Agent Hub rows with no live session) flag the fallback and keep the provider. */
435
+ resolvedModelIsFallback?: boolean;
422
436
  /** Data extracted by registered subprocess tool handlers (keyed by tool name) */
423
437
  extractedToolData?: Record<string, unknown[]>;
424
438
  /**
@@ -486,6 +500,8 @@ export interface SingleResult {
486
500
  modelOverride?: string | string[];
487
501
  /** Resolved model display string in the form `<provider>/<id>`, optionally suffixed with `:<thinkingLevel>` when the level was set explicitly. Omitted from tool-result JSON when undefined to keep wire payloads small. */
488
502
  resolvedModel?: string;
503
+ /** True when {@link resolvedModel} is the target of an active retry fallback. Mirrors {@link AgentProgress.resolvedModelIsFallback} onto the settled result. */
504
+ resolvedModelIsFallback?: boolean;
489
505
  error?: string;
490
506
  aborted?: boolean;
491
507
  abortReason?: string;
@@ -20,6 +20,7 @@ export interface ResolvedApproval {
20
20
  tier: ToolTier;
21
21
  reason?: string;
22
22
  override: boolean;
23
+ source?: "tool" | "user" | "mode";
23
24
  }
24
25
 
25
26
  const POLICY_VALUES: ReadonlySet<ApprovalPolicy> = new Set(["allow", "deny", "prompt"]);
@@ -50,7 +51,7 @@ function isToolTier(value: unknown): value is ToolTier {
50
51
  return typeof value === "string" && TIER_VALUES.has(value as ToolTier);
51
52
  }
52
53
 
53
- function normalizeDecision(value: unknown): Omit<ResolvedApproval, "policy"> {
54
+ function normalizeDecision(value: unknown): Omit<ResolvedApproval, "policy"> & { policy?: ApprovalPolicy } {
54
55
  if (isToolTier(value)) {
55
56
  return { tier: value, override: false };
56
57
  }
@@ -59,9 +60,11 @@ function normalizeDecision(value: unknown): Omit<ResolvedApproval, "policy"> {
59
60
  const record = value as Record<string, unknown>;
60
61
  const tier = isToolTier(record.tier) ? record.tier : "exec";
61
62
  const reason = typeof record.reason === "string" && record.reason.length > 0 ? record.reason : undefined;
63
+ const policy = normalizePolicy(record.policy);
62
64
  return {
63
65
  tier,
64
66
  override: record.override === true,
67
+ ...(policy ? { policy } : {}),
65
68
  ...(reason ? { reason } : {}),
66
69
  };
67
70
  }
@@ -69,7 +72,10 @@ function normalizeDecision(value: unknown): Omit<ResolvedApproval, "policy"> {
69
72
  return { tier: "exec", override: false };
70
73
  }
71
74
 
72
- function getToolDecision(tool: ApprovalSubject, args: unknown): Omit<ResolvedApproval, "policy"> {
75
+ function getToolDecision(
76
+ tool: ApprovalSubject,
77
+ args: unknown,
78
+ ): Omit<ResolvedApproval, "policy"> & { policy?: ApprovalPolicy } {
73
79
  const approval = tool.approval;
74
80
  const decision: ToolApprovalDecision | undefined = typeof approval === "function" ? approval(args) : approval;
75
81
  return normalizeDecision(decision);
@@ -110,34 +116,70 @@ export function resolveApproval(
110
116
  const decision = getToolDecision(tool, args);
111
117
  const userPolicy = Object.hasOwn(userConfig, tool.name) ? normalizePolicy(userConfig[tool.name]) : undefined;
112
118
 
119
+ if (decision.policy === "deny") {
120
+ return {
121
+ policy: "deny",
122
+ tier: decision.tier,
123
+ override: decision.override,
124
+ source: "tool",
125
+ ...(decision.reason ? { reason: decision.reason } : {}),
126
+ };
127
+ }
128
+ if (userPolicy === "deny") {
129
+ return { policy: "deny", tier: decision.tier, override: decision.override, source: "user" };
130
+ }
131
+
113
132
  if (mode === "yolo") {
114
- return { policy: userPolicy ?? "allow", tier: decision.tier, override: false };
133
+ if (decision.policy) {
134
+ return {
135
+ policy: decision.policy,
136
+ tier: decision.tier,
137
+ override: false,
138
+ source: "tool",
139
+ ...(decision.reason ? { reason: decision.reason } : {}),
140
+ };
141
+ }
142
+ return {
143
+ policy: userPolicy ?? "allow",
144
+ tier: decision.tier,
145
+ override: false,
146
+ source: userPolicy ? "user" : "mode",
147
+ };
115
148
  }
116
149
 
117
150
  if (decision.override) {
118
- if (userPolicy === "deny") {
119
- return { policy: "deny", tier: decision.tier, override: true };
120
- }
121
151
  return {
122
- policy: "prompt",
152
+ policy: decision.policy === "allow" ? "allow" : "prompt",
123
153
  tier: decision.tier,
124
154
  override: true,
155
+ source: "tool",
156
+ ...(decision.reason ? { reason: decision.reason } : {}),
157
+ };
158
+ }
159
+
160
+ if (decision.policy === "allow" || decision.policy === "prompt") {
161
+ return {
162
+ policy: decision.policy,
163
+ tier: decision.tier,
164
+ override: false,
165
+ source: "tool",
125
166
  ...(decision.reason ? { reason: decision.reason } : {}),
126
167
  };
127
168
  }
128
169
 
129
170
  if (userPolicy) {
130
- return { policy: userPolicy, tier: decision.tier, override: false };
171
+ return { policy: userPolicy, tier: decision.tier, override: false, source: "user" };
131
172
  }
132
173
 
133
174
  if (modeApprovesTier(mode, decision.tier)) {
134
- return { policy: "allow", tier: decision.tier, override: false };
175
+ return { policy: "allow", tier: decision.tier, override: false, source: "mode" };
135
176
  }
136
177
 
137
178
  return {
138
179
  policy: "prompt",
139
180
  tier: decision.tier,
140
181
  override: false,
182
+ source: "mode",
141
183
  ...(decision.reason ? { reason: decision.reason } : {}),
142
184
  };
143
185
  }
@@ -154,9 +196,12 @@ export function requiresApproval(
154
196
  mode: ApprovalMode,
155
197
  userConfig: Record<string, unknown> = {},
156
198
  ): { required: boolean; reason?: string } {
157
- const { policy, reason } = resolveApproval(tool, args, mode, userConfig);
199
+ const { policy, reason, source } = resolveApproval(tool, args, mode, userConfig);
158
200
 
159
201
  if (policy === "deny") {
202
+ if (source === "tool") {
203
+ throw new Error(`Tool "${tool.name}" is blocked by tool policy.${reason ? `\nReason: ${reason}` : ""}`);
204
+ }
160
205
  throw new Error(
161
206
  `Tool "${tool.name}" is blocked by user policy.\n` +
162
207
  `To allow: remove "tools.approval.${tool.name}: deny" from config.`,
@@ -32,6 +32,10 @@ function normalizeCaptureChunk(chunk: string): string {
32
32
  return sanitizeWithOptionalSixelPassthrough(normalized, sanitizeText);
33
33
  }
34
34
 
35
+ // Caps only the live xterm display backlog; OutputSink remains the bounded
36
+ // source of truth for the final captured output.
37
+ const MAX_LIVE_WRITE_QUEUE_CHUNKS = 512;
38
+
35
39
  // @xterm/headless is only needed once an interactive PTY session actually starts,
36
40
  // so it is loaded lazily (and memoized) instead of weighing down CLI startup.
37
41
  let xtermTerminalCtor: typeof XtermModule.Terminal | undefined;
@@ -142,9 +146,31 @@ class BashInteractiveOverlayComponent implements Component {
142
146
 
143
147
  appendOutput(chunk: string): void {
144
148
  this.#writeQueue.push(chunk);
149
+ this.#trimWriteQueue();
145
150
  this.#drainQueue();
146
151
  }
147
152
 
153
+ #trimWriteQueue(): void {
154
+ // Compact the consumed prefix first: the queue only self-resets on a
155
+ // full drain, which never happens while a fast producer keeps a
156
+ // backlog alive, so already-written chunks must be released here to
157
+ // keep the retained array itself bounded.
158
+ if (this.#writeOffset > 0) {
159
+ this.#writeQueue.splice(0, this.#writeOffset);
160
+ this.#writeOffset = 0;
161
+ }
162
+ const firstPending = this.#writing ? 1 : 0;
163
+ const overflow = this.#writeQueue.length - firstPending - MAX_LIVE_WRITE_QUEUE_CHUNKS;
164
+ if (overflow > 0) {
165
+ this.#writeQueue.splice(firstPending, overflow);
166
+ // Dropped chunks can split an in-flight DCS/OSC/APC string (e.g. a
167
+ // sixel payload) across the gap; a stray string terminator is a
168
+ // no-op in the ground state but resynchronizes the parser if the
169
+ // terminator was dropped.
170
+ this.#writeQueue[firstPending] = `\u001b\\${this.#writeQueue[firstPending]}`;
171
+ }
172
+ }
173
+
148
174
  #drainQueue(): void {
149
175
  if (this.#writing) return;
150
176
  if (this.#writeOffset >= this.#writeQueue.length) {
@@ -144,6 +144,8 @@ function unquoteToken(token: string): string {
144
144
  function isInsideShellQuote(command: string, index: number): boolean {
145
145
  type ShellQuote = "'" | '"' | undefined;
146
146
  interface CommandSubstitution {
147
+ /** `$(` … `)` tracks paren depth; `` ` `` … `` ` `` is a plain toggle. */
148
+ kind: "dollar" | "backtick";
147
149
  outerQuote: ShellQuote;
148
150
  depth: number;
149
151
  }
@@ -152,6 +154,19 @@ function isInsideShellQuote(command: string, index: number): boolean {
152
154
  const substitutions: CommandSubstitution[] = [];
153
155
  for (let i = 0; i < index; i++) {
154
156
  const char = command[i];
157
+ // Inside a backtick substitution nested in double quotes, bash treats `\"`
158
+ // as a quote delimiter for the inner command, not as an escaped literal.
159
+ if (
160
+ char === "\\" &&
161
+ command[i + 1] === '"' &&
162
+ quote !== "'" &&
163
+ substitutions.at(-1)?.kind === "backtick" &&
164
+ substitutions.at(-1)?.outerQuote === '"'
165
+ ) {
166
+ quote = quote === '"' ? undefined : '"';
167
+ i++;
168
+ continue;
169
+ }
155
170
  if (char === "\\" && quote !== "'") {
156
171
  i++;
157
172
  continue;
@@ -165,15 +180,26 @@ function isInsideShellQuote(command: string, index: number): boolean {
165
180
  continue;
166
181
  }
167
182
  if (char === "$" && command[i + 1] === "(" && quote !== "'") {
168
- substitutions.push({ outerQuote: quote, depth: 1 });
183
+ substitutions.push({ kind: "dollar", outerQuote: quote, depth: 1 });
169
184
  quote = undefined;
170
185
  i++;
171
186
  continue;
172
187
  }
188
+ if (char === "`" && quote !== "'") {
189
+ const top = substitutions.at(-1);
190
+ if (top?.kind === "backtick") {
191
+ substitutions.pop();
192
+ quote = top.outerQuote;
193
+ } else {
194
+ substitutions.push({ kind: "backtick", outerQuote: quote, depth: 0 });
195
+ quote = undefined;
196
+ }
197
+ continue;
198
+ }
173
199
  if (quote !== undefined) continue;
174
200
 
175
201
  const substitution = substitutions.at(-1);
176
- if (!substitution) continue;
202
+ if (substitution?.kind !== "dollar") continue;
177
203
  if (char === "(") {
178
204
  substitution.depth++;
179
205
  } else if (char === ")") {