@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
@@ -6,7 +6,7 @@ import { readFileSync } from "node:fs";
6
6
  import { homedir } from "node:os";
7
7
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
8
8
  import type { Model } from "@earendil-works/pi-ai";
9
- import type { ExtensionContext, LoadExtensionsResult } from "@earendil-works/pi-coding-agent";
9
+ import type { ExtensionContext, LoadExtensionsResult, ModelRuntime } from "@earendil-works/pi-coding-agent";
10
10
  import {
11
11
  type AgentSession,
12
12
  type AgentSessionEvent,
@@ -18,18 +18,14 @@ import {
18
18
  SettingsManager,
19
19
  } from "@earendil-works/pi-coding-agent";
20
20
  import { BUILTIN_TOOL_NAMES, getAgentConfig, getConfig, getMemoryToolNames, getReadOnlyMemoryToolNames, getToolNamesForType } from "./agent-types.js";
21
- import { runInChildSessionContext } from "./child-context.js";
22
21
  import { buildParentContext, extractText } from "./context.js";
23
22
  import { DEFAULT_AGENTS } from "./default-agents.js";
24
23
  import { detectEnv } from "./env.js";
25
24
  import { buildMemoryBlock, buildReadOnlyMemoryBlock } from "./memory.js";
26
- import { createNestedSubagentTools, getMaxSubagentDepth, type NestedAgentManager } from "./nested-tools.js";
27
25
  import { buildAgentPrompt, type PromptExtras } from "./prompts.js";
28
26
  import { preloadSkills } from "./skill-loader.js";
29
- import { createStructuredCapture, createStructuredOutputTool, structuredRetryPrompt } from "./structured-output.js";
30
27
  import type { SubagentType, ThinkingLevel } from "./types.js";
31
- import type { LifetimeUsage } from "./usage.js";
32
- import type { CompiledSchema } from "./workflow/json-schema.js";
28
+ import { createTrackedWriteTool } from "./write-execution.js";
33
29
 
34
30
  /**
35
31
  * Tool names registered by THIS extension. Single source of truth so the
@@ -39,7 +35,6 @@ import type { CompiledSchema } from "./workflow/json-schema.js";
39
35
  */
40
36
  export const SUBAGENT_TOOL_NAMES = {
41
37
  AGENT: "Agent",
42
- WORKFLOW: "SubagentWorkflow",
43
38
  GET_RESULT: "get_subagent_result",
44
39
  STEER: "steer_subagent",
45
40
  } as const;
@@ -236,18 +231,9 @@ export function installExtensionToolScope(
236
231
  disallowedSet: Set<string> | undefined;
237
232
  extNames: Set<string>;
238
233
  narrowing: Map<string, Set<string>>;
239
- /**
240
- * Injected `customTools` to keep active regardless of the built-in list.
241
- *
242
- * Two kinds arrive here and they are blocked for different reasons: opt-in
243
- * nested-delegation tools share EXCLUDED_TOOL_NAMES' names, and
244
- * StructuredOutput is simply not a built-in, so neither survives a `keep`
245
- * seeded from `toolNames`.
246
- */
247
- readmitToolNames: Set<string>;
248
234
  },
249
235
  ): void {
250
- const { loader, toolNames, disallowedSet, extNames, narrowing, readmitToolNames } = ctx;
236
+ const { loader, toolNames, disallowedSet, extNames, narrowing } = ctx;
251
237
 
252
238
  // The names allowed right now. Mirrors the `ext:` opt-in flip: when any `ext:`
253
239
  // selector is present, extension tools become an explicit allowlist — a loaded
@@ -269,11 +255,6 @@ export function installExtensionToolScope(
269
255
  }
270
256
  }
271
257
  for (const name of EXCLUDED_TOOL_NAMES) keep.delete(name);
272
- // Injected tools are legitimately active for this agent — re-admit them so
273
- // the renarrow keeps them in the active set and beforeToolCall doesn't
274
- // block them. Already vetted against `disallowed_tools` by the caller,
275
- // which is the only place that knows which kind may be taken back.
276
- for (const name of readmitToolNames) keep.add(name);
277
258
  return keep;
278
259
  };
279
260
 
