@code-yeongyu/senpi 2026.9.15-2 → 2026.9.16-2

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 (249) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +1 -1
  3. package/dist/core/agent-session.d.ts +28 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +111 -13
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/compaction/compaction.d.ts.map +1 -1
  8. package/dist/core/compaction/compaction.js +4 -2
  9. package/dist/core/compaction/compaction.js.map +1 -1
  10. package/dist/core/compaction/stream-watchdog.d.ts +56 -2
  11. package/dist/core/compaction/stream-watchdog.d.ts.map +1 -1
  12. package/dist/core/compaction/stream-watchdog.js +93 -15
  13. package/dist/core/compaction/stream-watchdog.js.map +1 -1
  14. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.d.ts +6 -0
  15. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.d.ts.map +1 -1
  16. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +17 -0
  17. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
  18. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.d.ts +4 -1
  19. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.d.ts.map +1 -1
  20. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.js +31 -0
  21. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.js.map +1 -1
  22. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts +2 -0
  23. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
  24. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +16 -0
  25. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
  26. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.d.ts.map +1 -1
  27. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js +19 -8
  28. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js.map +1 -1
  29. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.d.ts.map +1 -1
  30. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js +2 -1
  31. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js.map +1 -1
  32. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +13 -1
  33. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
  34. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +66 -2
  35. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
  36. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/compaction/index.js +16 -10
  38. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  39. package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -1
  40. package/dist/core/extensions/builtin/compaction/speculative-summary.js +4 -2
  41. package/dist/core/extensions/builtin/compaction/speculative-summary.js.map +1 -1
  42. package/dist/core/extensions/builtin/compaction/speculative.d.ts +8 -1
  43. package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
  44. package/dist/core/extensions/builtin/compaction/speculative.js +31 -7
  45. package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
  46. package/dist/core/extensions/builtin/compaction/transient-failure.d.ts.map +1 -1
  47. package/dist/core/extensions/builtin/compaction/transient-failure.js +6 -3
  48. package/dist/core/extensions/builtin/compaction/transient-failure.js.map +1 -1
  49. package/dist/core/extensions/kernel-tools-context.d.ts +13 -0
  50. package/dist/core/extensions/kernel-tools-context.d.ts.map +1 -0
  51. package/dist/core/extensions/kernel-tools-context.js +3 -0
  52. package/dist/core/extensions/kernel-tools-context.js.map +1 -0
  53. package/dist/core/extensions/runner.d.ts +19 -0
  54. package/dist/core/extensions/runner.d.ts.map +1 -1
  55. package/dist/core/extensions/runner.js +103 -1
  56. package/dist/core/extensions/runner.js.map +1 -1
  57. package/dist/core/extensions/types.d.ts +21 -0
  58. package/dist/core/extensions/types.d.ts.map +1 -1
  59. package/dist/core/extensions/types.js.map +1 -1
  60. package/dist/core/keybindings.d.ts +5 -0
  61. package/dist/core/keybindings.d.ts.map +1 -1
  62. package/dist/core/keybindings.js +1 -0
  63. package/dist/core/keybindings.js.map +1 -1
  64. package/dist/core/retry-fallback/settings.d.ts +3 -0
  65. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  66. package/dist/core/retry-fallback/settings.js.map +1 -1
  67. package/dist/core/sdk.d.ts.map +1 -1
  68. package/dist/core/sdk.js +1 -0
  69. package/dist/core/sdk.js.map +1 -1
  70. package/dist/core/session-manager.d.ts +27 -1
  71. package/dist/core/session-manager.d.ts.map +1 -1
  72. package/dist/core/session-manager.js +78 -5
  73. package/dist/core/session-manager.js.map +1 -1
  74. package/dist/core/session-resident-store.d.ts +33 -7
  75. package/dist/core/session-resident-store.d.ts.map +1 -1
  76. package/dist/core/session-resident-store.js +163 -14
  77. package/dist/core/session-resident-store.js.map +1 -1
  78. package/dist/core/session-write-reservation.d.ts +6 -0
  79. package/dist/core/session-write-reservation.d.ts.map +1 -1
  80. package/dist/core/session-write-reservation.js +19 -0
  81. package/dist/core/session-write-reservation.js.map +1 -1
  82. package/dist/core/settings-manager.d.ts +35 -1
  83. package/dist/core/settings-manager.d.ts.map +1 -1
  84. package/dist/core/settings-manager.js +62 -0
  85. package/dist/core/settings-manager.js.map +1 -1
  86. package/dist/core/slash-commands.d.ts.map +1 -1
  87. package/dist/core/slash-commands.js +2 -1
  88. package/dist/core/slash-commands.js.map +1 -1
  89. package/dist/core/tools/index.d.ts +1 -1
  90. package/dist/core/tools/index.d.ts.map +1 -1
  91. package/dist/core/tools/index.js +4 -3
  92. package/dist/core/tools/index.js.map +1 -1
  93. package/dist/core/tools/read.d.ts +3 -1
  94. package/dist/core/tools/read.d.ts.map +1 -1
  95. package/dist/core/tools/read.js +16 -2
  96. package/dist/core/tools/read.js.map +1 -1
  97. package/dist/index.d.ts +1 -0
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +1 -0
  100. package/dist/index.js.map +1 -1
  101. package/dist/modes/interactive/components/assistant-render-descriptors.d.ts.map +1 -1
  102. package/dist/modes/interactive/components/assistant-render-descriptors.js +12 -5
  103. package/dist/modes/interactive/components/assistant-render-descriptors.js.map +1 -1
  104. package/dist/modes/interactive/components/extension-input.d.ts +2 -0
  105. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  106. package/dist/modes/interactive/components/extension-input.js +5 -0
  107. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  108. package/dist/modes/interactive/interactive-mode.d.ts +19 -2
  109. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  110. package/dist/modes/interactive/interactive-mode.js +66 -14
  111. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  112. package/dist/modes/interactive/tips/catalog/session-tips.js +1 -1
  113. package/dist/modes/interactive/tips/catalog/session-tips.js.map +1 -1
  114. package/dist/modes/interactive/working-status.d.ts +3 -2
  115. package/dist/modes/interactive/working-status.d.ts.map +1 -1
  116. package/dist/modes/interactive/working-status.js +17 -4
  117. package/dist/modes/interactive/working-status.js.map +1 -1
  118. package/dist/modes/print-mode.d.ts +1 -1
  119. package/dist/modes/print-mode.d.ts.map +1 -1
  120. package/dist/modes/print-mode.js +5 -1
  121. package/dist/modes/print-mode.js.map +1 -1
  122. package/docs/extensions.md +5 -2
  123. package/docs/keybindings.md +1 -0
  124. package/docs/session-format.md +1 -1
  125. package/docs/sessions.md +3 -3
  126. package/docs/settings.md +31 -1
  127. package/docs/usage.md +1 -1
  128. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +35 -0
  129. package/node_modules/@code-yeongyu/senpi-codemode/README.md +24 -0
  130. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  131. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/http-server.ts +7 -1
  132. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/kernel-tools-protocol.ts +85 -0
  133. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +6 -0
  134. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +30 -11
  135. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +11 -0
  136. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +10 -0
  137. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +46 -0
  138. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +1 -1
  139. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +29 -0
  140. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +12 -0
  141. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.d.ts +13 -0
  142. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.js +7 -0
  143. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.d.ts +10 -0
  144. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.js +12 -0
  145. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.js +22 -0
  146. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.ts +26 -0
  147. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-host.ts +134 -0
  148. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-naming.js +28 -0
  149. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.d.ts +5 -0
  150. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.js +255 -0
  151. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-pump.js +105 -0
  152. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.d.ts +27 -0
  153. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.js +127 -0
  154. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-schema.js +69 -0
  155. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-types.ts +42 -0
  156. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +2 -0
  157. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +26 -3
  158. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +20 -8
  159. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-slot.ts +6 -1
  160. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-startup.ts +9 -7
  161. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/workpool.js +37 -0
  162. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/kernel-tools-unavailable.ts +5 -0
  163. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +13 -0
  164. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +57 -3
  165. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +13 -2
  166. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/workpool.rb +38 -0
  167. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +13 -0
  168. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +2 -0
  169. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +4 -2
  170. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +31 -3
  171. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +52 -30
  172. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +2 -0
  173. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  174. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +30 -3
  175. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  176. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +5 -0
  177. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  178. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +2 -0
  179. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  180. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.d.ts.map +1 -1
  181. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js +51 -12
  182. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js.map +1 -1
  183. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts +3 -0
  184. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts.map +1 -1
  185. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js +18 -3
  186. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js.map +1 -1
  187. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts +4 -0
  188. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts.map +1 -0
  189. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js +268 -0
  190. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js.map +1 -0
  191. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts +18 -0
  192. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts.map +1 -0
  193. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js +69 -0
  194. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js.map +1 -0
  195. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts +27 -0
  196. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts.map +1 -0
  197. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js +118 -0
  198. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js.map +1 -0
  199. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts +21 -0
  200. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts.map +1 -0
  201. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js +24 -0
  202. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js.map +1 -0
  203. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts +12 -0
  204. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts.map +1 -0
  205. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js +92 -0
  206. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js.map +1 -0
  207. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts +47 -0
  208. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts.map +1 -0
  209. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js +8 -0
  210. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js.map +1 -0
  211. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts +52 -0
  212. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts.map +1 -0
  213. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js +155 -0
  214. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js.map +1 -0
  215. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +4 -0
  216. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
  217. package/node_modules/@earendil-works/pi-agent-core/dist/index.js +3 -0
  218. package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
  219. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.d.ts +101 -0
  220. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.d.ts.map +1 -0
  221. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.js +178 -0
  222. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.js.map +1 -0
  223. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +9 -0
  224. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  225. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  226. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  227. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  228. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  229. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  230. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  231. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  232. package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -1
  233. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  234. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  235. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  236. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json +1 -1
  237. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts +15 -0
  238. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts.map +1 -0
  239. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js +15 -0
  240. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js.map +1 -0
  241. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +24 -0
  242. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  243. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +92 -0
  244. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  245. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  246. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  247. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  248. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  249. package/package.json +7 -7
@@ -1,7 +1,8 @@
1
1
  import { hasCredentialHeaders, isContextOverflow, isRetryableAssistantError, isRetryableErrorMessage, retryTransientCall, } from "@earendil-works/pi-ai";
2
2
  import { DEFAULT_COMPACTION_SETTINGS, estimateContextTokens, estimateTokens, prepareCompaction, } from "../../../compaction/index.js";
3
- import { StreamDurationBudgetError, StreamIdleTimeoutError, summarizationMaxDurationMs, } from "../../../compaction/stream-watchdog.js";
3
+ import { createSummarizationDeadline, StreamDurationBudgetError, StreamIdleTimeoutError, SummarizationTotalBudgetError, summarizationMaxDurationMs, summarizationTotalBudgetMs, } from "../../../compaction/stream-watchdog.js";
4
4
  import { createWarmAnchorSnapshot, isWarmSummaryAnchorValid, } from "../../../compaction/warm-anchor.js";
5
+ import { CredentialFailoverError, TURN_RETRY_SUPPRESSION_PREFIX } from "../../../credential-pool/failover.js";
5
6
  import { convertToLlm } from "../../../messages.js";
6
7
  import { pruneToolResults } from "./emergency-prune.js";
7
8
  import { allowOverflowRetry, boundSummarizationInput, SUMMARIZATION_INPUT_BUDGET_RATIO, SummarizationOverflowExhaustedError, shrinkSummarizationInputForOverflowRetry, } from "./overflow-retry.js";
@@ -23,11 +24,12 @@ function approxTokens(text) {
23
24
  return Math.ceil(text.length / 4);
24
25
  }
