@astralyn/pi 0.84.8 → 0.84.10

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 (270) hide show
  1. package/CHANGELOG.md +17 -2
  2. package/README.md +3 -2
  3. package/dist/cli/args.d.ts +1 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +29 -9
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/file-processor.d.ts.map +1 -1
  8. package/dist/cli/file-processor.js +2 -1
  9. package/dist/cli/file-processor.js.map +1 -1
  10. package/dist/config.d.ts +4 -3
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +22 -14
  13. package/dist/config.js.map +1 -1
  14. package/dist/core/agent-session.d.ts +26 -7
  15. package/dist/core/agent-session.d.ts.map +1 -1
  16. package/dist/core/agent-session.js +83 -64
  17. package/dist/core/agent-session.js.map +1 -1
  18. package/dist/core/auth-storage.d.ts.map +1 -1
  19. package/dist/core/auth-storage.js +6 -7
  20. package/dist/core/auth-storage.js.map +1 -1
  21. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  22. package/dist/core/compaction/branch-summarization.js +3 -0
  23. package/dist/core/compaction/branch-summarization.js.map +1 -1
  24. package/dist/core/compaction/compaction.d.ts +4 -3
  25. package/dist/core/compaction/compaction.d.ts.map +1 -1
  26. package/dist/core/compaction/compaction.js +41 -32
  27. package/dist/core/compaction/compaction.js.map +1 -1
  28. package/dist/core/compaction-controller.d.ts +2 -1
  29. package/dist/core/compaction-controller.d.ts.map +1 -1
  30. package/dist/core/compaction-controller.js +64 -21
  31. package/dist/core/compaction-controller.js.map +1 -1
  32. package/dist/core/defaults.d.ts +1 -0
  33. package/dist/core/defaults.d.ts.map +1 -1
  34. package/dist/core/defaults.js +9 -0
  35. package/dist/core/defaults.js.map +1 -1
  36. package/dist/core/extensions/index.d.ts +2 -2
  37. package/dist/core/extensions/index.d.ts.map +1 -1
  38. package/dist/core/extensions/index.js +1 -1
  39. package/dist/core/extensions/index.js.map +1 -1
  40. package/dist/core/extensions/loader.d.ts.map +1 -1
  41. package/dist/core/extensions/loader.js +115 -48
  42. package/dist/core/extensions/loader.js.map +1 -1
  43. package/dist/core/extensions/types.d.ts +38 -9
  44. package/dist/core/extensions/types.d.ts.map +1 -1
  45. package/dist/core/extensions/types.js +3 -0
  46. package/dist/core/extensions/types.js.map +1 -1
  47. package/dist/core/footer-data-provider.d.ts +1 -1
  48. package/dist/core/footer-data-provider.js +1 -1
  49. package/dist/core/footer-data-provider.js.map +1 -1
  50. package/dist/core/keybindings.d.ts +20 -19
  51. package/dist/core/keybindings.d.ts.map +1 -1
  52. package/dist/core/keybindings.js +26 -5
  53. package/dist/core/keybindings.js.map +1 -1
  54. package/dist/core/model-config.d.ts +5 -0
  55. package/dist/core/model-config.d.ts.map +1 -1
  56. package/dist/core/model-config.js +3 -1
  57. package/dist/core/model-config.js.map +1 -1
  58. package/dist/core/model-resolver.d.ts +1 -0
  59. package/dist/core/model-resolver.d.ts.map +1 -1
  60. package/dist/core/model-resolver.js +14 -8
  61. package/dist/core/model-resolver.js.map +1 -1
  62. package/dist/core/models-store.d.ts.map +1 -1
  63. package/dist/core/models-store.js +2 -1
  64. package/dist/core/models-store.js.map +1 -1
  65. package/dist/core/package-manager.d.ts.map +1 -1
  66. package/dist/core/package-manager.js +22 -14
  67. package/dist/core/package-manager.js.map +1 -1
  68. package/dist/core/pi-manifest.d.ts.map +1 -1
  69. package/dist/core/pi-manifest.js +2 -1
  70. package/dist/core/pi-manifest.js.map +1 -1
  71. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  72. package/dist/core/remote-catalog-provider.js +2 -1
  73. package/dist/core/remote-catalog-provider.js.map +1 -1
  74. package/dist/core/resource-loader.d.ts.map +1 -1
  75. package/dist/core/resource-loader.js +3 -2
  76. package/dist/core/resource-loader.js.map +1 -1
  77. package/dist/core/sdk.d.ts +2 -2
  78. package/dist/core/sdk.d.ts.map +1 -1
  79. package/dist/core/sdk.js +10 -3
  80. package/dist/core/sdk.js.map +1 -1
  81. package/dist/core/session-export.d.ts +4 -0
  82. package/dist/core/session-export.d.ts.map +1 -0
  83. package/dist/core/session-export.js +32 -0
  84. package/dist/core/session-export.js.map +1 -0
  85. package/dist/core/session-manager.d.ts.map +1 -1
  86. package/dist/core/session-manager.js +4 -3
  87. package/dist/core/session-manager.js.map +1 -1
  88. package/dist/core/settings-diagnostics.d.ts +9 -0
  89. package/dist/core/settings-diagnostics.d.ts.map +1 -0
  90. package/dist/core/settings-diagnostics.js +21 -0
  91. package/dist/core/settings-diagnostics.js.map +1 -0
  92. package/dist/core/settings-manager.d.ts +9 -0
  93. package/dist/core/settings-manager.d.ts.map +1 -1
  94. package/dist/core/settings-manager.js +51 -10
  95. package/dist/core/settings-manager.js.map +1 -1
  96. package/dist/core/skills.d.ts.map +1 -1
  97. package/dist/core/skills.js +51 -33
  98. package/dist/core/skills.js.map +1 -1
  99. package/dist/core/slash-commands.d.ts.map +1 -1
  100. package/dist/core/slash-commands.js +2 -1
  101. package/dist/core/slash-commands.js.map +1 -1
  102. package/dist/core/system-prompt.d.ts.map +1 -1
  103. package/dist/core/system-prompt.js +11 -2
  104. package/dist/core/system-prompt.js.map +1 -1
  105. package/dist/core/tools/bash.d.ts +19 -1
  106. package/dist/core/tools/bash.d.ts.map +1 -1
  107. package/dist/core/tools/bash.js +59 -37
  108. package/dist/core/tools/bash.js.map +1 -1
  109. package/dist/core/tools/edit-diff.d.ts +0 -5
  110. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  111. package/dist/core/tools/edit-diff.js +2 -5
  112. package/dist/core/tools/edit-diff.js.map +1 -1
  113. package/dist/core/tools/edit.d.ts.map +1 -1
  114. package/dist/core/tools/edit.js +20 -4
  115. package/dist/core/tools/edit.js.map +1 -1
  116. package/dist/core/tools/index.d.ts +4 -1
  117. package/dist/core/tools/index.d.ts.map +1 -1
  118. package/dist/core/tools/index.js +18 -1
  119. package/dist/core/tools/index.js.map +1 -1
  120. package/dist/core/tools/powershell.d.ts +16 -0
  121. package/dist/core/tools/powershell.d.ts.map +1 -0
  122. package/dist/core/tools/powershell.js +39 -0
  123. package/dist/core/tools/powershell.js.map +1 -0
  124. package/dist/core/trust-manager.d.ts.map +1 -1
  125. package/dist/core/trust-manager.js +2 -1
  126. package/dist/core/trust-manager.js.map +1 -1
  127. package/dist/extensions/background/registry.d.ts +2 -3
  128. package/dist/extensions/background/registry.d.ts.map +1 -1
  129. package/dist/extensions/background/registry.js +2 -6
  130. package/dist/extensions/background/registry.js.map +1 -1
  131. package/dist/extensions/llama/index.d.ts.map +1 -1
  132. package/dist/extensions/llama/index.js +2 -0
  133. package/dist/extensions/llama/index.js.map +1 -1
  134. package/dist/extensions/llama/provider.d.ts.map +1 -1
  135. package/dist/extensions/llama/provider.js +6 -2
  136. package/dist/extensions/llama/provider.js.map +1 -1
  137. package/dist/extensions/question/types.d.ts +0 -1
  138. package/dist/extensions/question/types.d.ts.map +1 -1
  139. package/dist/extensions/question/types.js +1 -1
  140. package/dist/extensions/question/types.js.map +1 -1
  141. package/dist/extensions/router/register.d.ts +0 -1
  142. package/dist/extensions/router/register.d.ts.map +1 -1
  143. package/dist/extensions/router/register.js +0 -3
  144. package/dist/extensions/router/register.js.map +1 -1
  145. package/dist/extensions/router/stream.d.ts +0 -2
  146. package/dist/extensions/router/stream.d.ts.map +1 -1
  147. package/dist/extensions/router/stream.js +1 -12
  148. package/dist/extensions/router/stream.js.map +1 -1
  149. package/dist/extensions/subagent/index.js +2 -2
  150. package/dist/extensions/subagent/index.js.map +1 -1
  151. package/dist/extensions/subagent/render.d.ts +6 -2
  152. package/dist/extensions/subagent/render.d.ts.map +1 -1
  153. package/dist/extensions/subagent/render.js +143 -132
  154. package/dist/extensions/subagent/render.js.map +1 -1
  155. package/dist/extensions/subagent/text.d.ts +0 -1
  156. package/dist/extensions/subagent/text.d.ts.map +1 -1
  157. package/dist/extensions/subagent/text.js +1 -30
  158. package/dist/extensions/subagent/text.js.map +1 -1
  159. package/dist/extensions/subagent/ui/model-list.d.ts +0 -3
  160. package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
  161. package/dist/extensions/subagent/ui/model-list.js +1 -10
  162. package/dist/extensions/subagent/ui/model-list.js.map +1 -1
  163. package/dist/index.d.ts +5 -5
  164. package/dist/index.d.ts.map +1 -1
  165. package/dist/index.js +4 -4
  166. package/dist/index.js.map +1 -1
  167. package/dist/main.d.ts +4 -0
  168. package/dist/main.d.ts.map +1 -1
  169. package/dist/main.js +18 -15
  170. package/dist/main.js.map +1 -1
  171. package/dist/migrations.js +5 -5
  172. package/dist/migrations.js.map +1 -1
  173. package/dist/modes/interactive/components/index.d.ts +0 -1
  174. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  175. package/dist/modes/interactive/components/index.js +0 -1
  176. package/dist/modes/interactive/components/index.js.map +1 -1
  177. package/dist/modes/interactive/components/model-selector.d.ts +9 -3
  178. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  179. package/dist/modes/interactive/components/model-selector.js +54 -11
  180. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  181. package/dist/modes/interactive/components/settings-selector.d.ts +7 -2
  182. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  183. package/dist/modes/interactive/components/settings-selector.js +118 -55
  184. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  185. package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
  186. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
  187. package/dist/modes/interactive/components/settings-submenu.js +151 -0
  188. package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
  189. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  190. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  191. package/dist/modes/interactive/components/thinking-selector.js +68 -17
  192. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  193. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  194. package/dist/modes/interactive/external-editor.js +2 -1
  195. package/dist/modes/interactive/external-editor.js.map +1 -1
  196. package/dist/modes/interactive/interactive-mode.d.ts +11 -0
  197. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  198. package/dist/modes/interactive/interactive-mode.js +167 -105
  199. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  200. package/dist/modes/interactive/session-share.d.ts +16 -0
  201. package/dist/modes/interactive/session-share.d.ts.map +1 -0
  202. package/dist/modes/interactive/session-share.js +188 -0
  203. package/dist/modes/interactive/session-share.js.map +1 -0
  204. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  205. package/dist/modes/interactive/theme/theme.js +3 -2
  206. package/dist/modes/interactive/theme/theme.js.map +1 -1
  207. package/dist/modes/json-event.d.ts +16 -13
  208. package/dist/modes/json-event.d.ts.map +1 -1
  209. package/dist/modes/json-event.js +20 -6
  210. package/dist/modes/json-event.js.map +1 -1
  211. package/dist/package-manager-cli.d.ts +1 -0
  212. package/dist/package-manager-cli.d.ts.map +1 -1
  213. package/dist/package-manager-cli.js +186 -2
  214. package/dist/package-manager-cli.js.map +1 -1
  215. package/dist/utils/frontmatter.d.ts.map +1 -1
  216. package/dist/utils/frontmatter.js +2 -1
  217. package/dist/utils/frontmatter.js.map +1 -1
  218. package/dist/utils/management-http.d.ts +5 -3
  219. package/dist/utils/management-http.d.ts.map +1 -1
  220. package/dist/utils/management-http.js +14 -10
  221. package/dist/utils/management-http.js.map +1 -1
  222. package/dist/utils/paths.d.ts +0 -5
  223. package/dist/utils/paths.d.ts.map +1 -1
  224. package/dist/utils/paths.js +0 -7
  225. package/dist/utils/paths.js.map +1 -1
  226. package/dist/utils/shell.d.ts +3 -0
  227. package/dist/utils/shell.d.ts.map +1 -1
  228. package/dist/utils/shell.js +17 -5
  229. package/dist/utils/shell.js.map +1 -1
  230. package/dist/utils/text.d.ts +8 -0
  231. package/dist/utils/text.d.ts.map +1 -0
  232. package/dist/utils/text.js +9 -0
  233. package/dist/utils/text.js.map +1 -0
  234. package/docs/bundled/extensions/subagent.md +40 -23
  235. package/docs/compaction.md +19 -2
  236. package/docs/custom-provider.md +5 -2
  237. package/docs/environment-variables.md +8 -8
  238. package/docs/extensions.md +22 -10
  239. package/docs/json.md +7 -2
  240. package/docs/keybindings.md +10 -8
  241. package/docs/llama-cpp.md +6 -4
  242. package/docs/models.md +10 -3
  243. package/docs/packages.md +2 -1
  244. package/docs/rpc.md +9 -3
  245. package/docs/sdk.md +12 -2
  246. package/docs/settings.md +16 -5
  247. package/docs/skills.md +5 -4
  248. package/docs/terminal-setup.md +11 -9
  249. package/docs/usage.md +6 -2
  250. package/docs/windows.md +24 -2
  251. package/examples/extensions/border-status-editor.ts +1 -1
  252. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  253. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  254. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  255. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  256. package/examples/extensions/doom-overlay/doom/build.sh +0 -0
  257. package/examples/extensions/git-checkpoint.ts +2 -2
  258. package/examples/extensions/gondolin/package-lock.json +2 -2
  259. package/examples/extensions/gondolin/package.json +1 -1
  260. package/examples/extensions/notify.ts +3 -1
  261. package/examples/extensions/sandbox/package-lock.json +2 -2
  262. package/examples/extensions/sandbox/package.json +1 -1
  263. package/examples/extensions/titlebar-spinner.ts +1 -1
  264. package/examples/extensions/with-deps/package-lock.json +2 -2
  265. package/examples/extensions/with-deps/package.json +1 -1
  266. package/examples/rpc-extension-ui.ts +1 -1
  267. package/examples/sdk/06-extensions.ts +1 -1
  268. package/examples/sdk/README.md +1 -1
  269. package/npm-shrinkwrap.json +196 -257
  270. package/package.json +6 -8
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACN,KAAK,GAAG,EACR,KAAK,OAAO,EACZ,iCAAiC,EACjC,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,MAAM,8BAA8B,CAAC;AAMtC,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,UAAU,CAAC,OAAO,iCAAiC,CAAC,CA0EtD;AAiHD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAyB/D;AAiED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACN,KAAK,GAAG,EACR,KAAK,OAAO,EACZ,iCAAiC,EACjC,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,MAAM,8BAA8B,CAAC;AAMtC,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,UAAU,CAAC,OAAO,iCAAiC,CAAC,CA0EtD;AAiHD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAyB/D"}
@@ -10,7 +10,7 @@
10
10
  * payload toward Codex CLI style so transparent gateways receive a friendlier body.
