@esso0428/pi-subagents 0.17.15 → 0.17.17

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 (359) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/ROADMAP.md +87 -0
  3. package/docs/post-0.17.6-agents-roster-viewer-spec.md +42 -0
  4. package/docs/post-0.17.6-durable-history-spec.md +41 -0
  5. package/docs/post-0.17.6-feature-specs.md +50 -0
  6. package/docs/post-0.17.6-nested-agents-spec.md +38 -0
  7. package/docs/post-0.17.6-recovery-shutdown-spec.md +46 -0
  8. package/docs/post-0.17.6-ui-latency-baseline-spec.md +46 -0
  9. package/docs/post-0.17.6-workflow-rpc-lifecycle-spec.md +54 -0
  10. package/package.json +2 -3
  11. package/src/agent-history.ts +2 -54
  12. package/src/agent-manager.ts +406 -1288
  13. package/src/agent-runner.ts +27 -251
  14. package/src/agent-types.ts +32 -188
  15. package/src/cross-extension-rpc.ts +20 -96
  16. package/src/custom-agents.ts +13 -170
  17. package/src/index.ts +480 -1920
  18. package/src/invocation-config.ts +3 -118
  19. package/src/model-resolver.ts +0 -18
  20. package/src/output-file.ts +6 -61
  21. package/src/prompts.ts +2 -45
  22. package/src/schedule.ts +14 -35
  23. package/src/settings.ts +2 -301
  24. package/src/status-note.ts +1 -66
  25. package/src/types.ts +10 -177
  26. package/src/ui/agent-widget.ts +57 -278
  27. package/src/ui/conversation-blocks.ts +0 -6
  28. package/src/ui/conversation-timeline.ts +25 -139
  29. package/src/ui/conversation-viewer.ts +48 -212
  30. package/src/ui/schedule-menu.ts +8 -9
  31. package/src/usage.ts +2 -109
  32. package/src/worktree.ts +55 -69
  33. package/dist/abortable.d.ts +0 -13
  34. package/dist/abortable.d.ts.map +0 -1
  35. package/dist/abortable.js +0 -43
  36. package/dist/abortable.js.map +0 -1
  37. package/dist/agent-color.d.ts +0 -36
  38. package/dist/agent-color.d.ts.map +0 -1
  39. package/dist/agent-color.js +0 -124
  40. package/dist/agent-color.js.map +0 -1
  41. package/dist/agent-file-toggle.d.ts +0 -126
  42. package/dist/agent-file-toggle.d.ts.map +0 -1
  43. package/dist/agent-file-toggle.js +0 -259
  44. package/dist/agent-file-toggle.js.map +0 -1
  45. package/dist/agent-history-list.d.ts +0 -19
  46. package/dist/agent-history-list.d.ts.map +0 -1
  47. package/dist/agent-history-list.js +0 -69
  48. package/dist/agent-history-list.js.map +0 -1
  49. package/dist/agent-history.d.ts +0 -35
  50. package/dist/agent-history.d.ts.map +0 -1
  51. package/dist/agent-history.js +0 -188
  52. package/dist/agent-history.js.map +0 -1
  53. package/dist/agent-manager.d.ts +0 -503
  54. package/dist/agent-manager.d.ts.map +0 -1
  55. package/dist/agent-manager.js +0 -1572
  56. package/dist/agent-manager.js.map +0 -1
  57. package/dist/agent-recovery.d.ts +0 -37
  58. package/dist/agent-recovery.d.ts.map +0 -1
  59. package/dist/agent-recovery.js +0 -171
  60. package/dist/agent-recovery.js.map +0 -1
  61. package/dist/agent-runner.d.ts +0 -303
  62. package/dist/agent-runner.d.ts.map +0 -1
  63. package/dist/agent-runner.js +0 -1003
  64. package/dist/agent-runner.js.map +0 -1
  65. package/dist/agent-types.d.ts +0 -120
  66. package/dist/agent-types.d.ts.map +0 -1
  67. package/dist/agent-types.js +0 -301
  68. package/dist/agent-types.js.map +0 -1
  69. package/dist/child-context.d.ts +0 -3
  70. package/dist/child-context.d.ts.map +0 -1
  71. package/dist/child-context.js +0 -13
  72. package/dist/child-context.js.map +0 -1
  73. package/dist/context.d.ts +0 -13
  74. package/dist/context.d.ts.map +0 -1
  75. package/dist/context.js +0 -57
  76. package/dist/context.js.map +0 -1
  77. package/dist/cross-extension-rpc.d.ts +0 -67
  78. package/dist/cross-extension-rpc.d.ts.map +0 -1
  79. package/dist/cross-extension-rpc.js +0 -139
  80. package/dist/cross-extension-rpc.js.map +0 -1
  81. package/dist/custom-agents.d.ts +0 -55
  82. package/dist/custom-agents.d.ts.map +0 -1
  83. package/dist/custom-agents.js +0 -309
  84. package/dist/custom-agents.js.map +0 -1
  85. package/dist/default-agents.d.ts +0 -8
  86. package/dist/default-agents.d.ts.map +0 -1
  87. package/dist/default-agents.js +0 -123
  88. package/dist/default-agents.js.map +0 -1
  89. package/dist/enabled-models.d.ts +0 -50
  90. package/dist/enabled-models.d.ts.map +0 -1
  91. package/dist/enabled-models.js +0 -146
  92. package/dist/enabled-models.js.map +0 -1
  93. package/dist/env.d.ts +0 -7
  94. package/dist/env.d.ts.map +0 -1
  95. package/dist/env.js +0 -29
  96. package/dist/env.js.map +0 -1
  97. package/dist/group-join.d.ts +0 -33
  98. package/dist/group-join.d.ts.map +0 -1
  99. package/dist/group-join.js +0 -117
  100. package/dist/group-join.js.map +0 -1
  101. package/dist/index.d.ts +0 -51
  102. package/dist/index.d.ts.map +0 -1
  103. package/dist/index.js +0 -3687
  104. package/dist/index.js.map +0 -1
  105. package/dist/invocation-config.d.ts +0 -108
  106. package/dist/invocation-config.d.ts.map +0 -1
  107. package/dist/invocation-config.js +0 -84
  108. package/dist/invocation-config.js.map +0 -1
  109. package/dist/memory.d.ts +0 -54
  110. package/dist/memory.d.ts.map +0 -1
  111. package/dist/memory.js +0 -166
  112. package/dist/memory.js.map +0 -1
  113. package/dist/mention-clone.d.ts +0 -88
  114. package/dist/mention-clone.d.ts.map +0 -1
  115. package/dist/mention-clone.js +0 -154
  116. package/dist/mention-clone.js.map +0 -1
  117. package/dist/mention.d.ts +0 -82
  118. package/dist/mention.d.ts.map +0 -1
  119. package/dist/mention.js +0 -132
  120. package/dist/mention.js.map +0 -1
  121. package/dist/model-resolver.d.ts +0 -37
  122. package/dist/model-resolver.d.ts.map +0 -1
  123. package/dist/model-resolver.js +0 -96
  124. package/dist/model-resolver.js.map +0 -1
  125. package/dist/model-scope.d.ts +0 -50
  126. package/dist/model-scope.d.ts.map +0 -1
  127. package/dist/model-scope.js +0 -49
  128. package/dist/model-scope.js.map +0 -1
  129. package/dist/nested-tools.d.ts +0 -57
  130. package/dist/nested-tools.d.ts.map +0 -1
  131. package/dist/nested-tools.js +0 -301
  132. package/dist/nested-tools.js.map +0 -1
  133. package/dist/nico-overrides.d.ts +0 -54
  134. package/dist/nico-overrides.d.ts.map +0 -1
  135. package/dist/nico-overrides.js +0 -170
  136. package/dist/nico-overrides.js.map +0 -1
  137. package/dist/output-file.d.ts +0 -44
  138. package/dist/output-file.d.ts.map +0 -1
  139. package/dist/output-file.js +0 -156
  140. package/dist/output-file.js.map +0 -1
  141. package/dist/prompts.d.ts +0 -56
  142. package/dist/prompts.d.ts.map +0 -1
  143. package/dist/prompts.js +0 -92
  144. package/dist/prompts.js.map +0 -1
  145. package/dist/schedule-store.d.ts +0 -39
  146. package/dist/schedule-store.d.ts.map +0 -1
  147. package/dist/schedule-store.js +0 -156
  148. package/dist/schedule-store.js.map +0 -1
  149. package/dist/schedule.d.ts +0 -110
  150. package/dist/schedule.d.ts.map +0 -1
  151. package/dist/schedule.js +0 -360
  152. package/dist/schedule.js.map +0 -1
  153. package/dist/settings.d.ts +0 -354
  154. package/dist/settings.d.ts.map +0 -1
  155. package/dist/settings.js +0 -247
  156. package/dist/settings.js.map +0 -1
  157. package/dist/skill-loader.d.ts +0 -25
  158. package/dist/skill-loader.d.ts.map +0 -1
  159. package/dist/skill-loader.js +0 -94
  160. package/dist/skill-loader.js.map +0 -1
  161. package/dist/status-note.d.ts +0 -62
  162. package/dist/status-note.d.ts.map +0 -1
  163. package/dist/status-note.js +0 -86
  164. package/dist/status-note.js.map +0 -1
  165. package/dist/structured-output.d.ts +0 -62
  166. package/dist/structured-output.d.ts.map +0 -1
  167. package/dist/structured-output.js +0 -113
  168. package/dist/structured-output.js.map +0 -1
  169. package/dist/types.d.ts +0 -372
  170. package/dist/types.d.ts.map +0 -1
  171. package/dist/types.js +0 -6
  172. package/dist/types.js.map +0 -1
  173. package/dist/ui/agent-mention.d.ts +0 -83
  174. package/dist/ui/agent-mention.d.ts.map +0 -1
  175. package/dist/ui/agent-mention.js +0 -188
  176. package/dist/ui/agent-mention.js.map +0 -1
  177. package/dist/ui/agent-widget.d.ts +0 -241
  178. package/dist/ui/agent-widget.d.ts.map +0 -1
  179. package/dist/ui/agent-widget.js +0 -992
  180. package/dist/ui/agent-widget.js.map +0 -1
  181. package/dist/ui/ccstyle/diff/ansi-utils.d.ts +0 -11
  182. package/dist/ui/ccstyle/diff/ansi-utils.d.ts.map +0 -1
  183. package/dist/ui/ccstyle/diff/ansi-utils.js +0 -145
  184. package/dist/ui/ccstyle/diff/ansi-utils.js.map +0 -1
  185. package/dist/ui/ccstyle/diff/diff-presentation.d.ts +0 -12
  186. package/dist/ui/ccstyle/diff/diff-presentation.d.ts.map +0 -1
  187. package/dist/ui/ccstyle/diff/diff-presentation.js +0 -48
  188. package/dist/ui/ccstyle/diff/diff-presentation.js.map +0 -1
  189. package/dist/ui/ccstyle/diff/diff-renderer.d.ts +0 -46
  190. package/dist/ui/ccstyle/diff/diff-renderer.d.ts.map +0 -1
  191. package/dist/ui/ccstyle/diff/diff-renderer.js +0 -2049
  192. package/dist/ui/ccstyle/diff/diff-renderer.js.map +0 -1
  193. package/dist/ui/ccstyle/diff/line-width-safety.d.ts +0 -12
  194. package/dist/ui/ccstyle/diff/line-width-safety.d.ts.map +0 -1
  195. package/dist/ui/ccstyle/diff/line-width-safety.js +0 -58
  196. package/dist/ui/ccstyle/diff/line-width-safety.js.map +0 -1
  197. package/dist/ui/ccstyle/diff/render-utils.d.ts +0 -6
  198. package/dist/ui/ccstyle/diff/render-utils.d.ts.map +0 -1
  199. package/dist/ui/ccstyle/diff/render-utils.js +0 -25
  200. package/dist/ui/ccstyle/diff/render-utils.js.map +0 -1
  201. package/dist/ui/ccstyle/diff/shiki-highlight.d.ts +0 -19
  202. package/dist/ui/ccstyle/diff/shiki-highlight.d.ts.map +0 -1
  203. package/dist/ui/ccstyle/diff/shiki-highlight.js +0 -85
  204. package/dist/ui/ccstyle/diff/shiki-highlight.js.map +0 -1
  205. package/dist/ui/ccstyle/diff/types.d.ts +0 -22
  206. package/dist/ui/ccstyle/diff/types.d.ts.map +0 -1
  207. package/dist/ui/ccstyle/diff/types.js +0 -10
  208. package/dist/ui/ccstyle/diff/types.js.map +0 -1
  209. package/dist/ui/ccstyle/diff/write-display-utils.d.ts +0 -2
  210. package/dist/ui/ccstyle/diff/write-display-utils.d.ts.map +0 -1
  211. package/dist/ui/ccstyle/diff/write-display-utils.js +0 -12
  212. package/dist/ui/ccstyle/diff/write-display-utils.js.map +0 -1
  213. package/dist/ui/ccstyle/tool-renderer.d.ts +0 -17
  214. package/dist/ui/ccstyle/tool-renderer.d.ts.map +0 -1
  215. package/dist/ui/ccstyle/tool-renderer.js +0 -74
  216. package/dist/ui/ccstyle/tool-renderer.js.map +0 -1
  217. package/dist/ui/ccstyle/tool-result.d.ts +0 -44
  218. package/dist/ui/ccstyle/tool-result.d.ts.map +0 -1
  219. package/dist/ui/ccstyle/tool-result.js +0 -423
  220. package/dist/ui/ccstyle/tool-result.js.map +0 -1
  221. package/dist/ui/conversation-blocks.d.ts +0 -46
  222. package/dist/ui/conversation-blocks.d.ts.map +0 -1
  223. package/dist/ui/conversation-blocks.js +0 -313
  224. package/dist/ui/conversation-blocks.js.map +0 -1
  225. package/dist/ui/conversation-nvim.d.ts +0 -8
  226. package/dist/ui/conversation-nvim.d.ts.map +0 -1
  227. package/dist/ui/conversation-nvim.js +0 -117
  228. package/dist/ui/conversation-nvim.js.map +0 -1
  229. package/dist/ui/conversation-role.d.ts +0 -13
  230. package/dist/ui/conversation-role.d.ts.map +0 -1
  231. package/dist/ui/conversation-role.js +0 -39
  232. package/dist/ui/conversation-role.js.map +0 -1
  233. package/dist/ui/conversation-search.d.ts +0 -39
  234. package/dist/ui/conversation-search.d.ts.map +0 -1
  235. package/dist/ui/conversation-search.js +0 -124
  236. package/dist/ui/conversation-search.js.map +0 -1
  237. package/dist/ui/conversation-timeline.d.ts +0 -102
  238. package/dist/ui/conversation-timeline.d.ts.map +0 -1
  239. package/dist/ui/conversation-timeline.js +0 -555
  240. package/dist/ui/conversation-timeline.js.map +0 -1
  241. package/dist/ui/conversation-viewer.d.ts +0 -138
  242. package/dist/ui/conversation-viewer.d.ts.map +0 -1
  243. package/dist/ui/conversation-viewer.js +0 -1175
  244. package/dist/ui/conversation-viewer.js.map +0 -1
  245. package/dist/ui/schedule-menu.d.ts +0 -17
  246. package/dist/ui/schedule-menu.d.ts.map +0 -1
  247. package/dist/ui/schedule-menu.js +0 -95
  248. package/dist/ui/schedule-menu.js.map +0 -1
  249. package/dist/ui/select-item.d.ts +0 -28
  250. package/dist/ui/select-item.d.ts.map +0 -1
  251. package/dist/ui/select-item.js +0 -35
  252. package/dist/ui/select-item.js.map +0 -1
  253. package/dist/ui/viewer-keys.d.ts +0 -21
  254. package/dist/ui/viewer-keys.d.ts.map +0 -1
  255. package/dist/ui/viewer-keys.js +0 -18
  256. package/dist/ui/viewer-keys.js.map +0 -1
  257. package/dist/ui/workflow-card.d.ts +0 -176
  258. package/dist/ui/workflow-card.d.ts.map +0 -1
  259. package/dist/ui/workflow-card.js +0 -333
  260. package/dist/ui/workflow-card.js.map +0 -1
  261. package/dist/ui/workflow-dialog.d.ts +0 -306
  262. package/dist/ui/workflow-dialog.d.ts.map +0 -1
  263. package/dist/ui/workflow-dialog.js +0 -844
  264. package/dist/ui/workflow-dialog.js.map +0 -1
  265. package/dist/ui/workflow-menu.d.ts +0 -42
  266. package/dist/ui/workflow-menu.d.ts.map +0 -1
  267. package/dist/ui/workflow-menu.js +0 -127
  268. package/dist/ui/workflow-menu.js.map +0 -1
  269. package/dist/usage.d.ts +0 -136
  270. package/dist/usage.d.ts.map +0 -1
  271. package/dist/usage.js +0 -121
  272. package/dist/usage.js.map +0 -1
  273. package/dist/workflow/collisions.d.ts +0 -96
  274. package/dist/workflow/collisions.d.ts.map +0 -1
  275. package/dist/workflow/collisions.js +0 -89
  276. package/dist/workflow/collisions.js.map +0 -1
  277. package/dist/workflow/entry.d.ts +0 -33
  278. package/dist/workflow/entry.d.ts.map +0 -1
  279. package/dist/workflow/entry.js +0 -30
  280. package/dist/workflow/entry.js.map +0 -1
  281. package/dist/workflow/host.d.ts +0 -63
  282. package/dist/workflow/host.d.ts.map +0 -1
  283. package/dist/workflow/host.js +0 -363
  284. package/dist/workflow/host.js.map +0 -1
  285. package/dist/workflow/journal.d.ts +0 -98
  286. package/dist/workflow/journal.d.ts.map +0 -1
  287. package/dist/workflow/journal.js +0 -121
  288. package/dist/workflow/journal.js.map +0 -1
  289. package/dist/workflow/json-schema.d.ts +0 -52
  290. package/dist/workflow/json-schema.d.ts.map +0 -1
  291. package/dist/workflow/json-schema.js +0 -112
  292. package/dist/workflow/json-schema.js.map +0 -1
  293. package/dist/workflow/meta.d.ts +0 -68
  294. package/dist/workflow/meta.d.ts.map +0 -1
  295. package/dist/workflow/meta.js +0 -318
  296. package/dist/workflow/meta.js.map +0 -1
  297. package/dist/workflow/progress.d.ts +0 -225
  298. package/dist/workflow/progress.d.ts.map +0 -1
  299. package/dist/workflow/progress.js +0 -362
  300. package/dist/workflow/progress.js.map +0 -1
  301. package/dist/workflow/runtime.d.ts +0 -335
  302. package/dist/workflow/runtime.d.ts.map +0 -1
  303. package/dist/workflow/runtime.js +0 -831
  304. package/dist/workflow/runtime.js.map +0 -1
  305. package/dist/workflow/saved.d.ts +0 -91
  306. package/dist/workflow/saved.d.ts.map +0 -1
  307. package/dist/workflow/saved.js +0 -204
  308. package/dist/workflow/saved.js.map +0 -1
  309. package/dist/workflow/task.d.ts +0 -137
  310. package/dist/workflow/task.d.ts.map +0 -1
  311. package/dist/workflow/task.js +0 -208
  312. package/dist/workflow/task.js.map +0 -1
  313. package/dist/workflow/tool-description.d.ts +0 -39
  314. package/dist/workflow/tool-description.d.ts.map +0 -1
  315. package/dist/workflow/tool-description.js +0 -200
  316. package/dist/workflow/tool-description.js.map +0 -1
  317. package/dist/workflow/worker-source.d.ts +0 -48
  318. package/dist/workflow/worker-source.d.ts.map +0 -1
  319. package/dist/workflow/worker-source.js +0 -779
  320. package/dist/workflow/worker-source.js.map +0 -1
  321. package/dist/worktree.d.ts +0 -53
  322. package/dist/worktree.d.ts.map +0 -1
  323. package/dist/worktree.js +0 -165
  324. package/dist/worktree.js.map +0 -1
  325. package/dist/write-execution.d.ts +0 -42
  326. package/dist/write-execution.d.ts.map +0 -1
  327. package/dist/write-execution.js +0 -138
  328. package/dist/write-execution.js.map +0 -1
  329. package/dist/xml.d.ts +0 -11
  330. package/dist/xml.d.ts.map +0 -1
  331. package/dist/xml.js +0 -13
  332. package/dist/xml.js.map +0 -1
  333. package/src/abortable.ts +0 -43
  334. package/src/agent-color.ts +0 -161
  335. package/src/agent-file-toggle.ts +0 -269
  336. package/src/child-context.ts +0 -15
  337. package/src/mention-clone.ts +0 -196
  338. package/src/mention.ts +0 -141
  339. package/src/model-scope.ts +0 -70
  340. package/src/nested-tools.ts +0 -424
  341. package/src/structured-output.ts +0 -130
  342. package/src/ui/agent-mention.ts +0 -216
  343. package/src/ui/select-item.ts +0 -45
  344. package/src/ui/workflow-card.ts +0 -470
  345. package/src/ui/workflow-dialog.ts +0 -1115
  346. package/src/ui/workflow-menu.ts +0 -166
  347. package/src/workflow/collisions.ts +0 -123
  348. package/src/workflow/entry.ts +0 -47
  349. package/src/workflow/host.ts +0 -403
  350. package/src/workflow/journal.ts +0 -164
  351. package/src/workflow/json-schema.ts +0 -128
  352. package/src/workflow/meta.ts +0 -325
  353. package/src/workflow/progress.ts +0 -550
  354. package/src/workflow/runtime.ts +0 -1219
  355. package/src/workflow/saved.ts +0 -217
  356. package/src/workflow/task.ts +0 -302
  357. package/src/workflow/tool-description.ts +0 -200
  358. package/src/workflow/worker-source.ts +0 -781
  359. package/src/xml.ts +0 -13