@@ -322,33 +303,6 @@ export function getDefaultMaxTurns(): number | undefined { return defaultMaxTurn
322
303
  /** Set the default max turns value. undefined or 0 = unlimited, otherwise minimum 1. */
323
304
  export function setDefaultMaxTurns(n: number | undefined): void { defaultMaxTurns = normalizeMaxTurns(n); }
324
305
 
325
- /**
326
- * The turn limit a run of `type` will actually enforce: an explicit value if the
327
- * caller supplied one, else the agent's own `max_turns`, else the project
328
- * default. `undefined` = unlimited.
329
- *
330
- * Exported because the widget's turn counter (`↻3≤20`) has to predict this
331
- * before the run starts, and a second copy of the expression would drift from
332
- * the one below that enforces it.
333
- */
334
- export function resolveEffectiveMaxTurns(type: string, explicit?: number): number | undefined {
335
- return normalizeMaxTurns(explicit ?? getAgentConfig(type)?.maxTurns ?? defaultMaxTurns);
336
- }
337
-
338
- /**
339
- * Project default for `persist_session`, from the `rememberAgents` setting.
340
- * On by default: a persisted session is what lets `@handle` reopen an agent's
341
- * conversation after its record has been evicted, which is the whole point of
342
- * addressing an agent by a name that outlives one run. Per-agent frontmatter
343
- * still overrides it in both directions.
344
- */
345
- let rememberAgents = true;
346
-
347
- /** Whether subagent sessions are persisted by default. */
348
- export function getRememberAgents(): boolean { return rememberAgents; }
349
- /** Set whether subagent sessions are persisted by default. */
350
- export function setRememberAgents(b: boolean): void { rememberAgents = b; }
351
-
352
306
  /** Additional turns allowed after the soft limit steer message. */
353
307
  let graceTurns = 5;
354
308
 
@@ -361,7 +315,7 @@ export function setGraceTurns(n: number): void { graceTurns = Math.max(1, n); }
361
315
  * Try to find the right model for an agent type.
362
316
  * Priority: explicit option > config.model > parent model.
363
317
  */
364
- export function resolveDefaultModel(
318
+ function resolveDefaultModel(
365
319
  parentModel: Model<any> | undefined,
366
320
  registry: { find(provider: string, modelId: string): Model<any> | undefined; getAvailable?(): Model<any>[] },
367
321
  configModel?: string,
@@ -405,39 +359,8 @@ export interface RunOptions {
405
359
  isolated?: boolean;
406
360
  inheritContext?: boolean;
407
361
  thinkingLevel?: ThinkingLevel;
408
- /**
409
- * Reopen this pi session file rather than starting an empty conversation.
410
- * `createAgentSession` seeds itself from whatever its SessionManager holds,
411
- * so pointing it at an existing file rehydrates that agent's history and the
412
- * prompt continues it. Everything else — tools, model, system prompt, turn
413
- * caps — is still resolved from the agent type, so the continuation runs
414
- * under the type's *current* definition, not the one the original run used.
415
- */
416
- resumeSessionFile?: string;
417
- /**
418
- * True when another agent spawned this one. Only top-level agents get a
419
- * handle, so only they can be reopened by name — which is the whole reason
420
- * `rememberAgents` persists a session at all. A nested run's transcript would
421
- * be unreachable by anything, so it stays in memory unless its own
422
- * frontmatter asks otherwise.
423
- */
424
- nested?: boolean;
425
- /**
426
- * True when a workflow run spawned this agent. Its final text is the value
427
- * `agent()` resolves to rather than a report a person reads, and the prompt
428
- * says so — but only when `structuredOutput` is unset, since that child
429
- * already has a `StructuredOutput` tool to answer through and two competing
430
- * "this is how you return your answer" instructions is worse than one.
431
- */
432
- workflow?: boolean;
433
362
  /** Override working directory (e.g. for worktree isolation). */
434
363
  cwd?: string;
435
- /**
436
- * Directory the worktree copy was created from. Set only when `cwd` points
437
- * into a worktree — the prompt then tells the agent to stay in the copy
438
- * instead of following the inherited parent prompt back to the main tree.
439
- */
440
- worktreeBase?: string;
441
364
  /**
442
365
  * Where .pi config is discovered (project extensions, skills, pi settings,
443
366
  * agent memory). Default: same as the working directory. The manager sets
@@ -463,33 +386,13 @@ export interface RunOptions {
463
386
  * Called once per assistant message_end with that message's usage delta.
464
387
  * Lets callers maintain a lifetime accumulator that survives compaction
465
388
  * (which replaces session.state.messages and resets stats-derived sums).
466
- *
467
- * `cost` is pi's own `usage.cost.total` for that message — priced from the
468
- * model's rates, so it is 0 (not missing) for a model pi has no pricing for.
469
- * We never price anything ourselves; every dollar figure this extension shows
470
- * or reports traces back to this field.
471
389
  */
472
- onAssistantUsage?: (usage: LifetimeUsage) => void;
390
+ onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number }) => void;
473
391
  /**
474
392
  * Called when the session successfully compacts. `tokensBefore` is upstream's
475
393
  * pre-compaction context size estimate. Aborted compactions don't fire.
476
394
  */
477
395
  onCompaction?: (info: { reason: "manual" | "threshold" | "overflow"; tokensBefore: number }) => void;
478
- /**
479
- * Make this child report through a `StructuredOutput` tool built from this
480
- * schema, and put the validated payload on {@link RunResult.structuredJson}.
481
- *
482
- * Already compiled by the caller, so a schema this runtime cannot validate
483
- * fails at the call that wrote it rather than inside the child.
484
- */
485
- structuredOutput?: CompiledSchema;
486
- /** Runtime bridge for opt-in child-safe nested delegation. */
487
- nestedRuntime?: {
488
- manager: NestedAgentManager;
489
- parentAgentId: string;
490
- depth: number;
491
- maxSubagentDepth?: number;
492
- };
493
396
  }
494
397
 
495
398
  export interface RunResult {
@@ -509,18 +412,6 @@ export interface RunResult {
509
412
  * stop that produced text (a legitimate truncated answer).
510
413
  */
511
414
  failure?: string;
512
- /**
513
- * The validated `StructuredOutput` payload as canonical JSON, when the caller
514
- * asked for a schema and the child produced one.
515
- *
516
- * Deliberately not folded into {@link responseText}: `record.result` picks up
517
- * a worktree branch note on the way out, which would leave the caller with
518
- * unparseable JSON, and merging the two would make "produced structured
519
- * output" indistinguishable from "happened to answer in JSON".
520
- */
521
- structuredJson?: string;
522
- /** Whether the extra structured-output prompt had to be sent. */
523
- structuredRetried?: boolean;
524
415
  }
525
416
 
526
417
  /**
@@ -629,8 +520,6 @@ export async function runAgent(
629
520
 
630
521
  // Build prompt extras (memory, skill preloading)
631
522
  const extras: PromptExtras = {};
632
- if (options.worktreeBase) extras.worktreeBase = options.worktreeBase;
633
- if (options.workflow && !options.structuredOutput) extras.workflowChild = true;
634
523
 
635
524
  // Resolve extensions/skills: isolated overrides to false
636
525
  const extensions = options.isolated ? false : config.extensions;
@@ -757,7 +646,7 @@ export async function runAgent(
757
646
  systemPromptOverride: () => systemPrompt,
758
647
  appendSystemPromptOverride: () => [],
759
648
  });
760
- await runInChildSessionContext(() => loader.reload());
649
+ await loader.reload();
761
650
 
762
651
  // Plain entries in `tools:` are expected to be built-in names (extension tools
763
652
  // go through `ext:`), so an unknown name there is unambiguously a typo. Previously
@@ -840,53 +729,6 @@ export async function runAgent(
840
729
  ? new Set(agentConfig.disallowedTools)
841
730
  : undefined;
842
731
 
843
- // Nested delegation tools (opt-in, ownership-scoped). Empty unless the agent
844
- // set `allowed_subagents` and a nestedRuntime was provided — and never when
845
- // isolated. Their names collide with EXCLUDED_TOOL_NAMES by design, so the
846
- // scoping below re-admits them explicitly (registry deny + active-set narrow).
847
- const effectiveMaxDepth = options.nestedRuntime?.maxSubagentDepth ?? getMaxSubagentDepth();
848
- // At (or past) the cap this agent can never spawn, so it can never own a child
849
- // to fetch from or steer either — inject nothing rather than three tools whose
850
- // every call is an error. This is also what makes `maxSubagentDepth` 0/1 mean
851
- // "nesting off" instead of "nesting always fails".
852
- const nestedRuntime = options.nestedRuntime && options.nestedRuntime.depth < effectiveMaxDepth
853
- ? options.nestedRuntime
854
- : undefined;
855
- const nestedTools = agentConfig?.allowedSubagents && nestedRuntime && !options.isolated
856
- ? createNestedSubagentTools({
857
- manager: nestedRuntime.manager,
858
- pi: options.pi,
859
- parentAgentId: nestedRuntime.parentAgentId,
860
- depth: nestedRuntime.depth,
861
- maxSubagentDepth: effectiveMaxDepth,
862
- allowedSubagents: agentConfig.allowedSubagents,
863
- configCwd,
864
- })
865
- : [];
866
- const nestedToolNames = new Set(nestedTools.map(tool => tool.name));
867
-
868
- // The `agent({ schema })` contract: this child reports its answer by calling
869
- // StructuredOutput, and `structuredJson` below is what the caller reads. The
870
- // schema was already compiled by whoever asked for it, so a bad one failed
871
- // before any of this ran.
872
- const structuredCapture = options.structuredOutput ? createStructuredCapture() : undefined;
873
- const structuredTools = options.structuredOutput && structuredCapture
874
- ? [createStructuredOutputTool(options.structuredOutput, structuredCapture)]
875
- : [];
876
- const structuredToolNames = new Set(structuredTools.map(tool => tool.name));
877
- // Re-admitted together at every gate below. Kept as one set so a new injected
878
- // tool cannot be added to some of the three gates and forgotten at the rest.
879
- //
880
- // `disallowed_tools` is applied HERE rather than at the gates, because the two
881
- // kinds answer to it differently: a nested delegation tool is an opt-in the
882
- // agent's own frontmatter can take back, while StructuredOutput exists only
883
- // because this call asked for a schema — removing it would make the request
884
- // unsatisfiable by construction rather than merely restricted.
885
- const readmitToolNames = new Set([
886
- ...[...nestedToolNames].filter(name => !disallowedSet?.has(name)),
887
- ...structuredToolNames,
888
- ]);
889
-
890
732
  // ─── Tool scoping ───────────────────────────────────────────────────────
891
733
  //
892
734
  // Some extensions register their tools ASYNCHRONOUSLY, long after the
@@ -919,35 +761,17 @@ export async function runAgent(
919
761
  let sessionTools: string[] | undefined;
920
762
  let sessionExcludeTools: string[] | undefined;
921
763
  if (noExtensions) {
922
- // Strict allowlist: built-ins the agent asked for, plus any opt-in nested
923
- // tools (whose names would otherwise be dropped as EXCLUDED_TOOL_NAMES).
924
- sessionTools = [
925
- ...toolNames.filter(
926
- (t) => !EXCLUDED_TOOL_NAMES.includes(t) && !disallowedSet?.has(t),
927
- ),
928
- ...[...nestedToolNames].filter((t) => !disallowedSet?.has(t)),
929
- // Not filtered through `disallowedSet`, unlike the nested tools above:
930
- // the caller asked for a schema, and removing the only tool that can
931
- // satisfy it would make the request unsatisfiable by construction rather
932
- // than merely restricted.
933
- ...structuredToolNames,
934
- ];
935
- } else {
936
- // Deny the orchestration tools EXCEPT the nested ones this agent opted into —
937
- // those are injected as customTools and must survive the registry gate.
938
- const denyTools = new Set<string>(
939
- EXCLUDED_TOOL_NAMES.filter((t) => !nestedToolNames.has(t)),
764
+ sessionTools = toolNames.filter(
765
+ (t) => !EXCLUDED_TOOL_NAMES.includes(t) && !disallowedSet?.has(t),
940
766
  );
767
+ } else {
768
+ const denyTools = new Set<string>(EXCLUDED_TOOL_NAMES);
941
769
  // Keep only the built-ins the agent asked for — deny the rest.
942
770
  for (const name of BUILTIN_TOOL_NAMES) {
943
771
  if (!builtinToolNameSet.has(name)) denyTools.add(name);
944
772
  }
945
773
  if (disallowedSet) {
946
- // disallowed_tools wins even over an opt-in nested tool of the same name.
947
- // Not over StructuredOutput, though — see the allowlist branch above.
948
- for (const name of disallowedSet) {
949
- if (!structuredToolNames.has(name)) denyTools.add(name);
950
- }
774
+ for (const name of disallowedSet) denyTools.add(name);
951
775
  }
952
776
  sessionExcludeTools = [...denyTools];
953
777
  }
@@ -955,48 +779,33 @@ export async function runAgent(
955
779
  const settingsManager = SettingsManager.create(configCwd, agentDir);
956
780
  const configuredSessionDir = resolveConfiguredSessionDir(agentConfig?.sessionDir, effectiveCwd);
957
781
  const defaultSessionDir = process.env.PI_CODING_AGENT_SESSION_DIR ?? settingsManager.getSessionDir?.();
958
- // Frontmatter wins when it says anything; otherwise the project default,
959
- // which `rememberAgents` supplies for top-level agents only. Same precedence
960
- // as `outputTranscript`.
961
- const persistSession = agentConfig?.persistSession ?? (options.nested ? false : rememberAgents);
962
- const sessionManager = options.resumeSessionFile
963
- // Reopening an existing conversation: the file already carries its own
964
- // header (cwd, parent) and history, so none of the create-time options
965
- // apply. `sessionDir` still matters for a later /new or /branch off it.
966
- ? SessionManager.open(options.resumeSessionFile, configuredSessionDir ?? defaultSessionDir)
967
- : persistSession
968
- ? SessionManager.create(effectiveCwd, configuredSessionDir ?? defaultSessionDir, {
969
- // Optional metadata — it only nests the subagent under its spawner in
970
- // `/resume`. Until `rememberAgents` this ran solely for the rare
971
- // `persist_session: true` agent; now it runs for every spawn, so a
972
- // context without a session manager (a bare programmatic ctx) must
973
- // still persist rather than take the whole spawn down.
974
- parentSession: ctx.sessionManager?.getSessionFile?.(),
975
- })
976
- : SessionManager.inMemory(effectiveCwd);
782
+ const sessionManager = agentConfig?.persistSession
783
+ ? SessionManager.create(effectiveCwd, configuredSessionDir ?? defaultSessionDir)
784
+ : SessionManager.inMemory(effectiveCwd);
785
+ // Keep write tracking session-local. The custom definition shadows only this
786
+ // child session's built-in write entry; the parent registry is untouched.
787
+ const trackedWriteTool = toolNames.includes("write")
788
+ ? createTrackedWriteTool(effectiveCwd)
789
+ : undefined;
977
790
 
978
791
  // Pi 0.80.8 replaced createAgentSession's modelRegistry option with
979
792
  // modelRuntime, but ExtensionContext still exposes only the registry facade.
980
793
  // Pass both so the full supported Pi range retains the parent's providers.
981
- const parentModelRuntime = (ctx.modelRegistry as unknown as { runtime?: unknown }).runtime;
794
+ const parentModelRuntime = (ctx.modelRegistry as unknown as { runtime?: ModelRuntime | null }).runtime ?? undefined;
982
795
  const sessionOpts: Parameters<typeof createAgentSession>[0] & {
983
796
  modelRegistry: ExtensionContext["modelRegistry"];
984
- modelRuntime?: unknown;
797
+ modelRuntime?: ModelRuntime;
985
798
  } = {
986
799
  cwd: effectiveCwd,
987
800
  agentDir,
988
801
  sessionManager,
989
802
  settingsManager,
990
803
  modelRegistry: ctx.modelRegistry,
991
- // `as never` is what keeps this assignable across the supported Pi range:
992
- // pre-0.80.8 the field exists only via the `modelRuntime?: unknown` shim
993
- // above, while newer Pi types it as `ModelRuntime` — a shape an opaque
994
- // `unknown` read off the private facade field can never satisfy.
995
- ...(parentModelRuntime !== undefined && { modelRuntime: parentModelRuntime as never }),
804
+ ...(parentModelRuntime !== undefined && { modelRuntime: parentModelRuntime }),
996
805
  model,
997
806
  tools: sessionTools,
998
- customTools: [...nestedTools, ...structuredTools],
999
807
  resourceLoader: loader,
808
+ ...(trackedWriteTool && { customTools: [trackedWriteTool as any] }),
1000
809
  };
1001
810
  if (sessionExcludeTools) {
1002
811
  sessionOpts.excludeTools = sessionExcludeTools;
@@ -1005,7 +814,7 @@ export async function runAgent(
1005
814
  sessionOpts.thinkingLevel = thinkingLevel;
1006
815
  }
1007
816
 
1008
- const { session } = await runInChildSessionContext(() => createAgentSession(sessionOpts));
817
+ const { session } = await createAgentSession(sessionOpts);
1009
818
 
1010
819
  const baseSessionName = agentConfig?.name ?? type;
1011
820
  session.setSessionName(
@@ -1038,7 +847,6 @@ export async function runAgent(
1038
847
  disallowedSet,
1039
848
  extNames,
1040
849
  narrowing,
1041
- readmitToolNames,
1042
850
  });
1043
851
  }
1044
852
 
@@ -1046,7 +854,7 @@ export async function runAgent(
1046
854
 
1047
855
  // Track turns for graceful max_turns enforcement
1048
856
  let turnCount = 0;
1049
- const maxTurns = resolveEffectiveMaxTurns(type, options.maxTurns);
857
+ const maxTurns = normalizeMaxTurns(options.maxTurns ?? agentConfig?.maxTurns ?? defaultMaxTurns);
1050
858
  let softLimitReached = false;
1051
859
  let aborted = false;
1052
860
 
@@ -1084,8 +892,6 @@ export async function runAgent(
1084
892
  input: u.input ?? 0,
1085
893
  output: u.output ?? 0,
1086
894
  cacheWrite: u.cacheWrite ?? 0,
1087
- cacheRead: u.cacheRead ?? 0,
1088
- cost: u.cost?.total ?? 0,
1089
895
  });
1090
896
  }
1091
897
  if (event.type === "compaction_end" && !event.aborted && event.result) {
@@ -1108,20 +914,8 @@ export async function runAgent(
1108
914
  // Boundary for the history fallback: only assistant text produced from here
1109
915
  // on counts as this run's output (a fresh session, so usually 0).
1110
916
  const startLen = session.messages.length;
1111
- let structuredRetried = false;
1112
917
  try {
1113
918
  await session.prompt(effectivePrompt);
1114
-
1115
- // One more prompt when a schema was asked for and nothing usable came back
1116
- // — the model answered in prose, or only ever called the tool invalidly.
1117
- // Inside this `try`, so the turn tracking, the text collector and above all
1118
- // the abort forwarding are still live: torn down first, a retry would be
1119
- // unkillable.
1120
- if (structuredCapture !== undefined && structuredCapture.json === undefined
1121
- && !aborted && options.signal?.aborted !== true) {
1122
- structuredRetried = true;
1123
- await session.prompt(structuredRetryPrompt(structuredCapture));
1124
- }
1125
919
  } finally {
1126
920
  unsubTurns();
1127
921
  collector.unsubscribe();
@@ -1129,23 +923,7 @@ export async function runAgent(
1129
923
  }
1130
924
 
1131
925
  const responseText = collector.getText().trim() || getLastAssistantText(session, startLen);
1132
- // A child asked for structured output that never gave any has failed, however
1133
- // articulate its prose was. Reported through `failure` so it travels the same
1134
- // path as a provider error rather than arriving as a successful empty answer.
1135
- const structuredFailure = structuredCapture !== undefined && structuredCapture.json === undefined
1136
- ? structuredCapture.lastError !== undefined
1137
- ? `The agent's StructuredOutput call did not match the required schema: ${structuredCapture.lastError}`
1138
- : "The agent did not report its answer through StructuredOutput."
1139
- : undefined;
1140
- return {
1141
- responseText,
1142
- session,
1143
- aborted,
1144
- steered: softLimitReached,
1145
- failure: finalTurnError(session, startLen) ?? structuredFailure,
1146
- ...(structuredCapture?.json !== undefined ? { structuredJson: structuredCapture.json } : {}),
1147
- ...(structuredRetried ? { structuredRetried } : {}),
1148
- };
926
+ return { responseText, session, aborted, steered: softLimitReached, failure: finalTurnError(session, startLen) };
1149
927
  }
1150
928
 
1151
929
  /**
@@ -1156,7 +934,7 @@ export async function resumeAgent(
1156
934
  prompt: string,
1157
935
  options: {
1158
936
  onToolActivity?: (activity: ToolActivity) => void;
1159
- onAssistantUsage?: (usage: LifetimeUsage) => void;
937
+ onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number }) => void;
1160
938
  onCompaction?: (info: { reason: "manual" | "threshold" | "overflow"; tokensBefore: number }) => void;
1161
939
  signal?: AbortSignal;
1162
940
  } = {},
@@ -1178,8 +956,6 @@ export async function resumeAgent(
1178
956
  input: u.input ?? 0,
1179
957
  output: u.output ?? 0,
1180
958
  cacheWrite: u.cacheWrite ?? 0,
1181
- cacheRead: u.cacheRead ?? 0,
1182
- cost: u.cost?.total ?? 0,
1183
959
  });
1184
960
  }
1185
961
  if (event.type === "compaction_end" && !event.aborted && event.result) {