11
11
  */
12
12
  import { createAssistantMessageEventStream, openAIResponsesApi, } from "@earendil-works/pi-ai/compat";
13
- import { DEFAULTS, formatError, ROUTER_API } from "./constants.js";
13
+ import { DEFAULTS, formatError } from "./constants.js";
14
14
  const responsesApi = openAIResponsesApi();
15
15
  export function streamRouterCodex(model, context, options) {
16
16
  const stream = createAssistantMessageEventStream();
@@ -259,15 +259,4 @@ function clampCacheKey(sessionId) {
259
259
  return undefined;
260
260
  return sessionId.length <= 64 ? sessionId : sessionId.slice(0, 64);
261
261
  }
262
- export function resolveResponsesUrl(baseUrl) {
263
- const normalized = baseUrl.trim().replace(/\/+$/, "");
264
- if (!normalized)
265
- throw new Error("Model baseUrl is empty.");
266
- if (normalized.endsWith("/responses"))
267
- return normalized;
268
- return `${normalized}/responses`;
269
- }
270
- export function isRouterApi(api) {
271
- return api === ROUTER_API;
272
- }
273
262
  //# sourceMappingURL=stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/extensions/router/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAGN,iCAAiC,EAEjC,kBAAkB,GAElB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEnE,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;AAE1C,MAAM,UAAU,iBAAiB,CAChC,KAAiB,EACjB,OAAgB,EAChB,OAA6B;IAE7B,MAAM,MAAM,GAAG,iCAAiC,EAAE,CAAC;IAEnD,KAAK,CAAC,KAAK,IAAI,EAAE;QAChB,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC;YAC/B,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;YAE3E,gFAAgF;YAChF,MAAM,YAAY,GAAG;gBACpB,GAAG,KAAK;gBACR,GAAG,EAAE,kBAA2B;gBAChC,MAAM,EAAE;oBACP,qBAAqB,EAAE,IAAI;oBAC3B,iEAAiE;oBACjE,qBAAqB,EAAE,kBAA2B;oBAClD,8DAA8D;oBAC9D,0BAA0B,EAAE,KAAK;oBACjC,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;iBACvB;aAC4B,CAAC;YAE/B,MAAM,OAAO,GAA2B;gBACvC,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,GAAI,OAAO,EAAE,OAA8C;aAC3D,CAAC;YAEF,4EAA4E;YAC5E,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YACpD,IAAI,SAAS,EAAE,CAAC;gBACf,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;oBAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;gBAC9D,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC;oBAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,SAAS,CAAC;YACjF,CAAC;YAED,MAAM,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,EAAE;gBAC9D,GAAG,OAAO;gBACV,MAAM;gBACN,OAAO;gBACP,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC;aAClG,CAAC,CAAC;YAEH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;gBACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;YACD,MAAM,CAAC,GAAG,EAAE,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,+DAA+D;YAC/D,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,OAAO;gBACb,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;gBACtD,KAAK,EAAE;oBACN,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,EAAE;oBACX,GAAG,EAAE,KAAK,CAAC,GAAG;oBACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,KAAK,EAAE,KAAK,CAAC,EAAE;oBACf,KAAK,EAAE;wBACN,KAAK,EAAE,CAAC;wBACR,MAAM,EAAE,CAAC;wBACT,SAAS,EAAE,CAAC;wBACZ,UAAU,EAAE,CAAC;wBACb,WAAW,EAAE,CAAC;wBACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;qBACpE;oBACD,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;oBAC1D,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC;oBAChC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;iBACrB;aACD,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,EAAE,CAAC;QACd,CAAC;IACF,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,sBAAsB,CACpC,OAAgB,EAChB,OAAgB,EAChB,aAA+C,EAC/C,KAAgC;IAEhC,MAAM,IAAI,GACT,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAChE,CAAC,CAAC,EAAE,GAAI,OAAmC,EAAE;QAC7C,CAAC,CAAE,EAA8B,CAAC;IAEpC,gDAAgD;IAChD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IAEnB,mFAAmF;IACnF,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtF,IAAI,YAAY;QAAE,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnD,IAAI,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAE5C,8EAA8E;IAC9E,0EAA0E;IAC1E,4CAA4C;IAC5C,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEvC,6EAA6E;IAC7E,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjD,IAAI,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;QAAE,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;IAC9D,IAAI,IAAI,CAAC,mBAAmB,KAAK,SAAS;QAAE,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAE5E,0EAA0E;IAC1E,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAI,IAAI,CAAC,OAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAEvB,qEAAqE;IACrE,OAAO,IAAI,CAAC,sBAAsB,CAAC;IACnC,OAAO,IAAI,CAAC,oBAAoB,CAAC;IACjC,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAC9B,OAAO,IAAI,CAAC,WAAW,CAAC;IACxB,OAAO,IAAI,CAAC,KAAK,CAAC;IAClB,OAAO,IAAI,CAAC,IAAI,CAAC;IACjB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IACzB,OAAO,IAAI,CAAC,UAAU,CAAC;IACvB,OAAO,IAAI,CAAC,kBAAkB,CAAC;IAC/B,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAC9B,OAAO,IAAI,CAAC,cAAc,CAAC;IAE3B,IAAI,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACtC,kBAAkB;IAClB,SAAS;IACT,eAAe;IACf,WAAW;IACX,kBAAkB;IAClB,eAAe;IACf,kBAAkB;IAClB,sBAAsB;IACtB,kBAAkB;IAClB,yBAAyB;IACzB,oBAAoB;IACpB,iBAAiB;IACjB,uBAAuB;IACvB,YAAY;IACZ,oBAAoB;IACpB,oBAAoB;CACpB,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACtC,SAAS;IACT,WAAW;IACX,eAAe;IACf,sBAAsB;IACtB,yBAAyB;CACzB,CAAC,CAAC;AAEH,MAAM,UAAU,0BAA0B,CAAC,KAAc;IACxD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QACvE,MAAM,MAAM,GAAG,IAA+B,CAAC;QAC/C,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,IAAI,IAAI,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,OAAO,MAAM,CAAC,EAAE,CAAC;QAClB,CAAC;QACD,IAAI,IAAI,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YACpE,OAAO,MAAM,CAAC,MAAM,CAAC;QACtB,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnC,IACC,IAAI;oBACJ,OAAO,IAAI,KAAK,QAAQ;oBACvB,IAA0B,CAAC,IAAI,KAAK,aAAa;oBAClD,aAAa,IAAI,IAAI,EACpB,CAAC;oBACF,OAAQ,IAAgC,CAAC,WAAW,CAAC;gBACtD,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAC3B,KAAc,EACd,YAAgC;IAEhC,2DAA2D;IAC3D,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAChD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,IAAI,KAAK,EAAE,CAAC;IACjE,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,EAAE,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,IACC,KAAK;QACL,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,MAAM,IAAI,KAAK;QACf,CAAE,KAA2B,CAAC,IAAI,KAAK,QAAQ,IAAK,KAA2B,CAAC,IAAI,KAAK,WAAW,CAAC,EACpG,CAAC;QACF,MAAM,OAAO,GAAI,KAA+B,CAAC,OAAO,CAAC;QACzD,MAAM,IAAI,GACT,OAAO,OAAO,KAAK,QAAQ;YAC1B,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;gBACvB,CAAC,CAAC,OAAO;qBACN,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACb,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI;oBACjD,CAAC,CAAC,MAAM,CAAE,IAA0B,CAAC,IAAI,CAAC;oBAC1C,CAAC,CAAC,EAAE,CACL;qBACA,IAAI,CAAC,EAAE,CAAC;gBACX,CAAC,CAAC,EAAE,CAAC;QACR,OAAO;YACN,YAAY,EAAE,IAAI,IAAI,SAAS;YAC/B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;SACrB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,CAAC;AAClB,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAc;IAC9C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,IACC,KAAK;QACL,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,CAAE,KAA2B,CAAC,IAAI,KAAK,QAAQ,IAAK,KAA2B,CAAC,IAAI,KAAK,WAAW,CAAC,EACpG,CAAC;QACF,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,SAA6B;IACnD,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,OAAO,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe;IAClD,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5D,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,UAAU,CAAC;IACzD,OAAO,GAAG,UAAU,YAAY,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACtC,OAAO,GAAG,KAAK,UAAU,CAAC;AAC3B,CAAC","sourcesContent":["/**\n * Codex-oriented Responses client for API relays.\n *\n * Follows Pi's documented custom-provider pattern (see coding-agent docs\n * providers.md / custom-provider.md and examples/custom-provider-gitlab-duo):\n * wrap a built-in pi-ai stream API from `@earendil-works/pi-ai/compat` instead of\n * reimplementing SSE or deep-importing internal modules.\n *\n * We use openAIResponsesApi (works with relay sk- keys) and reshape the request\n * payload toward Codex CLI style so transparent gateways receive a friendlier body.\n */\n\nimport {\n\ttype Api,\n\ttype Context,\n\tcreateAssistantMessageEventStream,\n\ttype Model,\n\topenAIResponsesApi,\n\ttype SimpleStreamOptions,\n} from \"@earendil-works/pi-ai/compat\";\n\nimport { DEFAULTS, formatError, ROUTER_API } from \"./constants.ts\";\n\nconst responsesApi = openAIResponsesApi();\n\nexport function streamRouterCodex(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): ReturnType<typeof createAssistantMessageEventStream> {\n\tconst stream = createAssistantMessageEventStream();\n\n\tvoid (async () => {\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey;\n\t\t\tif (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);\n\n\t\t\t// Built-in Responses stream expects api \"openai-responses\" on the model object.\n\t\t\tconst requestModel = {\n\t\t\t\t...model,\n\t\t\t\tapi: \"openai-responses\" as const,\n\t\t\t\tcompat: {\n\t\t\t\t\tsupportsDeveloperRole: true,\n\t\t\t\t\t// Avoid underscore session_id header that strict proxies reject.\n\t\t\t\t\tsessionAffinityFormat: \"openai-nosession\" as const,\n\t\t\t\t\t// Codex-style upstreams reject prompt_cache_retention: \"24h\".\n\t\t\t\t\tsupportsLongCacheRetention: false,\n\t\t\t\t\t...(model.compat ?? {}),\n\t\t\t\t},\n\t\t\t} as Model<\"openai-responses\">;\n\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\toriginator: DEFAULTS.originator,\n\t\t\t\t...(options?.headers as Record<string, string> | undefined),\n\t\t\t};\n\n\t\t\t// Prefer hyphenated Codex-style session affinity when we have a session id.\n\t\t\tconst sessionId = clampCacheKey(options?.sessionId);\n\t\t\tif (sessionId) {\n\t\t\t\tif (!headers[\"session-id\"]) headers[\"session-id\"] = sessionId;\n\t\t\t\tif (!headers[\"x-client-request-id\"]) headers[\"x-client-request-id\"] = sessionId;\n\t\t\t}\n\n\t\t\tconst inner = responsesApi.streamSimple(requestModel, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey,\n\t\t\t\theaders,\n\t\t\t\tonPayload: (payload) => reshapePayloadForRelay(payload, context, options?.onPayload, requestModel),\n\t\t\t});\n\n\t\t\tfor await (const event of inner) {\n\t\t\t\tstream.push(event);\n\t\t\t}\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\t// Match examples/custom-provider-gitlab-duo error event shape.\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: options?.signal?.aborted ? \"aborted\" : \"error\",\n\t\t\t\terror: {\n\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\tcontent: [],\n\t\t\t\t\tapi: model.api,\n\t\t\t\t\tprovider: model.provider,\n\t\t\t\t\tmodel: model.id,\n\t\t\t\t\tusage: {\n\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t\t},\n\t\t\t\t\tstopReason: options?.signal?.aborted ? \"aborted\" : \"error\",\n\t\t\t\t\terrorMessage: formatError(error),\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Nudge the OpenAI Responses payload toward Codex CLI request shape for\n * transparent relays: instructions + input, store:false, no max_output_tokens /\n * prompt_cache_retention, verbosity + parallel_tool_calls.\n */\nasync function reshapePayloadForRelay(\n\tpayload: unknown,\n\tcontext: Context,\n\tuserOnPayload: SimpleStreamOptions[\"onPayload\"],\n\tmodel: Model<\"openai-responses\">,\n): Promise<unknown> {\n\tconst base =\n\t\tpayload && typeof payload === \"object\" && !Array.isArray(payload)\n\t\t\t? { ...(payload as Record<string, unknown>) }\n\t\t\t: ({} as Record<string, unknown>);\n\n\t// Always safe for ChatGPT/Codex-style backends.\n\tbase.store = false;\n\tbase.stream = true;\n\n\t// Codex CLI sends system prompt as `instructions`, not as a role message in input.\n\tconst { instructions, input } = extractInstructions(base.input, context.systemPrompt);\n\tif (instructions) base.instructions = instructions;\n\tif (input !== undefined) base.input = input;\n\n\t// Released Codex CLI defaults omit replayed ResponseItem ids from store:false\n\t// requests. It also never emits `status` on the item types below, and its\n\t// output_text content has no `annotations`.\n\tsanitizeInputItemsForCodex(base.input);\n\n\t// Fields common on Codex CLI / rejected by many transparent Codex upstreams.\n\tif (!base.text || typeof base.text !== \"object\") {\n\t\tbase.text = { verbosity: \"low\" };\n\t}\n\tif (base.tool_choice === undefined) base.tool_choice = \"auto\";\n\tif (base.parallel_tool_calls === undefined) base.parallel_tool_calls = true;\n\n\t// Prefer encrypted reasoning content for multi-turn store:false sessions.\n\tconst include = Array.isArray(base.include) ? [...(base.include as unknown[])] : [];\n\tif (!include.includes(\"reasoning.encrypted_content\")) {\n\t\tinclude.push(\"reasoning.encrypted_content\");\n\t}\n\tbase.include = include;\n\n\t// Drop Platform-only fields that Codex OAuth endpoints often 400 on.\n\tdelete base.prompt_cache_retention;\n\tdelete base.prompt_cache_options;\n\tdelete base.max_output_tokens;\n\tdelete base.temperature;\n\tdelete base.top_p;\n\tdelete base.user;\n\tdelete base.metadata;\n\tdelete base.service_tier;\n\tdelete base.truncation;\n\tdelete base.context_management;\n\tdelete base.safety_identifier;\n\tdelete base.stream_options;\n\n\tif (userOnPayload) {\n\t\tconst next = await userOnPayload(base, model);\n\t\tif (next !== undefined) return next;\n\t}\n\treturn base;\n}\n\n/**\n * Match the released Codex CLI's default stateless request preparation:\n * optional ResponseItem identity ids are omitted from store:false requests,\n * while semantic ids, call_id, and encrypted_content remain available for\n * reference, tool, and reasoning continuity.\n *\n * These are the tagged variants handled by ResponseItem::set_id in Codex CLI\n * 0.145. Unknown input variants must retain `id`: for example,\n * item_reference.id and local_shell_call_output.id are required references,\n * not optional ResponseItem identities.\n */\nconst RESPONSE_ITEM_ID_TYPES = new Set([\n\t\"additional_tools\",\n\t\"message\",\n\t\"agent_message\",\n\t\"reasoning\",\n\t\"local_shell_call\",\n\t\"function_call\",\n\t\"tool_search_call\",\n\t\"function_call_output\",\n\t\"custom_tool_call\",\n\t\"custom_tool_call_output\",\n\t\"tool_search_output\",\n\t\"web_search_call\",\n\t\"image_generation_call\",\n\t\"compaction\",\n\t\"compaction_summary\",\n\t\"context_compaction\",\n]);\n\n/**\n * Codex ResponseItem serialization has NO `status` field on Message,\n * Reasoning, FunctionCall, FunctionCallOutput, or CustomToolCallOutput\n * (codex-rs/protocol/src/models.rs). Other item types either require `status`\n * (local_shell_call, tool_search_output, image_generation_call) or accept it\n * optionally (tool_search_call, custom_tool_call, web_search_call), so we must\n * not strip it there.\n */\nconst STATUS_LESS_ITEM_TYPES = new Set([\n\t\"message\",\n\t\"reasoning\",\n\t\"function_call\",\n\t\"function_call_output\",\n\t\"custom_tool_call_output\",\n]);\n\nexport function sanitizeInputItemsForCodex(input: unknown): void {\n\tif (!Array.isArray(input)) return;\n\tfor (const item of input) {\n\t\tif (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n\t\tconst record = item as Record<string, unknown>;\n\t\tconst type = typeof record.type === \"string\" ? record.type : undefined;\n\t\tif (type && RESPONSE_ITEM_ID_TYPES.has(type)) {\n\t\t\tdelete record.id;\n\t\t}\n\t\tif (type && STATUS_LESS_ITEM_TYPES.has(type) && \"status\" in record) {\n\t\t\tdelete record.status;\n\t\t}\n\t\tif (Array.isArray(record.content)) {\n\t\t\tfor (const part of record.content) {\n\t\t\t\tif (\n\t\t\t\t\tpart &&\n\t\t\t\t\ttypeof part === \"object\" &&\n\t\t\t\t\t(part as { type?: string }).type === \"output_text\" &&\n\t\t\t\t\t\"annotations\" in part\n\t\t\t\t) {\n\t\t\t\t\tdelete (part as Record<string, unknown>).annotations;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction extractInstructions(\n\tinput: unknown,\n\tsystemPrompt: string | undefined,\n): { instructions?: string; input: unknown } {\n\t// Prefer context.systemPrompt (matches Codex stream path).\n\tif (systemPrompt && systemPrompt.length > 0) {\n\t\tconst stripped = stripLeadingSystemRoles(input);\n\t\treturn { instructions: systemPrompt, input: stripped ?? input };\n\t}\n\n\tif (!Array.isArray(input) || input.length === 0) {\n\t\treturn { input };\n\t}\n\n\tconst first = input[0];\n\tif (\n\t\tfirst &&\n\t\ttypeof first === \"object\" &&\n\t\t!Array.isArray(first) &&\n\t\t\"role\" in first &&\n\t\t((first as { role?: string }).role === \"system\" || (first as { role?: string }).role === \"developer\")\n\t) {\n\t\tconst content = (first as { content?: unknown }).content;\n\t\tconst text =\n\t\t\ttypeof content === \"string\"\n\t\t\t\t? content\n\t\t\t\t: Array.isArray(content)\n\t\t\t\t\t? content\n\t\t\t\t\t\t\t.map((part) =>\n\t\t\t\t\t\t\t\tpart && typeof part === \"object\" && \"text\" in part\n\t\t\t\t\t\t\t\t\t? String((part as { text: unknown }).text)\n\t\t\t\t\t\t\t\t\t: \"\",\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.join(\"\")\n\t\t\t\t\t: \"\";\n\t\treturn {\n\t\t\tinstructions: text || undefined,\n\t\t\tinput: input.slice(1),\n\t\t};\n\t}\n\n\treturn { input };\n}\n\nfunction stripLeadingSystemRoles(input: unknown): unknown {\n\tif (!Array.isArray(input) || input.length === 0) return input;\n\tconst first = input[0];\n\tif (\n\t\tfirst &&\n\t\ttypeof first === \"object\" &&\n\t\t!Array.isArray(first) &&\n\t\t((first as { role?: string }).role === \"system\" || (first as { role?: string }).role === \"developer\")\n\t) {\n\t\treturn input.slice(1);\n\t}\n\treturn input;\n}\n\nfunction clampCacheKey(sessionId: string | undefined): string | undefined {\n\tif (!sessionId) return undefined;\n\treturn sessionId.length <= 64 ? sessionId : sessionId.slice(0, 64);\n}\n\nexport function resolveResponsesUrl(baseUrl: string): string {\n\tconst normalized = baseUrl.trim().replace(/\\/+$/, \"\");\n\tif (!normalized) throw new Error(\"Model baseUrl is empty.\");\n\tif (normalized.endsWith(\"/responses\")) return normalized;\n\treturn `${normalized}/responses`;\n}\n\nexport function isRouterApi(api: string): boolean {\n\treturn api === ROUTER_API;\n}\n"]}
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/extensions/router/stream.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Codex-oriented Responses client for API relays.\n *\n * Follows Pi's documented custom-provider pattern (see coding-agent docs\n * providers.md / custom-provider.md and examples/custom-provider-gitlab-duo):\n * wrap a built-in pi-ai stream API from `@earendil-works/pi-ai/compat` instead of\n * reimplementing SSE or deep-importing internal modules.\n *\n * We use openAIResponsesApi (works with relay sk- keys) and reshape the request\n * payload toward Codex CLI style so transparent gateways receive a friendlier body.\n */\n\nimport {\n\ttype Api,\n\ttype Context,\n\tcreateAssistantMessageEventStream,\n\ttype Model,\n\topenAIResponsesApi,\n\ttype SimpleStreamOptions,\n} from \"@earendil-works/pi-ai/compat\";\n\nimport { DEFAULTS, formatError } from \"./constants.ts\";\n\nconst responsesApi = openAIResponsesApi();\n\nexport function streamRouterCodex(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): ReturnType<typeof createAssistantMessageEventStream> {\n\tconst stream = createAssistantMessageEventStream();\n\n\tvoid (async () => {\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey;\n\t\t\tif (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);\n\n\t\t\t// Built-in Responses stream expects api \"openai-responses\" on the model object.\n\t\t\tconst requestModel = {\n\t\t\t\t...model,\n\t\t\t\tapi: \"openai-responses\" as const,\n\t\t\t\tcompat: {\n\t\t\t\t\tsupportsDeveloperRole: true,\n\t\t\t\t\t// Avoid underscore session_id header that strict proxies reject.\n\t\t\t\t\tsessionAffinityFormat: \"openai-nosession\" as const,\n\t\t\t\t\t// Codex-style upstreams reject prompt_cache_retention: \"24h\".\n\t\t\t\t\tsupportsLongCacheRetention: false,\n\t\t\t\t\t...(model.compat ?? {}),\n\t\t\t\t},\n\t\t\t} as Model<\"openai-responses\">;\n\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\toriginator: DEFAULTS.originator,\n\t\t\t\t...(options?.headers as Record<string, string> | undefined),\n\t\t\t};\n\n\t\t\t// Prefer hyphenated Codex-style session affinity when we have a session id.\n\t\t\tconst sessionId = clampCacheKey(options?.sessionId);\n\t\t\tif (sessionId) {\n\t\t\t\tif (!headers[\"session-id\"]) headers[\"session-id\"] = sessionId;\n\t\t\t\tif (!headers[\"x-client-request-id\"]) headers[\"x-client-request-id\"] = sessionId;\n\t\t\t}\n\n\t\t\tconst inner = responsesApi.streamSimple(requestModel, context, {\n\t\t\t\t...options,\n\t\t\t\tapiKey,\n\t\t\t\theaders,\n\t\t\t\tonPayload: (payload) => reshapePayloadForRelay(payload, context, options?.onPayload, requestModel),\n\t\t\t});\n\n\t\t\tfor await (const event of inner) {\n\t\t\t\tstream.push(event);\n\t\t\t}\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\t// Match examples/custom-provider-gitlab-duo error event shape.\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: options?.signal?.aborted ? \"aborted\" : \"error\",\n\t\t\t\terror: {\n\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\tcontent: [],\n\t\t\t\t\tapi: model.api,\n\t\t\t\t\tprovider: model.provider,\n\t\t\t\t\tmodel: model.id,\n\t\t\t\t\tusage: {\n\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t\t},\n\t\t\t\t\tstopReason: options?.signal?.aborted ? \"aborted\" : \"error\",\n\t\t\t\t\terrorMessage: formatError(error),\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Nudge the OpenAI Responses payload toward Codex CLI request shape for\n * transparent relays: instructions + input, store:false, no max_output_tokens /\n * prompt_cache_retention, verbosity + parallel_tool_calls.\n */\nasync function reshapePayloadForRelay(\n\tpayload: unknown,\n\tcontext: Context,\n\tuserOnPayload: SimpleStreamOptions[\"onPayload\"],\n\tmodel: Model<\"openai-responses\">,\n): Promise<unknown> {\n\tconst base =\n\t\tpayload && typeof payload === \"object\" && !Array.isArray(payload)\n\t\t\t? { ...(payload as Record<string, unknown>) }\n\t\t\t: ({} as Record<string, unknown>);\n\n\t// Always safe for ChatGPT/Codex-style backends.\n\tbase.store = false;\n\tbase.stream = true;\n\n\t// Codex CLI sends system prompt as `instructions`, not as a role message in input.\n\tconst { instructions, input } = extractInstructions(base.input, context.systemPrompt);\n\tif (instructions) base.instructions = instructions;\n\tif (input !== undefined) base.input = input;\n\n\t// Released Codex CLI defaults omit replayed ResponseItem ids from store:false\n\t// requests. It also never emits `status` on the item types below, and its\n\t// output_text content has no `annotations`.\n\tsanitizeInputItemsForCodex(base.input);\n\n\t// Fields common on Codex CLI / rejected by many transparent Codex upstreams.\n\tif (!base.text || typeof base.text !== \"object\") {\n\t\tbase.text = { verbosity: \"low\" };\n\t}\n\tif (base.tool_choice === undefined) base.tool_choice = \"auto\";\n\tif (base.parallel_tool_calls === undefined) base.parallel_tool_calls = true;\n\n\t// Prefer encrypted reasoning content for multi-turn store:false sessions.\n\tconst include = Array.isArray(base.include) ? [...(base.include as unknown[])] : [];\n\tif (!include.includes(\"reasoning.encrypted_content\")) {\n\t\tinclude.push(\"reasoning.encrypted_content\");\n\t}\n\tbase.include = include;\n\n\t// Drop Platform-only fields that Codex OAuth endpoints often 400 on.\n\tdelete base.prompt_cache_retention;\n\tdelete base.prompt_cache_options;\n\tdelete base.max_output_tokens;\n\tdelete base.temperature;\n\tdelete base.top_p;\n\tdelete base.user;\n\tdelete base.metadata;\n\tdelete base.service_tier;\n\tdelete base.truncation;\n\tdelete base.context_management;\n\tdelete base.safety_identifier;\n\tdelete base.stream_options;\n\n\tif (userOnPayload) {\n\t\tconst next = await userOnPayload(base, model);\n\t\tif (next !== undefined) return next;\n\t}\n\treturn base;\n}\n\n/**\n * Match the released Codex CLI's default stateless request preparation:\n * optional ResponseItem identity ids are omitted from store:false requests,\n * while semantic ids, call_id, and encrypted_content remain available for\n * reference, tool, and reasoning continuity.\n *\n * These are the tagged variants handled by ResponseItem::set_id in Codex CLI\n * 0.145. Unknown input variants must retain `id`: for example,\n * item_reference.id and local_shell_call_output.id are required references,\n * not optional ResponseItem identities.\n */\nconst RESPONSE_ITEM_ID_TYPES = new Set([\n\t\"additional_tools\",\n\t\"message\",\n\t\"agent_message\",\n\t\"reasoning\",\n\t\"local_shell_call\",\n\t\"function_call\",\n\t\"tool_search_call\",\n\t\"function_call_output\",\n\t\"custom_tool_call\",\n\t\"custom_tool_call_output\",\n\t\"tool_search_output\",\n\t\"web_search_call\",\n\t\"image_generation_call\",\n\t\"compaction\",\n\t\"compaction_summary\",\n\t\"context_compaction\",\n]);\n\n/**\n * Codex ResponseItem serialization has NO `status` field on Message,\n * Reasoning, FunctionCall, FunctionCallOutput, or CustomToolCallOutput\n * (codex-rs/protocol/src/models.rs). Other item types either require `status`\n * (local_shell_call, tool_search_output, image_generation_call) or accept it\n * optionally (tool_search_call, custom_tool_call, web_search_call), so we must\n * not strip it there.\n */\nconst STATUS_LESS_ITEM_TYPES = new Set([\n\t\"message\",\n\t\"reasoning\",\n\t\"function_call\",\n\t\"function_call_output\",\n\t\"custom_tool_call_output\",\n]);\n\nexport function sanitizeInputItemsForCodex(input: unknown): void {\n\tif (!Array.isArray(input)) return;\n\tfor (const item of input) {\n\t\tif (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n\t\tconst record = item as Record<string, unknown>;\n\t\tconst type = typeof record.type === \"string\" ? record.type : undefined;\n\t\tif (type && RESPONSE_ITEM_ID_TYPES.has(type)) {\n\t\t\tdelete record.id;\n\t\t}\n\t\tif (type && STATUS_LESS_ITEM_TYPES.has(type) && \"status\" in record) {\n\t\t\tdelete record.status;\n\t\t}\n\t\tif (Array.isArray(record.content)) {\n\t\t\tfor (const part of record.content) {\n\t\t\t\tif (\n\t\t\t\t\tpart &&\n\t\t\t\t\ttypeof part === \"object\" &&\n\t\t\t\t\t(part as { type?: string }).type === \"output_text\" &&\n\t\t\t\t\t\"annotations\" in part\n\t\t\t\t) {\n\t\t\t\t\tdelete (part as Record<string, unknown>).annotations;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction extractInstructions(\n\tinput: unknown,\n\tsystemPrompt: string | undefined,\n): { instructions?: string; input: unknown } {\n\t// Prefer context.systemPrompt (matches Codex stream path).\n\tif (systemPrompt && systemPrompt.length > 0) {\n\t\tconst stripped = stripLeadingSystemRoles(input);\n\t\treturn { instructions: systemPrompt, input: stripped ?? input };\n\t}\n\n\tif (!Array.isArray(input) || input.length === 0) {\n\t\treturn { input };\n\t}\n\n\tconst first = input[0];\n\tif (\n\t\tfirst &&\n\t\ttypeof first === \"object\" &&\n\t\t!Array.isArray(first) &&\n\t\t\"role\" in first &&\n\t\t((first as { role?: string }).role === \"system\" || (first as { role?: string }).role === \"developer\")\n\t) {\n\t\tconst content = (first as { content?: unknown }).content;\n\t\tconst text =\n\t\t\ttypeof content === \"string\"\n\t\t\t\t? content\n\t\t\t\t: Array.isArray(content)\n\t\t\t\t\t? content\n\t\t\t\t\t\t\t.map((part) =>\n\t\t\t\t\t\t\t\tpart && typeof part === \"object\" && \"text\" in part\n\t\t\t\t\t\t\t\t\t? String((part as { text: unknown }).text)\n\t\t\t\t\t\t\t\t\t: \"\",\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.join(\"\")\n\t\t\t\t\t: \"\";\n\t\treturn {\n\t\t\tinstructions: text || undefined,\n\t\t\tinput: input.slice(1),\n\t\t};\n\t}\n\n\treturn { input };\n}\n\nfunction stripLeadingSystemRoles(input: unknown): unknown {\n\tif (!Array.isArray(input) || input.length === 0) return input;\n\tconst first = input[0];\n\tif (\n\t\tfirst &&\n\t\ttypeof first === \"object\" &&\n\t\t!Array.isArray(first) &&\n\t\t((first as { role?: string }).role === \"system\" || (first as { role?: string }).role === \"developer\")\n\t) {\n\t\treturn input.slice(1);\n\t}\n\treturn input;\n}\n\nfunction clampCacheKey(sessionId: string | undefined): string | undefined {\n\tif (!sessionId) return undefined;\n\treturn sessionId.length <= 64 ? sessionId : sessionId.slice(0, 64);\n}\n"]}
@@ -60,8 +60,8 @@ export default function subagent(pi) {
60
60
  usage: execution.usage,
61
61
  };
62
62
  },