25
26
  export class SummaryRequestError extends Error {
26
- constructor(message, transient, failureKind) {
27
+ constructor(message, transient, failureKind, refused = false) {
27
28
  super(message);
28
29
  this.name = "SummaryRequestError";
29
30
  this.transient = transient;
30
31
  this.failureKind = failureKind;
32
+ this.refused = refused;
31
33
  }
32
34
  }
33
35
  const UPSTREAM_STREAM_TRUNCATED_PATTERN = /(?:^|[^A-Za-z0-9_])upstream_stream_truncated(?:[^A-Za-z0-9_]|$)/;
@@ -35,7 +37,8 @@ const UPSTREAM_STREAM_TRUNCATED_PATTERN = /(?:^|[^A-Za-z0-9_])upstream_stream_tr
35
37
  * Only failures with no cheaper recovery earn another billed request.
36
38
  *
37
39
  * Every class that `classifyRequiredCompactionFallbackFailure` recognizes
38
- * (watchdog timeouts, `upstream-stream-truncated`, overflow exhaustion,
40
+ * (watchdog timeouts, the compaction-wide total budget, terminal provider and
41
+ * credential failures, `upstream-stream-truncated`, overflow exhaustion,
39
42
  * empty-summary generation failures) already
40
43
  * has a deterministic zero-LLM recovery, and context overflow is answered by
41
44
  * shrinking the input in the surrounding loop - replaying those would pay for a
@@ -46,18 +49,32 @@ const UPSTREAM_STREAM_TRUNCATED_PATTERN = /(?:^|[^A-Za-z0-9_])upstream_stream_tr
46
49
  function isRetryableSummaryAttempt(error) {
47
50
  if (error instanceof StreamDurationBudgetError || error instanceof StreamIdleTimeoutError)
48
51
  return false;
52
+ if (error instanceof SummarizationTotalBudgetError)
53
+ return false;
49
54
  if (error instanceof SummarizationOverflowExhaustedError)
50
55
  return false;
51
56
  if (error instanceof SummaryGenerationError)
52
57
  return false;
58
+ // Mirrors the `summarization-provider-failure` class: credential rotation has
59
+ // already spent every slot it may spend, and the marker means output was
60
+ // committed, so another billed attempt buys nothing the fallback cannot
61
+ // rebuild for free. Message text alone must not re-authorize it - the wrapped
62
+ // provider detail can read as transient (#1741).
63
+ if (error instanceof CredentialFailoverError)
64
+ return false;
65
+ if (error instanceof Error && error.message.startsWith(TURN_RETRY_SUPPRESSION_PREFIX))
66
+ return false;
53
67
  if (error instanceof SummaryRequestError)
54
68
  return error.failureKind === undefined && error.transient;
55
69
  if (error instanceof Error)
56
70
  return isRetryableErrorMessage(error.message);
57
71
  return false;
58
72
  }
73
+ function isRefusalStop(response) {
74
+ return response.stopDetails?.type === "refusal" || response.stopDetails?.type === "sensitive";
75
+ }
59
76
  function summaryRequestFailureKind(response) {
60
- if (response.stopDetails?.type === "refusal" || response.stopDetails?.type === "sensitive")
77
+ if (isRefusalStop(response))
61
78
  return undefined;
62
79
  return UPSTREAM_STREAM_TRUNCATED_PATTERN.test(response.errorMessage ?? "") ? "upstream-stream-truncated" : undefined;
63
80
  }
@@ -145,6 +162,10 @@ export async function runExtensionCompaction(context, snapshot, signal, onProgre
145
162
  });
146
163
  const promptTokens = approxTokens(prompt.user);
147
164
  let messages = boundSummarizationInput(pruneToolResults([...requestSnapshot.preparation.messagesToSummarize, ...requestSnapshot.preparation.turnPrefixMessages], requestSnapshot.contextWindow, SUMMARIZATION_INPUT_BUDGET_RATIO), requestSnapshot.contextWindow, promptTokens);
165
+ // One deadline for the whole compaction. The per-attempt budget scales with the
166
+ // input and every retry re-arms it, so without this a large session could hold
167
+ // the turn for attempt-budget x attempts with no bound the user can predict.
168
+ const deadline = createSummarizationDeadline(summarizationTotalBudgetMs(requestSnapshot.preparation.settings.summarizationMaxDurationMs));
148
169
  const overflowRetryStartMs = Date.now();
149
170
  let overflowAttempts = 0;
150
171
  const summarizationToolsOffered = (requestSnapshot.tools?.length ?? 0) > 0;
@@ -175,7 +196,9 @@ export async function runExtensionCompaction(context, snapshot, signal, onProgre
175
196
  const attempt = await generateSummaryMessage({
176
197
  context,
177
198
  forbidToolCalls: toolUseRetrySpent,
178
- maxDurationMs: attemptBudgetMs,
199
+ // Re-clamped per attempt, not per loop turn: a retry that starts
200
+ // near the deadline gets only what is left, and none starts past it.
201
+ maxDurationMs: deadline.attemptBudgetMs(attemptBudgetMs),
179
202
  messages: currentMessages,
180
203
  onProgress,
181
204
  prompt,
@@ -192,10 +215,11 @@ export async function runExtensionCompaction(context, snapshot, signal, onProgre
192
215
  attempt.stopReason === "error" &&
193
216
  !isContextOverflow(attempt, snapshot.contextWindow)) {
194
217
  const failureKind = summaryRequestFailureKind(attempt);
195
- throw new SummaryRequestError(attempt.errorMessage || "Compaction summary request failed", failureKind !== undefined || isRetryableAssistantError(attempt), failureKind);
218
+ throw new SummaryRequestError(attempt.errorMessage || "Compaction summary request failed", failureKind !== undefined || isRetryableAssistantError(attempt), failureKind, isRefusalStop(attempt));
196
219
  }
197
220
  return attempt;
198
221
  }, (error) => retryEligible &&
222
+ deadline.remainingMs() > 0 &&
199
223
  allowSummarizationRetry(Date.now() - retryStartedMs, attemptBudgetMs) &&
200
224
  isRetryableSummaryAttempt(error), DEFAULT_SUMMARIZATION_RETRY_POLICY, signal);
201
225
  }
@@ -228,7 +252,7 @@ export async function runExtensionCompaction(context, snapshot, signal, onProgre
228
252
  // truncation class here so downstream recovery never trusts arbitrary
229
253
  // thrown error text as authorization for destructive context reduction.
230
254
  const failureKind = summaryRequestFailureKind(response);
231
- throw new SummaryRequestError(response.errorMessage || "Compaction summary request failed", failureKind !== undefined || isRetryableAssistantError(response), failureKind);
255
+ throw new SummaryRequestError(response.errorMessage || "Compaction summary request failed", failureKind !== undefined || isRetryableAssistantError(response), failureKind, isRefusalStop(response));
232
256
  }
233
257
  const summary = getSummaryText(response);
234
258
  if (!summary) {
@@ -1 +1 @@
1
- {"version":3,"file":"speculative.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/speculative.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AssistantMessage,\n\thasCredentialHeaders,\n\tisContextOverflow,\n\tisRetryableAssistantError,\n\tisRetryableErrorMessage,\n\ttype Message,\n\ttype Model,\n\tretryTransientCall,\n\ttype Tool,\n} from \"@earendil-works/pi-ai\";\nimport {\n\ttype CompactionPreparation,\n\ttype CompactionResult,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tprepareCompaction,\n} from \"../../../compaction/index.ts\";\nimport {\n\tStreamDurationBudgetError,\n\tStreamIdleTimeoutError,\n\tsummarizationMaxDurationMs,\n} from \"../../../compaction/stream-watchdog.ts\";\nimport {\n\tcreateWarmAnchorSnapshot,\n\tisWarmSummaryAnchorValid,\n\ttype WarmAnchorSnapshot,\n} from \"../../../compaction/warm-anchor.ts\";\nimport { convertToLlm } from \"../../../messages.ts\";\nimport type { ModelRegistry } from \"../../../model-registry.ts\";\nimport type { ReadonlySessionManager } from \"../../../session-manager.ts\";\nimport type { ApplyCompactionResult, ContextUsage, ProviderRequestPreparation } from \"../../types.ts\";\nimport { pruneToolResults } from \"./emergency-prune.ts\";\nimport {\n\tallowOverflowRetry,\n\tboundSummarizationInput,\n\tSUMMARIZATION_INPUT_BUDGET_RATIO,\n\tSummarizationOverflowExhaustedError,\n\tshrinkSummarizationInputForOverflowRetry,\n} from \"./overflow-retry.ts\";\nimport { computeEffectiveKeepRecentTokens, computeEffectiveThreshold } from \"./policy.ts\";\nimport { buildPrompt, type MergedCompactionPromptVariant } from \"./prompts.ts\";\nimport { generateSummaryMessage, getSummaryText, isAssistantMessage } from \"./speculative-summary.ts\";\n\nimport { allowSummarizationRetry, DEFAULT_SUMMARIZATION_RETRY_POLICY } from \"./summarization-retry.ts\";\n\nimport { extractTaskIntent, resolveInheritedTaskIntent } from \"./task-intent.ts\";\n\nexport {\n\tcreateEmergencyPruneLatch,\n\ttype EmergencyPruneLatch,\n\thardLimitEmergencyPrune,\n\ttruncateContextMessages,\n} from \"./emergency-prune.ts\";\n\nimport { computeStructuralYield } from \"./yield.ts\";\n\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\n// Hysteresis: the emergency prune engages at EMERGENCY_CONTEXT_TARGET_RATIO but only\n// releases once the context falls below this lower ratio. A single threshold makes a\n// session parked near the limit alternate between the pruned and un-pruned history on\n// consecutive requests; because pruning rewrites old tool results, every alternation\n// invalidates the provider prompt-cache prefix and re-bills the whole conversation.\nconst SUMMARY_SCHEMA = \"senpi.compaction.summary.v1\";\ntype CompactionProgressCallback = (delta: string) => void;\n\nexport interface SpeculativeCompactionContext {\n\tmodel: Model<any> | undefined;\n\tsessionManager: ReadonlySessionManager;\n\tmodelRegistry?: ModelRegistry;\n\tgetContextUsage(): ContextUsage | undefined;\n\tgetCompactionSettings?(): CompactionPreparation[\"settings\"];\n\tgetMessageRevision(): number;\n\tgetSystemPrompt?(): string;\n\tprepareProviderRequest?(messages: AgentMessage[]): Promise<ProviderRequestPreparation>;\n\tisIdle?(): boolean;\n\tapplyCompaction(\n\t\tprecomputed: CompactionResult,\n\t\toptions: {\n\t\t\treason: \"extension\";\n\t\t\texpectedRevision?: number;\n\t\t\texpectedWarmAnchor?: WarmAnchorSnapshot;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<ApplyCompactionResult>;\n}\n\nexport interface SpeculativeCompactionSnapshot {\n\tgeneration: number;\n\texpectedRevision: number;\n\tmodel: Model<any>;\n\tcontextWindow: number;\n\tpreparation: CompactionPreparation;\n\tbranchEntries?: ReturnType<ReadonlySessionManager[\"getBranch\"]>;\n\tpromptVariant: MergedCompactionPromptVariant;\n\torigin?: \"speculative\" | \"blocking\" | \"core-route\";\n\tcustomInstructions?: string;\n\t/** Agent system prompt; used to make the summarization request look like normal agent traffic. */\n\tsystemPrompt?: string;\n\t/** Agent tool definitions; forwarded so the request shape matches normal agent traffic. */\n\ttools?: Tool[];\n}\n\nexport type SpeculativeCompactionResult = ApplyCompactionResult | { applied: false; reason: \"unavailable\" | \"failed\" };\n\nfunction approxTokens(text: string): number {\n\treturn Math.ceil(text.length / 4);\n}\n\n/**\n * Summary-generation failure with a user-facing diagnosis. Distinct from a\n * user abort (which resolves `undefined`): callers surface `message` on the\n * manual route and degrade to \"unavailable\" on automatic routes.\n */\n/**\n * Provider `error` stop during summarization, carrying the metadata-aware\n * transient classification from the full assistant message. A refusal whose\n * text happens to look retryable must still surface loudly; the message\n * string alone cannot encode that.\n */\nexport type SummaryRequestFailureKind = \"upstream-stream-truncated\";\n\nexport class SummaryRequestError extends Error {\n\treadonly transient: boolean;\n\treadonly failureKind?: SummaryRequestFailureKind;\n\n\tconstructor(message: string, transient: boolean, failureKind?: SummaryRequestFailureKind) {\n\t\tsuper(message);\n\t\tthis.name = \"SummaryRequestError\";\n\t\tthis.transient = transient;\n\t\tthis.failureKind = failureKind;\n\t}\n}\n\nconst UPSTREAM_STREAM_TRUNCATED_PATTERN = /(?:^|[^A-Za-z0-9_])upstream_stream_truncated(?:[^A-Za-z0-9_]|$)/;\n\n/**\n * Only failures with no cheaper recovery earn another billed request.\n *\n * Every class that `classifyRequiredCompactionFallbackFailure` recognizes\n * (watchdog timeouts, `upstream-stream-truncated`, overflow exhaustion,\n * empty-summary generation failures) already\n * has a deterministic zero-LLM recovery, and context overflow is answered by\n * shrinking the input in the surrounding loop - replaying those would pay for a\n * summarization the fallback can rebuild for free. The classes checked here are\n * mirrored from that classifier rather than imported, because\n * `deterministic-fallback.ts` imports this module.\n */\nfunction isRetryableSummaryAttempt(error: unknown): boolean {\n\tif (error instanceof StreamDurationBudgetError || error instanceof StreamIdleTimeoutError) return false;\n\tif (error instanceof SummarizationOverflowExhaustedError) return false;\n\tif (error instanceof SummaryGenerationError) return false;\n\tif (error instanceof SummaryRequestError) return error.failureKind === undefined && error.transient;\n\tif (error instanceof Error) return isRetryableErrorMessage(error.message);\n\treturn false;\n}\n\nfunction summaryRequestFailureKind(response: AssistantMessage): SummaryRequestFailureKind | undefined {\n\tif (response.stopDetails?.type === \"refusal\" || response.stopDetails?.type === \"sensitive\") return undefined;\n\treturn UPSTREAM_STREAM_TRUNCATED_PATTERN.test(response.errorMessage ?? \"\") ? \"upstream-stream-truncated\" : undefined;\n}\n\nexport class SummaryGenerationError extends Error {\n\treadonly kind: \"auth\" | \"empty-summary\";\n\n\tconstructor(kind: \"auth\" | \"empty-summary\", message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"SummaryGenerationError\";\n\t\tthis.kind = kind;\n\t}\n}\n\n/**\n * Output budget for one summarization request. Adaptive-thinking models emit\n * reasoning tokens before the summary text, so the legacy flat 8192 cap could\n * be consumed entirely by thinking, ending the stream with zero text blocks.\n * Grant generous headroom, clamped to what the model can actually emit and to\n * half the context window: providers that enforce input + output <= window\n * would otherwise reject the request for models advertising contextWindow ==\n * maxTokens (every summarization request also carries conversation input).\n */\n\nexport function getPromptVariant(options: {\n\treason: string;\n\tpreparation: { previousSummary?: string; isSplitTurn: boolean };\n}): MergedCompactionPromptVariant {\n\tif (options.reason === \"branch\") return \"branch\";\n\tif (options.preparation.previousSummary) return \"update\";\n\tif (options.preparation.isSplitTurn) return \"turn_prefix\";\n\treturn \"default\";\n}\n\nexport function createSpeculativeCompactionSnapshot(\n\tcontext: SpeculativeCompactionContext,\n\toptions: {\n\t\tcustomInstructions?: string;\n\t\tgeneration: number;\n\t\torigin?: \"speculative\" | \"blocking\" | \"core-route\";\n\t\ttools?: Tool[];\n\t},\n): SpeculativeCompactionSnapshot | undefined {\n\tconst model = context.model;\n\tif (!model) return undefined;\n\n\tconst expectedRevision = context.getMessageRevision();\n\tconst branchEntries = context.sessionManager.getBranch();\n\tconst contextWindow = context.getContextUsage()?.contextWindow ?? model.contextWindow ?? DEFAULT_CONTEXT_WINDOW;\n\tconst settings = context.getCompactionSettings?.() ?? DEFAULT_COMPACTION_SETTINGS;\n\tconst thresholdRatio = computeEffectiveThreshold(contextWindow);\n\tconst preparation = prepareCompaction(branchEntries, {\n\t\t...settings,\n\t\tkeepRecentTokens: computeEffectiveKeepRecentTokens(settings.keepRecentTokens, contextWindow, thresholdRatio),\n\t});\n\tif (!preparation) return undefined;\n\n\treturn {\n\t\t...options,\n\t\texpectedRevision,\n\t\tmodel,\n\t\tcontextWindow,\n\t\tpreparation,\n\t\tbranchEntries,\n\t\tpromptVariant: getPromptVariant({ reason: \"extension\", preparation }),\n\t\tsystemPrompt: context.getSystemPrompt?.(),\n\t};\n}\n\n/**\n * Generate a compaction summary for the snapshot. Resolves `undefined` only\n * when the request was aborted (caller signal or an aborted stream); every\n * other failure throws — {@link SummaryGenerationError} for diagnosable\n * generation failures, the raw provider error otherwise. Abort is checked\n * before and after credential resolution so a cancelled request never\n * misreports as an auth failure.\n */\nexport async function runExtensionCompaction(\n\tcontext: SpeculativeCompactionContext,\n\tsnapshot: SpeculativeCompactionSnapshot,\n\tsignal?: AbortSignal,\n\tonProgress?: CompactionProgressCallback,\n): Promise<CompactionResult | undefined> {\n\tif (signal?.aborted) return undefined;\n\tconst auth = await context.modelRegistry?.getApiKeyAndHeaders(snapshot.model);\n\tif (signal?.aborted) return undefined;\n\t// A provider is authenticated for summarization by either a resolved key or a\n\t// credential request header: `headers`-authenticated providers (models.json and\n\t// extension providers alike) never resolve an apiKey, yet their normal agent\n\t// turns are fully authenticated.\n\tif (!auth?.ok || !(auth.apiKey || hasCredentialHeaders(auth.headers))) {\n\t\tconst detail =\n\t\t\tauth && !auth.ok ? auth.error : `no credentials resolved for provider \"${snapshot.model.provider}\"`;\n\t\tthrow new SummaryGenerationError(\"auth\", `summarization credentials unavailable: ${detail}`);\n\t}\n\tconst requestSnapshot = auth.baseUrl\n\t\t? { ...snapshot, model: { ...snapshot.model, baseUrl: auth.baseUrl } }\n\t\t: snapshot;\n\n\tconst prompt = buildPrompt({\n\t\tvariant: requestSnapshot.promptVariant,\n\t\tpreviousSummary: requestSnapshot.preparation.previousSummary,\n\t\ttaskIntent: resolveInheritedTaskIntent(requestSnapshot.branchEntries ?? []),\n\t\tcustomInstructions: requestSnapshot.customInstructions,\n\t});\n\tconst promptTokens = approxTokens(prompt.user);\n\tlet messages = boundSummarizationInput(\n\t\tpruneToolResults(\n\t\t\t[...requestSnapshot.preparation.messagesToSummarize, ...requestSnapshot.preparation.turnPrefixMessages],\n\t\t\trequestSnapshot.contextWindow,\n\t\t\tSUMMARIZATION_INPUT_BUDGET_RATIO,\n\t\t),\n\t\trequestSnapshot.contextWindow,\n\t\tpromptTokens,\n\t);\n\tconst overflowRetryStartMs = Date.now();\n\tlet overflowAttempts = 0;\n\tconst summarizationToolsOffered = (requestSnapshot.tools?.length ?? 0) > 0;\n\tlet toolUseRetrySpent = false;\n\n\twhile (true) {\n\t\tif (signal?.aborted) return undefined;\n\t\tlet response: Message | undefined;\n\t\tconst currentMessages = messages;\n\t\tconst retryStartedMs = Date.now();\n\t\t// Only the routes that block the user's turn retry here. The speculative\n\t\t// warm-up owns its own bounded retry (`idle-retry.ts`) with idle/breaker\n\t\t// guards re-evaluated between attempts, and a failed warm job must stay\n\t\t// inheritable so the next blocking route degrades on it instead of paying\n\t\t// for a second request.\n\t\tconst retryEligible = snapshot.origin === \"core-route\" || snapshot.origin === \"blocking\";\n\t\t// The attempt budget and the retry gate share one input-size-scaled number,\n\t\t// so a large session gets both a proportional attempt deadline and room to\n\t\t// retry transient failures without the 120s-era retry budget disqualifying\n\t\t// every slow attempt (#1068).\n\t\tconst attemptBudgetMs = summarizationMaxDurationMs(\n\t\t\tmessages.reduce((total, message) => total + estimateTokens(message), 0),\n\t\t\tsnapshot.preparation.settings.summarizationMaxDurationMs,\n\t\t);\n\t\ttry {\n\t\t\t// The provider `error` stop is raised INSIDE the retried producer so a\n\t\t\t// transient summarization failure spends the shared retry budget. The\n\t\t\t// surrounding loop keeps overflow shrinking and abort handling, which\n\t\t\t// must never be answered by replaying the same request.\n\t\t\tresponse = await retryTransientCall(\n\t\t\t\tasync () => {\n\t\t\t\t\tconst attempt = await generateSummaryMessage({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tforbidToolCalls: toolUseRetrySpent,\n\t\t\t\t\t\tmaxDurationMs: attemptBudgetMs,\n\t\t\t\t\t\tmessages: currentMessages,\n\t\t\t\t\t\tonProgress,\n\t\t\t\t\t\tprompt,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tsnapshot: requestSnapshot,\n\t\t\t\t\t\tauth: {\n\t\t\t\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\t\t\t\theaders: auth.headers,\n\t\t\t\t\t\t\textraBody: auth.extraBody,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tif (\n\t\t\t\t\t\tattempt &&\n\t\t\t\t\t\tisAssistantMessage(attempt) &&\n\t\t\t\t\t\tattempt.stopReason === \"error\" &&\n\t\t\t\t\t\t!isContextOverflow(attempt, snapshot.contextWindow)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst failureKind = summaryRequestFailureKind(attempt);\n\t\t\t\t\t\tthrow new SummaryRequestError(\n\t\t\t\t\t\t\tattempt.errorMessage || \"Compaction summary request failed\",\n\t\t\t\t\t\t\tfailureKind !== undefined || isRetryableAssistantError(attempt),\n\t\t\t\t\t\t\tfailureKind,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn attempt;\n\t\t\t\t},\n\t\t\t\t(error) =>\n\t\t\t\t\tretryEligible &&\n\t\t\t\t\tallowSummarizationRetry(Date.now() - retryStartedMs, attemptBudgetMs) &&\n\t\t\t\t\tisRetryableSummaryAttempt(error),\n\t\t\t\tDEFAULT_SUMMARIZATION_RETRY_POLICY,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted) return undefined;\n\t\t\tthrow error;\n\t\t}\n\t\tif (!response) return undefined;\n\n\t\tif (isAssistantMessage(response) && isContextOverflow(response, snapshot.contextWindow)) {\n\t\t\toverflowAttempts++;\n\t\t\tconst elapsedMs = Date.now() - overflowRetryStartMs;\n\t\t\tconst retryMessages = allowOverflowRetry(overflowAttempts, elapsedMs)\n\t\t\t\t? shrinkSummarizationInputForOverflowRetry(messages, snapshot.contextWindow, promptTokens)\n\t\t\t\t: undefined;\n\t\t\tif (!retryMessages) {\n\t\t\t\tthrow new SummarizationOverflowExhaustedError(overflowAttempts, elapsedMs);\n\t\t\t}\n\t\t\tmessages = retryMessages;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isAssistantMessage(response) && response.stopReason === \"aborted\") {\n\t\t\t// A partial summary from an aborted stream must never be applied.\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (isAssistantMessage(response) && response.stopReason === \"error\") {\n\t\t\t// Surface the real provider failure instead of silently degrading\n\t\t\t// into a generic \"Compaction cancelled\". Preserve the structured\n\t\t\t// truncation class here so downstream recovery never trusts arbitrary\n\t\t\t// thrown error text as authorization for destructive context reduction.\n\t\t\tconst failureKind = summaryRequestFailureKind(response);\n\t\t\tthrow new SummaryRequestError(\n\t\t\t\tresponse.errorMessage || \"Compaction summary request failed\",\n\t\t\t\tfailureKind !== undefined || isRetryableAssistantError(response),\n\t\t\t\tfailureKind,\n\t\t\t);\n\t\t}\n\n\t\tconst summary = getSummaryText(response);\n\t\tif (!summary) {\n\t\t\tconst stopReason = isAssistantMessage(response) ? response.stopReason : \"unknown\";\n\t\t\t// A summarizer can hijack the forwarded agent tools and answer with a\n\t\t\t// bare tool call (observed on openai-codex gpt-5.6-sol, 2026-08-31),\n\t\t\t// which used to surface as a terminal empty-summary failure. Spend one\n\t\t\t// retry with tool calling forbidden; the tools stay in the request\n\t\t\t// because Anthropic rejects tool_use history without the tools param.\n\t\t\tif (stopReason === \"toolUse\" && summarizationToolsOffered && !toolUseRetrySpent) {\n\t\t\t\ttoolUseRetrySpent = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthrow new SummaryGenerationError(\n\t\t\t\t\"empty-summary\",\n\t\t\t\t`summarization response contained no text (stopReason: ${stopReason})`,\n\t\t\t);\n\t\t}\n\n\t\t// Informational only: the core rejects an applied compaction that would\n\t\t// still overflow (_wouldCompactionOverflow). Rejecting here based on the\n\t\t// size of the *discarded* input made large sessions uncompactable.\n\t\tconst tokenEstimate = estimateContextTokens(convertToLlm(messages)).tokens + approxTokens(summary);\n\t\tconst parsedSummary = extractTaskIntent(summary);\n\t\tconst taskIntent = parsedSummary.taskIntent ?? resolveInheritedTaskIntent(snapshot.branchEntries ?? []);\n\n\t\treturn {\n\t\t\tsummary: parsedSummary.summaryText,\n\t\t\tfirstKeptEntryId: snapshot.preparation.firstKeptEntryId,\n\t\t\ttokensBefore: snapshot.preparation.tokensBefore,\n\t\t\tdetails: {\n\t\t\t\tschema: SUMMARY_SCHEMA,\n\t\t\t\tpromptVariant: snapshot.promptVariant,\n\t\t\t\ttokenEstimate,\n\t\t\t\tstructuralYield: computeStructuralYield({\n\t\t\t\t\tpreviousSummary: snapshot.preparation.previousSummary ?? \"\",\n\t\t\t\t\tmessagesToSummarize: snapshot.preparation.messagesToSummarize,\n\t\t\t\t\tturnPrefixMessages: snapshot.preparation.turnPrefixMessages,\n\t\t\t\t\tsummary: parsedSummary.summaryText,\n\t\t\t\t\ttokensBefore: snapshot.preparation.tokensBefore,\n\t\t\t\t}),\n\t\t\t\t...(snapshot.origin ? { origin: snapshot.origin } : {}),\n\t\t\t\t...(taskIntent ? { taskIntent } : {}),\n\t\t\t},\n\t\t};\n\t}\n}\n\nexport async function applyGeneratedCompaction(\n\tcontext: SpeculativeCompactionContext,\n\tsnapshot: SpeculativeCompactionSnapshot | undefined,\n\tgetCurrentGeneration: () => number,\n\tcompaction: CompactionResult | undefined,\n\tsignal?: AbortSignal,\n): Promise<SpeculativeCompactionResult> {\n\tconst provider = context.model?.provider;\n\tif ((provider === \"cursor\" || provider === \"cursor-cli-oauth\") && context.isIdle && !context.isIdle()) {\n\t\treturn { applied: false, reason: \"rejected\" };\n\t}\n\tif (!snapshot || !compaction) return { applied: false, reason: \"unavailable\" };\n\n\tif (snapshot.generation !== getCurrentGeneration()) {\n\t\treturn { applied: false, reason: \"stale\" };\n\t}\n\n\tconst revisionUnchanged = snapshot.expectedRevision === context.getMessageRevision();\n\tconst warmAnchor = createWarmAnchorSnapshot(snapshot.preparation.firstKeptEntryId, snapshot.branchEntries ?? []);\n\tif (\n\t\t!revisionUnchanged &&\n\t\t(!warmAnchor || !isWarmSummaryAnchorValid(warmAnchor, context.sessionManager.getBranch()))\n\t) {\n\t\treturn { applied: false, reason: \"stale\" };\n\t}\n\n\treturn await context.applyCompaction(compaction, {\n\t\treason: \"extension\",\n\t\t...(revisionUnchanged || !warmAnchor\n\t\t\t? { expectedRevision: snapshot.expectedRevision }\n\t\t\t: { expectedWarmAnchor: warmAnchor }),\n\t\tsignal,\n\t});\n}\n\nexport async function applySpeculativeCompaction(\n\tcontext: SpeculativeCompactionContext,\n\tsnapshot: SpeculativeCompactionSnapshot | undefined,\n\tgetCurrentGeneration: () => number,\n\tgenerate: () => Promise<CompactionResult | undefined>,\n): Promise<SpeculativeCompactionResult> {\n\tif (!snapshot) return { applied: false, reason: \"unavailable\" };\n\n\tconst compaction = await generate();\n\treturn await applyGeneratedCompaction(context, snapshot, getCurrentGeneration, compaction);\n}\n"]}
1
+ {"version":3,"file":"speculative.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/speculative.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AssistantMessage,\n\thasCredentialHeaders,\n\tisContextOverflow,\n\tisRetryableAssistantError,\n\tisRetryableErrorMessage,\n\ttype Message,\n\ttype Model,\n\tretryTransientCall,\n\ttype Tool,\n} from \"@earendil-works/pi-ai\";\nimport {\n\ttype CompactionPreparation,\n\ttype CompactionResult,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tprepareCompaction,\n} from \"../../../compaction/index.ts\";\nimport {\n\tcreateSummarizationDeadline,\n\tStreamDurationBudgetError,\n\tStreamIdleTimeoutError,\n\tSummarizationTotalBudgetError,\n\tsummarizationMaxDurationMs,\n\tsummarizationTotalBudgetMs,\n} from \"../../../compaction/stream-watchdog.ts\";\nimport {\n\tcreateWarmAnchorSnapshot,\n\tisWarmSummaryAnchorValid,\n\ttype WarmAnchorSnapshot,\n} from \"../../../compaction/warm-anchor.ts\";\nimport { CredentialFailoverError, TURN_RETRY_SUPPRESSION_PREFIX } from \"../../../credential-pool/failover.ts\";\nimport { convertToLlm } from \"../../../messages.ts\";\nimport type { ModelRegistry } from \"../../../model-registry.ts\";\nimport type { ReadonlySessionManager } from \"../../../session-manager.ts\";\nimport type { ApplyCompactionResult, ContextUsage, ProviderRequestPreparation } from \"../../types.ts\";\nimport { pruneToolResults } from \"./emergency-prune.ts\";\nimport {\n\tallowOverflowRetry,\n\tboundSummarizationInput,\n\tSUMMARIZATION_INPUT_BUDGET_RATIO,\n\tSummarizationOverflowExhaustedError,\n\tshrinkSummarizationInputForOverflowRetry,\n} from \"./overflow-retry.ts\";\nimport { computeEffectiveKeepRecentTokens, computeEffectiveThreshold } from \"./policy.ts\";\nimport { buildPrompt, type MergedCompactionPromptVariant } from \"./prompts.ts\";\nimport { generateSummaryMessage, getSummaryText, isAssistantMessage } from \"./speculative-summary.ts\";\n\nimport { allowSummarizationRetry, DEFAULT_SUMMARIZATION_RETRY_POLICY } from \"./summarization-retry.ts\";\n\nimport { extractTaskIntent, resolveInheritedTaskIntent } from \"./task-intent.ts\";\n\nexport {\n\tcreateEmergencyPruneLatch,\n\ttype EmergencyPruneLatch,\n\thardLimitEmergencyPrune,\n\ttruncateContextMessages,\n} from \"./emergency-prune.ts\";\n\nimport { computeStructuralYield } from \"./yield.ts\";\n\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\n// Hysteresis: the emergency prune engages at EMERGENCY_CONTEXT_TARGET_RATIO but only\n// releases once the context falls below this lower ratio. A single threshold makes a\n// session parked near the limit alternate between the pruned and un-pruned history on\n// consecutive requests; because pruning rewrites old tool results, every alternation\n// invalidates the provider prompt-cache prefix and re-bills the whole conversation.\nconst SUMMARY_SCHEMA = \"senpi.compaction.summary.v1\";\ntype CompactionProgressCallback = (delta: string) => void;\n\nexport interface SpeculativeCompactionContext {\n\tmodel: Model<any> | undefined;\n\tsessionManager: ReadonlySessionManager;\n\tmodelRegistry?: ModelRegistry;\n\tgetContextUsage(): ContextUsage | undefined;\n\tgetCompactionSettings?(): CompactionPreparation[\"settings\"];\n\tgetMessageRevision(): number;\n\tgetSystemPrompt?(): string;\n\tprepareProviderRequest?(messages: AgentMessage[]): Promise<ProviderRequestPreparation>;\n\tisIdle?(): boolean;\n\tapplyCompaction(\n\t\tprecomputed: CompactionResult,\n\t\toptions: {\n\t\t\treason: \"extension\";\n\t\t\texpectedRevision?: number;\n\t\t\texpectedWarmAnchor?: WarmAnchorSnapshot;\n\t\t\tsignal?: AbortSignal;\n\t\t},\n\t): Promise<ApplyCompactionResult>;\n}\n\nexport interface SpeculativeCompactionSnapshot {\n\tgeneration: number;\n\texpectedRevision: number;\n\tmodel: Model<any>;\n\tcontextWindow: number;\n\tpreparation: CompactionPreparation;\n\tbranchEntries?: ReturnType<ReadonlySessionManager[\"getBranch\"]>;\n\tpromptVariant: MergedCompactionPromptVariant;\n\torigin?: \"speculative\" | \"blocking\" | \"core-route\";\n\tcustomInstructions?: string;\n\t/** Agent system prompt; used to make the summarization request look like normal agent traffic. */\n\tsystemPrompt?: string;\n\t/** Agent tool definitions; forwarded so the request shape matches normal agent traffic. */\n\ttools?: Tool[];\n}\n\nexport type SpeculativeCompactionResult = ApplyCompactionResult | { applied: false; reason: \"unavailable\" | \"failed\" };\n\nfunction approxTokens(text: string): number {\n\treturn Math.ceil(text.length / 4);\n}\n\n/**\n * Summary-generation failure with a user-facing diagnosis. Distinct from a\n * user abort (which resolves `undefined`): callers surface `message` on the\n * manual route and degrade to \"unavailable\" on automatic routes.\n */\n/**\n * Provider `error` stop during summarization, carrying the metadata-aware\n * transient classification from the full assistant message. A refusal whose\n * text happens to look retryable must still surface loudly; the message\n * string alone cannot encode that.\n */\nexport type SummaryRequestFailureKind = \"upstream-stream-truncated\";\n\nexport class SummaryRequestError extends Error {\n\treadonly transient: boolean;\n\treadonly failureKind?: SummaryRequestFailureKind;\n\t/**\n\t * The provider refused the request (refusal/sensitive stop details) rather\n\t * than failing it. Carried explicitly because the message text cannot encode\n\t * it, and because a refusal must never authorize destructive context\n\t * reduction: dropping older detail would not make the model comply.\n\t */\n\treadonly refused: boolean;\n\n\tconstructor(message: string, transient: boolean, failureKind?: SummaryRequestFailureKind, refused = false) {\n\t\tsuper(message);\n\t\tthis.name = \"SummaryRequestError\";\n\t\tthis.transient = transient;\n\t\tthis.failureKind = failureKind;\n\t\tthis.refused = refused;\n\t}\n}\n\nconst UPSTREAM_STREAM_TRUNCATED_PATTERN = /(?:^|[^A-Za-z0-9_])upstream_stream_truncated(?:[^A-Za-z0-9_]|$)/;\n\n/**\n * Only failures with no cheaper recovery earn another billed request.\n *\n * Every class that `classifyRequiredCompactionFallbackFailure` recognizes\n * (watchdog timeouts, the compaction-wide total budget, terminal provider and\n * credential failures, `upstream-stream-truncated`, overflow exhaustion,\n * empty-summary generation failures) already\n * has a deterministic zero-LLM recovery, and context overflow is answered by\n * shrinking the input in the surrounding loop - replaying those would pay for a\n * summarization the fallback can rebuild for free. The classes checked here are\n * mirrored from that classifier rather than imported, because\n * `deterministic-fallback.ts` imports this module.\n */\nfunction isRetryableSummaryAttempt(error: unknown): boolean {\n\tif (error instanceof StreamDurationBudgetError || error instanceof StreamIdleTimeoutError) return false;\n\tif (error instanceof SummarizationTotalBudgetError) return false;\n\tif (error instanceof SummarizationOverflowExhaustedError) return false;\n\tif (error instanceof SummaryGenerationError) return false;\n\t// Mirrors the `summarization-provider-failure` class: credential rotation has\n\t// already spent every slot it may spend, and the marker means output was\n\t// committed, so another billed attempt buys nothing the fallback cannot\n\t// rebuild for free. Message text alone must not re-authorize it - the wrapped\n\t// provider detail can read as transient (#1741).\n\tif (error instanceof CredentialFailoverError) return false;\n\tif (error instanceof Error && error.message.startsWith(TURN_RETRY_SUPPRESSION_PREFIX)) return false;\n\tif (error instanceof SummaryRequestError) return error.failureKind === undefined && error.transient;\n\tif (error instanceof Error) return isRetryableErrorMessage(error.message);\n\treturn false;\n}\n\nfunction isRefusalStop(response: AssistantMessage): boolean {\n\treturn response.stopDetails?.type === \"refusal\" || response.stopDetails?.type === \"sensitive\";\n}\n\nfunction summaryRequestFailureKind(response: AssistantMessage): SummaryRequestFailureKind | undefined {\n\tif (isRefusalStop(response)) return undefined;\n\treturn UPSTREAM_STREAM_TRUNCATED_PATTERN.test(response.errorMessage ?? \"\") ? \"upstream-stream-truncated\" : undefined;\n}\n\nexport class SummaryGenerationError extends Error {\n\treadonly kind: \"auth\" | \"empty-summary\";\n\n\tconstructor(kind: \"auth\" | \"empty-summary\", message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"SummaryGenerationError\";\n\t\tthis.kind = kind;\n\t}\n}\n\n/**\n * Output budget for one summarization request. Adaptive-thinking models emit\n * reasoning tokens before the summary text, so the legacy flat 8192 cap could\n * be consumed entirely by thinking, ending the stream with zero text blocks.\n * Grant generous headroom, clamped to what the model can actually emit and to\n * half the context window: providers that enforce input + output <= window\n * would otherwise reject the request for models advertising contextWindow ==\n * maxTokens (every summarization request also carries conversation input).\n */\n\nexport function getPromptVariant(options: {\n\treason: string;\n\tpreparation: { previousSummary?: string; isSplitTurn: boolean };\n}): MergedCompactionPromptVariant {\n\tif (options.reason === \"branch\") return \"branch\";\n\tif (options.preparation.previousSummary) return \"update\";\n\tif (options.preparation.isSplitTurn) return \"turn_prefix\";\n\treturn \"default\";\n}\n\nexport function createSpeculativeCompactionSnapshot(\n\tcontext: SpeculativeCompactionContext,\n\toptions: {\n\t\tcustomInstructions?: string;\n\t\tgeneration: number;\n\t\torigin?: \"speculative\" | \"blocking\" | \"core-route\";\n\t\ttools?: Tool[];\n\t},\n): SpeculativeCompactionSnapshot | undefined {\n\tconst model = context.model;\n\tif (!model) return undefined;\n\n\tconst expectedRevision = context.getMessageRevision();\n\tconst branchEntries = context.sessionManager.getBranch();\n\tconst contextWindow = context.getContextUsage()?.contextWindow ?? model.contextWindow ?? DEFAULT_CONTEXT_WINDOW;\n\tconst settings = context.getCompactionSettings?.() ?? DEFAULT_COMPACTION_SETTINGS;\n\tconst thresholdRatio = computeEffectiveThreshold(contextWindow);\n\tconst preparation = prepareCompaction(branchEntries, {\n\t\t...settings,\n\t\tkeepRecentTokens: computeEffectiveKeepRecentTokens(settings.keepRecentTokens, contextWindow, thresholdRatio),\n\t});\n\tif (!preparation) return undefined;\n\n\treturn {\n\t\t...options,\n\t\texpectedRevision,\n\t\tmodel,\n\t\tcontextWindow,\n\t\tpreparation,\n\t\tbranchEntries,\n\t\tpromptVariant: getPromptVariant({ reason: \"extension\", preparation }),\n\t\tsystemPrompt: context.getSystemPrompt?.(),\n\t};\n}\n\n/**\n * Generate a compaction summary for the snapshot. Resolves `undefined` only\n * when the request was aborted (caller signal or an aborted stream); every\n * other failure throws — {@link SummaryGenerationError} for diagnosable\n * generation failures, the raw provider error otherwise. Abort is checked\n * before and after credential resolution so a cancelled request never\n * misreports as an auth failure.\n */\nexport async function runExtensionCompaction(\n\tcontext: SpeculativeCompactionContext,\n\tsnapshot: SpeculativeCompactionSnapshot,\n\tsignal?: AbortSignal,\n\tonProgress?: CompactionProgressCallback,\n): Promise<CompactionResult | undefined> {\n\tif (signal?.aborted) return undefined;\n\tconst auth = await context.modelRegistry?.getApiKeyAndHeaders(snapshot.model);\n\tif (signal?.aborted) return undefined;\n\t// A provider is authenticated for summarization by either a resolved key or a\n\t// credential request header: `headers`-authenticated providers (models.json and\n\t// extension providers alike) never resolve an apiKey, yet their normal agent\n\t// turns are fully authenticated.\n\tif (!auth?.ok || !(auth.apiKey || hasCredentialHeaders(auth.headers))) {\n\t\tconst detail =\n\t\t\tauth && !auth.ok ? auth.error : `no credentials resolved for provider \"${snapshot.model.provider}\"`;\n\t\tthrow new SummaryGenerationError(\"auth\", `summarization credentials unavailable: ${detail}`);\n\t}\n\tconst requestSnapshot = auth.baseUrl\n\t\t? { ...snapshot, model: { ...snapshot.model, baseUrl: auth.baseUrl } }\n\t\t: snapshot;\n\n\tconst prompt = buildPrompt({\n\t\tvariant: requestSnapshot.promptVariant,\n\t\tpreviousSummary: requestSnapshot.preparation.previousSummary,\n\t\ttaskIntent: resolveInheritedTaskIntent(requestSnapshot.branchEntries ?? []),\n\t\tcustomInstructions: requestSnapshot.customInstructions,\n\t});\n\tconst promptTokens = approxTokens(prompt.user);\n\tlet messages = boundSummarizationInput(\n\t\tpruneToolResults(\n\t\t\t[...requestSnapshot.preparation.messagesToSummarize, ...requestSnapshot.preparation.turnPrefixMessages],\n\t\t\trequestSnapshot.contextWindow,\n\t\t\tSUMMARIZATION_INPUT_BUDGET_RATIO,\n\t\t),\n\t\trequestSnapshot.contextWindow,\n\t\tpromptTokens,\n\t);\n\t// One deadline for the whole compaction. The per-attempt budget scales with the\n\t// input and every retry re-arms it, so without this a large session could hold\n\t// the turn for attempt-budget x attempts with no bound the user can predict.\n\tconst deadline = createSummarizationDeadline(\n\t\tsummarizationTotalBudgetMs(requestSnapshot.preparation.settings.summarizationMaxDurationMs),\n\t);\n\tconst overflowRetryStartMs = Date.now();\n\tlet overflowAttempts = 0;\n\tconst summarizationToolsOffered = (requestSnapshot.tools?.length ?? 0) > 0;\n\tlet toolUseRetrySpent = false;\n\n\twhile (true) {\n\t\tif (signal?.aborted) return undefined;\n\t\tlet response: Message | undefined;\n\t\tconst currentMessages = messages;\n\t\tconst retryStartedMs = Date.now();\n\t\t// Only the routes that block the user's turn retry here. The speculative\n\t\t// warm-up owns its own bounded retry (`idle-retry.ts`) with idle/breaker\n\t\t// guards re-evaluated between attempts, and a failed warm job must stay\n\t\t// inheritable so the next blocking route degrades on it instead of paying\n\t\t// for a second request.\n\t\tconst retryEligible = snapshot.origin === \"core-route\" || snapshot.origin === \"blocking\";\n\t\t// The attempt budget and the retry gate share one input-size-scaled number,\n\t\t// so a large session gets both a proportional attempt deadline and room to\n\t\t// retry transient failures without the 120s-era retry budget disqualifying\n\t\t// every slow attempt (#1068).\n\t\tconst attemptBudgetMs = summarizationMaxDurationMs(\n\t\t\tmessages.reduce((total, message) => total + estimateTokens(message), 0),\n\t\t\tsnapshot.preparation.settings.summarizationMaxDurationMs,\n\t\t);\n\t\ttry {\n\t\t\t// The provider `error` stop is raised INSIDE the retried producer so a\n\t\t\t// transient summarization failure spends the shared retry budget. The\n\t\t\t// surrounding loop keeps overflow shrinking and abort handling, which\n\t\t\t// must never be answered by replaying the same request.\n\t\t\tresponse = await retryTransientCall(\n\t\t\t\tasync () => {\n\t\t\t\t\tconst attempt = await generateSummaryMessage({\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\tforbidToolCalls: toolUseRetrySpent,\n\t\t\t\t\t\t// Re-clamped per attempt, not per loop turn: a retry that starts\n\t\t\t\t\t\t// near the deadline gets only what is left, and none starts past it.\n\t\t\t\t\t\tmaxDurationMs: deadline.attemptBudgetMs(attemptBudgetMs),\n\t\t\t\t\t\tmessages: currentMessages,\n\t\t\t\t\t\tonProgress,\n\t\t\t\t\t\tprompt,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tsnapshot: requestSnapshot,\n\t\t\t\t\t\tauth: {\n\t\t\t\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\t\t\t\theaders: auth.headers,\n\t\t\t\t\t\t\textraBody: auth.extraBody,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tif (\n\t\t\t\t\t\tattempt &&\n\t\t\t\t\t\tisAssistantMessage(attempt) &&\n\t\t\t\t\t\tattempt.stopReason === \"error\" &&\n\t\t\t\t\t\t!isContextOverflow(attempt, snapshot.contextWindow)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst failureKind = summaryRequestFailureKind(attempt);\n\t\t\t\t\t\tthrow new SummaryRequestError(\n\t\t\t\t\t\t\tattempt.errorMessage || \"Compaction summary request failed\",\n\t\t\t\t\t\t\tfailureKind !== undefined || isRetryableAssistantError(attempt),\n\t\t\t\t\t\t\tfailureKind,\n\t\t\t\t\t\t\tisRefusalStop(attempt),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn attempt;\n\t\t\t\t},\n\t\t\t\t(error) =>\n\t\t\t\t\tretryEligible &&\n\t\t\t\t\tdeadline.remainingMs() > 0 &&\n\t\t\t\t\tallowSummarizationRetry(Date.now() - retryStartedMs, attemptBudgetMs) &&\n\t\t\t\t\tisRetryableSummaryAttempt(error),\n\t\t\t\tDEFAULT_SUMMARIZATION_RETRY_POLICY,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted) return undefined;\n\t\t\tthrow error;\n\t\t}\n\t\tif (!response) return undefined;\n\n\t\tif (isAssistantMessage(response) && isContextOverflow(response, snapshot.contextWindow)) {\n\t\t\toverflowAttempts++;\n\t\t\tconst elapsedMs = Date.now() - overflowRetryStartMs;\n\t\t\tconst retryMessages = allowOverflowRetry(overflowAttempts, elapsedMs)\n\t\t\t\t? shrinkSummarizationInputForOverflowRetry(messages, snapshot.contextWindow, promptTokens)\n\t\t\t\t: undefined;\n\t\t\tif (!retryMessages) {\n\t\t\t\tthrow new SummarizationOverflowExhaustedError(overflowAttempts, elapsedMs);\n\t\t\t}\n\t\t\tmessages = retryMessages;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isAssistantMessage(response) && response.stopReason === \"aborted\") {\n\t\t\t// A partial summary from an aborted stream must never be applied.\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (isAssistantMessage(response) && response.stopReason === \"error\") {\n\t\t\t// Surface the real provider failure instead of silently degrading\n\t\t\t// into a generic \"Compaction cancelled\". Preserve the structured\n\t\t\t// truncation class here so downstream recovery never trusts arbitrary\n\t\t\t// thrown error text as authorization for destructive context reduction.\n\t\t\tconst failureKind = summaryRequestFailureKind(response);\n\t\t\tthrow new SummaryRequestError(\n\t\t\t\tresponse.errorMessage || \"Compaction summary request failed\",\n\t\t\t\tfailureKind !== undefined || isRetryableAssistantError(response),\n\t\t\t\tfailureKind,\n\t\t\t\tisRefusalStop(response),\n\t\t\t);\n\t\t}\n\n\t\tconst summary = getSummaryText(response);\n\t\tif (!summary) {\n\t\t\tconst stopReason = isAssistantMessage(response) ? response.stopReason : \"unknown\";\n\t\t\t// A summarizer can hijack the forwarded agent tools and answer with a\n\t\t\t// bare tool call (observed on openai-codex gpt-5.6-sol, 2026-08-31),\n\t\t\t// which used to surface as a terminal empty-summary failure. Spend one\n\t\t\t// retry with tool calling forbidden; the tools stay in the request\n\t\t\t// because Anthropic rejects tool_use history without the tools param.\n\t\t\tif (stopReason === \"toolUse\" && summarizationToolsOffered && !toolUseRetrySpent) {\n\t\t\t\ttoolUseRetrySpent = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthrow new SummaryGenerationError(\n\t\t\t\t\"empty-summary\",\n\t\t\t\t`summarization response contained no text (stopReason: ${stopReason})`,\n\t\t\t);\n\t\t}\n\n\t\t// Informational only: the core rejects an applied compaction that would\n\t\t// still overflow (_wouldCompactionOverflow). Rejecting here based on the\n\t\t// size of the *discarded* input made large sessions uncompactable.\n\t\tconst tokenEstimate = estimateContextTokens(convertToLlm(messages)).tokens + approxTokens(summary);\n\t\tconst parsedSummary = extractTaskIntent(summary);\n\t\tconst taskIntent = parsedSummary.taskIntent ?? resolveInheritedTaskIntent(snapshot.branchEntries ?? []);\n\n\t\treturn {\n\t\t\tsummary: parsedSummary.summaryText,\n\t\t\tfirstKeptEntryId: snapshot.preparation.firstKeptEntryId,\n\t\t\ttokensBefore: snapshot.preparation.tokensBefore,\n\t\t\tdetails: {\n\t\t\t\tschema: SUMMARY_SCHEMA,\n\t\t\t\tpromptVariant: snapshot.promptVariant,\n\t\t\t\ttokenEstimate,\n\t\t\t\tstructuralYield: computeStructuralYield({\n\t\t\t\t\tpreviousSummary: snapshot.preparation.previousSummary ?? \"\",\n\t\t\t\t\tmessagesToSummarize: snapshot.preparation.messagesToSummarize,\n\t\t\t\t\tturnPrefixMessages: snapshot.preparation.turnPrefixMessages,\n\t\t\t\t\tsummary: parsedSummary.summaryText,\n\t\t\t\t\ttokensBefore: snapshot.preparation.tokensBefore,\n\t\t\t\t}),\n\t\t\t\t...(snapshot.origin ? { origin: snapshot.origin } : {}),\n\t\t\t\t...(taskIntent ? { taskIntent } : {}),\n\t\t\t},\n\t\t};\n\t}\n}\n\nexport async function applyGeneratedCompaction(\n\tcontext: SpeculativeCompactionContext,\n\tsnapshot: SpeculativeCompactionSnapshot | undefined,\n\tgetCurrentGeneration: () => number,\n\tcompaction: CompactionResult | undefined,\n\tsignal?: AbortSignal,\n): Promise<SpeculativeCompactionResult> {\n\tconst provider = context.model?.provider;\n\tif ((provider === \"cursor\" || provider === \"cursor-cli-oauth\") && context.isIdle && !context.isIdle()) {\n\t\treturn { applied: false, reason: \"rejected\" };\n\t}\n\tif (!snapshot || !compaction) return { applied: false, reason: \"unavailable\" };\n\n\tif (snapshot.generation !== getCurrentGeneration()) {\n\t\treturn { applied: false, reason: \"stale\" };\n\t}\n\n\tconst revisionUnchanged = snapshot.expectedRevision === context.getMessageRevision();\n\tconst warmAnchor = createWarmAnchorSnapshot(snapshot.preparation.firstKeptEntryId, snapshot.branchEntries ?? []);\n\tif (\n\t\t!revisionUnchanged &&\n\t\t(!warmAnchor || !isWarmSummaryAnchorValid(warmAnchor, context.sessionManager.getBranch()))\n\t) {\n\t\treturn { applied: false, reason: \"stale\" };\n\t}\n\n\treturn await context.applyCompaction(compaction, {\n\t\treason: \"extension\",\n\t\t...(revisionUnchanged || !warmAnchor\n\t\t\t? { expectedRevision: snapshot.expectedRevision }\n\t\t\t: { expectedWarmAnchor: warmAnchor }),\n\t\tsignal,\n\t});\n}\n\nexport async function applySpeculativeCompaction(\n\tcontext: SpeculativeCompactionContext,\n\tsnapshot: SpeculativeCompactionSnapshot | undefined,\n\tgetCurrentGeneration: () => number,\n\tgenerate: () => Promise<CompactionResult | undefined>,\n): Promise<SpeculativeCompactionResult> {\n\tif (!snapshot) return { applied: false, reason: \"unavailable\" };\n\n\tconst compaction = await generate();\n\treturn await applyGeneratedCompaction(context, snapshot, getCurrentGeneration, compaction);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"transient-failure.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/transient-failure.ts"],"names":[],"mappings":"AAoBA,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKxF"}
1
+ {"version":3,"file":"transient-failure.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/transient-failure.ts"],"names":[],"mappings":"AAyBA,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAMxF"}
@@ -9,17 +9,20 @@
9
9
  *
10
10
  * Provider `error` stops carry metadata-aware classification through
11
11
  * `SummaryRequestError` (a refusal whose text merely looks retryable stays
12
- * loud). Watchdog trips — a stalled stream or a stream that outlived its
13
- * wall-clock budget — are infrastructure-slowness outcomes and always degrade.
12
+ * loud). Watchdog trips — a stalled stream, a stream that outlived its
13
+ * wall-clock budget, or a compaction that outlived its total budget — are
14
+ * infrastructure-slowness outcomes and always degrade.
14
15
  * Everything else falls back to the shared message classifier.
