@code-yeongyu/senpi 2026.9.21-2 → 2026.9.22

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 (239) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/bundle/chunks/{anthropic-messages-C3ZY2ANT.js → anthropic-messages-2P7APOOQ.js} +1 -1
  3. package/dist/bundle/chunks/{app-server-command-HSX5RFAP.js → app-server-command-DLBXJ5K5.js} +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-7TAGS2VU.js → azure-openai-responses-3AH7MJWF.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-3SLCHXZO.js → chunk-4AXZDO3E.js} +2 -2
  6. package/dist/bundle/chunks/{chunk-Z3KQB2R3.js → chunk-7ICH7UFW.js} +12 -12
  7. package/dist/bundle/chunks/{chunk-KNM6SRPE.js → chunk-AAVNXTGQ.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-IDTLJYJ5.js → chunk-AY37SZJZ.js} +4 -4
  9. package/dist/bundle/chunks/{chunk-XHMOFY4T.js → chunk-BUPX33Q4.js} +3 -3
  10. package/dist/bundle/chunks/{chunk-GLKVDRNP.js → chunk-CWCY7LXK.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-POMPEGWQ.js → chunk-F3DXL5MX.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-GVI2HP7N.js → chunk-I2HIIJPI.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-T6XA2IZR.js → chunk-JR4X6ECO.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-M2XAY6I7.js → chunk-M2HSO7MH.js} +1 -1
  15. package/dist/bundle/chunks/{chunk-MIVOQT3Q.js → chunk-N5AQJAQ2.js} +1 -1
  16. package/dist/bundle/chunks/{chunk-UYVPLEOL.js → chunk-NK2RNX25.js} +1 -1
  17. package/dist/bundle/chunks/chunk-NMB4C6ZZ.js +2 -0
  18. package/dist/bundle/chunks/{chunk-B7W62BM7.js → chunk-P4OHEJ7P.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-I425CMTO.js → chunk-VBNHBSBD.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-B2IM56LB.js → chunk-VYIJQQ5I.js} +1 -1
  21. package/dist/bundle/chunks/chunk-XRHUMMIW.js +8 -0
  22. package/dist/bundle/chunks/{chunk-47GF6XYZ.js → chunk-YT2ZSZOY.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-OSDJ2SYO.js → chunk-ZCBX2K34.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-D5CL7PPD.js → chunk-ZMVXBX33.js} +2 -2
  25. package/dist/bundle/chunks/{cli-main-GQTEEZ2V.js → cli-main-D2VPNIQ3.js} +1 -1
  26. package/dist/bundle/chunks/{google-generative-ai-JWIH75VF.js → google-generative-ai-Y2IYMUVC.js} +1 -1
  27. package/dist/bundle/chunks/{google-vertex-IRGAY5XR.js → google-vertex-TKBBMPHV.js} +1 -1
  28. package/dist/bundle/chunks/{host-command-KOEKIHIZ.js → host-command-IFIIOX5S.js} +1 -1
  29. package/dist/bundle/chunks/host-lifecycle-3OJZA4QQ.js +3 -0
  30. package/dist/bundle/chunks/host-lifecycle.js +3 -3
  31. package/dist/bundle/chunks/{interactive-host-runtime-2KTFEW7O.js → interactive-host-runtime-V7PBDIOJ.js} +1 -1
  32. package/dist/bundle/chunks/{interactive-mode-I3ILWXQB.js → interactive-mode-RFMMGQCT.js} +1 -1
  33. package/dist/bundle/chunks/kimi-coding.js +2 -2
  34. package/dist/bundle/chunks/{mistral-conversations-VOBYATVJ.js → mistral-conversations-ZYDVFRYF.js} +1 -1
  35. package/dist/bundle/chunks/{multi-session-host-S5FWCIWE.js → multi-session-host-45YMCQIH.js} +8 -7
  36. package/dist/bundle/chunks/openai-codex-responses-MEIUNROM.js +10 -0
  37. package/dist/bundle/chunks/{openai-completions-YK6QTYOH.js → openai-completions-4V76L5ZJ.js} +1 -1
  38. package/dist/bundle/chunks/openai-responses-YR7WRBG3.js +2 -0
  39. package/dist/bundle/chunks/{package-manager-cli-HOL6CAI6.js → package-manager-cli-7DQKRSI5.js} +1 -1
  40. package/dist/bundle/chunks/rotation-stream-YPZP3VJS.js +2 -0
  41. package/dist/bundle/chunks/{rpc-mode-L3DSGTVM.js → rpc-mode-4GWZCJKI.js} +1 -1
  42. package/dist/bundle/chunks/{session-picker-L3FYEQBL.js → session-picker-ZKRYWZGC.js} +1 -1
  43. package/dist/bundle/chunks/session-worker.js +38 -37
  44. package/dist/bundle/cli.js +1 -1
  45. package/dist/bundle/index.js +1 -1
  46. package/dist/bundle/rpc-entry.js +1 -1
  47. package/dist/core/agent-session.d.ts +6 -4
  48. package/dist/core/agent-session.d.ts.map +1 -1
  49. package/dist/core/agent-session.js +9 -7
  50. package/dist/core/agent-session.js.map +1 -1
  51. package/dist/core/credential-pool/classify.d.ts.map +1 -1
  52. package/dist/core/credential-pool/classify.js +12 -0
  53. package/dist/core/credential-pool/classify.js.map +1 -1
  54. package/dist/core/credential-pool/failover.d.ts +37 -5
  55. package/dist/core/credential-pool/failover.d.ts.map +1 -1
  56. package/dist/core/credential-pool/failover.js +60 -24
  57. package/dist/core/credential-pool/failover.js.map +1 -1
  58. package/dist/core/credential-pool/rotation-events.d.ts +5 -0
  59. package/dist/core/credential-pool/rotation-events.d.ts.map +1 -0
  60. package/dist/core/credential-pool/rotation-events.js +25 -0
  61. package/dist/core/credential-pool/rotation-events.js.map +1 -0
  62. package/dist/core/credential-pool/rotation-stream.d.ts +4 -3
  63. package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -1
  64. package/dist/core/credential-pool/rotation-stream.js +8 -11
  65. package/dist/core/credential-pool/rotation-stream.js.map +1 -1
  66. package/dist/core/extensions/builtin/ask-user/schema.d.ts +2 -25
  67. package/dist/core/extensions/builtin/ask-user/schema.d.ts.map +1 -1
  68. package/dist/core/extensions/builtin/ask-user/schema.js.map +1 -1
  69. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +2 -7
  70. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
  71. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +2 -8
  72. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
  73. package/dist/core/extensions/builtin/mcp/expose/naming.d.ts +0 -1
  74. package/dist/core/extensions/builtin/mcp/expose/naming.d.ts.map +1 -1
  75. package/dist/core/extensions/builtin/mcp/expose/naming.js +0 -3
  76. package/dist/core/extensions/builtin/mcp/expose/naming.js.map +1 -1
  77. package/dist/core/extensions/builtin/mcp/expose/register.d.ts +1 -2
  78. package/dist/core/extensions/builtin/mcp/expose/register.d.ts.map +1 -1
  79. package/dist/core/extensions/builtin/mcp/expose/register.js +0 -21
  80. package/dist/core/extensions/builtin/mcp/expose/register.js.map +1 -1
  81. package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts +2 -2
  82. package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts.map +1 -1
  83. package/dist/core/extensions/builtin/mcp/expose/schema-compat.js +2 -2
  84. package/dist/core/extensions/builtin/mcp/expose/schema-compat.js.map +1 -1
  85. package/dist/core/http-dispatcher.d.ts +29 -0
  86. package/dist/core/http-dispatcher.d.ts.map +1 -1
  87. package/dist/core/http-dispatcher.js +30 -3
  88. package/dist/core/http-dispatcher.js.map +1 -1
  89. package/dist/modes/interactive/components/assistant-render-descriptors.d.ts.map +1 -1
  90. package/dist/modes/interactive/components/assistant-render-descriptors.js +8 -7
  91. package/dist/modes/interactive/components/assistant-render-descriptors.js.map +1 -1
  92. package/dist/modes/print-mode.d.ts.map +1 -1
  93. package/dist/modes/print-mode.js +7 -5
  94. package/dist/modes/print-mode.js.map +1 -1
  95. package/dist/modes/rpc/handoff-activity.d.ts +4 -0
  96. package/dist/modes/rpc/handoff-activity.d.ts.map +1 -0
  97. package/dist/modes/rpc/handoff-activity.js +6 -0
  98. package/dist/modes/rpc/handoff-activity.js.map +1 -0
  99. package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
  100. package/dist/modes/rpc/host-ensure.js +60 -17
  101. package/dist/modes/rpc/host-ensure.js.map +1 -1
  102. package/dist/modes/rpc/host-lifecycle.d.ts +3 -0
  103. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
  104. package/dist/modes/rpc/host-lifecycle.js +25 -5
  105. package/dist/modes/rpc/host-lifecycle.js.map +1 -1
  106. package/dist/modes/rpc/multi-session-host.d.ts +1 -0
  107. package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
  108. package/dist/modes/rpc/multi-session-host.js +40 -7
  109. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  110. package/dist/modes/rpc/rpc-types.d.ts +13 -0
  111. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  112. package/dist/modes/rpc/rpc-types.js.map +1 -1
  113. package/dist/modes/rpc/session-command-router.d.ts +10 -4
  114. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  115. package/dist/modes/rpc/session-command-router.js +90 -18
  116. package/dist/modes/rpc/session-command-router.js.map +1 -1
  117. package/dist/modes/rpc/session-event-writer.d.ts +5 -3
  118. package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
  119. package/dist/modes/rpc/session-event-writer.js +21 -2
  120. package/dist/modes/rpc/session-event-writer.js.map +1 -1
  121. package/dist/modes/rpc/session-worker-client.d.ts +1 -0
  122. package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
  123. package/dist/modes/rpc/session-worker-client.js +3 -0
  124. package/dist/modes/rpc/session-worker-client.js.map +1 -1
  125. package/dist/modes/rpc/session-worker-protocol.d.ts +3 -1
  126. package/dist/modes/rpc/session-worker-protocol.d.ts.map +1 -1
  127. package/dist/modes/rpc/session-worker-protocol.js.map +1 -1
  128. package/dist/modes/rpc/session-worker.js +7 -1
  129. package/dist/modes/rpc/session-worker.js.map +1 -1
  130. package/docs/providers.md +9 -1
  131. package/docs/rpc.md +58 -8
  132. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +15 -0
  133. package/node_modules/@code-yeongyu/senpi-codemode/README.md +51 -13
  134. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  135. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +53 -9
  136. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/reserved-dispatch.ts +1 -0
  137. package/node_modules/@code-yeongyu/senpi-codemode/src/config/settings.ts +18 -0
  138. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/eval-status.ts +9 -4
  139. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +3 -0
  140. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/AGENTS.md +2 -2
  141. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +10 -0
  142. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +18 -6
  143. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +2 -6
  144. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +1 -1
  145. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/run-queue.ts +17 -7
  146. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +6 -1
  147. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel-contract.ts +2 -5
  148. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +37 -5
  149. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +11 -2
  150. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +6 -0
  151. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-contract.ts +2 -5
  152. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +14 -4
  153. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +18 -5
  154. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +3 -2
  155. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +4 -1
  156. package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/idle-timeout.ts +9 -2
  157. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/AGENTS.md +2 -0
  158. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-execution.ts +19 -2
  159. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-runtime.ts +11 -3
  160. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-contract.ts +6 -1
  161. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +72 -20
  162. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-snapshot.ts +28 -4
  163. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-state.ts +5 -4
  164. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-status.ts +5 -2
  165. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-eval-result.ts +76 -25
  166. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-execution-event.ts +4 -0
  167. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-kernel-reset-refused-error.ts +12 -0
  168. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-request.ts +2 -1
  169. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool-options.ts +3 -1
  170. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +58 -37
  171. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/managed-cell.ts +15 -8
  172. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +20 -6
  173. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +89 -25
  174. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/terminal-snapshot-store.ts +4 -0
  175. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +51 -10
  176. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  177. package/node_modules/@earendil-works/pi-ai/README.md +1 -1
  178. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +14 -56
  179. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  180. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  181. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +18 -27
  182. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  183. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.d.ts +40 -0
  184. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.d.ts.map +1 -0
  185. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.js +102 -0
  186. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.js.map +1 -0
  187. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts +4 -3
  188. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  189. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +28 -14
  190. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js.map +1 -1
  191. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.d.ts +44 -0
  192. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.d.ts.map +1 -0
  193. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.js +120 -0
  194. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.js.map +1 -0
  195. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts +2 -2
  196. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts.map +1 -1
  197. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js +2 -2
  198. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js.map +1 -1
  199. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts +3 -0
  200. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts.map +1 -1
  201. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js +21 -15
  202. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js.map +1 -1
  203. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  204. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  205. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  206. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  207. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  208. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  209. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
  210. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
  211. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  212. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  213. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  214. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.d.ts +9 -0
  215. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.d.ts.map +1 -0
  216. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.js +43 -0
  217. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.js.map +1 -0
  218. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.d.ts.map +1 -1
  219. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js +3 -2
  220. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js.map +1 -1
  221. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.d.ts +19 -0
  222. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.d.ts.map +1 -0
  223. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.js +63 -0
  224. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.js.map +1 -0
  225. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +1 -0
  226. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  227. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +1 -1
  228. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  229. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  230. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  231. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  232. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  233. package/package.json +7 -7
  234. package/dist/bundle/chunks/chunk-5J5R5AMP.js +0 -8
  235. package/dist/bundle/chunks/chunk-I3F6VZZF.js +0 -2
  236. package/dist/bundle/chunks/host-lifecycle-DGZJTBDJ.js +0 -3
  237. package/dist/bundle/chunks/openai-codex-responses-L2PO2D6F.js +0 -10
  238. package/dist/bundle/chunks/openai-responses-YDUBVF4S.js +0 -2
  239. package/dist/bundle/chunks/rotation-stream-Y4YU6HV4.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"schema-compat.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/schema-compat.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { type TSchema, Type } from \"typebox\";\nimport { buildMcpToolName, buildMcpToolNames, type McpToolNameEntry } from \"./naming.ts\";\nimport { collectAllPages, type McpListPage, type McpPaginationResult } from \"./pagination.ts\";\n\nexport type { McpListPage, McpPaginationResult, McpToolNameEntry };\nexport { buildMcpToolName, buildMcpToolNames, collectAllPages };\n\ninterface SchemaConversionResult {\n\tschema: TSchema;\n\twarnings: string[];\n}\n\ninterface OutputSchemaRetryResult {\n\tschema: Record<string, unknown>;\n\twarnings: string[];\n}\n\nexport type McpContentBlock =\n\t| { type: \"text\"; text?: unknown }\n\t| { type: \"image\"; data?: unknown; mimeType?: unknown }\n\t| { type: \"audio\"; data?: unknown; mimeType?: unknown }\n\t| { type: \"resource\"; resource?: unknown }\n\t| { type: \"resource_link\"; uri?: unknown; name?: unknown; description?: unknown; mimeType?: unknown }\n\t| Record<string, unknown>;\n\nexport type McpMappedContentBlock =\n\t| TextContent\n\t| ImageContent\n\t| { type: \"audio\"; data: string; mimeType: string }\n\t| { type: \"resource\"; resource: unknown }\n\t| { type: \"resource_link\"; uri: string; name?: string; description?: string; mimeType?: string };\n\nexport interface McpToolResultLike {\n\tcontent?: McpContentBlock[];\n\tstructuredContent?: unknown;\n\tisError?: boolean;\n}\n\nexport type McpMappedToolResult =\n\t| { ok: true; content: McpMappedContentBlock[] }\n\t| { ok: false; error: { message: string; content: McpMappedContentBlock[] } };\n\nconst PERMISSIVE_OBJECT_SCHEMA = { type: \"object\", properties: {} } as const;\n\nexport function convertJsonSchemaToTypeBox(schema: unknown): SchemaConversionResult {\n\tconst warnings: string[] = [];\n\tconst resolved = resolveRefs(stripTopLevelSchemaKeys(schema), schema, new Set<string>(), warnings);\n\tif (warnings.length > 0) {\n\t\treturn { schema: Type.Unsafe<unknown>({ ...PERMISSIVE_OBJECT_SCHEMA }), warnings };\n\t}\n\tif (!isRecord(resolved)) {\n\t\treturn {\n\t\t\tschema: Type.Unsafe<unknown>({ ...PERMISSIVE_OBJECT_SCHEMA }),\n\t\t\twarnings: [\"MCP schema is not an object; using permissive object schema.\"],\n\t\t};\n\t}\n\treturn { schema: Type.Unsafe<unknown>(resolved), warnings };\n}\n\nexport function prepareOutputSchemaRetry(schema: unknown): OutputSchemaRetryResult {\n\tconst warnings: string[] = [];\n\tconst record: Record<string, unknown> = isRecord(schema) ? { ...schema } : { ...PERMISSIVE_OBJECT_SCHEMA };\n\tif (hasOwn(record, \"$schema\")) {\n\t\tdelete record.$schema;\n\t\twarnings.push(\"Stripped top-level $schema from MCP outputSchema retry.\");\n\t}\n\tif (hasOwn(record, \"additionalProperties\")) {\n\t\tdelete record.additionalProperties;\n\t\twarnings.push(\"Stripped top-level additionalProperties from MCP outputSchema retry.\");\n\t}\n\treturn { schema: record, warnings };\n}\n\nexport function mapMcpToolResult(result: McpToolResultLike): McpMappedToolResult {\n\tconst content = mapMcpContent(result);\n\tif (result.isError === true) {\n\t\treturn { ok: false, error: { message: contentToErrorMessage(content), content } };\n\t}\n\treturn { ok: true, content };\n}\n\nfunction mapMcpContent(result: McpToolResultLike): McpMappedContentBlock[] {\n\tconst content: McpMappedContentBlock[] = [];\n\tfor (const block of result.content ?? []) {\n\t\tcontent.push(mapContentBlock(block));\n\t}\n\tif (result.structuredContent !== undefined) {\n\t\tcontent.push({ type: \"text\", text: stringifyJson(result.structuredContent) });\n\t}\n\tif (content.length === 0) {\n\t\tcontent.push({ type: \"text\", text: \"(empty result)\" });\n\t}\n\treturn content;\n}\n\nfunction mapContentBlock(block: McpContentBlock): McpMappedContentBlock {\n\tif (block.type === \"text\") {\n\t\treturn { type: \"text\", text: typeof block.text === \"string\" ? block.text : stringifyJson(block.text) };\n\t}\n\tif (block.type === \"image\" && typeof block.data === \"string\" && typeof block.mimeType === \"string\") {\n\t\treturn { type: \"image\", data: block.data, mimeType: block.mimeType };\n\t}\n\tif (block.type === \"audio\" && typeof block.data === \"string\" && typeof block.mimeType === \"string\") {\n\t\treturn { type: \"audio\", data: block.data, mimeType: block.mimeType };\n\t}\n\tif (block.type === \"resource\" && hasOwn(block, \"resource\")) {\n\t\treturn { type: \"resource\", resource: block.resource };\n\t}\n\tif (block.type === \"resource_link\" && typeof block.uri === \"string\") {\n\t\treturn {\n\t\t\ttype: \"resource_link\",\n\t\t\turi: block.uri,\n\t\t\t...(typeof block.name === \"string\" ? { name: block.name } : {}),\n\t\t\t...(typeof block.description === \"string\" ? { description: block.description } : {}),\n\t\t\t...(typeof block.mimeType === \"string\" ? { mimeType: block.mimeType } : {}),\n\t\t};\n\t}\n\treturn { type: \"text\", text: stringifyJson(block) };\n}\n\nfunction contentToErrorMessage(content: readonly McpMappedContentBlock[]): string {\n\tconst firstText = content.find((block): block is TextContent => block.type === \"text\");\n\treturn firstText?.text.trim() || \"MCP tool returned an error result.\";\n}\n\nfunction stripTopLevelSchemaKeys(schema: unknown): unknown {\n\tif (!isRecord(schema)) return schema;\n\tconst result = { ...schema };\n\tdelete result.$schema;\n\tdelete result.additionalProperties;\n\treturn result;\n}\n\nfunction resolveRefs(value: unknown, root: unknown, seenRefs: Set<string>, warnings: string[]): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map((entry) => resolveRefs(entry, root, seenRefs, warnings));\n\t}\n\tif (!isRecord(value)) return value;\n\n\tif (typeof value.$ref === \"string\") {\n\t\tconst ref = value.$ref;\n\t\tconst resolved = resolveLocalRef(root, ref);\n\t\tif (resolved === undefined || seenRefs.has(ref)) {\n\t\t\twarnings.push(`MCP schema contains unresolvable $ref '${ref}'; using permissive object schema.`);\n\t\t\treturn { ...PERMISSIVE_OBJECT_SCHEMA };\n\t\t}\n\t\tconst nextSeenRefs = new Set(seenRefs);\n\t\tnextSeenRefs.add(ref);\n\t\treturn resolveRefs(resolved, root, nextSeenRefs, warnings);\n\t}\n\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, child] of Object.entries(value)) {\n\t\tif (key === \"type\" && child === null) continue;\n\t\tresult[key] = resolveRefs(child, root, seenRefs, warnings);\n\t}\n\treturn result;\n}\n\nfunction resolveLocalRef(root: unknown, ref: string): unknown {\n\tif (!ref.startsWith(\"#/\")) return undefined;\n\tlet current: unknown = root;\n\tfor (const part of ref\n\t\t.slice(2)\n\t\t.split(\"/\")\n\t\t.map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"))) {\n\t\tif (!isRecord(current) || !(part in current)) return undefined;\n\t\tcurrent = current[part];\n\t}\n\treturn current;\n}\n\nfunction stringifyJson(value: unknown): string {\n\tconst text = JSON.stringify(value);\n\treturn text ?? String(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOwn(value: Record<string, unknown>, key: string): boolean {\n\treturn Object.getOwnPropertyDescriptor(value, key) !== undefined;\n}\n"]}
1
+ {"version":3,"file":"schema-compat.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/schema-compat.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { type TSchema, Type } from \"typebox\";\nimport { buildMcpToolNames, type McpToolNameEntry } from \"./naming.ts\";\nimport { collectAllPages, type McpListPage, type McpPaginationResult } from \"./pagination.ts\";\n\nexport type { McpListPage, McpPaginationResult, McpToolNameEntry };\nexport { buildMcpToolNames, collectAllPages };\n\ninterface SchemaConversionResult {\n\tschema: TSchema;\n\twarnings: string[];\n}\n\ninterface OutputSchemaRetryResult {\n\tschema: Record<string, unknown>;\n\twarnings: string[];\n}\n\nexport type McpContentBlock =\n\t| { type: \"text\"; text?: unknown }\n\t| { type: \"image\"; data?: unknown; mimeType?: unknown }\n\t| { type: \"audio\"; data?: unknown; mimeType?: unknown }\n\t| { type: \"resource\"; resource?: unknown }\n\t| { type: \"resource_link\"; uri?: unknown; name?: unknown; description?: unknown; mimeType?: unknown }\n\t| Record<string, unknown>;\n\nexport type McpMappedContentBlock =\n\t| TextContent\n\t| ImageContent\n\t| { type: \"audio\"; data: string; mimeType: string }\n\t| { type: \"resource\"; resource: unknown }\n\t| { type: \"resource_link\"; uri: string; name?: string; description?: string; mimeType?: string };\n\nexport interface McpToolResultLike {\n\tcontent?: McpContentBlock[];\n\tstructuredContent?: unknown;\n\tisError?: boolean;\n}\n\nexport type McpMappedToolResult =\n\t| { ok: true; content: McpMappedContentBlock[] }\n\t| { ok: false; error: { message: string; content: McpMappedContentBlock[] } };\n\nconst PERMISSIVE_OBJECT_SCHEMA = { type: \"object\", properties: {} } as const;\n\nexport function convertJsonSchemaToTypeBox(schema: unknown): SchemaConversionResult {\n\tconst warnings: string[] = [];\n\tconst resolved = resolveRefs(stripTopLevelSchemaKeys(schema), schema, new Set<string>(), warnings);\n\tif (warnings.length > 0) {\n\t\treturn { schema: Type.Unsafe<unknown>({ ...PERMISSIVE_OBJECT_SCHEMA }), warnings };\n\t}\n\tif (!isRecord(resolved)) {\n\t\treturn {\n\t\t\tschema: Type.Unsafe<unknown>({ ...PERMISSIVE_OBJECT_SCHEMA }),\n\t\t\twarnings: [\"MCP schema is not an object; using permissive object schema.\"],\n\t\t};\n\t}\n\treturn { schema: Type.Unsafe<unknown>(resolved), warnings };\n}\n\nexport function prepareOutputSchemaRetry(schema: unknown): OutputSchemaRetryResult {\n\tconst warnings: string[] = [];\n\tconst record: Record<string, unknown> = isRecord(schema) ? { ...schema } : { ...PERMISSIVE_OBJECT_SCHEMA };\n\tif (hasOwn(record, \"$schema\")) {\n\t\tdelete record.$schema;\n\t\twarnings.push(\"Stripped top-level $schema from MCP outputSchema retry.\");\n\t}\n\tif (hasOwn(record, \"additionalProperties\")) {\n\t\tdelete record.additionalProperties;\n\t\twarnings.push(\"Stripped top-level additionalProperties from MCP outputSchema retry.\");\n\t}\n\treturn { schema: record, warnings };\n}\n\nexport function mapMcpToolResult(result: McpToolResultLike): McpMappedToolResult {\n\tconst content = mapMcpContent(result);\n\tif (result.isError === true) {\n\t\treturn { ok: false, error: { message: contentToErrorMessage(content), content } };\n\t}\n\treturn { ok: true, content };\n}\n\nfunction mapMcpContent(result: McpToolResultLike): McpMappedContentBlock[] {\n\tconst content: McpMappedContentBlock[] = [];\n\tfor (const block of result.content ?? []) {\n\t\tcontent.push(mapContentBlock(block));\n\t}\n\tif (result.structuredContent !== undefined) {\n\t\tcontent.push({ type: \"text\", text: stringifyJson(result.structuredContent) });\n\t}\n\tif (content.length === 0) {\n\t\tcontent.push({ type: \"text\", text: \"(empty result)\" });\n\t}\n\treturn content;\n}\n\nfunction mapContentBlock(block: McpContentBlock): McpMappedContentBlock {\n\tif (block.type === \"text\") {\n\t\treturn { type: \"text\", text: typeof block.text === \"string\" ? block.text : stringifyJson(block.text) };\n\t}\n\tif (block.type === \"image\" && typeof block.data === \"string\" && typeof block.mimeType === \"string\") {\n\t\treturn { type: \"image\", data: block.data, mimeType: block.mimeType };\n\t}\n\tif (block.type === \"audio\" && typeof block.data === \"string\" && typeof block.mimeType === \"string\") {\n\t\treturn { type: \"audio\", data: block.data, mimeType: block.mimeType };\n\t}\n\tif (block.type === \"resource\" && hasOwn(block, \"resource\")) {\n\t\treturn { type: \"resource\", resource: block.resource };\n\t}\n\tif (block.type === \"resource_link\" && typeof block.uri === \"string\") {\n\t\treturn {\n\t\t\ttype: \"resource_link\",\n\t\t\turi: block.uri,\n\t\t\t...(typeof block.name === \"string\" ? { name: block.name } : {}),\n\t\t\t...(typeof block.description === \"string\" ? { description: block.description } : {}),\n\t\t\t...(typeof block.mimeType === \"string\" ? { mimeType: block.mimeType } : {}),\n\t\t};\n\t}\n\treturn { type: \"text\", text: stringifyJson(block) };\n}\n\nfunction contentToErrorMessage(content: readonly McpMappedContentBlock[]): string {\n\tconst firstText = content.find((block): block is TextContent => block.type === \"text\");\n\treturn firstText?.text.trim() || \"MCP tool returned an error result.\";\n}\n\nfunction stripTopLevelSchemaKeys(schema: unknown): unknown {\n\tif (!isRecord(schema)) return schema;\n\tconst result = { ...schema };\n\tdelete result.$schema;\n\tdelete result.additionalProperties;\n\treturn result;\n}\n\nfunction resolveRefs(value: unknown, root: unknown, seenRefs: Set<string>, warnings: string[]): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map((entry) => resolveRefs(entry, root, seenRefs, warnings));\n\t}\n\tif (!isRecord(value)) return value;\n\n\tif (typeof value.$ref === \"string\") {\n\t\tconst ref = value.$ref;\n\t\tconst resolved = resolveLocalRef(root, ref);\n\t\tif (resolved === undefined || seenRefs.has(ref)) {\n\t\t\twarnings.push(`MCP schema contains unresolvable $ref '${ref}'; using permissive object schema.`);\n\t\t\treturn { ...PERMISSIVE_OBJECT_SCHEMA };\n\t\t}\n\t\tconst nextSeenRefs = new Set(seenRefs);\n\t\tnextSeenRefs.add(ref);\n\t\treturn resolveRefs(resolved, root, nextSeenRefs, warnings);\n\t}\n\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, child] of Object.entries(value)) {\n\t\tif (key === \"type\" && child === null) continue;\n\t\tresult[key] = resolveRefs(child, root, seenRefs, warnings);\n\t}\n\treturn result;\n}\n\nfunction resolveLocalRef(root: unknown, ref: string): unknown {\n\tif (!ref.startsWith(\"#/\")) return undefined;\n\tlet current: unknown = root;\n\tfor (const part of ref\n\t\t.slice(2)\n\t\t.split(\"/\")\n\t\t.map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"))) {\n\t\tif (!isRecord(current) || !(part in current)) return undefined;\n\t\tcurrent = current[part];\n\t}\n\treturn current;\n}\n\nfunction stringifyJson(value: unknown): string {\n\tconst text = JSON.stringify(value);\n\treturn text ?? String(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOwn(value: Record<string, unknown>, key: string): boolean {\n\treturn Object.getOwnPropertyDescriptor(value, key) !== undefined;\n}\n"]}
@@ -15,6 +15,35 @@ export declare const HTTP_IDLE_TIMEOUT_CHOICES: readonly [{
15
15
  readonly label: "disabled";
16
16
  readonly timeoutMs: 0;
17
17
  }];
18
+ /** Facts the global-install decision reads; injected so the decision is testable per runtime. */
19
+ export interface UndiciGlobalsInstallInput {
20
+ /** `process.versions`; a `bun` entry means this process IS Bun. */
21
+ readonly versions: Readonly<Record<string, string | undefined>>;
22
+ /** `globalThis.fetch` at the time of the call. */
23
+ readonly currentFetch: unknown;
24
+ /** `globalThis.fetch` captured when this module loaded. */
25
+ readonly originalFetch: unknown;
26
+ /** `globalThis.fetch` left behind by the previous install, if any. */
27
+ readonly installedFetch: unknown;
28
+ }
29
+ /**
30
+ * Whether `configureHttpDispatcher` may replace the global `fetch` (and the
31
+ * WebSocket/Headers/Request/Response constructors) with the bundled Undici
32
+ * implementation.
33
+ *
34
+ * Bun keeps its native fetch: the distributed CLI inlines npm undici, and its
35
+ * fetch running on Bun 1.3.x answers with the response headers but never
36
+ * delivers a streamed body, so every SSE model response stalls after the
37
+ * headers (#1890). Bun's own fetch honors HTTP_PROXY / HTTPS_PROXY / NO_PROXY,
38
+ * which `applyHttpProxySettings` sets, and stream stalls stay bounded by the
39
+ * agent-level idle and stream-start guards derived from the same
40
+ * `httpIdleTimeoutMs` setting.
41
+ *
42
+ * Node installs the globals so fetch and the dispatcher share one undici
43
+ * implementation (see the call site); a caller that deliberately replaced
44
+ * `fetch` after module load keeps its override.
45
+ */
46
+ export declare function shouldInstallUndiciGlobals(input: UndiciGlobalsInstallInput): boolean;
18
47
  export declare function parseHttpIdleTimeoutMs(value: unknown): number | undefined;
19
48
  export declare function formatHttpIdleTimeoutMs(timeoutMs: number): string;
20
49
  export declare function applyHttpProxySettings(httpProxy: string | undefined): void;
@@ -1 +1 @@
1
- {"version":3,"file":"http-dispatcher.d.ts","sourceRoot":"","sources":["../../src/core/http-dispatcher.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B,SAAU,CAAC;AAIpD,eAAO,MAAM,yBAAyB;aACnC,KAAK,EAAE,QAAQ;aAAE,SAAS,EAAE,KAAM;;aAClC,KAAK,EAAE,OAAO;aAAE,SAAS,EAAE,KAAM;;aACjC,KAAK,EAAE,OAAO;aAAE,SAAS,EAAE,MAAO;;aAClC,KAAK,EAAE,OAAO;aAAE,SAAS,EAAE,MAAO;;aAClC,KAAK,EAAE,UAAU;aAAE,SAAS,EAAE,CAAC;EACxB,CAAC;AAUX,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAgBzE;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMjE;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAa1E;AA+BD,wBAAgB,uBAAuB,CAAC,SAAS,GAAE,MAAqC,GAAG,IAAI,CAwC9F"}
1
+ {"version":3,"file":"http-dispatcher.d.ts","sourceRoot":"","sources":["../../src/core/http-dispatcher.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B,SAAU,CAAC;AAIpD,eAAO,MAAM,yBAAyB;aACnC,KAAK,EAAE,QAAQ;aAAE,SAAS,EAAE,KAAM;;aAClC,KAAK,EAAE,OAAO;aAAE,SAAS,EAAE,KAAM;;aACjC,KAAK,EAAE,OAAO;aAAE,SAAS,EAAE,MAAO;;aAClC,KAAK,EAAE,OAAO;aAAE,SAAS,EAAE,MAAO;;aAClC,KAAK,EAAE,UAAU;aAAE,SAAS,EAAE,CAAC;EACxB,CAAC;AAMX,iGAAiG;AACjG,MAAM,WAAW,yBAAyB;IACzC,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAChE,kDAAkD;IAClD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,2DAA2D;IAC3D,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,sEAAsE;IACtE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAKpF;AAMD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAgBzE;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMjE;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAa1E;AA+BD,wBAAgB,uBAAuB,CAAC,SAAS,GAAE,MAAqC,GAAG,IAAI,CA0C9F"}
@@ -13,6 +13,30 @@ export const HTTP_IDLE_TIMEOUT_CHOICES = [
13
13
  const originalGlobalFetch = globalThis.fetch;
14
14
  let installedGlobalFetch;
15
15
  let multiSessionDispatcherTimeoutMs;
16
+ /**
17
+ * Whether `configureHttpDispatcher` may replace the global `fetch` (and the
18
+ * WebSocket/Headers/Request/Response constructors) with the bundled Undici
19
+ * implementation.
20
+ *
21
+ * Bun keeps its native fetch: the distributed CLI inlines npm undici, and its
22
+ * fetch running on Bun 1.3.x answers with the response headers but never
23
+ * delivers a streamed body, so every SSE model response stalls after the
24
+ * headers (#1890). Bun's own fetch honors HTTP_PROXY / HTTPS_PROXY / NO_PROXY,
25
+ * which `applyHttpProxySettings` sets, and stream stalls stay bounded by the
26
+ * agent-level idle and stream-start guards derived from the same
27
+ * `httpIdleTimeoutMs` setting.
28
+ *
29
+ * Node installs the globals so fetch and the dispatcher share one undici
30
+ * implementation (see the call site); a caller that deliberately replaced
31
+ * `fetch` after module load keeps its override.
32
+ */
33
+ export function shouldInstallUndiciGlobals(input) {
34
+ if (input.versions.bun !== undefined)
35
+ return false;
36
+ return input.installedFetch === undefined
37
+ ? input.currentFetch === input.originalFetch
38
+ : input.currentFetch === input.installedFetch;
39
+ }
16
40
  function isMultiSessionRpcProcess() {
17
41
  return process.argv.includes("--multi-session");
18
42
  }
@@ -103,9 +127,12 @@ export function configureHttpDispatcher(timeoutMs = DEFAULT_HTTP_IDLE_TIMEOUT_MS
103
127
  // bundled fetch can otherwise consume compressed responses through npm undici's
104
128
  // dispatcher without decompressing them, causing response.json() failures.
105
129
  // If a caller replaced fetch after module load, preserve that deliberate override.
106
- const shouldInstallGlobals = installedGlobalFetch === undefined
107
- ? globalThis.fetch === originalGlobalFetch
108
- : globalThis.fetch === installedGlobalFetch;
130
+ const shouldInstallGlobals = shouldInstallUndiciGlobals({
131
+ versions: process.versions,
132
+ currentFetch: globalThis.fetch,
133
+ originalFetch: originalGlobalFetch,
134
+ installedFetch: installedGlobalFetch,
135
+ });
109
136
  if (shouldInstallGlobals) {
110
137
  undici.install?.();
111
138
  installedGlobalFetch = globalThis.fetch;
@@ -1 +1 @@
1
- {"version":3,"file":"http-dispatcher.js","sourceRoot":"","sources":["../../src/core/http-dispatcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"node:events\";\nimport * as undici from \"undici\";\n\nexport const DEFAULT_HTTP_IDLE_TIMEOUT_MS = 300_000;\n// Node's 250ms default can terminate valid connection attempts on high-latency routes.\nconst DEFAULT_AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS = 2_000;\n\nexport const HTTP_IDLE_TIMEOUT_CHOICES = [\n\t{ label: \"30 sec\", timeoutMs: 30_000 },\n\t{ label: \"1 min\", timeoutMs: 60_000 },\n\t{ label: \"2 min\", timeoutMs: 120_000 },\n\t{ label: \"5 min\", timeoutMs: 300_000 },\n\t{ label: \"disabled\", timeoutMs: 0 },\n] as const;\n\nconst originalGlobalFetch = globalThis.fetch;\nlet installedGlobalFetch: typeof globalThis.fetch | undefined;\nlet multiSessionDispatcherTimeoutMs: number | undefined;\n\nfunction isMultiSessionRpcProcess(): boolean {\n\treturn process.argv.includes(\"--multi-session\");\n}\n\nexport function parseHttpIdleTimeoutMs(value: unknown): number | undefined {\n\tif (typeof value === \"string\") {\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed.toLowerCase() === \"disabled\") {\n\t\t\treturn 0;\n\t\t}\n\t\tif (trimmed.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn parseHttpIdleTimeoutMs(Number(trimmed));\n\t}\n\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n\t\treturn undefined;\n\t}\n\treturn Math.floor(value);\n}\n\nexport function formatHttpIdleTimeoutMs(timeoutMs: number): string {\n\tconst choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.timeoutMs === timeoutMs);\n\tif (choice) {\n\t\treturn choice.label;\n\t}\n\treturn `${timeoutMs / 1000} sec`;\n}\n\nexport function applyHttpProxySettings(httpProxy: string | undefined): void {\n\tconst proxy = httpProxy?.trim();\n\tif (!proxy) return;\n\tif (isMultiSessionRpcProcess()) {\n\t\tconst existing = process.env.HTTP_PROXY ?? process.env.HTTPS_PROXY;\n\t\tif (existing !== undefined && existing !== proxy) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Multi-session RPC shares one process-global HTTP proxy; proxy settings must be fixed at process startup.\",\n\t\t\t);\n\t\t}\n\t}\n\tprocess.env.HTTP_PROXY ??= proxy;\n\tprocess.env.HTTPS_PROXY ??= proxy;\n}\n\nconst ignoreUndiciDispatcherError = (_error: unknown): void => {};\n\n// Undici can emit an internal Client \"error\" while terminating a mid-stream\n// fetch body. The body stream still rejects through reader.read(); this listener\n// only prevents EventEmitter's unhandled \"error\" special case from crashing pi.\nfunction withUndiciErrorListener<T extends undici.Dispatcher>(dispatcher: T): T {\n\tif (dispatcher instanceof EventEmitter) {\n\t\tEventEmitter.prototype.on.call(dispatcher, \"error\", ignoreUndiciDispatcherError);\n\t}\n\treturn dispatcher;\n}\n\nfunction createUndiciClient(origin: string | URL, options: object): undici.Dispatcher {\n\treturn withUndiciErrorListener(new undici.Client(origin, options as undici.Client.Options));\n}\n\nfunction createUndiciOriginDispatcher(origin: string | URL, options: object): undici.Dispatcher {\n\tconst dispatcherOptions = options as undici.Pool.Options;\n\tif (dispatcherOptions.connections === 1) {\n\t\treturn createUndiciClient(origin, dispatcherOptions);\n\t}\n\treturn withUndiciErrorListener(\n\t\tnew undici.Pool(origin, {\n\t\t\t...dispatcherOptions,\n\t\t\tfactory: createUndiciClient,\n\t\t}),\n\t);\n}\n\nexport function configureHttpDispatcher(timeoutMs: number = DEFAULT_HTTP_IDLE_TIMEOUT_MS): void {\n\tconst normalizedTimeoutMs = parseHttpIdleTimeoutMs(timeoutMs);\n\tif (normalizedTimeoutMs === undefined) {\n\t\tthrow new Error(`Invalid HTTP idle timeout: ${String(timeoutMs)}`);\n\t}\n\tif (isMultiSessionRpcProcess()) {\n\t\tif (multiSessionDispatcherTimeoutMs !== undefined && multiSessionDispatcherTimeoutMs !== normalizedTimeoutMs) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Multi-session RPC shares one process-global Undici dispatcher; HTTP idle timeout must be fixed at process startup.\",\n\t\t\t);\n\t\t}\n\t\tmultiSessionDispatcherTimeoutMs = normalizedTimeoutMs;\n\t}\n\tconst dispatcher = withUndiciErrorListener(\n\t\tnew undici.EnvHttpProxyAgent({\n\t\t\tallowH2: false,\n\t\t\t// Keep HTTP origins on CONNECT tunnels as they were before Undici 8.7.\n\t\t\tproxyTunnel: true,\n\t\t\tbodyTimeout: normalizedTimeoutMs,\n\t\t\tconnect: {\n\t\t\t\tautoSelectFamilyAttemptTimeout: DEFAULT_AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS,\n\t\t\t},\n\t\t\theadersTimeout: normalizedTimeoutMs,\n\t\t\tclientFactory: createUndiciClient,\n\t\t\tfactory: createUndiciOriginDispatcher,\n\t\t}),\n\t);\n\tundici.setGlobalDispatcher(dispatcher);\n\t// Keep fetch and the dispatcher on the same undici implementation. Node 26.0's\n\t// bundled fetch can otherwise consume compressed responses through npm undici's\n\t// dispatcher without decompressing them, causing response.json() failures.\n\t// If a caller replaced fetch after module load, preserve that deliberate override.\n\tconst shouldInstallGlobals =\n\t\tinstalledGlobalFetch === undefined\n\t\t\t? globalThis.fetch === originalGlobalFetch\n\t\t\t: globalThis.fetch === installedGlobalFetch;\n\tif (shouldInstallGlobals) {\n\t\tundici.install?.();\n\t\tinstalledGlobalFetch = globalThis.fetch;\n\t}\n}\n"]}
1
+ {"version":3,"file":"http-dispatcher.js","sourceRoot":"","sources":["../../src/core/http-dispatcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"node:events\";\nimport * as undici from \"undici\";\n\nexport const DEFAULT_HTTP_IDLE_TIMEOUT_MS = 300_000;\n// Node's 250ms default can terminate valid connection attempts on high-latency routes.\nconst DEFAULT_AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS = 2_000;\n\nexport const HTTP_IDLE_TIMEOUT_CHOICES = [\n\t{ label: \"30 sec\", timeoutMs: 30_000 },\n\t{ label: \"1 min\", timeoutMs: 60_000 },\n\t{ label: \"2 min\", timeoutMs: 120_000 },\n\t{ label: \"5 min\", timeoutMs: 300_000 },\n\t{ label: \"disabled\", timeoutMs: 0 },\n] as const;\n\nconst originalGlobalFetch = globalThis.fetch;\nlet installedGlobalFetch: typeof globalThis.fetch | undefined;\nlet multiSessionDispatcherTimeoutMs: number | undefined;\n\n/** Facts the global-install decision reads; injected so the decision is testable per runtime. */\nexport interface UndiciGlobalsInstallInput {\n\t/** `process.versions`; a `bun` entry means this process IS Bun. */\n\treadonly versions: Readonly<Record<string, string | undefined>>;\n\t/** `globalThis.fetch` at the time of the call. */\n\treadonly currentFetch: unknown;\n\t/** `globalThis.fetch` captured when this module loaded. */\n\treadonly originalFetch: unknown;\n\t/** `globalThis.fetch` left behind by the previous install, if any. */\n\treadonly installedFetch: unknown;\n}\n\n/**\n * Whether `configureHttpDispatcher` may replace the global `fetch` (and the\n * WebSocket/Headers/Request/Response constructors) with the bundled Undici\n * implementation.\n *\n * Bun keeps its native fetch: the distributed CLI inlines npm undici, and its\n * fetch running on Bun 1.3.x answers with the response headers but never\n * delivers a streamed body, so every SSE model response stalls after the\n * headers (#1890). Bun's own fetch honors HTTP_PROXY / HTTPS_PROXY / NO_PROXY,\n * which `applyHttpProxySettings` sets, and stream stalls stay bounded by the\n * agent-level idle and stream-start guards derived from the same\n * `httpIdleTimeoutMs` setting.\n *\n * Node installs the globals so fetch and the dispatcher share one undici\n * implementation (see the call site); a caller that deliberately replaced\n * `fetch` after module load keeps its override.\n */\nexport function shouldInstallUndiciGlobals(input: UndiciGlobalsInstallInput): boolean {\n\tif (input.versions.bun !== undefined) return false;\n\treturn input.installedFetch === undefined\n\t\t? input.currentFetch === input.originalFetch\n\t\t: input.currentFetch === input.installedFetch;\n}\n\nfunction isMultiSessionRpcProcess(): boolean {\n\treturn process.argv.includes(\"--multi-session\");\n}\n\nexport function parseHttpIdleTimeoutMs(value: unknown): number | undefined {\n\tif (typeof value === \"string\") {\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed.toLowerCase() === \"disabled\") {\n\t\t\treturn 0;\n\t\t}\n\t\tif (trimmed.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn parseHttpIdleTimeoutMs(Number(trimmed));\n\t}\n\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n\t\treturn undefined;\n\t}\n\treturn Math.floor(value);\n}\n\nexport function formatHttpIdleTimeoutMs(timeoutMs: number): string {\n\tconst choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.timeoutMs === timeoutMs);\n\tif (choice) {\n\t\treturn choice.label;\n\t}\n\treturn `${timeoutMs / 1000} sec`;\n}\n\nexport function applyHttpProxySettings(httpProxy: string | undefined): void {\n\tconst proxy = httpProxy?.trim();\n\tif (!proxy) return;\n\tif (isMultiSessionRpcProcess()) {\n\t\tconst existing = process.env.HTTP_PROXY ?? process.env.HTTPS_PROXY;\n\t\tif (existing !== undefined && existing !== proxy) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Multi-session RPC shares one process-global HTTP proxy; proxy settings must be fixed at process startup.\",\n\t\t\t);\n\t\t}\n\t}\n\tprocess.env.HTTP_PROXY ??= proxy;\n\tprocess.env.HTTPS_PROXY ??= proxy;\n}\n\nconst ignoreUndiciDispatcherError = (_error: unknown): void => {};\n\n// Undici can emit an internal Client \"error\" while terminating a mid-stream\n// fetch body. The body stream still rejects through reader.read(); this listener\n// only prevents EventEmitter's unhandled \"error\" special case from crashing pi.\nfunction withUndiciErrorListener<T extends undici.Dispatcher>(dispatcher: T): T {\n\tif (dispatcher instanceof EventEmitter) {\n\t\tEventEmitter.prototype.on.call(dispatcher, \"error\", ignoreUndiciDispatcherError);\n\t}\n\treturn dispatcher;\n}\n\nfunction createUndiciClient(origin: string | URL, options: object): undici.Dispatcher {\n\treturn withUndiciErrorListener(new undici.Client(origin, options as undici.Client.Options));\n}\n\nfunction createUndiciOriginDispatcher(origin: string | URL, options: object): undici.Dispatcher {\n\tconst dispatcherOptions = options as undici.Pool.Options;\n\tif (dispatcherOptions.connections === 1) {\n\t\treturn createUndiciClient(origin, dispatcherOptions);\n\t}\n\treturn withUndiciErrorListener(\n\t\tnew undici.Pool(origin, {\n\t\t\t...dispatcherOptions,\n\t\t\tfactory: createUndiciClient,\n\t\t}),\n\t);\n}\n\nexport function configureHttpDispatcher(timeoutMs: number = DEFAULT_HTTP_IDLE_TIMEOUT_MS): void {\n\tconst normalizedTimeoutMs = parseHttpIdleTimeoutMs(timeoutMs);\n\tif (normalizedTimeoutMs === undefined) {\n\t\tthrow new Error(`Invalid HTTP idle timeout: ${String(timeoutMs)}`);\n\t}\n\tif (isMultiSessionRpcProcess()) {\n\t\tif (multiSessionDispatcherTimeoutMs !== undefined && multiSessionDispatcherTimeoutMs !== normalizedTimeoutMs) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Multi-session RPC shares one process-global Undici dispatcher; HTTP idle timeout must be fixed at process startup.\",\n\t\t\t);\n\t\t}\n\t\tmultiSessionDispatcherTimeoutMs = normalizedTimeoutMs;\n\t}\n\tconst dispatcher = withUndiciErrorListener(\n\t\tnew undici.EnvHttpProxyAgent({\n\t\t\tallowH2: false,\n\t\t\t// Keep HTTP origins on CONNECT tunnels as they were before Undici 8.7.\n\t\t\tproxyTunnel: true,\n\t\t\tbodyTimeout: normalizedTimeoutMs,\n\t\t\tconnect: {\n\t\t\t\tautoSelectFamilyAttemptTimeout: DEFAULT_AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS,\n\t\t\t},\n\t\t\theadersTimeout: normalizedTimeoutMs,\n\t\t\tclientFactory: createUndiciClient,\n\t\t\tfactory: createUndiciOriginDispatcher,\n\t\t}),\n\t);\n\tundici.setGlobalDispatcher(dispatcher);\n\t// Keep fetch and the dispatcher on the same undici implementation. Node 26.0's\n\t// bundled fetch can otherwise consume compressed responses through npm undici's\n\t// dispatcher without decompressing them, causing response.json() failures.\n\t// If a caller replaced fetch after module load, preserve that deliberate override.\n\tconst shouldInstallGlobals = shouldInstallUndiciGlobals({\n\t\tversions: process.versions,\n\t\tcurrentFetch: globalThis.fetch,\n\t\toriginalFetch: originalGlobalFetch,\n\t\tinstalledFetch: installedGlobalFetch,\n\t});\n\tif (shouldInstallGlobals) {\n\t\tundici.install?.();\n\t\tinstalledGlobalFetch = globalThis.fetch;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-render-descriptors.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-render-descriptors.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EAGrB,MAAM,uBAAuB,CAAC;AAK/B,KAAK,sBAAsB,GAAG,SAAS,GAAG,aAAa,CAAC;AACxD,KAAK,kBAAkB,GAAG,gBAAgB,GAAG,yBAAyB,GAAG,sBAAsB,GAAG,YAAY,CAAC;AAC/G,KAAK,6BAA6B,GAAG,QAAQ,GAAG,sBAAsB,GAAG,kBAAkB,CAAC;AAE5F,MAAM,MAAM,yBAAyB,GAAG;IACvC,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,KAAK,gCAAgC,GAAG;IACvC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,mFAAmF;IACnF,QAAQ,CAAC,2BAA2B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAC/B,CAAC;AAuBF,wBAAgB,gCAAgC,CAC/C,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,gCAAgC,GACvC,SAAS,yBAAyB,EAAE,CAwHtC"}
1
+ {"version":3,"file":"assistant-render-descriptors.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-render-descriptors.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EAIrB,MAAM,uBAAuB,CAAC;AAK/B,KAAK,sBAAsB,GAAG,SAAS,GAAG,aAAa,CAAC;AACxD,KAAK,kBAAkB,GAAG,gBAAgB,GAAG,yBAAyB,GAAG,sBAAsB,GAAG,YAAY,CAAC;AAC/G,KAAK,6BAA6B,GAAG,QAAQ,GAAG,sBAAsB,GAAG,kBAAkB,CAAC;AAE5F,MAAM,MAAM,yBAAyB,GAAG;IACvC,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,KAAK,gCAAgC,GAAG;IACvC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,mFAAmF;IACnF,QAAQ,CAAC,2BAA2B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAC/B,CAAC;AAuBF,wBAAgB,gCAAgC,CAC/C,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,gCAAgC,GACvC,SAAS,yBAAyB,EAAE,CA2HtC"}
@@ -1,4 +1,4 @@
1
- import { describeProviderStallForUser, SERVER_FALLBACK_ABORTED_DIAGNOSTIC, } from "@earendil-works/pi-ai";
1
+ import { describeProviderFailureForUser, SERVER_FALLBACK_ABORTED_DIAGNOSTIC, stripTurnRetrySuppressionPrefix, } from "@earendil-works/pi-ai";
2
2
  import { formatDuration } from "../../../utils/duration.js";
3
3
  import { formatProviderNativeBody, formatProviderNativeSummary } from "../../provider-native-rendering.js";
4
4
  import { theme } from "../theme/theme.js";
@@ -116,7 +116,7 @@ export function createAssistantRenderDescriptors(message, options) {
116
116
  if (options.providerErrorOwned)
117
117
  break;
118
118
  const abortMessage = message.errorMessage && message.errorMessage !== "Request was aborted"
119
- ? message.errorMessage
119
+ ? stripTurnRetrySuppressionPrefix(message.errorMessage)
120
120
  : "Operation aborted";
121
121
  addError(abortMessage);
122
122
  break;
@@ -128,11 +128,12 @@ export function createAssistantRenderDescriptors(message, options) {
128
128
  break;
129
129
  if (message.diagnostics?.some((entry) => entry.type === SERVER_FALLBACK_ABORTED_DIAGNOSTIC))
130
130
  break;
131
- // A provider-stream stall carries the watchdog's own wording so the retry
132
- // engine can classify it; the transcript gets the plain-language version,
133
- // without the recovery advice a retry still in flight would contradict.
134
- const stall = describeProviderStallForUser(message.errorMessage);
135
- addError(stall ?? `Error: ${message.errorMessage || "Unknown error"}`);
131
+ // A provider-stream stall or transport drop carries the classifier's own
132
+ // wording so the retry engine can read it; the transcript gets the
133
+ // plain-language version, without the recovery advice a retry still in
134
+ // flight would contradict, and never the internal replay marker.
135
+ const described = describeProviderFailureForUser(message.errorMessage);
136
+ addError(described ?? `Error: ${stripTurnRetrySuppressionPrefix(message.errorMessage ?? "") || "Unknown error"}`);
136
137
  break;
137
138
  }
138
139
  case "pending":
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-render-descriptors.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-render-descriptors.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,4BAA4B,EAC5B,kCAAkC,GAClC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AAC3G,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAuB1C,MAAM,iBAAiB,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAA+C,CAAC;AAEpG,SAAS,WAAW,CAAC,KAAY;IAChC,MAAM,IAAI,SAAS,CAAC,wCAAwC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,gBAAgB,CAAC,OAA4C,EAAE,qBAA8B;IACrG,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,MAAM;YACV,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACrC,KAAK,UAAU;YACd,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACzC,KAAK,gBAAgB;YACpB,OAAO,qBAAqB,CAAC;QAC9B,KAAK,UAAU;YACd,OAAO,KAAK,CAAC;QACd;YACC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,gCAAgC,CAC/C,OAAyB,EACzB,OAAyC;IAEzC,MAAM,WAAW,GAAgC,EAAE,CAAC;IACpD,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAAE,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC5G,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACtB,KAAK,MAAM,EAAE,CAAC;gBACb,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACjC,IAAI,IAAI;oBAAE,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtD,MAAM;YACP,CAAC;YACD,KAAK,UAAU,EAAE,CAAC;gBACjB,MAAM,cAAc,GAAa,EAAE,CAAC;gBACpC,IAAI,SAAS,GAAG,KAAK,CAAC;gBACtB,IAAI,MAAM,GAAG,IAAI,CAAC;gBAClB,IAAI,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC;gBACxC,IAAI,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC;gBACtC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACxC,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;oBAC3C,IAAI,eAAe,CAAC,IAAI,KAAK,UAAU;wBAAE,MAAM;oBAC/C,MAAM,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC;oBAC5C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;wBAC7B,SAAS,GAAG,IAAI,CAAC;wBACjB,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;wBACzC,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC;wBACxC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;4BAC3B,MAAM,GAAG,KAAK,CAAC;wBAChB,CAAC;6BAAM,CAAC;4BACP,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;wBACpC,CAAC;oBACF,CAAC;oBACD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;oBACjD,IAAI,QAAQ;wBAAE,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC7C,CAAC;gBACD,CAAC,EAAE,CAAC;gBACJ,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;oBAAE,MAAM;gBACvC,MAAM,WAAW,GAAG,gBAAgB,EAAE,CAAC;gBACvC,MAAM,MAAM,GAAG,OAAO,CAAC,2BAA2B,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,iBAAiB,CAAC;gBAClG,IAAI,CAAC,SAAS,EAAE,CAAC;oBAChB,MAAM,IAAI,GAAG,MAAM;wBAClB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;wBACrE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC/B,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC1F,CAAC;qBAAM,CAAC;oBACP,MAAM,KAAK,GAAG,MAAM;wBACnB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,YAAY,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;wBACtG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC;oBACvE,IAAI,MAAM,EAAE,CAAC;wBACZ,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;oBACxE,CAAC;yBAAM,CAAC;wBACP,WAAW,CAAC,IAAI,CACf,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,EACpD,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CACvE,CAAC;oBACH,CAAC;gBACF,CAAC;gBACD,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;oBACvF,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACrC,MAAM;YACP,CAAC;YACD,KAAK,gBAAgB;gBACpB,WAAW,CAAC,IAAI,CACf;oBACC,IAAI,EAAE,yBAAyB;oBAC/B,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;iBACxF,EACD;oBACC,IAAI,EAAE,sBAAsB;oBAC5B,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;iBAC1E,CACD,CAAC;gBACF,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;oBACtF,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACrC,MAAM;YACP,KAAK,UAAU;gBACd,MAAM;YACP;gBACC,WAAW,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAQ,EAAE;QACvC,WAAW,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC;IACF,QAAQ,OAAO,CAAC,UAAU,EAAE,CAAC;QAC5B,KAAK,QAAQ;YACZ,QAAQ,CACP,yGAAyG,CACzG,CAAC;YACF,MAAM;QACP,KAAK,SAAS,EAAE,CAAC;YAChB,IAAI,OAAO,CAAC,YAAY;gBAAE,MAAM;YAChC,IAAI,OAAO,CAAC,kBAAkB;gBAAE,MAAM;YACtC,MAAM,YAAY,GACjB,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,KAAK,qBAAqB;gBACrE,CAAC,CAAC,OAAO,CAAC,YAAY;gBACtB,CAAC,CAAC,mBAAmB,CAAC;YACxB,QAAQ,CAAC,YAAY,CAAC,CAAC;YACvB,MAAM;QACP,CAAC;QACD,KAAK,OAAO,EAAE,CAAC;YACd,IAAI,OAAO,CAAC,YAAY;gBAAE,MAAM;YAChC,IAAI,OAAO,CAAC,kBAAkB;gBAAE,MAAM;YACtC,IAAI,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,kCAAkC,CAAC;gBAAE,MAAM;YACnG,0EAA0E;YAC1E,0EAA0E;YAC1E,wEAAwE;YACxE,MAAM,KAAK,GAAG,4BAA4B,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACjE,QAAQ,CAAC,KAAK,IAAI,UAAU,OAAO,CAAC,YAAY,IAAI,eAAe,EAAE,CAAC,CAAC;YACvE,MAAM;QACP,CAAC;QACD,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS,CAAC;QACf,KAAK,UAAU;YACd,MAAM;QACP;YACC,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,WAAW,CAAC;AACpB,CAAC","sourcesContent":["import {\n\ttype AssistantMessage,\n\tdescribeProviderStallForUser,\n\tSERVER_FALLBACK_ABORTED_DIAGNOSTIC,\n} from \"@earendil-works/pi-ai\";\nimport { formatDuration } from \"../../../utils/duration.ts\";\nimport { formatProviderNativeBody, formatProviderNativeSummary } from \"../../provider-native-rendering.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\ntype MarkdownDescriptorKind = \"text-md\" | \"thinking-md\";\ntype TextDescriptorKind = \"thinking-label\" | \"provider-native-summary\" | \"provider-native-body\" | \"error-text\";\ntype AssistantRenderDescriptorKind = \"spacer\" | MarkdownDescriptorKind | TextDescriptorKind;\n\nexport type AssistantRenderDescriptor = {\n\treadonly kind: AssistantRenderDescriptorKind;\n\treadonly text: string;\n\t/** Index of the thinking run this label/body belongs to; set only for thinking descriptors. */\n\treadonly thinkingRun?: number;\n};\n\ntype AssistantRenderDescriptorOptions = {\n\treadonly expanded: boolean;\n\treadonly providerErrorOwned?: boolean;\n\treadonly hiddenThinkingLabel: string;\n\treadonly hideThinkingBlock: boolean;\n\t/** Per-run click overrides of `hideThinkingBlock`, keyed by thinking run index. */\n\treadonly thinkingVisibilityOverrides?: ReadonlyMap<number, boolean>;\n\treadonly hasToolCalls: boolean;\n};\n\nconst SPACER_DESCRIPTOR = { kind: \"spacer\", text: \"\" } as const satisfies AssistantRenderDescriptor;\n\nfunction assertNever(value: never): never {\n\tthrow new TypeError(`Unexpected assistant render variant: ${String(value)}`);\n}\n\nfunction isVisibleContent(content: AssistantMessage[\"content\"][number], providerNativeVisible: boolean): boolean {\n\tswitch (content.type) {\n\t\tcase \"text\":\n\t\t\treturn Boolean(content.text.trim());\n\t\tcase \"thinking\":\n\t\t\treturn Boolean(content.thinking.trim());\n\t\tcase \"providerNative\":\n\t\t\treturn providerNativeVisible;\n\t\tcase \"toolCall\":\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn assertNever(content);\n\t}\n}\n\nexport function createAssistantRenderDescriptors(\n\tmessage: AssistantMessage,\n\toptions: AssistantRenderDescriptorOptions,\n): readonly AssistantRenderDescriptor[] {\n\tconst descriptors: AssistantRenderDescriptor[] = [];\n\tif (message.content.some((content) => isVisibleContent(content, true))) descriptors.push(SPACER_DESCRIPTOR);\n\tlet thinkingRunIndex = 0;\n\tfor (let i = 0; i < message.content.length; i++) {\n\t\tconst content = message.content[i];\n\t\tswitch (content.type) {\n\t\t\tcase \"text\": {\n\t\t\t\tconst text = content.text.trim();\n\t\t\t\tif (text) descriptors.push({ kind: \"text-md\", text });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"thinking\": {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tlet hasTiming = false;\n\t\t\t\tlet isDone = true;\n\t\t\t\tlet minStart = Number.POSITIVE_INFINITY;\n\t\t\t\tlet maxEnd = Number.NEGATIVE_INFINITY;\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") break;\n\t\t\t\t\tconst startedAt = thinkingContent.startedAt;\n\t\t\t\t\tif (startedAt !== undefined) {\n\t\t\t\t\t\thasTiming = true;\n\t\t\t\t\t\tminStart = Math.min(minStart, startedAt);\n\t\t\t\t\t\tconst endedAt = thinkingContent.endedAt;\n\t\t\t\t\t\tif (endedAt === undefined) {\n\t\t\t\t\t\t\tisDone = false;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmaxEnd = Math.max(maxEnd, endedAt);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) thinkingBlocks.push(thinking);\n\t\t\t\t}\n\t\t\t\ti--;\n\t\t\t\tif (thinkingBlocks.length === 0) break;\n\t\t\t\tconst thinkingRun = thinkingRunIndex++;\n\t\t\t\tconst hidden = options.thinkingVisibilityOverrides?.get(thinkingRun) ?? options.hideThinkingBlock;\n\t\t\t\tif (!hasTiming) {\n\t\t\t\t\tconst text = hidden\n\t\t\t\t\t\t? theme.italic(theme.fg(\"thinkingText\", options.hiddenThinkingLabel))\n\t\t\t\t\t\t: thinkingBlocks.join(\"\\n\\n\");\n\t\t\t\t\tdescriptors.push({ kind: hidden ? \"thinking-label\" : \"thinking-md\", text, thinkingRun });\n\t\t\t\t} else {\n\t\t\t\t\tconst label = isDone\n\t\t\t\t\t\t? theme.italic(theme.fg(\"thinkingText\", `Thought: ${formatDuration(Math.max(0, maxEnd - minStart))}`))\n\t\t\t\t\t\t: theme.italic(theme.fg(\"thinkingText\", options.hiddenThinkingLabel));\n\t\t\t\t\tif (hidden) {\n\t\t\t\t\t\tdescriptors.push({ kind: \"thinking-label\", text: label, thinkingRun });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdescriptors.push(\n\t\t\t\t\t\t\t{ kind: \"thinking-label\", text: label, thinkingRun },\n\t\t\t\t\t\t\t{ kind: \"thinking-md\", text: thinkingBlocks.join(\"\\n\\n\"), thinkingRun },\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (message.content.slice(i + 1).some((following) => isVisibleContent(following, false)))\n\t\t\t\t\tdescriptors.push(SPACER_DESCRIPTOR);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"providerNative\":\n\t\t\t\tdescriptors.push(\n\t\t\t\t\t{\n\t\t\t\t\t\tkind: \"provider-native-summary\",\n\t\t\t\t\t\ttext: theme.fg(\"muted\", formatProviderNativeSummary(message, content, options.expanded)),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkind: \"provider-native-body\",\n\t\t\t\t\t\ttext: theme.fg(\"dim\", formatProviderNativeBody(content, options.expanded)),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (message.content.slice(i + 1).some((following) => isVisibleContent(following, true)))\n\t\t\t\t\tdescriptors.push(SPACER_DESCRIPTOR);\n\t\t\t\tbreak;\n\t\t\tcase \"toolCall\":\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tassertNever(content);\n\t\t}\n\t}\n\tconst addError = (text: string): void => {\n\t\tdescriptors.push(SPACER_DESCRIPTOR, { kind: \"error-text\", text: theme.fg(\"error\", text) });\n\t};\n\tswitch (message.stopReason) {\n\t\tcase \"length\":\n\t\t\taddError(\n\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t);\n\t\t\tbreak;\n\t\tcase \"aborted\": {\n\t\t\tif (options.hasToolCalls) break;\n\t\t\tif (options.providerErrorOwned) break;\n\t\t\tconst abortMessage =\n\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t: \"Operation aborted\";\n\t\t\taddError(abortMessage);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"error\": {\n\t\t\tif (options.hasToolCalls) break;\n\t\t\tif (options.providerErrorOwned) break;\n\t\t\tif (message.diagnostics?.some((entry) => entry.type === SERVER_FALLBACK_ABORTED_DIAGNOSTIC)) break;\n\t\t\t// A provider-stream stall carries the watchdog's own wording so the retry\n\t\t\t// engine can classify it; the transcript gets the plain-language version,\n\t\t\t// without the recovery advice a retry still in flight would contradict.\n\t\t\tconst stall = describeProviderStallForUser(message.errorMessage);\n\t\t\taddError(stall ?? `Error: ${message.errorMessage || \"Unknown error\"}`);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"pending\":\n\t\tcase \"stop\":\n\t\tcase \"toolUse\":\n\t\tcase \"deferred\":\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tassertNever(message.stopReason);\n\t}\n\treturn descriptors;\n}\n"]}
1
+ {"version":3,"file":"assistant-render-descriptors.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-render-descriptors.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype AssistantMessage,\n\tdescribeProviderFailureForUser,\n\tSERVER_FALLBACK_ABORTED_DIAGNOSTIC,\n\tstripTurnRetrySuppressionPrefix,\n} from \"@earendil-works/pi-ai\";\nimport { formatDuration } from \"../../../utils/duration.ts\";\nimport { formatProviderNativeBody, formatProviderNativeSummary } from \"../../provider-native-rendering.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\ntype MarkdownDescriptorKind = \"text-md\" | \"thinking-md\";\ntype TextDescriptorKind = \"thinking-label\" | \"provider-native-summary\" | \"provider-native-body\" | \"error-text\";\ntype AssistantRenderDescriptorKind = \"spacer\" | MarkdownDescriptorKind | TextDescriptorKind;\n\nexport type AssistantRenderDescriptor = {\n\treadonly kind: AssistantRenderDescriptorKind;\n\treadonly text: string;\n\t/** Index of the thinking run this label/body belongs to; set only for thinking descriptors. */\n\treadonly thinkingRun?: number;\n};\n\ntype AssistantRenderDescriptorOptions = {\n\treadonly expanded: boolean;\n\treadonly providerErrorOwned?: boolean;\n\treadonly hiddenThinkingLabel: string;\n\treadonly hideThinkingBlock: boolean;\n\t/** Per-run click overrides of `hideThinkingBlock`, keyed by thinking run index. */\n\treadonly thinkingVisibilityOverrides?: ReadonlyMap<number, boolean>;\n\treadonly hasToolCalls: boolean;\n};\n\nconst SPACER_DESCRIPTOR = { kind: \"spacer\", text: \"\" } as const satisfies AssistantRenderDescriptor;\n\nfunction assertNever(value: never): never {\n\tthrow new TypeError(`Unexpected assistant render variant: ${String(value)}`);\n}\n\nfunction isVisibleContent(content: AssistantMessage[\"content\"][number], providerNativeVisible: boolean): boolean {\n\tswitch (content.type) {\n\t\tcase \"text\":\n\t\t\treturn Boolean(content.text.trim());\n\t\tcase \"thinking\":\n\t\t\treturn Boolean(content.thinking.trim());\n\t\tcase \"providerNative\":\n\t\t\treturn providerNativeVisible;\n\t\tcase \"toolCall\":\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn assertNever(content);\n\t}\n}\n\nexport function createAssistantRenderDescriptors(\n\tmessage: AssistantMessage,\n\toptions: AssistantRenderDescriptorOptions,\n): readonly AssistantRenderDescriptor[] {\n\tconst descriptors: AssistantRenderDescriptor[] = [];\n\tif (message.content.some((content) => isVisibleContent(content, true))) descriptors.push(SPACER_DESCRIPTOR);\n\tlet thinkingRunIndex = 0;\n\tfor (let i = 0; i < message.content.length; i++) {\n\t\tconst content = message.content[i];\n\t\tswitch (content.type) {\n\t\t\tcase \"text\": {\n\t\t\t\tconst text = content.text.trim();\n\t\t\t\tif (text) descriptors.push({ kind: \"text-md\", text });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"thinking\": {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tlet hasTiming = false;\n\t\t\t\tlet isDone = true;\n\t\t\t\tlet minStart = Number.POSITIVE_INFINITY;\n\t\t\t\tlet maxEnd = Number.NEGATIVE_INFINITY;\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") break;\n\t\t\t\t\tconst startedAt = thinkingContent.startedAt;\n\t\t\t\t\tif (startedAt !== undefined) {\n\t\t\t\t\t\thasTiming = true;\n\t\t\t\t\t\tminStart = Math.min(minStart, startedAt);\n\t\t\t\t\t\tconst endedAt = thinkingContent.endedAt;\n\t\t\t\t\t\tif (endedAt === undefined) {\n\t\t\t\t\t\t\tisDone = false;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmaxEnd = Math.max(maxEnd, endedAt);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) thinkingBlocks.push(thinking);\n\t\t\t\t}\n\t\t\t\ti--;\n\t\t\t\tif (thinkingBlocks.length === 0) break;\n\t\t\t\tconst thinkingRun = thinkingRunIndex++;\n\t\t\t\tconst hidden = options.thinkingVisibilityOverrides?.get(thinkingRun) ?? options.hideThinkingBlock;\n\t\t\t\tif (!hasTiming) {\n\t\t\t\t\tconst text = hidden\n\t\t\t\t\t\t? theme.italic(theme.fg(\"thinkingText\", options.hiddenThinkingLabel))\n\t\t\t\t\t\t: thinkingBlocks.join(\"\\n\\n\");\n\t\t\t\t\tdescriptors.push({ kind: hidden ? \"thinking-label\" : \"thinking-md\", text, thinkingRun });\n\t\t\t\t} else {\n\t\t\t\t\tconst label = isDone\n\t\t\t\t\t\t? theme.italic(theme.fg(\"thinkingText\", `Thought: ${formatDuration(Math.max(0, maxEnd - minStart))}`))\n\t\t\t\t\t\t: theme.italic(theme.fg(\"thinkingText\", options.hiddenThinkingLabel));\n\t\t\t\t\tif (hidden) {\n\t\t\t\t\t\tdescriptors.push({ kind: \"thinking-label\", text: label, thinkingRun });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdescriptors.push(\n\t\t\t\t\t\t\t{ kind: \"thinking-label\", text: label, thinkingRun },\n\t\t\t\t\t\t\t{ kind: \"thinking-md\", text: thinkingBlocks.join(\"\\n\\n\"), thinkingRun },\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (message.content.slice(i + 1).some((following) => isVisibleContent(following, false)))\n\t\t\t\t\tdescriptors.push(SPACER_DESCRIPTOR);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"providerNative\":\n\t\t\t\tdescriptors.push(\n\t\t\t\t\t{\n\t\t\t\t\t\tkind: \"provider-native-summary\",\n\t\t\t\t\t\ttext: theme.fg(\"muted\", formatProviderNativeSummary(message, content, options.expanded)),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tkind: \"provider-native-body\",\n\t\t\t\t\t\ttext: theme.fg(\"dim\", formatProviderNativeBody(content, options.expanded)),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (message.content.slice(i + 1).some((following) => isVisibleContent(following, true)))\n\t\t\t\t\tdescriptors.push(SPACER_DESCRIPTOR);\n\t\t\t\tbreak;\n\t\t\tcase \"toolCall\":\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tassertNever(content);\n\t\t}\n\t}\n\tconst addError = (text: string): void => {\n\t\tdescriptors.push(SPACER_DESCRIPTOR, { kind: \"error-text\", text: theme.fg(\"error\", text) });\n\t};\n\tswitch (message.stopReason) {\n\t\tcase \"length\":\n\t\t\taddError(\n\t\t\t\t\"Error: Model stopped because it reached the maximum output token limit. The response may be incomplete.\",\n\t\t\t);\n\t\t\tbreak;\n\t\tcase \"aborted\": {\n\t\t\tif (options.hasToolCalls) break;\n\t\t\tif (options.providerErrorOwned) break;\n\t\t\tconst abortMessage =\n\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t? stripTurnRetrySuppressionPrefix(message.errorMessage)\n\t\t\t\t\t: \"Operation aborted\";\n\t\t\taddError(abortMessage);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"error\": {\n\t\t\tif (options.hasToolCalls) break;\n\t\t\tif (options.providerErrorOwned) break;\n\t\t\tif (message.diagnostics?.some((entry) => entry.type === SERVER_FALLBACK_ABORTED_DIAGNOSTIC)) break;\n\t\t\t// A provider-stream stall or transport drop carries the classifier's own\n\t\t\t// wording so the retry engine can read it; the transcript gets the\n\t\t\t// plain-language version, without the recovery advice a retry still in\n\t\t\t// flight would contradict, and never the internal replay marker.\n\t\t\tconst described = describeProviderFailureForUser(message.errorMessage);\n\t\t\taddError(\n\t\t\t\tdescribed ?? `Error: ${stripTurnRetrySuppressionPrefix(message.errorMessage ?? \"\") || \"Unknown error\"}`,\n\t\t\t);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"pending\":\n\t\tcase \"stop\":\n\t\tcase \"toolUse\":\n\t\tcase \"deferred\":\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tassertNever(message.stopReason);\n\t}\n\treturn descriptors;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAM5E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuK/G"}
1
+ {"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEN,KAAK,YAAY,EAEjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAM5E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2K/G"}
@@ -5,7 +5,7 @@
5
5
  * - `pi -p "prompt"` - text output
6
6
  * - `senpi --mode json "prompt"` - JSON event stream
7
7
  */
8
- import { describeProviderStallForUser } from "@earendil-works/pi-ai";
8
+ import { describeProviderFailureForUser, stripTurnRetrySuppressionPrefix, } from "@earendil-works/pi-ai";
9
9
  import { flushRawStdout, waitForRawStdoutBackpressure, writeRawStdout } from "../core/output-guard.js";
10
10
  import { killTrackedDetachedChildren } from "../utils/shell.js";
11
11
  import { toJsonEvent } from "./json-event.js";
@@ -141,10 +141,12 @@ export async function runPrintMode(runtimeHost, options) {
141
141
  if (lastMessage?.role === "assistant") {
142
142
  const assistantMsg = lastMessage;
143
143
  if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
144
- // A provider-stream stall keeps the watchdog wording on the message for
145
- // the retry classifier; stdout gets the plain-language version instead.
146
- const stall = describeProviderStallForUser(assistantMsg.errorMessage);
147
- console.error(stall ?? (assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`));
144
+ // A provider-stream stall or transport drop keeps the classifier wording
145
+ // on the message; stderr gets the plain-language version instead.
146
+ const described = describeProviderFailureForUser(assistantMsg.errorMessage);
147
+ console.error(described ??
148
+ (stripTurnRetrySuppressionPrefix(assistantMsg.errorMessage ?? "") ||
149
+ `Request ${assistantMsg.stopReason}`));
148
150
  exitCode = 1;
149
151
  }
150
152
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `senpi --mode json \"prompt\"` - JSON event stream\n */\n\nimport { describeProviderStallForUser, type ImageContent } from \"@earendil-works/pi-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.ts\";\nimport { flushRawStdout, waitForRawStdoutBackpressure, writeRawStdout } from \"../core/output-guard.ts\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.ts\";\nimport { toJsonEvent } from \"./json-event.ts\";\nimport { formatProviderNativeBody, formatProviderNativeSummary } from \"./provider-native-rendering.ts\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet session = runtimeHost.session;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet unsubscribeBackpressure: (() => void) | undefined;\n\tlet disposed = false;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst disposeRuntime = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tunsubscribeBackpressure?.();\n\t\tawait runtimeHost.dispose();\n\t};\n\n\tconst registerSignalHandlers = (): void => {\n\t\tconst signals: NodeJS.Signals[] = [\"SIGTERM\"];\n\t\tif (process.platform !== \"win32\") {\n\t\t\tsignals.push(\"SIGHUP\");\n\t\t}\n\n\t\tfor (const signal of signals) {\n\t\t\tconst handler = () => {\n\t\t\t\tkillTrackedDetachedChildren();\n\t\t\t\tvoid disposeRuntime().finally(() => {\n\t\t\t\t\tprocess.exit(signal === \"SIGHUP\" ? 129 : 143);\n\t\t\t\t});\n\t\t\t};\n\t\t\tprocess.on(signal, handler);\n\t\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t\t}\n\t};\n\n\tregisterSignalHandlers();\n\n\truntimeHost.setRebindSession(async () => {\n\t\tawait rebindSession();\n\t});\n\n\tconst rebindSession = async (): Promise<void> => {\n\t\tsession = runtimeHost.session;\n\t\tawait session.bindExtensions({\n\t\t\tmode: mode === \"json\" ? \"json\" : \"print\",\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.waitForIdle(),\n\t\t\t\tnewSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n\t\t\t\tfork: async (entryId, forkOptions) => {\n\t\t\t\t\tconst result = await runtimeHost.fork(entryId, forkOptions);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, navigateOptions) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: navigateOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: navigateOptions?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: navigateOptions?.replaceInstructions,\n\t\t\t\t\t\tlabel: navigateOptions?.label,\n\t\t\t\t\t\texpectedLeafId: navigateOptions?.expectedLeafId,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\teditAssistantMessage: async (entryId, text, editOptions) => {\n\t\t\t\t\tconst result = await session.editAssistantMessage(entryId, text, {\n\t\t\t\t\t\tsummarize: editOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: editOptions?.customInstructions,\n\t\t\t\t\t\texpectedLeafId: editOptions?.expectedLeafId,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled, unchanged: result.unchanged, entryId: result.entryId };\n\t\t\t\t},\n\t\t\t\teditUserMessage: async (entryId, text, editOptions) => {\n\t\t\t\t\tconst result = await session.editUserMessage(entryId, text, {\n\t\t\t\t\t\tsummarize: editOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: editOptions?.customInstructions,\n\t\t\t\t\t\texpectedLeafId: editOptions?.expectedLeafId,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled, unchanged: result.unchanged, entryId: result.entryId };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath, switchOptions) => {\n\t\t\t\t\treturn runtimeHost.switchSession(sessionPath, switchOptions);\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\tunsubscribe?.();\n\t\tunsubscribeBackpressure?.();\n\t\tunsubscribe = session.subscribe((event) => {\n\t\t\tif (event.type === \"retry_fallback_applied\") {\n\t\t\t\tconsole.error(`Model fallback: ${event.from} -> ${event.to} (${event.reason})`);\n\t\t\t} else if (event.type === \"retry_fallback_exhausted\") {\n\t\t\t\tconsole.error(`Model fallback exhausted: ${event.chainKey} (${event.lastError})`);\n\t\t\t} else if (event.type === \"retry_fallback_reverted\") {\n\t\t\t\tconsole.error(`Model fallback reverted: ${event.from} -> ${event.to}`);\n\t\t\t}\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(toJsonEvent(event))}\\n`);\n\t\t\t}\n\t\t});\n\t\tunsubscribeBackpressure =\n\t\t\tmode === \"json\"\n\t\t\t\t? session.agent.subscribe(async () => {\n\t\t\t\t\t\tawait waitForRawStdoutBackpressure();\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\t};\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tawait rebindSession();\n\n\t\tif (initialMessage) {\n\t\t\tawait session.prompt(initialMessage, { images: initialImages, sessionTitlePrompt: false });\n\t\t}\n\n\t\tfor (const message of messages) {\n\t\t\tawait session.prompt(message, { sessionTitlePrompt: false });\n\t\t}\n\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages.findLast((message) => message.role === \"assistant\");\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage;\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\t// A provider-stream stall keeps the watchdog wording on the message for\n\t\t\t\t\t// the retry classifier; stdout gets the plain-language version instead.\n\t\t\t\t\tconst stall = describeProviderStallForUser(assistantMsg.errorMessage);\n\t\t\t\t\tconsole.error(stall ?? (assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`));\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t} else if (content.type === \"providerNative\") {\n\t\t\t\t\t\t\twriteRawStdout(`${formatProviderNativeSummary(assistantMsg, content, false)}\\n`);\n\t\t\t\t\t\t\twriteRawStdout(`${formatProviderNativeBody(content, false)}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tawait session.waitForSettledSessionWork();\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeRuntime();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
1
+ {"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `senpi --mode json \"prompt\"` - JSON event stream\n */\n\nimport {\n\tdescribeProviderFailureForUser,\n\ttype ImageContent,\n\tstripTurnRetrySuppressionPrefix,\n} from \"@earendil-works/pi-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.ts\";\nimport { flushRawStdout, waitForRawStdoutBackpressure, writeRawStdout } from \"../core/output-guard.ts\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.ts\";\nimport { toJsonEvent } from \"./json-event.ts\";\nimport { formatProviderNativeBody, formatProviderNativeSummary } from \"./provider-native-rendering.ts\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet session = runtimeHost.session;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet unsubscribeBackpressure: (() => void) | undefined;\n\tlet disposed = false;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst disposeRuntime = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tunsubscribeBackpressure?.();\n\t\tawait runtimeHost.dispose();\n\t};\n\n\tconst registerSignalHandlers = (): void => {\n\t\tconst signals: NodeJS.Signals[] = [\"SIGTERM\"];\n\t\tif (process.platform !== \"win32\") {\n\t\t\tsignals.push(\"SIGHUP\");\n\t\t}\n\n\t\tfor (const signal of signals) {\n\t\t\tconst handler = () => {\n\t\t\t\tkillTrackedDetachedChildren();\n\t\t\t\tvoid disposeRuntime().finally(() => {\n\t\t\t\t\tprocess.exit(signal === \"SIGHUP\" ? 129 : 143);\n\t\t\t\t});\n\t\t\t};\n\t\t\tprocess.on(signal, handler);\n\t\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t\t}\n\t};\n\n\tregisterSignalHandlers();\n\n\truntimeHost.setRebindSession(async () => {\n\t\tawait rebindSession();\n\t});\n\n\tconst rebindSession = async (): Promise<void> => {\n\t\tsession = runtimeHost.session;\n\t\tawait session.bindExtensions({\n\t\t\tmode: mode === \"json\" ? \"json\" : \"print\",\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.waitForIdle(),\n\t\t\t\tnewSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n\t\t\t\tfork: async (entryId, forkOptions) => {\n\t\t\t\t\tconst result = await runtimeHost.fork(entryId, forkOptions);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, navigateOptions) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: navigateOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: navigateOptions?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: navigateOptions?.replaceInstructions,\n\t\t\t\t\t\tlabel: navigateOptions?.label,\n\t\t\t\t\t\texpectedLeafId: navigateOptions?.expectedLeafId,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\teditAssistantMessage: async (entryId, text, editOptions) => {\n\t\t\t\t\tconst result = await session.editAssistantMessage(entryId, text, {\n\t\t\t\t\t\tsummarize: editOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: editOptions?.customInstructions,\n\t\t\t\t\t\texpectedLeafId: editOptions?.expectedLeafId,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled, unchanged: result.unchanged, entryId: result.entryId };\n\t\t\t\t},\n\t\t\t\teditUserMessage: async (entryId, text, editOptions) => {\n\t\t\t\t\tconst result = await session.editUserMessage(entryId, text, {\n\t\t\t\t\t\tsummarize: editOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: editOptions?.customInstructions,\n\t\t\t\t\t\texpectedLeafId: editOptions?.expectedLeafId,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled, unchanged: result.unchanged, entryId: result.entryId };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath, switchOptions) => {\n\t\t\t\t\treturn runtimeHost.switchSession(sessionPath, switchOptions);\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\tunsubscribe?.();\n\t\tunsubscribeBackpressure?.();\n\t\tunsubscribe = session.subscribe((event) => {\n\t\t\tif (event.type === \"retry_fallback_applied\") {\n\t\t\t\tconsole.error(`Model fallback: ${event.from} -> ${event.to} (${event.reason})`);\n\t\t\t} else if (event.type === \"retry_fallback_exhausted\") {\n\t\t\t\tconsole.error(`Model fallback exhausted: ${event.chainKey} (${event.lastError})`);\n\t\t\t} else if (event.type === \"retry_fallback_reverted\") {\n\t\t\t\tconsole.error(`Model fallback reverted: ${event.from} -> ${event.to}`);\n\t\t\t}\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(toJsonEvent(event))}\\n`);\n\t\t\t}\n\t\t});\n\t\tunsubscribeBackpressure =\n\t\t\tmode === \"json\"\n\t\t\t\t? session.agent.subscribe(async () => {\n\t\t\t\t\t\tawait waitForRawStdoutBackpressure();\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\t};\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tawait rebindSession();\n\n\t\tif (initialMessage) {\n\t\t\tawait session.prompt(initialMessage, { images: initialImages, sessionTitlePrompt: false });\n\t\t}\n\n\t\tfor (const message of messages) {\n\t\t\tawait session.prompt(message, { sessionTitlePrompt: false });\n\t\t}\n\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages.findLast((message) => message.role === \"assistant\");\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage;\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\t// A provider-stream stall or transport drop keeps the classifier wording\n\t\t\t\t\t// on the message; stderr gets the plain-language version instead.\n\t\t\t\t\tconst described = describeProviderFailureForUser(assistantMsg.errorMessage);\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tdescribed ??\n\t\t\t\t\t\t\t(stripTurnRetrySuppressionPrefix(assistantMsg.errorMessage ?? \"\") ||\n\t\t\t\t\t\t\t\t`Request ${assistantMsg.stopReason}`),\n\t\t\t\t\t);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t} else if (content.type === \"providerNative\") {\n\t\t\t\t\t\t\twriteRawStdout(`${formatProviderNativeSummary(assistantMsg, content, false)}\\n`);\n\t\t\t\t\t\t\twriteRawStdout(`${formatProviderNativeBody(content, false)}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tawait session.waitForSettledSessionWork();\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeRuntime();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { type SessionActivitySnapshot } from "../../core/session-activity.ts";
2
+ /** Handoff preserves turns and requests, but durable wake sources resume when the file is reopened. */
3
+ export declare function isHandoffBusy(snapshot: SessionActivitySnapshot): boolean;
4
+ //# sourceMappingURL=handoff-activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff-activity.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/handoff-activity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAErG,uGAAuG;AACvG,wBAAgB,aAAa,CAAC,QAAQ,EAAE,uBAAuB,GAAG,OAAO,CAExE"}
@@ -0,0 +1,6 @@
1
+ import { isSessionBusySnapshot } from "../../core/session-activity.js";
2
+ /** Handoff preserves turns and requests, but durable wake sources resume when the file is reopened. */
3
+ export function isHandoffBusy(snapshot) {
4
+ return isSessionBusySnapshot({ ...snapshot, hasActiveWakeSource: false });
5
+ }
6
+ //# sourceMappingURL=handoff-activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff-activity.js","sourceRoot":"","sources":["../../../src/modes/rpc/handoff-activity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAgC,MAAM,gCAAgC,CAAC;AAErG,uGAAuG;AACvG,MAAM,UAAU,aAAa,CAAC,QAAiC;IAC9D,OAAO,qBAAqB,CAAC,EAAE,GAAG,QAAQ,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["import { isSessionBusySnapshot, type SessionActivitySnapshot } from \"../../core/session-activity.ts\";\n\n/** Handoff preserves turns and requests, but durable wake sources resume when the file is reopened. */\nexport function isHandoffBusy(snapshot: SessionActivitySnapshot): boolean {\n\treturn isSessionBusySnapshot({ ...snapshot, hasActiveWakeSource: false });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"host-ensure.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"AA0CA,OAAO,EAA6B,KAAK,aAAa,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAMnH,OAAO,EACN,qBAAqB,EACrB,mBAAmB,EACnB,KAAK,eAAe,EACpB,oBAAoB,EACpB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,CAAC;AAExD;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,mBAAmB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAC3C,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACvD,iGAAiG;IACjG,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE;QAChB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAChF,6FAA6F;QAC7F,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK;YAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAC9G,oFAAoF;QACpF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD;;;;WAIG;QACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,4EAA4E;QAC5E,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;KAC7E,CAAC;CACF;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AAsBD,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBjF"}
1
+ {"version":3,"file":"host-ensure.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"AA0CA,OAAO,EAA6B,KAAK,aAAa,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAOnH,OAAO,EACN,qBAAqB,EACrB,mBAAmB,EACnB,KAAK,eAAe,EACpB,oBAAoB,EACpB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACtF,OAAO,EAAE,KAAK,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,CAAC;AAExD;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,mBAAmB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAC3C,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACvD,iGAAiG;IACjG,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE;QAChB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAChF,6FAA6F;QAC7F,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK;YAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAC9G,oFAAoF;QACpF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD;;;;WAIG;QACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,4EAA4E;QAC5E,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;KAC7E,CAAC;CACF;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AAsBD,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBjF"}
@@ -17,6 +17,7 @@ import { DEFAULT_HOST_IDLE_EXIT_MS } from "./host-lifecycle.js";
17
17
  import { probeProtocolInfo, probeSocketReachable } from "./host-probe.js";
18
18
  import { acquireOwnershipSafeLock } from "./ownership-safe-lock.js";
19
19
  import { HOST_GENERATION_ENV, HOST_INSTANCE_ID_ENV, hostLaunchProfile } from "./protocol-identity.js";
20
+ import { statSocketIdentity } from "./socket-ownership.js";
20
21
  import { createSocketSecret, resolveSocketTransportAddress, socketSecretPath } from "./socket-transport.js";
21
22
  export { createHostDaemonPaths, daemonDirectoryName, HostDaemonStateError, } from "./host-daemon-paths.js";
22
23
  export { defaultHostLaunch, PINNED_HOST_CLIENT_CAPABILITIES } from "./host-launch.js";
@@ -91,29 +92,66 @@ async function ensureHostLocked(paths, socket, options) {
91
92
  }
92
93
  const probe = testOptions?.readProcessStartTime ?? readProcessStartTime;
93
94
  const pidMatches = registeredHere && registered ? await matchesPidFileOrUnknown(registered.record, probe) : false;
95
+ // The generation this start leaves RUNNING beside the new one, when there is one.
96
+ let stranded;
94
97
  if (registered && pidMatches) {
95
- // I1: the socket is silent, but the process behind it is alive. Only the process that WROTE
96
- // this record may end it - anyone else refuses rather than signalling somebody else's host.
97
- if (!startedByUs)
98
- throw new HostEnsureRefusedError(socket, "foreign_writer", protocol);
99
- // ... and silent is not the same as gone. A host serving many sessions can miss a probe
100
- // budget while its event loop is busy; its socket still ACCEPTS the connection. Ending it
101
- // then would destroy every live session to replace a host that was never broken, so a
102
- // reachable socket is refused instead of signalled - the caller retries or falls back.
103
- if (await probeSocketReachable(socket, EXISTING_HOST_PROBE_TIMEOUT_MS)) {
104
- throw new HostEnsureRefusedError(socket, "host_busy", protocol);
98
+ if (!startedByUs) {
99
+ // I1: the socket is silent, but the process behind it is alive. Only the process that WROTE
100
+ // this record may end it - anyone else refuses rather than signalling somebody else's host.
101
+ if (await publicEndpointAccepts(socket))
102
+ throw new HostEnsureRefusedError(socket, "foreign_writer", protocol);
103
+ // A foreign record whose public endpoint accepts NOTHING names a generation nobody can reach:
104
+ // its entry was replaced (so it is already draining, #1893) or removed, or a dead listener
105
+ // left the entry behind. Refusing here locked every client out until that process happened
106
+ // to exit (#1936). Binding a fresh generation there signals nothing, so that is what happens -
107
+ // the stranded one keeps its record.
108
+ stranded = registered;
109
+ }
110
+ else {
111
+ // Silent is not the same as gone. A host serving many sessions can miss a probe budget
112
+ // while its event loop is busy; its socket still ACCEPTS the connection. Ending it then
113
+ // would destroy every live session to replace a host that was never broken, so a
114
+ // reachable socket is refused instead of signalled - the caller retries or falls back.
115
+ if (await probeSocketReachable(socket, EXISTING_HOST_PROBE_TIMEOUT_MS)) {
116
+ throw new HostEnsureRefusedError(socket, "host_busy", protocol);
117
+ }
118
+ await stopManagedHost(registered.record, testOptions?.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS, probe);
105
119
  }
106
- await stopManagedHost(registered.record, testOptions?.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS, probe);
107
120
  }
108
121
  // A host from before this layout registered itself in the FLAT directory. Its files are another
109
122
  // process's state: never read as ours, never signalled, never removed - and while it is alive,
110
123
  // this ensure refuses instead of binding a socket it may still be serving.
111
124
  if (await legacyHostIsLive(paths, probe))
112
125
  throw new HostEnsureRefusedError(socket, "legacy_host", protocol);
126
+ if (stranded !== undefined)
127
+ return startHost(paths, socket, options, stranded.generation + 1);
113
128
  if (registeredHere)
114
129
  await clearHostRegistration(paths);
115
130
  return startHost(paths, socket, options);
116
131
  }
132
+ /**
133
+ * Only the connect matters here, never an answer: the kernel completes it from the listen backlog
134
+ * without the host's event loop, so a live owner under load still accepts within this budget.
135
+ */
136
+ const FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS = 2_000;
137
+ /**
138
+ * Whether SOMETHING still accepts connections at the public path - the one fact that says a
139
+ * registered process may still own the endpoint. A missing entry and an entry nobody listens
140
+ * behind (connection refused) both answer no; an accepted connection, however silent, answers yes.
141
+ * A named pipe has no entry to lose and an abstract socket has no path, so both read as owned;
142
+ * so does an entry this process cannot stat, because an owner that cannot be ruled out is one
143
+ * this ensure must not bind over.
144
+ */
145
+ async function publicEndpointAccepts(socket) {
146
+ if (process.platform === "win32" || socket.startsWith("\0"))
147
+ return true;
148
+ const entry = await statSocketIdentity(socket).then((identity) => (identity === undefined ? "absent" : "present"), () => "unknown");
149
+ if (entry === "absent")
150
+ return false;
151
+ if (entry === "unknown")
152
+ return true;
153
+ return probeSocketReachable(socket, FOREIGN_ENDPOINT_PROBE_TIMEOUT_MS);
154
+ }
117
155
  /** `fallback` belongs to clients that can live without a host; an ensure must produce one or fail. */
118
156
  function decide(options, startedByUs, protocol) {
119
157
  if (options.upgrade !== "if-engine-differs") {
@@ -169,7 +207,11 @@ function registersSocket(registered, socket) {
169
207
  return false;
170
208
  return registered.socket === undefined || registered.socket === socket;
171
209
  }
172
- async function startHost(paths, socket, options) {
210
+ /**
211
+ * `generation` is 0 for a fresh endpoint; a start that leaves a stranded generation running beside
212
+ * the new one numbers it after that generation, as a handoff would.
213
+ */
214
+ async function startHost(paths, socket, options, generation = 0) {
173
215
  const testOptions = options._test;
174
216
  // The generation this ensure is about to spawn, chosen HERE so its directory exists before the
175
217
  // host boots and the pointer can name it the moment the host is registered.
@@ -183,10 +225,11 @@ async function startHost(paths, socket, options) {
183
225
  capabilities: PINNED_HOST_CLIENT_CAPABILITIES,
184
226
  coldStart: options.policy?.coldStart ?? "transient",
185
227
  idleExitMs: options.policy?.idleExitMs ?? DEFAULT_HOST_IDLE_EXIT_MS,
186
- generation: 0,
228
+ generation,
187
229
  instanceId,
188
230
  });
189
- const stderr = await open(paths.stderrLog, "w", 0o600);
231
+ // A stranded generation is still writing its diagnostics here; only a fresh endpoint starts over.
232
+ const stderr = await open(paths.stderrLog, generation === 0 ? "w" : "a", 0o600);
190
233
  let pidFile;
191
234
  let child;
192
235
  let exitedEarly;
@@ -197,7 +240,7 @@ async function startHost(paths, socket, options) {
197
240
  child = spawn(launch.command, [...launch.args], {
198
241
  detached: true,
199
242
  windowsHide: true,
200
- env: hostEnv(options, { paths, instanceId }),
243
+ env: hostEnv(options, { paths, instanceId, generation }),
201
244
  stdio: ["ignore", "ignore", stderr.fd],
202
245
  });
203
246
  childExit = new Promise((resolveExit) => {
@@ -232,7 +275,7 @@ async function startHost(paths, socket, options) {
232
275
  record: pidFile,
233
276
  socket,
234
277
  instanceId,
235
- generation: 0,
278
+ generation,
236
279
  launchProfileId: hostLaunchProfile(hostChildArgv(options.hostArgs ?? []), process.cwd()).profile_id,
237
280
  });
238
281
  child.unref();
@@ -432,7 +475,7 @@ function hostEnv(options, generation) {
432
475
  // its own host's identity to the one it spawns, and two hosts claiming one instance id make a
433
476
  // handoff - which completes exactly when the instance id changes - impossible to observe.
434
477
  env[HOST_INSTANCE_ID_ENV] = generation.instanceId;
435
- env[HOST_GENERATION_ENV] = "0";
478
+ env[HOST_GENERATION_ENV] = String(generation.generation);
436
479
  env[HOST_DAEMON_DIR_ENV] = generation.paths.dir;
437
480
  return env;
438
481
  }