63
- renderCall(args, theme) {
64
- return renderSubagentCall(args, theme);
63
+ renderCall(args, theme, context) {
64
+ return renderSubagentCall(args, theme, context);
65
65
  },
66
66
  renderResult(result, options, theme, context) {
67
67
  scheduleLiveRefresh(context, options.isPartial);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/subagent/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAgentDir } from \"../../config.ts\";\nimport type { AgentToolResult, ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { emptyUsage } from \"./activity.ts\";\nimport { subagentToolDescription } from \"./agents.ts\";\nimport { showAgentsCommand } from \"./agents-command.ts\";\nimport { SUBAGENT_COMMAND_NAME, SUBAGENT_TOOL_LABEL, SUBAGENT_TOOL_NAME } from \"./constants.ts\";\nimport { renderSubagentCall, renderSubagentResult, type SubagentRenderState, scheduleLiveRefresh } from \"./render.ts\";\nimport type { ParentModelContext } from \"./resolve.ts\";\nimport { ConcurrencyGate, isSubagentError, runSubagentInvocation } from \"./runner.ts\";\nimport { SubagentParamsSchema } from \"./schema.ts\";\nimport { statusSummary } from \"./state.ts\";\nimport type { SubagentDetails } from \"./types.ts\";\n\nexport default function subagent(pi: ExtensionAPI): void {\n\tconst gate = new ConcurrencyGate();\n\tconst activeAborters = new Set<() => Promise<void>>();\n\n\tpi.registerTool<typeof SubagentParamsSchema, SubagentDetails, SubagentRenderState>({\n\t\tname: SUBAGENT_TOOL_NAME,\n\t\tlabel: SUBAGENT_TOOL_LABEL,\n\t\tdescription: subagentToolDescription(),\n\t\tpromptSnippet: \"Delegate bounded work to isolated explorer or general workers\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `subagent` for bounded work that benefits from isolated context or concurrent investigation; do not delegate a task you can finish with one or two direct tool calls.\",\n\t\t],\n\t\tparameters: SubagentParamsSchema,\n\t\tasync execute(toolCallId, params, signal, onUpdate, ctx): Promise<AgentToolResult<SubagentDetails>> {\n\t\t\t// First paint before task preflight so filesystem and model checks\n\t\t\t// cannot leave the transcript card empty.\n\t\t\tonUpdate?.({\n\t\t\t\tcontent: [{ type: \"text\", text: \"Initializing…\" }],\n\t\t\t\tdetails: {\n\t\t\t\t\tstatus: \"running\",\n\t\t\t\t\truns: [],\n\t\t\t\t\tstartedAt: Date.now(),\n\t\t\t\t\tusage: emptyUsage(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst parent: ParentModelContext = {\n\t\t\t\tmodel: ctx.model,\n\t\t\t\tthinking: pi.getThinkingLevel(),\n\t\t\t\tmodelRegistry: ctx.modelRegistry,\n\t\t\t};\n\t\t\tconst execution = await runSubagentInvocation({\n\t\t\t\tparams,\n\t\t\t\tparentCwd: ctx.cwd,\n\t\t\t\tparent,\n\t\t\t\tmodelRuntime: ctx.modelRuntime,\n\t\t\t\tagentDir: getAgentDir(),\n\t\t\t\tprojectTrusted: ctx.isProjectTrusted(),\n\t\t\t\tsignal,\n\t\t\t\tgate,\n\t\t\t\tbatchId: toolCallId,\n\t\t\t\tonUpdate: (details) => {\n\t\t\t\t\tonUpdate?.({ content: [{ type: \"text\", text: statusSummary(details) }], details });\n\t\t\t\t},\n\t\t\t\tregisterAbort: (abort) => {\n\t\t\t\t\tactiveAborters.add(abort);\n\t\t\t\t\treturn () => activeAborters.delete(abort);\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: execution.content }],\n\t\t\t\tdetails: execution.details,\n\t\t\t\tusage: execution.usage,\n\t\t\t};\n\t\t},\n\t\trenderCall(args, theme) {\n\t\t\treturn renderSubagentCall(args, theme);\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tscheduleLiveRefresh(context, options.isPartial);\n\t\t\treturn renderSubagentResult(result, options, theme, context.args, context.isError);\n\t\t},\n\t});\n\n\tpi.registerCommand(SUBAGENT_COMMAND_NAME, {\n\t\tdescription: \"Configure Subagent profiles, models, and thinking levels\",\n\t\thandler: async (_args, ctx) => showAgentsCommand(ctx, pi.getThinkingLevel()),\n\t});\n\n\tpi.on(\"tool_result\", async (event) => {\n\t\tif (event.toolName !== SUBAGENT_TOOL_NAME) return;\n\t\tconst details = event.details as SubagentDetails | undefined;\n\t\tif (details && isSubagentError(details)) return { isError: true };\n\t});\n\n\tpi.on(\"session_shutdown\", async () => {\n\t\tawait Promise.allSettled([...activeAborters].map((abort) => abort()));\n\t\tactiveAborters.clear();\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/subagent/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAgentDir } from \"../../config.ts\";\nimport type { AgentToolResult, ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { emptyUsage } from \"./activity.ts\";\nimport { subagentToolDescription } from \"./agents.ts\";\nimport { showAgentsCommand } from \"./agents-command.ts\";\nimport { SUBAGENT_COMMAND_NAME, SUBAGENT_TOOL_LABEL, SUBAGENT_TOOL_NAME } from \"./constants.ts\";\nimport { renderSubagentCall, renderSubagentResult, type SubagentRenderState, scheduleLiveRefresh } from \"./render.ts\";\nimport type { ParentModelContext } from \"./resolve.ts\";\nimport { ConcurrencyGate, isSubagentError, runSubagentInvocation } from \"./runner.ts\";\nimport { SubagentParamsSchema } from \"./schema.ts\";\nimport { statusSummary } from \"./state.ts\";\nimport type { SubagentDetails } from \"./types.ts\";\n\nexport default function subagent(pi: ExtensionAPI): void {\n\tconst gate = new ConcurrencyGate();\n\tconst activeAborters = new Set<() => Promise<void>>();\n\n\tpi.registerTool<typeof SubagentParamsSchema, SubagentDetails, SubagentRenderState>({\n\t\tname: SUBAGENT_TOOL_NAME,\n\t\tlabel: SUBAGENT_TOOL_LABEL,\n\t\tdescription: subagentToolDescription(),\n\t\tpromptSnippet: \"Delegate bounded work to isolated explorer or general workers\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `subagent` for bounded work that benefits from isolated context or concurrent investigation; do not delegate a task you can finish with one or two direct tool calls.\",\n\t\t],\n\t\tparameters: SubagentParamsSchema,\n\t\tasync execute(toolCallId, params, signal, onUpdate, ctx): Promise<AgentToolResult<SubagentDetails>> {\n\t\t\t// First paint before task preflight so filesystem and model checks\n\t\t\t// cannot leave the transcript card empty.\n\t\t\tonUpdate?.({\n\t\t\t\tcontent: [{ type: \"text\", text: \"Initializing…\" }],\n\t\t\t\tdetails: {\n\t\t\t\t\tstatus: \"running\",\n\t\t\t\t\truns: [],\n\t\t\t\t\tstartedAt: Date.now(),\n\t\t\t\t\tusage: emptyUsage(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst parent: ParentModelContext = {\n\t\t\t\tmodel: ctx.model,\n\t\t\t\tthinking: pi.getThinkingLevel(),\n\t\t\t\tmodelRegistry: ctx.modelRegistry,\n\t\t\t};\n\t\t\tconst execution = await runSubagentInvocation({\n\t\t\t\tparams,\n\t\t\t\tparentCwd: ctx.cwd,\n\t\t\t\tparent,\n\t\t\t\tmodelRuntime: ctx.modelRuntime,\n\t\t\t\tagentDir: getAgentDir(),\n\t\t\t\tprojectTrusted: ctx.isProjectTrusted(),\n\t\t\t\tsignal,\n\t\t\t\tgate,\n\t\t\t\tbatchId: toolCallId,\n\t\t\t\tonUpdate: (details) => {\n\t\t\t\t\tonUpdate?.({ content: [{ type: \"text\", text: statusSummary(details) }], details });\n\t\t\t\t},\n\t\t\t\tregisterAbort: (abort) => {\n\t\t\t\t\tactiveAborters.add(abort);\n\t\t\t\t\treturn () => activeAborters.delete(abort);\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: execution.content }],\n\t\t\t\tdetails: execution.details,\n\t\t\t\tusage: execution.usage,\n\t\t\t};\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\treturn renderSubagentCall(args, theme, context);\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tscheduleLiveRefresh(context, options.isPartial);\n\t\t\treturn renderSubagentResult(result, options, theme, context.args, context.isError);\n\t\t},\n\t});\n\n\tpi.registerCommand(SUBAGENT_COMMAND_NAME, {\n\t\tdescription: \"Configure Subagent profiles, models, and thinking levels\",\n\t\thandler: async (_args, ctx) => showAgentsCommand(ctx, pi.getThinkingLevel()),\n\t});\n\n\tpi.on(\"tool_result\", async (event) => {\n\t\tif (event.toolName !== SUBAGENT_TOOL_NAME) return;\n\t\tconst details = event.details as SubagentDetails | undefined;\n\t\tif (details && isSubagentError(details)) return { isError: true };\n\t});\n\n\tpi.on(\"session_shutdown\", async () => {\n\t\tawait Promise.allSettled([...activeAborters].map((abort) => abort()));\n\t\tactiveAborters.clear();\n\t});\n}\n"]}