15
16
  */
16
17
  import { isRetryableErrorMessage } from "@earendil-works/pi-ai";
17
- import { StreamDurationBudgetError, StreamIdleTimeoutError } from "../../../compaction/stream-watchdog.js";
18
+ import { StreamDurationBudgetError, StreamIdleTimeoutError, SummarizationTotalBudgetError, } from "../../../compaction/stream-watchdog.js";
18
19
  import { SummarizationOverflowExhaustedError } from "./overflow-retry.js";
19
20
  import { SummaryRequestError } from "./speculative.js";
20
21
  export function isTransientSummarizationFailure(error, message) {
21
22
  if (error instanceof StreamDurationBudgetError || error instanceof StreamIdleTimeoutError)
22
23
  return true;
24
+ if (error instanceof SummarizationTotalBudgetError)
25
+ return true;
23
26
  if (error instanceof SummaryRequestError)
24
27
  return error.transient;
25
28
  if (error instanceof SummarizationOverflowExhaustedError)
@@ -1 +1 @@
1
- {"version":3,"file":"transient-failure.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/transient-failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAC3G,OAAO,EAAE,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,UAAU,+BAA+B,CAAC,KAAc,EAAE,OAAe;IAC9E,IAAI,KAAK,YAAY,yBAAyB,IAAI,KAAK,YAAY,sBAAsB;QAAE,OAAO,IAAI,CAAC;IACvG,IAAI,KAAK,YAAY,mBAAmB;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC;IACjE,IAAI,KAAK,YAAY,mCAAmC;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC","sourcesContent":["/**\n * Classifies a summarization failure as transient (degrade quietly through the\n * compaction failure path) or terminal (surface loudly).\n *\n * Transient failures must not escape as extension errors: the runner would print\n * a raw stack on top of the `compaction_end` message the user already saw, while\n * the turn's own provider request surfaces the same outage again through the\n * normal retry path.\n *\n * Provider `error` stops carry metadata-aware classification through\n * `SummaryRequestError` (a refusal whose text merely looks retryable stays\n * loud). Watchdog trips — a stalled stream or a stream that outlived its\n * wall-clock budget — are infrastructure-slowness outcomes and always degrade.\n * Everything else falls back to the shared message classifier.\n */\nimport { isRetryableErrorMessage } from \"@earendil-works/pi-ai\";\nimport { StreamDurationBudgetError, StreamIdleTimeoutError } from \"../../../compaction/stream-watchdog.ts\";\nimport { SummarizationOverflowExhaustedError } from \"./overflow-retry.ts\";\nimport { SummaryRequestError } from \"./speculative.ts\";\n\nexport function isTransientSummarizationFailure(error: unknown, message: string): boolean {\n\tif (error instanceof StreamDurationBudgetError || error instanceof StreamIdleTimeoutError) return true;\n\tif (error instanceof SummaryRequestError) return error.transient;\n\tif (error instanceof SummarizationOverflowExhaustedError) return true;\n\treturn isRetryableErrorMessage(message);\n}\n"]}
1
+ {"version":3,"file":"transient-failure.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/transient-failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EACN,yBAAyB,EACzB,sBAAsB,EACtB,6BAA6B,GAC7B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,UAAU,+BAA+B,CAAC,KAAc,EAAE,OAAe;IAC9E,IAAI,KAAK,YAAY,yBAAyB,IAAI,KAAK,YAAY,sBAAsB;QAAE,OAAO,IAAI,CAAC;IACvG,IAAI,KAAK,YAAY,6BAA6B;QAAE,OAAO,IAAI,CAAC;IAChE,IAAI,KAAK,YAAY,mBAAmB;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC;IACjE,IAAI,KAAK,YAAY,mCAAmC;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC","sourcesContent":["/**\n * Classifies a summarization failure as transient (degrade quietly through the\n * compaction failure path) or terminal (surface loudly).\n *\n * Transient failures must not escape as extension errors: the runner would print\n * a raw stack on top of the `compaction_end` message the user already saw, while\n * the turn's own provider request surfaces the same outage again through the\n * normal retry path.\n *\n * Provider `error` stops carry metadata-aware classification through\n * `SummaryRequestError` (a refusal whose text merely looks retryable stays\n * loud). Watchdog trips — a stalled stream, a stream that outlived its\n * wall-clock budget, or a compaction that outlived its total budget — are\n * infrastructure-slowness outcomes and always degrade.\n * Everything else falls back to the shared message classifier.\n */\nimport { isRetryableErrorMessage } from \"@earendil-works/pi-ai\";\nimport {\n\tStreamDurationBudgetError,\n\tStreamIdleTimeoutError,\n\tSummarizationTotalBudgetError,\n} from \"../../../compaction/stream-watchdog.ts\";\nimport { SummarizationOverflowExhaustedError } from \"./overflow-retry.ts\";\nimport { SummaryRequestError } from \"./speculative.ts\";\n\nexport function isTransientSummarizationFailure(error: unknown, message: string): boolean {\n\tif (error instanceof StreamDurationBudgetError || error instanceof StreamIdleTimeoutError) return true;\n\tif (error instanceof SummarizationTotalBudgetError) return true;\n\tif (error instanceof SummaryRequestError) return error.transient;\n\tif (error instanceof SummarizationOverflowExhaustedError) return true;\n\treturn isRetryableErrorMessage(message);\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ export type ExtensionKernelTools = {
3
+ describe(names: readonly string[]): Promise<unknown>;
4
+ invoke(request: {
5
+ name: string;
6
+ kernel_generation: number;
7
+ definition_revision: number;
8
+ args: unknown;
9
+ call_id: string;
10
+ }, signal?: AbortSignal): Promise<unknown>;
11
+ };
12
+ export declare const kernelToolsStorage: AsyncLocalStorage<ExtensionKernelTools>;
13
+ //# sourceMappingURL=kernel-tools-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel-tools-context.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/kernel-tools-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,MAAM,oBAAoB,GAAG;IAClC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,CACL,OAAO,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;QAC1B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,IAAI,EAAE,OAAO,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KAChB,EACD,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,OAAO,CAAC,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,kBAAkB,yCAAgD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ export const kernelToolsStorage = new AsyncLocalStorage();
3
+ //# sourceMappingURL=kernel-tools-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel-tools-context.js","sourceRoot":"","sources":["../../../src/core/extensions/kernel-tools-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,iBAAiB,EAAwB,CAAC","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport type ExtensionKernelTools = {\n\tdescribe(names: readonly string[]): Promise<unknown>;\n\tinvoke(\n\t\trequest: {\n\t\t\tname: string;\n\t\t\tkernel_generation: number;\n\t\t\tdefinition_revision: number;\n\t\t\targs: unknown;\n\t\t\tcall_id: string;\n\t\t},\n\t\tsignal?: AbortSignal,\n\t): Promise<unknown>;\n};\n\nexport const kernelToolsStorage = new AsyncLocalStorage<ExtensionKernelTools>();\n"]}
@@ -97,6 +97,9 @@ export type ShutdownHandler = () => void;
97
97
  /**
98
98
  * Helper function to emit session_shutdown event to extensions.
99
99
  * Returns true if the event was emitted, false if there were no handlers.
100
+ *
101
+ * Each handler runs under the host's shutdown budget (see
102
+ * `ExtensionRunner.emit`), so a hung extension cannot hold teardown hostage.
100
103
  */
101
104
  export declare function emitSessionShutdownEvent(extensionRunner: ExtensionRunner, event: SessionShutdownEvent): Promise<boolean>;
102
105
  export declare function emitProjectTrustEvent(extensionsResult: LoadExtensionsResult, event: ProjectTrustEvent, ctx: ProjectTrustContext): Promise<{
@@ -232,6 +235,22 @@ export declare class ExtensionRunner {
232
235
  createContext(excludeBeforeProviderRequestExtensionPath?: string): ExtensionContext;
233
236
  createCommandContext(): ExtensionCommandContext;
234
237
  private isSessionBeforeEvent;
238
+ /**
239
+ * Host budget for `session_shutdown` handlers, read from settings once per
240
+ * shutdown emission (teardown runs once per runner, so a settings edit takes
241
+ * effect without a reload). A malformed value must never break teardown, so
242
+ * an invalid setting is reported and the shipped defaults are used.
243
+ */
244
+ private resolveSessionShutdownBudget;
245
+ /**
246
+ * Runs one `session_shutdown` handler under the host budget. The handler sees
247
+ * the budget through `event.signal`, which this runner aborts at the hard cap;
248
+ * the host then stops waiting (the handler itself keeps running detached),
249
+ * reports an extension error and lets teardown continue with the next handler.
250
+ * Handler rejections are rethrown so emit()'s existing error path reports them
251
+ * exactly as before.
252
+ */
253
+ private runSessionShutdownHandler;
235
254
  emit<TEvent extends RunnerEmitEvent>(event: TEvent): Promise<RunnerEmitResult<TEvent>>;
236
255
  emitModelSelect(event: ModelSelectEvent): Promise<ModelSelectEventResult | undefined>;
237
256
  emitMessageEnd(event: MessageEndEvent): Promise<AgentMessage | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAIpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAAkB,KAAK,QAAQ,EAA+B,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACrH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAsD,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMhH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAKpE,OAAO,KAAK,EACX,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAE1B,YAAY,EAGZ,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,uBAAuB,EACvB,8BAA8B,EAC9B,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EAEf,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,cAAc,EACd,0BAA0B,EAE1B,8BAA8B,EAC9B,cAAc,EACd,sBAAsB,EACtB,eAAe,EAEf,sBAAsB,EAGtB,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EAErB,aAAa,EACb,mBAAmB,EACnB,MAAM,YAAY,CAAC;AAgDpB,2DAA2D;AAC3D,UAAU,8BAA8B;IACvC,QAAQ,CAAC,EAAE,WAAW,CAAC,2BAA2B,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,KAAK,eAAe,GAAG,OAAO,CAC7B,cAAc,EACZ,aAAa,GACb,iBAAiB,GACjB,eAAe,GACf,aAAa,GACb,YAAY,GACZ,0BAA0B,GAC1B,0BAA0B,GAC1B,qBAAqB,GACrB,gBAAgB,GAChB,eAAe,GACf,sBAAsB,GACtB,UAAU,CACZ,CAAC;AAqBF,KAAK,gBAAgB,CAAC,MAAM,SAAS,eAAe,IAAI,MAAM,SAAS;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACrG,yBAAyB,GAAG,SAAS,GACrC,MAAM,SAAS;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GAC7C,uBAAuB,GAAG,SAAS,GACnC,MAAM,SAAS;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GAC/C,yBAAyB,GAAG,SAAS,GACrC,MAAM,SAAS;IAAE,IAAI,EAAE,wBAAwB,CAAA;CAAE,GAChD,0BAA0B,GAAG,SAAS,GACtC,MAAM,SAAS;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GAC7C,uBAAuB,GAAG,SAAS,GACnC,SAAS,CAAC;AAUjB,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAgBrE,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,aAAa,CAAC;AACjE,MAAM,MAAM,gCAAgC,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAElF,KAAK,mCAAmC,GAAG;IAC1C,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GACxC,CAAC,mCAAmC,GAAG;IACvC,KAAK,EAAE,OAAO,CAAC;CACd,CAAC,GACF,CAAC,mCAAmC,GAAG;IACvC,KAAK,EAAE,QAAQ,CAAC;CACf,CAAC,GACF,CAAC,mCAAmC,GAAG;IACvC,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gCAAgC,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAAC;AAEN,MAAM,MAAM,kCAAkC,GAAG,CAAC,KAAK,EAAE,+BAA+B,KAAK,IAAI,CAAC;AAElG,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,CAAC,EAAE;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D,KAAK,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtC,MAAM,MAAM,WAAW,GAAG,CACzB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,KAClG,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAErC,MAAM,MAAM,mBAAmB,GAAG,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KACzG,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAErC,MAAM,MAAM,2BAA2B,GAAG,CACzC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,KACnF,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE5E,MAAM,MAAM,oBAAoB,GAAG,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,KACtE,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAErC,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC;AAUzC;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC7C,eAAe,EAAE,eAAe,EAChC,KAAK,EAAE,oBAAoB,GACzB,OAAO,CAAC,OAAO,CAAC,CAMlB;AAED,wBAAsB,qBAAqB,CAC1C,gBAAgB,EAAE,oBAAoB,EACtC,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,mBAAmB,GACtB,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,uBAAuB,CAAC;IAAC,MAAM,EAAE,cAAc,EAAE,CAAA;CAAE,CAAC,CA0BzE;AA4DD,qBAAa,eAAe;IAC3B,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,QAAQ,CAAiD;IACjE,OAAO,CAAC,cAAc,CAAkD;IACxE,OAAO,CAAC,uBAAuB,CAA8D;IAC7F,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,WAAW,CAAkD;IACrE,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,OAAO,CAA8C;IAC7D,OAAO,CAAC,oBAAoB,CAA8B;IAC1D,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,iBAAiB,CAA6C;IACtE,OAAO,CAAC,iBAAiB,CAAmD;IAC5E,OAAO,CAAC,uBAAuB,CAI5B;IACH,OAAO,CAAC,+BAA+B,CAA6C;IACpF,OAAO,CAAC,sCAAsC,CAA2B;IACzE,OAAO,CAAC,iCAAiC,CAC4D;IACrG,OAAO,CAAC,mBAAmB,CAGxB;IACH,OAAO,CAAC,oBAAoB,CAGzB;IACH,OAAO,CAAC,kBAAkB,CAGvB;IACH,OAAO,CAAC,iBAAiB,CAA2E;IACpG,OAAO,CAAC,SAAS,CAAgD;IACjE,OAAO,CAAC,iBAAiB,CAAyD;IAClF,OAAO,CAAC,kBAAkB,CAA0D;IACpF,OAAO,CAAC,eAAe,CAAuD;IAC9E,OAAO,CAAC,oBAAoB,CAAyB;IACrD,OAAO,CAAC,iBAAiB,CAGtB;IACH,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,sBAAsB,CAS3B;IACH,OAAO,CAAC,wBAAwB,CAA6D;IAC7F,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,iBAAiB,CAAyD;IAClF,OAAO,CAAC,WAAW,CAAmD;IACtE,OAAO,CAAC,mBAAmB,CAA2D;IACtF,OAAO,CAAC,2BAA2B,CAAmE;IACtG,OAAO,CAAC,oBAAoB,CAA4D;IACxF,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,oBAAoB,CAA4B;IACxD,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,mBAAmB,CAA4B;IACvD,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,yBAAyB,CAAiD;IAClF,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAqD;IAE3E,YACC,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,cAAc,EAC9B,aAAa,EAAE,aAAa,EAC5B,QAAQ,GAAE,QAA2B,EASrC;IAED,QAAQ,CACP,OAAO,EAAE,gBAAgB,EACzB,cAAc,EAAE,uBAAuB,EACvC,eAAe,CAAC,EAAE;QACjB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;QAClE,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QACtD,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;KAC5C,GACC,IAAI,CAqHN;IAED,kBAAkB,CAAC,OAAO,CAAC,EAAE,8BAA8B,GAAG,IAAI,CAmBjE;IAED,OAAO,CAAC,aAAa;IAUrB,YAAY,CAAC,SAAS,CAAC,EAAE,kBAAkB,EAAE,IAAI,GAAE,aAAuB,GAAG,IAAI,CAGhF;IAED,4BAA4B,CAAC,QAAQ,CAAC,EAAE,kCAAkC,GAAG,IAAI,CAEhF;IAED,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,iBAAiB;IAMzB,YAAY,IAAI,kBAAkB,CAEjC;IAED,KAAK,IAAI,OAAO,CAEf;IAED,iBAAiB,IAAI,MAAM,EAAE,CAE5B;IAED,sBAAsB,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAEtE;IAED;;;OAGG;IACH,qBAAqB,IAAI,cAAc,EAAE,CAWxC;IAED,6EAA6E;IAC7E,8BAA8B,IAAI,SAAS,MAAM,EAAE,CAIlD;IAED,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAIlE;IAED;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAExE;IAED,4EAA4E;IAC5E,uBAAuB,IAAI,SAAS,8BAA8B,EAAE,CAenE;IAED,qEAAqE;IACrE,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAQ5E;IAED,QAAQ,IAAI,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAUrC;IAED,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAExD;IAED,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CAE7C;IAED,YAAY,CAAC,mBAAmB,EAAE,iBAAiB,GAAG,GAAG,CAAC,KAAK,EAAE,iBAAiB,CAAC,CA2ClF;IAED,sBAAsB,IAAI,kBAAkB,EAAE,CAE7C;IAED,UAAU,CACT,OAAO,SAAgX,GACrX,IAAI,CAKN;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM,IAAI,CAGpD;IAED,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAIrC;IAED,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAQtC;IAED,OAAO,CAAC,wBAAwB;IAwBhC,OAAO,CAAC,0BAA0B;IAIlC,OAAO,CAAC,gBAAgB;IAiDxB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAQlE;IAED,uBAAuB,IAAI,mBAAmB,EAAE,CAE/C;IAED,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAQ9D;IAED,OAAO,CAAC,yBAAyB;IAoCjC,gBAAgB,IAAI,aAAa,CAEhC;IAED,qBAAqB,IAAI,eAAe,EAAE,CAGzC;IAED,qBAAqB,IAAI,kBAAkB,EAAE,CAE5C;IAED,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEpD;IAEK,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB9D;IAED;;;OAGG;IACH,QAAQ,IAAI,IAAI,CAEf;IAED,cAAc,IAAI,MAAM,EAAE,CAGzB;IAED;;;OAGG;IACH,aAAa,CAAC,yCAAyC,CAAC,EAAE,MAAM,GAAG,gBAAgB,CA2LlF;IAED,oBAAoB,IAAI,uBAAuB,CAqC9C;IAED,OAAO,CAAC,oBAAoB;IAU5B;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IAqBpC;;;;;;;OAOG;YACW,yBAAyB;IA+DjC,IAAI,CAAC,MAAM,SAAS,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CA+C3F;IAEK,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CA6C1F;IAEK,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAyC9E;IAEK,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAkEvF;IAEK,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAqCjF;IAEK,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAyBjF;IAEK,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAiClG;IAEK,sBAAsB,CAC3B,QAAQ,EAAE,YAAY,EAAE,EACxB,oBAAoB,CAAC,EAAE,MAAM,GAC3B,OAAO,CAAC,0BAA0B,CAAC,CAOrC;IAEK,yBAAyB,CAC9B,OAAO,EAAE,OAAO,EAChB,oBAAoB,CAAC,EAAE,MAAM,EAC7B,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,GACvD,OAAO,CAAC,OAAO,CAAC,CAiClB;IAEK,yBAAyB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CA2BlF;IAEK,oBAAoB,CACzB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,EAAE,GAAG,SAAS,EAClC,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,wBAAwB,GAC3C,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC,CA6DrD;IAEK,qBAAqB,CAC1B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GACtC,OAAO,CAAC;QACV,UAAU,EAAE,uBAAuB,EAAE,CAAC;QACtC,WAAW,EAAE,uBAAuB,EAAE,CAAC;QACvC,UAAU,EAAE,uBAAuB,EAAE,CAAC;QACtC,SAAS,EAAE,uBAAuB,EAAE,CAAC;KACrC,CAAC,CAgDD;IAED,oEAAoE;IAC9D,SAAS,CACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,EAAE,GAAG,SAAS,EAClC,MAAM,EAAE,WAAW,EACnB,iBAAiB,CAAC,EAAE,OAAO,GAAG,UAAU,EACxC,OAAO,SAAU,GACf,OAAO,CAAC,gBAAgB,CAAC,CAkC3B;CACD"}
@@ -7,9 +7,10 @@ import { theme } from "../../modes/interactive/theme/theme.js";
7
7
  import { stripAnsi } from "../../utils/ansi.js";
8
8
  import { createEventBus, EXTENSION_RPC_EVENT_CHANNEL } from "../event-bus.js";
9
9
  import { getSessionContextEntryId, SESSION_CONTEXT_ENTRY_ID } from "../session-manager.js";
10
- import { SettingsManager } from "../settings-manager.js";
10
+ import { DEFAULT_SESSION_SHUTDOWN_HANDLER_TIMEOUT_MS, DEFAULT_SESSION_SHUTDOWN_HANDLER_WARN_MS, SettingsManager, } from "../settings-manager.js";
11
11
  import { goalFilePath } from "./builtin/goal/persistence.js";
12
12
  import { goalStoreRef } from "./builtin/goal/store-ref.js";
13
+ import { kernelToolsStorage } from "./kernel-tools-context.js";
13
14
  import { drainPendingProviderRegistrations } from "./loader.js";
14
15
  // Extension shortcuts compete with canonical keybinding ids from keybindings.json.
15
16
  // Only editor-global shortcuts are reserved here. Picker-specific bindings are not.
@@ -75,6 +76,9 @@ function sanitizedToolHookStatusMessage(message) {
75
76
  /**
76
77
  * Helper function to emit session_shutdown event to extensions.
77
78
  * Returns true if the event was emitted, false if there were no handlers.
79
+ *
80
+ * Each handler runs under the host's shutdown budget (see
81
+ * `ExtensionRunner.emit`), so a hung extension cannot hold teardown hostage.
78
82
  */
79
83
  export async function emitSessionShutdownEvent(extensionRunner, event) {
80
84
  if (extensionRunner.hasHandlers("session_shutdown")) {
@@ -837,6 +841,10 @@ export class ExtensionRunner {
837
841
  runner.assertActive();
838
842
  return runner.getSignalFn();
839
843
  },
844
+ get kernelTools() {
845
+ runner.assertActive();
846
+ return kernelToolsStorage.getStore();
847
+ },
840
848
  abort: (source) => {
841
849
  runner.assertActive();
842
850
  runner.abortFn(source);
@@ -987,14 +995,108 @@ export class ExtensionRunner {
987
995
  event.type === "session_before_compact" ||
988
996
  event.type === "session_before_tree");
989
997
  }
998
+ /**
999
+ * Host budget for `session_shutdown` handlers, read from settings once per
1000
+ * shutdown emission (teardown runs once per runner, so a settings edit takes
1001
+ * effect without a reload). A malformed value must never break teardown, so
1002
+ * an invalid setting is reported and the shipped defaults are used.
1003
+ */
1004
+ resolveSessionShutdownBudget() {
1005
+ try {
1006
+ const settings = SettingsManager.create(this.cwd, this.getAgentDirFn(), {
1007
+ projectTrusted: this.isProjectTrustedFn(),
1008
+ });
1009
+ return {
1010
+ warnMs: settings.getSessionShutdownHandlerWarnMs(),
1011
+ timeoutMs: settings.getSessionShutdownHandlerTimeoutMs(),
1012
+ };
1013
+ }
1014
+ catch (err) {
1015
+ const message = err instanceof Error ? err.message : String(err);
1016
+ console.warn(`Using the default session_shutdown handler budget (warn ${DEFAULT_SESSION_SHUTDOWN_HANDLER_WARN_MS}ms, hard cap ${DEFAULT_SESSION_SHUTDOWN_HANDLER_TIMEOUT_MS}ms): ${message}`);
1017
+ return {
1018
+ warnMs: DEFAULT_SESSION_SHUTDOWN_HANDLER_WARN_MS,
1019
+ timeoutMs: DEFAULT_SESSION_SHUTDOWN_HANDLER_TIMEOUT_MS,
1020
+ };
1021
+ }
1022
+ }
1023
+ /**
1024
+ * Runs one `session_shutdown` handler under the host budget. The handler sees
1025
+ * the budget through `event.signal`, which this runner aborts at the hard cap;
1026
+ * the host then stops waiting (the handler itself keeps running detached),
1027
+ * reports an extension error and lets teardown continue with the next handler.
1028
+ * Handler rejections are rethrown so emit()'s existing error path reports them
1029
+ * exactly as before.
1030
+ */
1031
+ async runSessionShutdownHandler(extensionPath, event, handler, budget) {
1032
+ const controller = new AbortController();
1033
+ const startedAt = Date.now();
1034
+ let outcome;
1035
+ // Settle the handler through a captured outcome so a late rejection after a
1036
+ // timeout is already handled instead of becoming an unhandled rejection.
1037
+ const settled = Promise.resolve(handler({ ...event, signal: controller.signal }, this.createContext(extensionPath))).then(() => {
1038
+ outcome = { ok: true };
1039
+ }, (error) => {
1040
+ outcome = { ok: false, error };
1041
+ });
1042
+ if (budget.warnMs > 0 || budget.timeoutMs > 0) {
1043
+ let warnTimer;
1044
+ let capTimer;
1045
+ let timedOut = false;
1046
+ try {
1047
+ timedOut = await new Promise((resolve) => {
1048
+ if (budget.warnMs > 0) {
1049
+ warnTimer = setTimeout(() => {
1050
+ const capNote = budget.timeoutMs > 0 ? ` (hard cap ${budget.timeoutMs}ms)` : "";
1051
+ console.warn(`Extension ${extensionPath} is still running its session_shutdown handler after ${Date.now() - startedAt}ms${capNote}.`);
1052
+ }, budget.warnMs);
1053
+ }
1054
+ if (budget.timeoutMs > 0) {
1055
+ capTimer = setTimeout(() => resolve(true), budget.timeoutMs);
1056
+ }
1057
+ void settled.then(() => resolve(false));
1058
+ });
1059
+ }
1060
+ finally {
1061
+ clearTimeout(warnTimer);
1062
+ clearTimeout(capTimer);
1063
+ }
1064
+ if (timedOut) {
1065
+ controller.abort(new Error(`session_shutdown handler timed out after ${budget.timeoutMs}ms`));
1066
+ this.emitError({
1067
+ extensionPath,
1068
+ event: "session_shutdown",
1069
+ error: `handler timed out after ${budget.timeoutMs}ms`,
1070
+ });
1071
+ return;
1072
+ }
1073
+ }
1074
+ else {
1075
+ await settled;
1076
+ }
1077
+ if (outcome && !outcome.ok) {
1078
+ throw outcome.error;
1079
+ }
1080
+ }
990
1081
  async emit(event) {
991
1082
  let result;
1083
+ // session_shutdown is the one host-bounded event: a hung handler must not hold
1084
+ // Ctrl+C / quit / reload / new / resume hostage. Every other event still awaits
1085
+ // its handlers without a cap (ask-user and approval dialogs legitimately block).
1086
+ // The budget is resolved lazily so runners with no shutdown handler read no settings.
1087
+ const isSessionShutdown = event.type === "session_shutdown";
1088
+ let shutdownBudget;
992
1089
  for (const ext of this.extensions) {
993
1090
  const handlers = ext.handlers.get(event.type);
994
1091
  if (!handlers || handlers.length === 0)
995
1092
  continue;
996
1093
  for (const handler of handlers) {
997
1094
  try {
1095
+ if (isSessionShutdown) {
1096
+ shutdownBudget ??= this.resolveSessionShutdownBudget();
1097
+ await this.runSessionShutdownHandler(ext.path, event, handler, shutdownBudget);
1098
+ continue;
1099
+ }
998
1100
  const handlerResult = await handler(event, this.createContext(ext.path));
999
1101
  if (this.isSessionBeforeEvent(event) && handlerResult) {
1000
1102
  result = handlerResult;