package/src/settings.ts CHANGED
@@ -5,33 +5,10 @@
5
5
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
6
  import { dirname, join } from "node:path";
7
7
  import { getAgentDir } from "@earendil-works/pi-coding-agent";
8
- import { NO_FALLBACK } from "./agent-types.js";
9
- import type { AgentMentionMode, JoinMode, ViewerMarkdownMode, WidgetMode } from "./types.js";
8
+ import type { JoinMode, WidgetMode } from "./types.js";
10
9
 
11
10
  export interface SubagentsSettings {
12
11
  maxConcurrent?: number;
13
- /**
14
- * Max concurrent FOREGROUND (blocking) agents — `0` = unlimited, the default,
15
- * which preserves the behaviour that has always applied: nothing bounded
16
- * foreground work, and pi dispatches a message's tool calls through
17
- * `Promise.all`, so an unqualified fan-out of blocking `Agent` calls runs all
18
- * at once. Set it to bound that (#253 — on local models, parallel agents
19
- * thrash the prompt cache).
20
- *
21
- * Deliberately independent of `maxConcurrent` rather than folded into it: a
22
- * foreground agent blocks the parent anyway, so charging it to the background
23
- * pool would let a saturated pool starve the main session of work it could
24
- * have done itself.
25
- *
26
- * Bounds only spawns a caller is blocking on inline. Nested children are
27
- * exempt — their parent is blocked awaiting them, so queueing a child behind
28
- * its own parent would deadlock — and so are detached spawns from
29
- * cross-extension RPC or `@handle` mentions, which block nobody and are
30
- * documented to start immediately. Foreground `resume` is also outside the
31
- * pool: it reuses an existing session and never reaches the spawn path, so
32
- * several blocking resumes in one message can still exceed the limit.
33
- */
34
- maxConcurrentForeground?: number;
35
12
  /**
36
13
  * 0 = unlimited — the extension's single source of truth for that convention:
37
14
  * `normalizeMaxTurns()` in agent-runner.ts treats 0 → `undefined`, and the
@@ -40,23 +17,6 @@ export interface SubagentsSettings {
40
17
  defaultMaxTurns?: number;
41
18
  graceTurns?: number;
42
19
  defaultJoinMode?: JoinMode;
43
- /**
44
- * Whether a top-level `Agent` spawn that doesn't say runs detached.
45
- * Defaults to `true`, following Claude Code, where the agent backgrounds
46
- * unless the caller passes `run_in_background: false`. Set `false` to restore
47
- * the previous behaviour, where an unqualified spawn blocked the turn and
48
- * returned its result inline.
49
- *
50
- * Top-level only. Nested spawns (a subagent spawning its own) always default
51
- * to foreground regardless of this setting — see `nested-tools.ts`, where a
52
- * detached child would be killed by `abortOwnedChildren` when its parent
53
- * settles, with no notification path to deliver its result.
54
- *
55
- * An explicit `run_in_background` on the call, or in the agent file's
56
- * frontmatter, overrides this in both directions; the setting only decides
57
- * what "unspecified" means.
58
- */
59
- backgroundByDefault?: boolean;
60
20
  /**
61
21
  * Master switch for the schedule subagent feature. Defaults to `true`.
62
22
  * When `false`: the `Agent` tool's `schedule` param + its guideline are
@@ -88,18 +48,6 @@ export interface SubagentsSettings {
88
48
  * against. Defaults to false: subagents may use any model.
89
49
  */
90
50
  scopeModels?: boolean;
91
- /**
92
- * When true, an unreadable or unparseable agent `.md` aborts extension load
93
- * instead of being skipped with a warning — pi exits, naming the file.
94
- *
95
- * Startup only, by design. Mid-session reloads (one per `Agent` call) keep
96
- * warning: a bad edit at 3pm should not kill the session on the next
97
- * unrelated spawn, where the failure would look disconnected from its cause.
98
- * For a checked-in `.pi/agents/`, failing at startup is the point — the
99
- * alternative is running a *different* agent than the file names.
100
- * Defaults to false.
101
- */
102
- strictAgentFiles?: boolean;
103
51
  /**
104
52
  * When true, the three built-in default agents (general-purpose, Explore, Plan)
105
53
  * are not registered at startup. User-defined agents from project/global custom
@@ -118,34 +66,6 @@ export interface SubagentsSettings {
118
66
  * next pi session.
119
67
  */
120
68
  toolDescriptionMode?: ToolDescriptionMode;
121
- /**
122
- * Whether `@handle message` typed at the prompt is routed to that subagent
123
- * instead of the main model, and whether `@` offers running agents alongside
124
- * pi's file completion. Defaults to `model`. Applied live.
125
- *
126
- * - `model`: mentioning an agent that is not running asks the main model to
127
- * spawn it with the `Agent` tool, Claude Code's behaviour. Costs a turn,
128
- * and the model writes the agent's prompt rather than your text being it.
129
- * - `direct`: that agent is started here instead, with the typed message as
130
- * its prompt and no main-model turn spent.
131
- * - `off`: the input hook falls straight through and the stacked
132
- * autocomplete provider delegates everything back to pi's built-in one.
133
- *
134
- * Messaging a running agent and resuming a finished one are direct in both
135
- * `model` and `direct`. The legacy booleans are still accepted: `true` reads
136
- * as `model`, `false` as `off`.
137
- */
138
- agentMentions?: AgentMentionMode;
139
- /**
140
- * Whether subagents persist their pi session by default, so `@handle` can
141
- * reopen an agent's conversation long after its in-memory record is gone.
142
- * Defaults to `true`. Per-agent `persist_session:` frontmatter overrides it
143
- * in both directions. Turning it off restores the previous behaviour, where
144
- * a handle stops resolving roughly ten minutes after the agent finishes and
145
- * mentioning it starts a fresh run instead. Persisted sessions also appear
146
- * nested under the spawning session in pi's `/resume`.
147
- */
148
- rememberAgents?: boolean;
149
69
  /**
150
70
  * Display mode for the persistent above-editor agent widget:
151
71
  * - `all`: show every agent (foreground + background).
@@ -153,7 +73,7 @@ export interface SubagentsSettings {
153
73
  * Agent tool result, so the widget would otherwise double-render them
154
74
  * (#118); everything else (background, queued, scheduled, RPC) stays.
155
75
  * - `off`: hide the widget entirely.
156
- * Defaults to `background`. Pure-UI and applied live (toggling refreshes the
76
+ * Defaults to `all`. Pure-UI and applied live (toggling refreshes the
157
77
  * widget).
158
78
  */
159
79
  widgetMode?: WidgetMode;
@@ -168,134 +88,6 @@ export interface SubagentsSettings {
168
88
  * (`isolation: worktree`), or memory files.
169
89
  */
170
90
  outputTranscript?: boolean;
171
- /**
172
- * Whether `isolation: "worktree"` may create a worktree at all. Defaults to
173
- * `true`. Set `false` on a repo where worktrees are too slow or too large to
174
- * be worth it (#184): a requested worktree is then dropped and the agent runs
175
- * in the main checkout.
176
- *
177
- * The drop is deliberately silent — there is no per-result note, because the
178
- * setting exists for projects whose model asks for a worktree on every call,
179
- * where a note would be noise on every result. What keeps the orchestrator
180
- * from claiming a `pi-agent-*` branch anyway is that it is never told the
181
- * capability exists: `isolationParam` (invocation-config.ts) drops the field
182
- * from both tool schemas, and `isolationGuideline` (index.ts) drops the
183
- * matching prose from the full and compact descriptions — a custom one opts
184
- * in via the `{{isolationGuideline}}` placeholder. Anything that
185
- * reintroduces the prose has to reintroduce a note with it.
186
- *
187
- * Deliberately a downgrade rather than an error. The fail-loud rule covers
188
- * worktrees that *cannot* be created; this is the user declining one, and
189
- * throwing would reject exactly the calls that the `isolation: "off"` value
190
- * exists to tolerate. Enforced below the tool boundary, so it also covers the
191
- * scheduler and the unvalidated cross-extension RPC path.
192
- */
193
- worktreeIsolation?: boolean;
194
- /**
195
- * Master switch for scripted workflows. Defaults to `true`.
196
- *
197
- * Off is not a soft hide: the `SubagentWorkflow` tool is never registered, so
198
- * the model is not told it exists and cannot call it, the `/agents`
199
- * Workflows entry is hidden, and `--subagents-workflow-file` is refused.
200
- *
201
- * Absent is not the same as `true`. Unset means *auto*: on, but yielding to
202
- * another extension that already offers a workflow tool, because two
203
- * orchestrators in one tool spec is a worse default than none — the model
204
- * has to guess which to call, and pays for both descriptions to find out.
205
- * Setting it explicitly pins the answer in both directions: `true` keeps
206
- * ours whatever else is loaded, `false` is off regardless. See
207
- * `resolveWorkflowCollisions` in index.ts.
208
- *
209
- * Read once at extension init, before registration, so flipping it in
210
- * `/agents → Settings` takes effect on the next pi session — the same
211
- * contract `schedulingEnabled` has, and for the same reason: a tool spec is
212
- * fixed once pi has it.
213
- */
214
- workflowsEnabled?: boolean;
215
- /**
216
- * Hard ceiling on nested subagent delegation, counted from the main session:
217
- * main = 0, its subagents = 1, their children = 2. Defaults to `2`; `0` or `1`
218
- * disables nesting project-wide. Read when a subagent session is built, so a
219
- * change applies to agents started after it.
220
- */
221
- maxSubagentDepth?: number;
222
- /**
223
- * Agent type substituted when a caller-supplied `subagent_type` doesn't
224
- * resolve to exactly one enabled agent (unknown, disabled, or ambiguous by
225
- * case). Omitted keeps the historical `general-purpose` fallback; a type name
226
- * routes those calls to that agent instead; `"none"` disables the fallback so
227
- * dispatch fails closed with an error naming the available types.
228
- *
229
- * The boolean `false` is accepted as a spelling of `"none"`, because a boolean
230
- * would otherwise be dropped as the wrong type and silently leave the
231
- * PERMISSIVE default in place while the author believes strict dispatch is on
232
- * — the wrong direction to fail for this setting. Every other value is an
233
- * agent name, so a mistaken `"off"` fails loudly at dispatch rather than
234
- * meaning one thing here and another in the resolver.
235
- */
236
- fallbackSubagent?: string;
237
- /**
238
- * Whether this extension's tool results carry a `usage` field, so subagent
239
- * spend reaches the parent session's own accounting. Defaults to `false`.
240
- *
241
- * Subagents run in their own pi sessions, so by default the parent's footer,
242
- * statusline and `/cost` show only what the main model spent — a session that
243
- * delegated most of its work reads as nearly free. Pi folds
244
- * `toolResult.usage` into `getSessionStats()`, so attaching it makes those
245
- * surfaces count subagents too, under `/cost`'s "Tools/summaries" bucket.
246
- *
247
- * Off by default because it changes numbers the user may already be tracking
248
- * (a statusline reading session cost will step up), not because the numbers
249
- * are wrong.
250
- *
251
- * Three properties of what gets reported:
252
- * - Tokens exclude `cacheRead`, for the reason in `usage.ts` — the parent's
253
- * token total therefore rises by billed tokens only.
254
- * - Cost is pi's own per-message `usage.cost.total`; we price nothing, and
255
- * a model pi has no rates for contributes 0.
256
- * - The context-window percentage is untouched. Pi derives it from assistant
257
- * messages alone (`getContextUsage`), so a delegating session's context
258
- * does not appear to fill up faster.
259
- */
260
- reportUsage?: boolean;
261
- /**
262
- * Whether the subagent surfaces show an estimated dollar cost next to their
263
- * token counts (widget, conversation viewer, foreground results,
264
- * completion notifications). Defaults to `false`. Applied live.
265
- *
266
- * Rendered as `~$0.0042` — the tilde marks it as pi's reported estimate
267
- * rather than a billed figure, and it is omitted entirely when the model has
268
- * no pricing data, so a local model shows tokens and no dollars.
269
- *
270
- * Independent of `reportUsage`: this one is what a human reads, that one is
271
- * what the parent session counts.
272
- */
273
- showCost?: boolean;
274
-
275
- /**
276
- * Whether the widget's running rows name the model driving each agent and the
277
- * thinking level it is running at.
278
- *
279
- * Off by default, unlike the tool result and the conversation viewer, which
280
- * show the pair unconditionally: those have a line to themselves, while the
281
- * widget row already carries the description, turns, tool uses, tokens and
282
- * elapsed time, and every character it gains is one the description loses on a
283
- * narrow terminal.
284
- */
285
- showModel?: boolean;
286
- /**
287
- * How much of the conversation viewer's transcript renders as Markdown.
288
- * Defaults to `assistant`. Applied live — the viewer's `m` key cycles this
289
- * same setting, so a choice made in the overlay persists like one made in
290
- * `/agents → Settings`.
291
- *
292
- * Scoped rather than all-or-nothing because the two kinds of content have
293
- * different contracts: assistant text is authored as Markdown, while a tool
294
- * result is whatever bytes the tool produced. Rendering the latter as
295
- * Markdown is lossy in ways that look like the tool misbehaved — see
296
- * `ViewerMarkdownMode` for the specific rewrites — so `all` is opt-in.
297
- */
298
- viewerMarkdown?: ViewerMarkdownMode;
299
91
  }
300
92
 
301
93
  export type ToolDescriptionMode = "full" | "compact" | "custom";
@@ -303,28 +95,15 @@ export type ToolDescriptionMode = "full" | "compact" | "custom";
303
95
  /** Setter hooks used by applySettings to wire persisted values into in-memory state. */
304
96
  export interface SettingsAppliers {
305
97
  setMaxConcurrent: (n: number) => void;
306
- setMaxConcurrentForeground: (n: number) => void;
307
98
  setDefaultMaxTurns: (n: number) => void;
308
99
  setGraceTurns: (n: number) => void;
309
100
  setDefaultJoinMode: (mode: JoinMode) => void;
310
- setBackgroundByDefault: (b: boolean) => void;
311
101
  setSchedulingEnabled: (b: boolean) => void;
312
102
  setScopeModels: (enabled: boolean) => void;
313
- setStrictAgentFiles: (b: boolean) => void;
314
103
  setDisableDefaultAgents: (b: boolean) => void;
315
104
  setToolDescriptionMode: (mode: ToolDescriptionMode) => void;
316
- setAgentMentions: (mode: AgentMentionMode) => void;
317
- setRememberAgents: (b: boolean) => void;
318
105
  setWidgetMode: (mode: WidgetMode) => void;
319
106
  setOutputTranscript: (b: boolean) => void;
320
- setWorktreeIsolation: (b: boolean) => void;
321
- setWorkflowsEnabled: (b: boolean) => void;
322
- setMaxSubagentDepth: (n: number) => void;
323
- setFallbackSubagent: (v: string | undefined) => void;
324
- setReportUsage: (b: boolean) => void;
325
- setShowCost: (b: boolean) => void;
326
- setShowModel: (b: boolean) => void;
327
- setViewerMarkdown: (mode: ViewerMarkdownMode) => void;
328
107
  }
329
108
 
330
109
  /** Emit callback — a subset of `pi.events.emit` to keep helpers testable. */
@@ -333,8 +112,6 @@ export type SettingsEmit = (event: string, payload: unknown) => void;
333
112
  const VALID_JOIN_MODES: ReadonlySet<string> = new Set<JoinMode>(["async", "group", "smart"]);
334
113
  const VALID_TOOL_DESCRIPTION_MODES: ReadonlySet<string> = new Set<ToolDescriptionMode>(["full", "compact", "custom"]);
335
114
  const VALID_WIDGET_MODES: ReadonlySet<string> = new Set<WidgetMode>(["all", "background", "off"]);
336
- const VALID_VIEWER_MARKDOWN_MODES: ReadonlySet<string> = new Set<ViewerMarkdownMode>(["off", "assistant", "all"]);
337
- const VALID_AGENT_MENTION_MODES: ReadonlySet<string> = new Set<AgentMentionMode>(["model", "direct", "off"]);
338
115
 
339
116
  // Sanity ceilings — prevent hand-edited configs from asking for values that
340
117
  // make no operational sense (e.g. 1e6 concurrent subagents). Permissive enough
@@ -342,7 +119,6 @@ const VALID_AGENT_MENTION_MODES: ReadonlySet<string> = new Set<AgentMentionMode>
342
119
  const MAX_CONCURRENT_CEILING = 1024;
343
120
  const MAX_TURNS_CEILING = 10_000;
344
121
  const GRACE_TURNS_CEILING = 1_000;
345
- const SUBAGENT_DEPTH_CEILING = 16;
346
122
 
347
123
  /** Drop fields that don't match the expected shape. Silent — garbage becomes absent. */
348
124
  function sanitize(raw: unknown): SubagentsSettings {
@@ -356,15 +132,6 @@ function sanitize(raw: unknown): SubagentsSettings {
356
132
  ) {
357
133
  out.maxConcurrent = r.maxConcurrent as number;
358
134
  }
359
- // Floor 0, not 1 like maxConcurrent above: 0 is the documented "unlimited"
360
- // value and the default, so dropping it would silently be unrepresentable.
361
- if (
362
- Number.isInteger(r.maxConcurrentForeground) &&
363
- (r.maxConcurrentForeground as number) >= 0 &&
364
- (r.maxConcurrentForeground as number) <= MAX_CONCURRENT_CEILING
365
- ) {
366
- out.maxConcurrentForeground = r.maxConcurrentForeground as number;
367
- }
368
135
  if (
369
136
  Number.isInteger(r.defaultMaxTurns) &&
370
137
  (r.defaultMaxTurns as number) >= 0 &&
@@ -379,78 +146,27 @@ function sanitize(raw: unknown): SubagentsSettings {
379
146
  ) {
380
147
  out.graceTurns = r.graceTurns as number;
381
148
  }
382
- if (
383
- Number.isInteger(r.maxSubagentDepth) &&
384
- (r.maxSubagentDepth as number) >= 0 &&
385
- (r.maxSubagentDepth as number) <= SUBAGENT_DEPTH_CEILING
386
- ) {
387
- out.maxSubagentDepth = r.maxSubagentDepth as number;
388
- }
389
149
  if (typeof r.defaultJoinMode === "string" && VALID_JOIN_MODES.has(r.defaultJoinMode)) {
390
150
  out.defaultJoinMode = r.defaultJoinMode as JoinMode;
391
151
  }
392
- if (typeof r.backgroundByDefault === "boolean") {
393
- out.backgroundByDefault = r.backgroundByDefault;
394
- }
395
152
  if (typeof r.schedulingEnabled === "boolean") {
396
153
  out.schedulingEnabled = r.schedulingEnabled;
397
154
  }
398
155
  if (typeof r.scopeModels === "boolean") {
399
156
  out.scopeModels = r.scopeModels;
400
157
  }
401
- if (typeof r.strictAgentFiles === "boolean") {
402
- out.strictAgentFiles = r.strictAgentFiles;
403
- }
404
158
  if (typeof r.disableDefaultAgents === "boolean") {
405
159
  out.disableDefaultAgents = r.disableDefaultAgents;
406
160
  }
407
161
  if (typeof r.toolDescriptionMode === "string" && VALID_TOOL_DESCRIPTION_MODES.has(r.toolDescriptionMode)) {
408
162
  out.toolDescriptionMode = r.toolDescriptionMode as ToolDescriptionMode;
409
163
  }
410
- // Was a boolean before the `model` mode existed. A hand-written or
411
- // previously-written `true` means "on", which is now the default `model`.
412
- if (typeof r.agentMentions === "boolean") {
413
- out.agentMentions = r.agentMentions ? "model" : "off";
414
- } else if (typeof r.agentMentions === "string" && VALID_AGENT_MENTION_MODES.has(r.agentMentions)) {
415
- out.agentMentions = r.agentMentions as AgentMentionMode;
416
- }
417
- if (typeof r.rememberAgents === "boolean") {
418
- out.rememberAgents = r.rememberAgents;
419
- }
420
164
  if (typeof r.widgetMode === "string" && VALID_WIDGET_MODES.has(r.widgetMode)) {
421
165
  out.widgetMode = r.widgetMode as WidgetMode;
422
166
  }
423
167
  if (typeof r.outputTranscript === "boolean") {
424
168
  out.outputTranscript = r.outputTranscript;
425
169
  }
426
- if (typeof r.worktreeIsolation === "boolean") {
427
- out.worktreeIsolation = r.worktreeIsolation;
428
- }
429
- if (typeof r.reportUsage === "boolean") {
430
- out.reportUsage = r.reportUsage;
431
- }
432
- if (typeof r.showCost === "boolean") {
433
- out.showCost = r.showCost;
434
- }
435
- if (typeof r.showModel === "boolean") {
436
- out.showModel = r.showModel;
437
- }
438
- if (typeof r.viewerMarkdown === "string" && VALID_VIEWER_MARKDOWN_MODES.has(r.viewerMarkdown)) {
439
- out.viewerMarkdown = r.viewerMarkdown as ViewerMarkdownMode;
440
- }
441
- if (typeof r.workflowsEnabled === "boolean") {
442
- out.workflowsEnabled = r.workflowsEnabled;
443
- }
444
- if (r.fallbackSubagent === false) {
445
- // The only non-string spelling worth accepting: a boolean would otherwise be
446
- // dropped, silently leaving the PERMISSIVE default in place. Every string is
447
- // an agent name except the `none` sentinel, which the resolver recognizes —
448
- // so a mistaken "off" fails loudly at dispatch instead of meaning something
449
- // different here than it does there.
450
- out.fallbackSubagent = NO_FALLBACK;
451
- } else if (typeof r.fallbackSubagent === "string" && r.fallbackSubagent.trim()) {
452
- out.fallbackSubagent = r.fallbackSubagent.trim();
453
- }
454
170
  return out;
455
171
  }
456
172
 
@@ -502,30 +218,15 @@ export function saveSettings(s: SubagentsSettings, cwd: string = process.cwd()):
502
218
  /** Apply persisted settings to the in-memory state via caller-supplied setters. */
503
219
  export function applySettings(s: SubagentsSettings, appliers: SettingsAppliers): void {
504
220
  if (typeof s.maxConcurrent === "number") appliers.setMaxConcurrent(s.maxConcurrent);
505
- if (typeof s.maxConcurrentForeground === "number") {
506
- appliers.setMaxConcurrentForeground(s.maxConcurrentForeground);
507
- }
508
221
  if (typeof s.defaultMaxTurns === "number") appliers.setDefaultMaxTurns(s.defaultMaxTurns);
509
222
  if (typeof s.graceTurns === "number") appliers.setGraceTurns(s.graceTurns);
510
- if (typeof s.maxSubagentDepth === "number") appliers.setMaxSubagentDepth(s.maxSubagentDepth);
511
- if (typeof s.fallbackSubagent === "string") appliers.setFallbackSubagent(s.fallbackSubagent);
512
223
  if (s.defaultJoinMode) appliers.setDefaultJoinMode(s.defaultJoinMode);
513
- if (typeof s.backgroundByDefault === "boolean") appliers.setBackgroundByDefault(s.backgroundByDefault);
514
224
  if (typeof s.schedulingEnabled === "boolean") appliers.setSchedulingEnabled(s.schedulingEnabled);
515
225
  if (typeof s.scopeModels === "boolean") appliers.setScopeModels(s.scopeModels);
516
- if (typeof s.strictAgentFiles === "boolean") appliers.setStrictAgentFiles(s.strictAgentFiles);
517
226
  if (typeof s.disableDefaultAgents === "boolean") appliers.setDisableDefaultAgents(s.disableDefaultAgents);
518
227
  if (s.toolDescriptionMode) appliers.setToolDescriptionMode(s.toolDescriptionMode);
519
- if (s.agentMentions) appliers.setAgentMentions(s.agentMentions);
520
- if (typeof s.rememberAgents === "boolean") appliers.setRememberAgents(s.rememberAgents);
521
228
  if (s.widgetMode) appliers.setWidgetMode(s.widgetMode);
522
229
  if (typeof s.outputTranscript === "boolean") appliers.setOutputTranscript(s.outputTranscript);
523
- if (typeof s.worktreeIsolation === "boolean") appliers.setWorktreeIsolation(s.worktreeIsolation);
524
- if (typeof s.reportUsage === "boolean") appliers.setReportUsage(s.reportUsage);
525
- if (typeof s.showCost === "boolean") appliers.setShowCost(s.showCost);
526
- if (typeof s.showModel === "boolean") appliers.setShowModel(s.showModel);
527
- if (s.viewerMarkdown) appliers.setViewerMarkdown(s.viewerMarkdown);
528
- if (typeof s.workflowsEnabled === "boolean") appliers.setWorkflowsEnabled(s.workflowsEnabled);
529
230
  }
530
231
 
531
232
  /**
@@ -1,15 +1,7 @@
1
1
  /**
2
- * status-note.ts — Honest framing for an agent result: the parenthetical status
3
- * note for a non-normal outcome, and the salvaged partial output of a failure.
4
- *
5
- * Lives here rather than in an index.ts closure because both entry points need
6
- * it — the top-level tools and the nested delegation tools, which can't import
7
- * from index.ts (that is the extension entry, and it already reaches these tools
8
- * through agent-runner).
2
+ * status-note.ts — Parenthetical status note appended to agent result text.
9
3
  */
10
4
 
11
- import type { AgentRecord } from "./types.js";
12
-
13
5
  /**
14
6
  * Explicit parenthetical note for a non-normal terminal outcome, so the parent
15
7
  * agent can't mistake partial output for a completed result. Empty string for a
@@ -31,60 +23,3 @@ export function getStatusNote(status: string): string {
31
23
  return "";
32
24
  }
33
25
  }
34
-
35
- /**
36
- * Foreground variant of `getStatusNote`. A foreground caller is in a different
37
- * position from a background one, so it needs different text:
38
- *
39
- * - It already holds the agent's ENTIRE output inline, whereas the background
40
- * notification carries a 500-char preview. So only here can we truthfully
41
- * say there is nothing more to fetch — which is the whole point, because
42
- * - it has no agent id. The id travels in the tool result's renderer
43
- * `details`, which is never serialized to the model. A parent that reads
44
- * "output may be partial" as "truncated, go retrieve the rest" therefore
45
- * has nothing valid to call `get_subagent_result` with, and will invent an
46
- * id (#174).
47
- *
48
- * Only the lead clause varies between the three, and each variation carries
49
- * information: `wrapped up` vs `aborted` tells the parent whether the output is
50
- * a considered final answer or a fragment, and `stopped` shouts because a human
51
- * intervening outranks everything else in the string. Only `steered` hedges on
52
- * completion — it was told to wrap up and did, so it may well have finished at
53
- * the limit; an aborted run blew through its grace turns while still working,
54
- * and `stopped` can only fire on a running agent, so neither ever delivered a
55
- * final answer. Identical confidence gets identical wording: phrasing one fact
56
- * two ways invites a hunt for a distinction that isn't there.
57
- *
58
- * Every clause is a statement about state, never an instruction to act, and
59
- * `get_subagent_result` is never named — naming the tool we steer away from only
60
- * raises its salience. Two instructions were tried here and cut: "re-spawn with
61
- * a higher max_turns" (pushes a fresh multi-minute run to save one wasted tool
62
- * call) and, on `stopped`, "ask before restarting it" (restates the lead, and
63
- * presumes someone is present to ask — false under `pi -p`, in scheduled jobs,
64
- * and in any background-driven run). Nothing here can measure whether wording
65
- * improves parent behavior, so removing a false cue (which cannot induce new
66
- * behavior) and adding an instruction (which can) are not equally safe bets.
67
- * Don't add either back without a way to measure it.
68
- */
69
- export function getForegroundOutcomeNote(status: string): string {
70
- switch (status) {
71
- case "stopped":
72
- return " (STOPPED BY THE USER — everything the agent produced is above; the task is unfinished)";
73
- case "aborted":
74
- return " (aborted at the turn limit — everything the agent produced is above; the task is unfinished)";
75
- case "steered":
76
- return " (wrapped up at the turn limit — everything the agent produced is above; the task may be unfinished)";
77
- default:
78
- return "";
79
- }
80
- }
81
-
82
- /**
83
- * Salvaged partial output of a failed run, as a labeled suffix for the error
84
- * surfaces (or "" if the run produced nothing). `record.result` is bounded to
85
- * the run's own turns, so this is never a stale earlier answer (#144).
86
- */
87
- export function partialOutputSuffix(record: AgentRecord): string {
88
- const partial = record.result?.trim();
89
- return partial ? `\n\nPartial output before the failure:\n${partial}` : "";
90
- }