@@ -3,11 +3,15 @@ import type { AgentToolResult, ToolRenderContext, ToolRenderResultOptions } from
3
3
  import { type Theme } from "../../modes/interactive/theme/theme.ts";
4
4
  import type { SubagentParams } from "./schema.ts";
5
5
  import type { SubagentDetails } from "./types.ts";
6
- /** Per-result live-refresh state owned by the shell's render context. */
6
+ /** Per-result live-refresh and timing state owned by the shell's render context. */
7
7
  export interface SubagentRenderState {
8
8
  refreshTimer?: ReturnType<typeof setTimeout>;
9
+ startedAt?: number;
10
+ endedAt?: number;
9
11
  }
12
+ type SubagentToolRenderContext = ToolRenderContext<SubagentRenderState, SubagentParams, SubagentDetails>;
10
13
  export declare function scheduleLiveRefresh(context: ToolRenderContext<SubagentRenderState>, isPartial: boolean): void;
11
- export declare function renderSubagentCall(args: SubagentParams, theme: Theme): Component;
14
+ export declare function renderSubagentCall(args: SubagentParams, theme: Theme, context?: SubagentToolRenderContext): Component;
12
15
  export declare function renderSubagentResult(result: AgentToolResult<SubagentDetails>, options: ToolRenderResultOptions, theme: Theme, args: SubagentParams, isError: boolean): Component;
16
+ export {};
13
17
  //# sourceMappingURL=render.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqC,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAClH,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAItF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,OAAO,KAAK,EAAE,eAAe,EAAuD,MAAM,YAAY,CAAC;AA2OvG,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IACnC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;CAC7C;AAID,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAgB7G;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,CAQhF;AAED,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,EACxC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,OAAO,GACd,SAAS,CA6BX"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAsD,MAAM,wBAAwB,CAAC;AAC5G,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAClH,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAGtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,OAAO,KAAK,EAAE,eAAe,EAAuD,MAAM,YAAY,CAAC;AAuPvG,oFAAoF;AACpF,MAAM,WAAW,mBAAmB;IACnC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,yBAAyB,GAAG,iBAAiB,CAAC,mBAAmB,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC;AAiBzG,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAgB7G;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAYrH;AAED,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,EACxC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,OAAO,GACd,SAAS,CAqBX"}
@@ -1,25 +1,30 @@
1
- import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
1
+ import { Container, Markdown, Spacer, Text, truncateToWidth } from "@earendil-works/pi-tui";
2
2
  import { getMarkdownTheme } from "../../modes/interactive/theme/theme.js";
3
- import { formatTokens } from "./activity.js";
4
3
  import { AGENT_PROFILE_LABELS } from "./agents.js";
5
- import { getSubagentRetryView, statusSummary } from "./state.js";
6
- import { firstPlainLine, plainLine, truncate } from "./text.js";
7
- const TASK_SUMMARY_LIMIT = 72;
8
- const ACTIVITY_SUMMARY_LIMIT = 120;
4
+ import { COMPACTION_ACTIVITY_ID } from "./constants.js";
5
+ import { getSubagentRetryView } from "./state.js";
6
+ import { plainLine, truncate } from "./text.js";
9
7
  const ACTIVITY_RESULT_LIMIT = 96;
10
8
  const RETRY_ERROR_LIMIT = 160;
11
9
  const FALLBACK_OUTPUT_LIMIT = 4_000;
12
10
  const ACTIVITY_DURATION_MIN_MS = 10_000;
11
+ const OUTPUT_TRUNCATION_NOTICE_PATTERN = /\s*\[Output truncated(?:: \d+ bytes omitted)?\.\]\s*$/u;
12
+ /** Width-aware single-line text for compact rows and section headers. */
13
+ class SingleLineText {
14
+ constructor(text) {
15
+ this.text = text;
16
+ }
17
+ render(width) {
18
+ return [truncateToWidth(this.text, Math.max(1, width), "...")];
19
+ }
20
+ invalidate() { }
21
+ }
13
22
  function taskPrompt(args, index, run) {
14
23
  // Tool calls restored from before the tasks-array shape carry a legacy
15
- // args object without `tasks`; those rows fall back to the description.
24
+ // args object without `tasks`; those sections fall back to the description.
16
25
  const tasks = args.tasks;
17
26
  return tasks?.[index]?.prompt ?? run.description;
18
27
  }
19
- function taskSummary(args, index, run) {
20
- const firstLine = firstPlainLine(taskPrompt(args, index, run));
21
- return truncate(firstLine || plainLine(run.description) || `Task ${index + 1}`, TASK_SUMMARY_LIMIT);
22
- }
23
28
  function profileLabel(agent) {
24
29
  return AGENT_PROFILE_LABELS[agent] ?? agent;
25
30
  }
@@ -68,159 +73,150 @@ function statusWord(status) {
68
73
  if (status === "aborted")
69
74
  return "Aborted";
70
75
  if (status === "running")
71
- return "Running";
76
+ return "Thinking...";
72
77
  return "Queued";
73
78
  }
79
+ function displayLine(text) {
80
+ return plainLine(text).replace(OUTPUT_TRUNCATION_NOTICE_PATTERN, "...").trim();
81
+ }
74
82
  function retryText(run) {
75
83
  const retry = getSubagentRetryView(run);
76
84
  if (!retry)
77
85
  return undefined;
78
86
  const state = retry.remainingSeconds > 0
79
87
  ? `Retrying (${retry.attempt}/${retry.maxAttempts}) in ${retry.remainingSeconds}s`
80
- : `Retrying now… (${retry.attempt}/${retry.maxAttempts})`;
81
- const error = truncate(plainLine(retry.error), RETRY_ERROR_LIMIT);
82
- return error ? `${state} — ${error}` : state;
88
+ : `Retrying (${retry.attempt}/${retry.maxAttempts}) now...`;
89
+ const error = truncate(displayLine(retry.error), RETRY_ERROR_LIMIT);
90
+ return error ? `${state} · ${error}` : state;
83
91
  }
84
- function runningDetail(run) {
85
- const retry = retryText(run);
86
- if (retry)
87
- return retry;
88
- if (run.currentActivity)
89
- return truncate(plainLine(run.currentActivity), ACTIVITY_SUMMARY_LIMIT);
90
- if (run.status === "queued")
91
- return "Waiting for a worker slot";
92
- if (run.status === "running" && run.usage.turns === 0 && run.usage.toolUses === 0)
93
- return "Initializing…";
94
- if (run.status === "running")
95
- return "Thinking…";
96
- if ((run.status === "failed" || run.status === "aborted") && run.error) {
97
- return truncate(plainLine(run.error), ACTIVITY_RESULT_LIMIT);
92
+ function replaceToolPrefix(text, toolName, label, emptyLabel = label) {
93
+ if (text === toolName)
94
+ return emptyLabel;
95
+ if (text.startsWith(`${toolName} `))
96
+ return `${label}${text.slice(toolName.length)}`;
97
+ return text;
98
+ }
99
+ function activitySummary(activity) {
100
+ const summary = displayLine(activity.summary);
101
+ if (activity.toolName === COMPACTION_ACTIVITY_ID) {
102
+ return activity.status === "running" ? "Compacting..." : summary;
98
103
  }
99
- return undefined;
104
+ if (activity.toolName === "bash")
105
+ return summary === "bash" ? "Run" : summary;
106
+ if (activity.toolName === "read")
107
+ return replaceToolPrefix(summary, "read", "Read");
108
+ if (activity.toolName === "grep")
109
+ return replaceToolPrefix(summary, "grep", "Search");
110
+ if (activity.toolName === "find")
111
+ return replaceToolPrefix(summary, "find", "Find");
112
+ if (activity.toolName === "ls")
113
+ return replaceToolPrefix(summary, "ls", "List", "List .");
114
+ if (activity.toolName === "edit")
115
+ return replaceToolPrefix(summary, "edit", "Edit");
116
+ if (activity.toolName === "write")
117
+ return replaceToolPrefix(summary, "write", "Write");
118
+ return summary || activity.toolName;
100
119
  }
101
- function batchMarker(details, theme) {
102
- if (details.runs.some((run) => run.status === "failed"))
103
- return theme.fg("error", "×");
104
- if (details.runs.some((run) => run.status === "aborted"))
105
- return theme.fg("warning", "■");
106
- return theme.fg("success", "✓");
120
+ function latestRunningActivity(run, toolName) {
121
+ for (let index = run.activities.length - 1; index >= 0; index--) {
122
+ const activity = run.activities[index];
123
+ if (activity?.status === "running" && (toolName === undefined || activity.toolName === toolName))
124
+ return activity;
125
+ }
126
+ return undefined;
107
127
  }
108
- function progressHeader(details, theme) {
109
- const settled = details.runs.filter((run) => run.status !== "running" && run.status !== "queued").length;
110
- return theme.fg("accent", `› ${settled}/${details.runs.length} done · ${elapsed(details.startedAt) ?? "0.0s"}`);
128
+ function fallbackCurrentActivity(run) {
129
+ if (!run.currentActivity)
130
+ return undefined;
131
+ const current = displayLine(run.currentActivity);
132
+ if (/^Compacting(?: context)?(?:…|\.\.\.)?$/u.test(current))
133
+ return "Compacting...";
134
+ return current;
111
135
  }
112
- function taskRow(run, index, args, theme, live) {
113
- let line = ` ${statusMarker(run.status, theme)} ${theme.fg("accent", profileLabel(run.agent))}${theme.fg("dim", ` · ${taskSummary(args, index, run)}`)}`;
114
- const detail = live ? runningDetail(run) : undefined;
115
- if (detail) {
116
- line += theme.fg("dim", ` — ${detail}`);
117
- }
118
- else if (run.status !== "running" && run.status !== "queued") {
136
+ function runStateText(run) {
137
+ if (run.status === "completed" || run.status === "failed" || run.status === "aborted") {
119
138
  const duration = elapsed(run.startedAt, run.endedAt);
120
- if (duration)
121
- line += theme.fg("dim", ` · ${duration}`);
139
+ return duration ? `${statusWord(run.status)} · ${duration}` : statusWord(run.status);
122
140
  }
123
- return line;
141
+ const retry = retryText(run);
142
+ if (retry)
143
+ return retry;
144
+ if (run.status === "queued")
145
+ return "Queued";
146
+ const compaction = latestRunningActivity(run, COMPACTION_ACTIVITY_ID);
147
+ if (compaction)
148
+ return "Compacting...";
149
+ const activity = latestRunningActivity(run);
150
+ if (activity)
151
+ return activitySummary(activity);
152
+ const current = fallbackCurrentActivity(run);
153
+ if (current)
154
+ return current;
155
+ if (run.status === "running" && run.usage.turns === 0 && run.usage.toolUses === 0)
156
+ return "Starting...";
157
+ return statusWord(run.status);
124
158
  }
125
- function outcomeSummary(details) {
126
- const completed = details.runs.filter((run) => run.status === "completed").length;
127
- const failed = details.runs.filter((run) => run.status === "failed").length;
128
- const aborted = details.runs.filter((run) => run.status === "aborted").length;
129
- const parts = [];
130
- if (completed)
131
- parts.push(`${completed} completed`);
132
- if (failed)
133
- parts.push(`${failed} failed`);
134
- if (aborted)
135
- parts.push(`${aborted} aborted`);
136
- if (parts.length === 0)
137
- parts.push(statusSummary(details));
138
- const duration = elapsed(details.startedAt, details.endedAt);
139
- if (duration)
140
- parts.push(duration);
141
- if (details.usage.cost)
142
- parts.push(`$${details.usage.cost.toFixed(3)}`);
143
- return parts.join(" · ");
159
+ function taskRow(run, index, theme) {
160
+ return `${statusMarker(run.status, theme)} ${theme.fg("dim", `#${index + 1}`)} ${theme.fg("accent", profileLabel(run.agent))}${theme.fg("dim", ` · ${runStateText(run)}`)}`;
144
161
  }
145
- function runMetrics(run) {
146
- const items = [run.model];
162
+ function runHeader(run, index, theme) {
163
+ const metrics = [run.model];
147
164
  if (run.thinking !== "off")
148
- items.push(`${run.thinking} thinking`);
165
+ metrics.push(run.thinking);
149
166
  if (run.cwd)
150
- items.push(`cwd: ${run.cwd}`);
151
- const settled = run.status !== "running" && run.status !== "queued";
152
- if (settled && run.usage.totalTokens)
153
- items.push(`${formatTokens(run.usage.totalTokens)} tok`);
167
+ metrics.push(`cwd: ${run.cwd}`);
154
168
  if (run.usage.toolUses)
155
- items.push(`${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? "" : "s"}`);
169
+ metrics.push(`${run.usage.toolUses} tool use${run.usage.toolUses === 1 ? "" : "s"}`);
156
170
  if (run.usage.turns)
157
- items.push(`${run.usage.turns} turn${run.usage.turns === 1 ? "" : "s"}`);
158
- if (run.usage.contextTokens)
159
- items.push(`ctx: ${formatTokens(run.usage.contextTokens)}`);
160
- if (run.usage.cost)
161
- items.push(`$${run.usage.cost.toFixed(3)}`);
171
+ metrics.push(`${run.usage.turns} turn${run.usage.turns === 1 ? "" : "s"}`);
162
172
  const duration = elapsed(run.startedAt, run.endedAt);
163
173
  if (duration)
164
- items.push(duration);
165
- return items.join(" · ");
174
+ metrics.push(duration);
175
+ return `${theme.fg("dim", `── #${index + 1} `)}${theme.fg("accent", profileLabel(run.agent))}${theme.fg("dim", ` · ${metrics.join(" · ")}`)}`;
166
176
  }
167
- function activityLine(activity, run, theme) {
168
- const summary = activity.status === "running" && run.currentActivity
169
- ? truncate(plainLine(run.currentActivity), ACTIVITY_SUMMARY_LIMIT)
170
- : truncate(plainLine(activity.summary), ACTIVITY_SUMMARY_LIMIT);
177
+ function activityLine(activity, theme) {
178
+ const summary = activitySummary(activity);
171
179
  let line = activity.status === "failed"
172
180
  ? `${theme.fg("error", "×")} ${theme.fg("toolOutput", summary)}`
173
181
  : activity.status === "running"
174
182
  ? `${theme.fg("accent", "›")} ${theme.fg("toolOutput", summary)}`
175
183
  : ` ${theme.fg("toolOutput", summary)}`;
176
184
  if (activity.status === "failed" && activity.resultSummary) {
177
- line += theme.fg("error", ` · ${truncate(plainLine(activity.resultSummary), ACTIVITY_RESULT_LIMIT)}`);
185
+ line += theme.fg("error", ` · ${truncate(displayLine(activity.resultSummary), ACTIVITY_RESULT_LIMIT)}`);
178
186
  }
179
187
  if (activity.endedAt !== undefined && activity.endedAt - activity.startedAt >= ACTIVITY_DURATION_MIN_MS) {
180
188
  line += theme.fg("dim", ` · ${formatDuration((activity.endedAt - activity.startedAt) / 1_000)}`);
181
189
  }
182
190
  return line;
183
191
  }
184
- function runHeader(run, index, args, theme) {
185
- return `${theme.fg("dim", `── #${index + 1} `)}${statusMarker(run.status, theme)} ${theme.fg("accent", profileLabel(run.agent))}${theme.fg("dim", ` · ${taskSummary(args, index, run)}`)}`;
192
+ function addPrompt(container, run, index, args, theme) {
193
+ container.addChild(new Spacer(1));
194
+ container.addChild(new Text(theme.fg("muted", "Prompt"), 0, 0));
195
+ container.addChild(new Text(theme.fg("toolOutput", taskPrompt(args, index, run)), 0, 0));
186
196
  }
187
197
  function renderRunningRun(run, index, args, theme) {
188
198
  const container = new Container();
189
- container.addChild(new Text(runHeader(run, index, args, theme), 0, 0));
190
- container.addChild(new Text(theme.fg("dim", runMetrics(run)), 0, 0));
191
- const retry = retryText(run);
192
- if (retry)
193
- container.addChild(new Text(theme.fg("accent", retry), 0, 0));
199
+ container.addChild(new SingleLineText(runHeader(run, index, theme)));
200
+ addPrompt(container, run, index, args, theme);
194
201
  container.addChild(new Spacer(1));
195
202
  const total = Math.max(run.usage.toolUses, run.activities.length);
196
203
  const label = total > run.activities.length ? `Activity · last ${run.activities.length} of ${total}` : "Activity";
197
204
  container.addChild(new Text(theme.fg("muted", label), 0, 0));
198
- if (run.activities.length > 0) {
199
- for (const activity of run.activities)
200
- container.addChild(new Text(activityLine(activity, run, theme), 0, 0));
201
- }
202
- else {
203
- const fallback = retry
204
- ? "Waiting to retry"
205
- : run.status === "failed" || run.status === "aborted"
206
- ? "No activity recorded"
207
- : (runningDetail(run) ?? statusWord(run.status));
208
- container.addChild(new Text(theme.fg("dim", ` ${fallback}`), 0, 0));
205
+ const retry = retryText(run);
206
+ if (retry) {
207
+ container.addChild(new SingleLineText(`${statusMarker(run.status, theme)} ${theme.fg("toolOutput", retry)}`));
209
208
  }
210
- if (run.error) {
211
- container.addChild(new Spacer(1));
212
- container.addChild(new Text(theme.fg("muted", "Error"), 0, 0));
213
- container.addChild(new Text(theme.fg("error", run.error), 0, 0));
209
+ for (const activity of run.activities)
210
+ container.addChild(new SingleLineText(activityLine(activity, theme)));
211
+ if (!retry && run.activities.length === 0) {
212
+ container.addChild(new SingleLineText(theme.fg("dim", ` ${runStateText(run)}`)));
214
213
  }
215
214
  return container;
216
215
  }
217
216
  function renderSettledRun(run, index, args, theme) {
218
217
  const container = new Container();
219
- container.addChild(new Text(runHeader(run, index, args, theme), 0, 0));
220
- container.addChild(new Text(theme.fg("dim", runMetrics(run)), 0, 0));
221
- container.addChild(new Spacer(1));
222
- container.addChild(new Text(theme.fg("muted", "Prompt"), 0, 0));
223
- container.addChild(new Text(theme.fg("toolOutput", taskPrompt(args, index, run)), 0, 0));
218
+ container.addChild(new SingleLineText(runHeader(run, index, theme)));
219
+ addPrompt(container, run, index, args, theme);
224
220
  if (run.error) {
225
221
  container.addChild(new Spacer(1));
226
222
  container.addChild(new Text(theme.fg("muted", "Error"), 0, 0));
@@ -244,6 +240,18 @@ function fallbackResult(result, theme, isError) {
244
240
  const value = text?.type === "text" ? truncate(text.text, FALLBACK_OUTPUT_LIMIT) : "(no output)";
245
241
  return new Text(theme.fg(isError ? "error" : "muted", value), 0, 0);
246
242
  }
243
+ function observeTiming(context) {
244
+ const details = context.result?.details;
245
+ const startedAt = details?.startedAt;
246
+ if (typeof startedAt === "number" && Number.isFinite(startedAt)) {
247
+ context.state.startedAt =
248
+ context.state.startedAt === undefined ? startedAt : Math.min(context.state.startedAt, startedAt);
249
+ }
250
+ if (!context.isPartial && context.state.endedAt === undefined) {
251
+ const endedAt = details?.endedAt;
252
+ context.state.endedAt = typeof endedAt === "number" && Number.isFinite(endedAt) ? endedAt : Date.now();
253
+ }
254
+ }
247
255
  // Re-render elapsed time and retry countdowns once per second while the
248
256
  // result is still partial; the first settled render clears the timer.
249
257
  export function scheduleLiveRefresh(context, isPartial) {
@@ -263,36 +271,39 @@ export function scheduleLiveRefresh(context, isPartial) {
263
271
  state.refreshTimer = undefined;
264
272
  }
265
273
  }
266
- export function renderSubagentCall(args, theme) {
274
+ export function renderSubagentCall(args, theme, context) {
267
275
  const count = Array.isArray(args.tasks) ? args.tasks.length : 0;
268
- const label = `${count} task${count === 1 ? "" : "s"}`;
269
- return new Text(`${theme.fg("toolTitle", theme.bold("Subagent"))}${theme.fg(count > 0 ? "dim" : "error", ` · ${label}`)}`, 0, 0);
276
+ const title = theme.fg(count > 0 ? "toolTitle" : "error", theme.bold("Subagent"));
277
+ if (!context)
278
+ return new Text(title, 0, 0);
279
+ observeTiming(context);
280
+ const metadata = [];
281
+ const duration = elapsed(context.state.startedAt, context.state.endedAt);
282
+ if (duration)
283
+ metadata.push(duration);
284
+ const cost = context.isPartial ? undefined : context.result?.details?.usage.cost;
285
+ if (typeof cost === "number" && Number.isFinite(cost) && cost > 0)
286
+ metadata.push(`$${cost.toFixed(3)}`);
287
+ return new Text(`${title}${metadata.length > 0 ? theme.fg("dim", ` · ${metadata.join(" · ")}`) : ""}`, 0, 0);
270
288
  }
271
289
  export function renderSubagentResult(result, options, theme, args, isError) {
272
290
  const details = result.details;
273
291
  if (!details || !Array.isArray(details.runs))
274
292
  return fallbackResult(result, theme, isError);
275
293
  if (details.runs.length === 0)
276
- return new Text(theme.fg("muted", "Initializing…"), 0, 0);
294
+ return new Text(theme.fg("muted", "Starting..."), 0, 0);
295
+ const container = new Container();
277
296
  if (!options.expanded) {
278
- const container = new Container();
279
- const header = options.isPartial
280
- ? progressHeader(details, theme)
281
- : `${batchMarker(details, theme)} ${theme.fg(isError ? "error" : "muted", outcomeSummary(details))}`;
282
- container.addChild(new Text(header, 0, 0));
283
297
  for (const [index, run] of details.runs.entries()) {
284
- container.addChild(new Text(taskRow(run, index, args, theme, options.isPartial), 0, 0));
298
+ container.addChild(new SingleLineText(taskRow(run, index, theme)));
285
299
  }
286
300
  return container;
287
301
  }
288
- const container = new Container();
289
- const header = options.isPartial
290
- ? progressHeader(details, theme)
291
- : `${batchMarker(details, theme)} ${theme.fg(isError ? "error" : "toolTitle", outcomeSummary(details))}`;
292
- container.addChild(new Text(header, 0, 0));
293
302
  for (const [index, run] of details.runs.entries()) {
294
- container.addChild(new Spacer(1));
295
- container.addChild(options.isPartial ? renderRunningRun(run, index, args, theme) : renderSettledRun(run, index, args, theme));
303
+ if (index > 0)
304
+ container.addChild(new Spacer(1));
305
+ const settled = run.status === "completed" || run.status === "failed" || run.status === "aborted";
306
+ container.addChild(settled ? renderSettledRun(run, index, args, theme) : renderRunningRun(run, index, args, theme));
296
307
  }
297
308
  return container;
298
309
  }