@code-yeongyu/senpi 2026.7.20 → 2026.7.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +1 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +1 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +32 -0
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +409 -68
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/auth-storage.js +1 -1
  11. package/dist/core/auth-storage.js.map +1 -1
  12. package/dist/core/compaction/compaction.d.ts +2 -2
  13. package/dist/core/compaction/compaction.d.ts.map +1 -1
  14. package/dist/core/compaction/compaction.js +67 -16
  15. package/dist/core/compaction/compaction.js.map +1 -1
  16. package/dist/core/compaction/stream-watchdog.d.ts +31 -0
  17. package/dist/core/compaction/stream-watchdog.d.ts.map +1 -0
  18. package/dist/core/compaction/stream-watchdog.js +78 -0
  19. package/dist/core/compaction/stream-watchdog.js.map +1 -0
  20. package/dist/core/extensions/builtin/btw/index.d.ts +3 -0
  21. package/dist/core/extensions/builtin/btw/index.d.ts.map +1 -0
  22. package/dist/core/extensions/builtin/btw/index.js +120 -0
  23. package/dist/core/extensions/builtin/btw/index.js.map +1 -0
  24. package/dist/core/extensions/builtin/btw/panel.d.ts +21 -0
  25. package/dist/core/extensions/builtin/btw/panel.d.ts.map +1 -0
  26. package/dist/core/extensions/builtin/btw/panel.js +61 -0
  27. package/dist/core/extensions/builtin/btw/panel.js.map +1 -0
  28. package/dist/core/extensions/builtin/btw/side-query.d.ts +31 -0
  29. package/dist/core/extensions/builtin/btw/side-query.d.ts.map +1 -0
  30. package/dist/core/extensions/builtin/btw/side-query.js +68 -0
  31. package/dist/core/extensions/builtin/btw/side-query.js.map +1 -0
  32. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  33. package/dist/core/extensions/builtin/compaction/index.js +47 -11
  34. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  35. package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/compaction/openai-remote.js +3 -1
  37. package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -1
  38. package/dist/core/extensions/builtin/compaction/speculative.d.ts +17 -0
  39. package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
  40. package/dist/core/extensions/builtin/compaction/speculative.js +93 -26
  41. package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
  42. package/dist/core/extensions/builtin/config-reload/index.d.ts +39 -0
  43. package/dist/core/extensions/builtin/config-reload/index.d.ts.map +1 -0
  44. package/dist/core/extensions/builtin/config-reload/index.js +659 -0
  45. package/dist/core/extensions/builtin/config-reload/index.js.map +1 -0
  46. package/dist/core/extensions/builtin/config-reload/log.d.ts +55 -0
  47. package/dist/core/extensions/builtin/config-reload/log.d.ts.map +1 -0
  48. package/dist/core/extensions/builtin/config-reload/log.js +128 -0
  49. package/dist/core/extensions/builtin/config-reload/log.js.map +1 -0
  50. package/dist/core/extensions/builtin/config-reload/protocol.d.ts +71 -0
  51. package/dist/core/extensions/builtin/config-reload/protocol.d.ts.map +1 -0
  52. package/dist/core/extensions/builtin/config-reload/protocol.js +83 -0
  53. package/dist/core/extensions/builtin/config-reload/protocol.js.map +1 -0
  54. package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts +43 -0
  55. package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts.map +1 -0
  56. package/dist/core/extensions/builtin/config-reload/watch-engine.js +298 -0
  57. package/dist/core/extensions/builtin/config-reload/watch-engine.js.map +1 -0
  58. package/dist/core/extensions/builtin/goal/command-registration.d.ts +2 -2
  59. package/dist/core/extensions/builtin/goal/command-registration.d.ts.map +1 -1
  60. package/dist/core/extensions/builtin/goal/command-registration.js +3 -4
  61. package/dist/core/extensions/builtin/goal/command-registration.js.map +1 -1
  62. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  63. package/dist/core/extensions/builtin/goal/index.js +11 -27
  64. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  65. package/dist/core/extensions/builtin/goal/tool-registration.d.ts +2 -2
  66. package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
  67. package/dist/core/extensions/builtin/goal/tool-registration.js +2 -3
  68. package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
  69. package/dist/core/extensions/builtin/goal/turn-usage.d.ts +20 -0
  70. package/dist/core/extensions/builtin/goal/turn-usage.d.ts.map +1 -0
  71. package/dist/core/extensions/builtin/goal/turn-usage.js +61 -0
  72. package/dist/core/extensions/builtin/goal/turn-usage.js.map +1 -0
  73. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  74. package/dist/core/extensions/builtin/index.js +9 -0
  75. package/dist/core/extensions/builtin/index.js.map +1 -1
  76. package/dist/core/extensions/builtin/look-at/arguments.d.ts +27 -0
  77. package/dist/core/extensions/builtin/look-at/arguments.d.ts.map +1 -0
  78. package/dist/core/extensions/builtin/look-at/arguments.js +109 -0
  79. package/dist/core/extensions/builtin/look-at/arguments.js.map +1 -0
  80. package/dist/core/extensions/builtin/look-at/commands.d.ts +9 -0
  81. package/dist/core/extensions/builtin/look-at/commands.d.ts.map +1 -0
  82. package/dist/core/extensions/builtin/look-at/commands.js +102 -0
  83. package/dist/core/extensions/builtin/look-at/commands.js.map +1 -0
  84. package/dist/core/extensions/builtin/look-at/image-input.d.ts +21 -0
  85. package/dist/core/extensions/builtin/look-at/image-input.d.ts.map +1 -0
  86. package/dist/core/extensions/builtin/look-at/image-input.js +151 -0
  87. package/dist/core/extensions/builtin/look-at/image-input.js.map +1 -0
  88. package/dist/core/extensions/builtin/look-at/index.d.ts +3 -0
  89. package/dist/core/extensions/builtin/look-at/index.d.ts.map +1 -0
  90. package/dist/core/extensions/builtin/look-at/index.js +58 -0
  91. package/dist/core/extensions/builtin/look-at/index.js.map +1 -0
  92. package/dist/core/extensions/builtin/look-at/model-selector.d.ts +9 -0
  93. package/dist/core/extensions/builtin/look-at/model-selector.d.ts.map +1 -0
  94. package/dist/core/extensions/builtin/look-at/model-selector.js +77 -0
  95. package/dist/core/extensions/builtin/look-at/model-selector.js.map +1 -0
  96. package/dist/core/extensions/builtin/look-at/prompts.d.ts +5 -0
  97. package/dist/core/extensions/builtin/look-at/prompts.d.ts.map +1 -0
  98. package/dist/core/extensions/builtin/look-at/prompts.js +19 -0
  99. package/dist/core/extensions/builtin/look-at/prompts.js.map +1 -0
  100. package/dist/core/extensions/builtin/look-at/render.d.ts +26 -0
  101. package/dist/core/extensions/builtin/look-at/render.d.ts.map +1 -0
  102. package/dist/core/extensions/builtin/look-at/render.js +70 -0
  103. package/dist/core/extensions/builtin/look-at/render.js.map +1 -0
  104. package/dist/core/extensions/builtin/look-at/runner.d.ts +16 -0
  105. package/dist/core/extensions/builtin/look-at/runner.d.ts.map +1 -0
  106. package/dist/core/extensions/builtin/look-at/runner.js +108 -0
  107. package/dist/core/extensions/builtin/look-at/runner.js.map +1 -0
  108. package/dist/core/extensions/builtin/look-at/settings.d.ts +13 -0
  109. package/dist/core/extensions/builtin/look-at/settings.d.ts.map +1 -0
  110. package/dist/core/extensions/builtin/look-at/settings.js +20 -0
  111. package/dist/core/extensions/builtin/look-at/settings.js.map +1 -0
  112. package/dist/core/extensions/builtin/mcp/commands.d.ts.map +1 -1
  113. package/dist/core/extensions/builtin/mcp/commands.js +2 -0
  114. package/dist/core/extensions/builtin/mcp/commands.js.map +1 -1
  115. package/dist/core/extensions/builtin/mcp/config-schema.d.ts +6 -0
  116. package/dist/core/extensions/builtin/mcp/config-schema.d.ts.map +1 -1
  117. package/dist/core/extensions/builtin/mcp/config-schema.js +1 -0
  118. package/dist/core/extensions/builtin/mcp/config-schema.js.map +1 -1
  119. package/dist/core/extensions/builtin/mcp/config.d.ts.map +1 -1
  120. package/dist/core/extensions/builtin/mcp/config.js +9 -1
  121. package/dist/core/extensions/builtin/mcp/config.js.map +1 -1
  122. package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
  123. package/dist/core/extensions/builtin/mcp/service.js +22 -6
  124. package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
  125. package/dist/core/extensions/builtin/mcp/startup-race.d.ts +10 -0
  126. package/dist/core/extensions/builtin/mcp/startup-race.d.ts.map +1 -1
  127. package/dist/core/extensions/builtin/mcp/startup-race.js +18 -1
  128. package/dist/core/extensions/builtin/mcp/startup-race.js.map +1 -1
  129. package/dist/core/extensions/builtin/model-fallback/index.d.ts +4 -0
  130. package/dist/core/extensions/builtin/model-fallback/index.d.ts.map +1 -0
  131. package/dist/core/extensions/builtin/model-fallback/index.js +55 -0
  132. package/dist/core/extensions/builtin/model-fallback/index.js.map +1 -0
  133. package/dist/core/extensions/builtin/model-fallback/settings.d.ts +6 -0
  134. package/dist/core/extensions/builtin/model-fallback/settings.d.ts.map +1 -0
  135. package/dist/core/extensions/builtin/model-fallback/settings.js +11 -0
  136. package/dist/core/extensions/builtin/model-fallback/settings.js.map +1 -0
  137. package/dist/core/extensions/builtin/model-fallback/ui.d.ts +12 -0
  138. package/dist/core/extensions/builtin/model-fallback/ui.d.ts.map +1 -0
  139. package/dist/core/extensions/builtin/model-fallback/ui.js +72 -0
  140. package/dist/core/extensions/builtin/model-fallback/ui.js.map +1 -0
  141. package/dist/core/extensions/builtin/nested-agents-md/index.d.ts.map +1 -1
  142. package/dist/core/extensions/builtin/nested-agents-md/index.js +4 -1
  143. package/dist/core/extensions/builtin/nested-agents-md/index.js.map +1 -1
  144. package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
  145. package/dist/core/extensions/builtin/rules/index.js +4 -1
  146. package/dist/core/extensions/builtin/rules/index.js.map +1 -1
  147. package/dist/core/extensions/builtin/terminal/output-format.d.ts +28 -0
  148. package/dist/core/extensions/builtin/terminal/output-format.d.ts.map +1 -0
  149. package/dist/core/extensions/builtin/terminal/output-format.js +74 -0
  150. package/dist/core/extensions/builtin/terminal/output-format.js.map +1 -0
  151. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts +3 -0
  152. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts.map +1 -1
  153. package/dist/core/extensions/builtin/terminal/runtime-session.js +22 -2
  154. package/dist/core/extensions/builtin/terminal/runtime-session.js.map +1 -1
  155. package/dist/core/extensions/builtin/terminal/shared.d.ts +7 -0
  156. package/dist/core/extensions/builtin/terminal/shared.d.ts.map +1 -1
  157. package/dist/core/extensions/builtin/terminal/shared.js +14 -0
  158. package/dist/core/extensions/builtin/terminal/shared.js.map +1 -1
  159. package/dist/core/extensions/builtin/terminal/tools/bash-output.d.ts +5 -1
  160. package/dist/core/extensions/builtin/terminal/tools/bash-output.d.ts.map +1 -1
  161. package/dist/core/extensions/builtin/terminal/tools/bash-output.js +88 -6
  162. package/dist/core/extensions/builtin/terminal/tools/bash-output.js.map +1 -1
  163. package/dist/core/extensions/builtin/terminal/tools/bash.d.ts +12 -1
  164. package/dist/core/extensions/builtin/terminal/tools/bash.d.ts.map +1 -1
  165. package/dist/core/extensions/builtin/terminal/tools/bash.js +82 -8
  166. package/dist/core/extensions/builtin/terminal/tools/bash.js.map +1 -1
  167. package/dist/core/extensions/builtin/terminal/tools/render.d.ts +16 -0
  168. package/dist/core/extensions/builtin/terminal/tools/render.d.ts.map +1 -0
  169. package/dist/core/extensions/builtin/terminal/tools/render.js +30 -0
  170. package/dist/core/extensions/builtin/terminal/tools/render.js.map +1 -0
  171. package/dist/core/extensions/builtin/terminal/tools/spawn.d.ts +2 -0
  172. package/dist/core/extensions/builtin/terminal/tools/spawn.d.ts.map +1 -1
  173. package/dist/core/extensions/builtin/terminal/tools/spawn.js +1 -1
  174. package/dist/core/extensions/builtin/terminal/tools/spawn.js.map +1 -1
  175. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts.map +1 -1
  176. package/dist/core/extensions/builtin/todotools/tools/todo.js +22 -6
  177. package/dist/core/extensions/builtin/todotools/tools/todo.js.map +1 -1
  178. package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.d.ts +1 -0
  179. package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.d.ts.map +1 -1
  180. package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.js +13 -4
  181. package/dist/core/extensions/builtin/webfetch/webfetch/fetcher.js.map +1 -1
  182. package/dist/core/extensions/builtin/webfetch/webfetch/renderers.d.ts.map +1 -1
  183. package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js +17 -2
  184. package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js.map +1 -1
  185. package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts +8 -1
  186. package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts.map +1 -1
  187. package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +45 -3
  188. package/dist/core/extensions/builtin/webfetch/webfetch/tool.js.map +1 -1
  189. package/dist/core/extensions/builtin/websearch/websearch/renderers.d.ts.map +1 -1
  190. package/dist/core/extensions/builtin/websearch/websearch/renderers.js +13 -4
  191. package/dist/core/extensions/builtin/websearch/websearch/renderers.js.map +1 -1
  192. package/dist/core/extensions/builtin/websearch/websearch/search.d.ts +3 -2
  193. package/dist/core/extensions/builtin/websearch/websearch/search.d.ts.map +1 -1
  194. package/dist/core/extensions/builtin/websearch/websearch/search.js +2 -1
  195. package/dist/core/extensions/builtin/websearch/websearch/search.js.map +1 -1
  196. package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts.map +1 -1
  197. package/dist/core/extensions/builtin/websearch/websearch/tool.js +17 -1
  198. package/dist/core/extensions/builtin/websearch/websearch/tool.js.map +1 -1
  199. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +2 -0
  200. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
  201. package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
  202. package/dist/core/extensions/runner.d.ts +6 -0
  203. package/dist/core/extensions/runner.d.ts.map +1 -1
  204. package/dist/core/extensions/runner.js +71 -3
  205. package/dist/core/extensions/runner.js.map +1 -1
  206. package/dist/core/extensions/types.d.ts +96 -10
  207. package/dist/core/extensions/types.d.ts.map +1 -1
  208. package/dist/core/extensions/types.js.map +1 -1
  209. package/dist/core/model-config-schema.d.ts +1942 -0
  210. package/dist/core/model-config-schema.d.ts.map +1 -0
  211. package/dist/core/model-config-schema.js +197 -0
  212. package/dist/core/model-config-schema.js.map +1 -0
  213. package/dist/core/model-config.d.ts +2 -578
  214. package/dist/core/model-config.d.ts.map +1 -1
  215. package/dist/core/model-config.js +1 -194
  216. package/dist/core/model-config.js.map +1 -1
  217. package/dist/core/model-resolver.d.ts.map +1 -1
  218. package/dist/core/model-resolver.js +1 -0
  219. package/dist/core/model-resolver.js.map +1 -1
  220. package/dist/core/model-runtime.d.ts.map +1 -1
  221. package/dist/core/model-runtime.js +9 -3
  222. package/dist/core/model-runtime.js.map +1 -1
  223. package/dist/core/provider-composer.d.ts +1 -0
  224. package/dist/core/provider-composer.d.ts.map +1 -1
  225. package/dist/core/provider-composer.js +3 -2
  226. package/dist/core/provider-composer.js.map +1 -1
  227. package/dist/core/provider-display-names.d.ts.map +1 -1
  228. package/dist/core/provider-display-names.js +1 -0
  229. package/dist/core/provider-display-names.js.map +1 -1
  230. package/dist/core/retry-fallback/chains.d.ts +29 -0
  231. package/dist/core/retry-fallback/chains.d.ts.map +1 -0
  232. package/dist/core/retry-fallback/chains.js +109 -0
  233. package/dist/core/retry-fallback/chains.js.map +1 -0
  234. package/dist/core/retry-fallback/controller.d.ts +77 -0
  235. package/dist/core/retry-fallback/controller.d.ts.map +1 -0
  236. package/dist/core/retry-fallback/controller.js +157 -0
  237. package/dist/core/retry-fallback/controller.js.map +1 -0
  238. package/dist/core/retry-fallback/cooldown.d.ts +21 -0
  239. package/dist/core/retry-fallback/cooldown.d.ts.map +1 -0
  240. package/dist/core/retry-fallback/cooldown.js +49 -0
  241. package/dist/core/retry-fallback/cooldown.js.map +1 -0
  242. package/dist/core/retry-fallback/log.d.ts +10 -0
  243. package/dist/core/retry-fallback/log.d.ts.map +1 -0
  244. package/dist/core/retry-fallback/log.js +128 -0
  245. package/dist/core/retry-fallback/log.js.map +1 -0
  246. package/dist/core/retry-fallback/validate.d.ts +8 -0
  247. package/dist/core/retry-fallback/validate.d.ts.map +1 -0
  248. package/dist/core/retry-fallback/validate.js +63 -0
  249. package/dist/core/retry-fallback/validate.js.map +1 -0
  250. package/dist/core/sdk.d.ts.map +1 -1
  251. package/dist/core/sdk.js +1 -0
  252. package/dist/core/sdk.js.map +1 -1
  253. package/dist/core/session-manager.d.ts +39 -3
  254. package/dist/core/session-manager.d.ts.map +1 -1
  255. package/dist/core/session-manager.js +125 -16
  256. package/dist/core/session-manager.js.map +1 -1
  257. package/dist/core/settings-manager.d.ts +33 -0
  258. package/dist/core/settings-manager.d.ts.map +1 -1
  259. package/dist/core/settings-manager.js +153 -6
  260. package/dist/core/settings-manager.js.map +1 -1
  261. package/dist/modes/interactive/components/footer.d.ts +2 -1
  262. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  263. package/dist/modes/interactive/components/footer.js +30 -20
  264. package/dist/modes/interactive/components/footer.js.map +1 -1
  265. package/dist/modes/interactive/components/todo-strike.d.ts +8 -0
  266. package/dist/modes/interactive/components/todo-strike.d.ts.map +1 -0
  267. package/dist/modes/interactive/components/todo-strike.js +35 -0
  268. package/dist/modes/interactive/components/todo-strike.js.map +1 -0
  269. package/dist/modes/interactive/components/tool-execution-renderer.d.ts.map +1 -1
  270. package/dist/modes/interactive/components/tool-execution-renderer.js +8 -1
  271. package/dist/modes/interactive/components/tool-execution-renderer.js.map +1 -1
  272. package/dist/modes/interactive/components/tool-execution.d.ts +4 -0
  273. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  274. package/dist/modes/interactive/components/tool-execution.js +51 -2
  275. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  276. package/dist/modes/interactive/interactive-mode.d.ts +6 -0
  277. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  278. package/dist/modes/interactive/interactive-mode.js +124 -4
  279. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  280. package/dist/modes/interactive/tool-progress.d.ts +8 -0
  281. package/dist/modes/interactive/tool-progress.d.ts.map +1 -0
  282. package/dist/modes/interactive/tool-progress.js +26 -0
  283. package/dist/modes/interactive/tool-progress.js.map +1 -0
  284. package/dist/modes/interactive/tool-result-reveal.d.ts +18 -0
  285. package/dist/modes/interactive/tool-result-reveal.d.ts.map +1 -0
  286. package/dist/modes/interactive/tool-result-reveal.js +155 -0
  287. package/dist/modes/interactive/tool-result-reveal.js.map +1 -0
  288. package/dist/utils/fs-watch.d.ts +2 -2
  289. package/dist/utils/fs-watch.d.ts.map +1 -1
  290. package/dist/utils/fs-watch.js +2 -2
  291. package/dist/utils/fs-watch.js.map +1 -1
  292. package/docs/extensions.md +79 -1
  293. package/docs/mcp.md +10 -1
  294. package/docs/models.md +102 -1
  295. package/docs/providers.md +3 -1
  296. package/docs/settings.md +35 -0
  297. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
  298. package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
  299. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +13 -1
  300. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  301. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +76 -8
  302. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  303. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  304. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +26 -1
  305. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  306. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  307. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +24 -2
  308. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  309. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +5 -0
  310. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  311. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  312. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  313. package/node_modules/@earendil-works/pi-ai/README.md +2 -0
  314. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  315. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +68 -25
  316. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  317. package/node_modules/@earendil-works/pi-ai/dist/api/lazy.d.ts.map +1 -1
  318. package/node_modules/@earendil-works/pi-ai/dist/api/lazy.js +33 -6
  319. package/node_modules/@earendil-works/pi-ai/dist/api/lazy.js.map +1 -1
  320. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
  321. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +6 -1
  322. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
  323. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.d.ts.map +1 -1
  324. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js +62 -52
  325. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js.map +1 -1
  326. package/node_modules/@earendil-works/pi-ai/dist/api-registry.d.ts +19 -0
  327. package/node_modules/@earendil-works/pi-ai/dist/api-registry.d.ts.map +1 -0
  328. package/node_modules/@earendil-works/pi-ai/dist/api-registry.js +50 -0
  329. package/node_modules/@earendil-works/pi-ai/dist/api-registry.js.map +1 -0
  330. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts +2 -17
  331. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts.map +1 -1
  332. package/node_modules/@earendil-works/pi-ai/dist/compat.js +3 -52
  333. package/node_modules/@earendil-works/pi-ai/dist/compat.js.map +1 -1
  334. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  335. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +1 -0
  336. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js.map +1 -1
  337. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +45 -0
  338. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  339. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +45 -0
  340. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  341. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +5 -0
  342. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  343. package/node_modules/@earendil-works/pi-ai/dist/index.js +5 -0
  344. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  345. package/node_modules/@earendil-works/pi-ai/dist/model.d.ts +27 -0
  346. package/node_modules/@earendil-works/pi-ai/dist/model.d.ts.map +1 -0
  347. package/node_modules/@earendil-works/pi-ai/dist/model.js +2 -0
  348. package/node_modules/@earendil-works/pi-ai/dist/model.js.map +1 -0
  349. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +1178 -1072
  350. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  351. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +2 -0
  352. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
  353. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.d.ts +3 -0
  354. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.d.ts.map +1 -0
  355. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.js +15 -0
  356. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.js.map +1 -0
  357. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.d.ts +64 -0
  358. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.d.ts.map +1 -0
  359. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.js +5 -0
  360. package/node_modules/@earendil-works/pi-ai/dist/providers/alibaba-token-plan.models.js.map +1 -0
  361. package/node_modules/@earendil-works/pi-ai/dist/providers/all.d.ts.map +1 -1
  362. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js +2 -0
  363. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js.map +1 -1
  364. package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -0
  365. package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
  366. package/node_modules/@earendil-works/pi-ai/dist/providers/data/kimi-coding.json +1 -1
  367. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  368. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  369. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  370. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts +1 -0
  371. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts.map +1 -1
  372. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js +1 -0
  373. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js.map +1 -1
  374. package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.d.ts +8 -0
  375. package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.d.ts.map +1 -1
  376. package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.js.map +1 -1
  377. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +0 -4
  378. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
  379. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
  380. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts +12 -4
  381. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts.map +1 -1
  382. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js.map +1 -1
  383. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +20 -4
  384. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
  385. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  386. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +16 -0
  387. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  388. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  389. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts +1 -0
  390. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts.map +1 -1
  391. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js +8 -0
  392. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js.map +1 -1
  393. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.d.ts +20 -0
  394. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.d.ts.map +1 -0
  395. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.js +79 -0
  396. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-stream-helpers.js.map +1 -0
  397. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts +2 -18
  398. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts.map +1 -1
  399. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js +4 -218
  400. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js.map +1 -1
  401. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.d.ts +38 -0
  402. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.d.ts.map +1 -0
  403. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.js +210 -0
  404. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-syntax.js.map +1 -0
  405. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.d.ts +9 -0
  406. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.d.ts.map +1 -0
  407. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.js +231 -0
  408. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-stream.js.map +1 -0
  409. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.d.ts +38 -0
  410. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.d.ts.map +1 -0
  411. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.js +84 -0
  412. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/recovery-wrapper-state.js.map +1 -0
  413. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.d.ts.map +1 -1
  414. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js +20 -57
  415. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js.map +1 -1
  416. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts.map +1 -1
  417. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js +16 -99
  418. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js.map +1 -1
  419. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.d.ts +1 -0
  420. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.d.ts.map +1 -1
  421. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.js +1 -0
  422. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.js.map +1 -1
  423. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.d.ts +5 -0
  424. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.d.ts.map +1 -0
  425. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js +6 -0
  426. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js.map +1 -0
  427. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.d.ts +19 -0
  428. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.d.ts.map +1 -0
  429. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.js +185 -0
  430. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-code-mask.js.map +1 -0
  431. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.d.ts +11 -0
  432. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.d.ts.map +1 -0
  433. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.js +24 -0
  434. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-content-lifecycle.js.map +1 -0
  435. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.d.ts +4 -0
  436. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.d.ts.map +1 -0
  437. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.js +13 -0
  438. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-diagnostics.js.map +1 -0
  439. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.d.ts +15 -0
  440. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.d.ts.map +1 -0
  441. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.js +37 -0
  442. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-event-stream.js.map +1 -0
  443. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.d.ts +4 -0
  444. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.d.ts.map +1 -0
  445. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.js +61 -0
  446. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-message-snapshot.js.map +1 -0
  447. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.d.ts +29 -0
  448. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.d.ts.map +1 -0
  449. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.js +148 -0
  450. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-native-projection.js.map +1 -0
  451. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.d.ts +5 -0
  452. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.d.ts.map +1 -0
  453. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.js +36 -0
  454. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-failure.js.map +1 -0
  455. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.d.ts +15 -0
  456. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.d.ts.map +1 -0
  457. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.js +88 -0
  458. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-terminal.js.map +1 -0
  459. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.d.ts +3 -0
  460. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.d.ts.map +1 -0
  461. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.js +233 -0
  462. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-stream-wrapper.js.map +1 -0
  463. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.d.ts +23 -0
  464. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.d.ts.map +1 -0
  465. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.js +77 -0
  466. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/recovery-text-projection.js.map +1 -0
  467. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.d.ts +5 -0
  468. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.d.ts.map +1 -0
  469. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.js +63 -0
  470. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-message-metadata.js.map +1 -0
  471. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.d.ts +13 -0
  472. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.d.ts.map +1 -0
  473. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.js +52 -0
  474. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-thinking-projection.js.map +1 -0
  475. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.d.ts +41 -0
  476. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.d.ts.map +1 -0
  477. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.js +209 -0
  478. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper-shared.js.map +1 -0
  479. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper.d.ts.map +1 -1
  480. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper.js +70 -346
  481. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/stream-wrapper.js.map +1 -1
  482. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +18 -23
  483. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  484. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  485. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  486. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +5 -1
  487. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  488. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts +4 -0
  489. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts.map +1 -0
  490. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js +6 -0
  491. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js.map +1 -0
  492. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  493. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  494. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  495. package/package.json +6 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-watchdog.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/stream-watchdog.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,qBAAa,sBAAuB,SAAQ,KAAK;IAChD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,YAAY,aAAa,EAAE,MAAM,EAIhC;CACD;AAED,2EAA2E;AAC3E,eAAO,MAAM,qCAAqC,SAAU,CAAC;AAE7D,MAAM,WAAW,mCAAmC,CAAC,CAAC;IACrD,gEAAgE;IAChE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAKD;;;;GAIG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EACnD,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,OAAO,EAAE,mCAAmC,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Idle watchdog for compaction summarization streams.
3
+ *
4
+ * A provider connection can stall — open but silent — for far longer than any
5
+ * user will wait, and compaction previously had no bound at all: the session
6
+ * sat on "Compacting…" until ESC aborted it. The agent loop's main-turn
7
+ * reader already has this shape of protection (`StreamIdleTimeoutError` in
8
+ * packages/agent); this brings the same guarantee to summarization requests.
9
+ */
10
+ export class StreamIdleTimeoutError extends Error {
11
+ constructor(idleTimeoutMs) {
12
+ super(`Summarization stream stalled: no provider events for ${idleTimeoutMs}ms; treating the request as dead`);
13
+ this.name = "StreamIdleTimeoutError";
14
+ this.idleTimeoutMs = idleTimeoutMs;
15
+ }
16
+ }
17
+ /** Matches the agent stream idle-timeout default (`httpIdleTimeoutMs`). */
18
+ export const DEFAULT_SUMMARIZATION_IDLE_TIMEOUT_MS = 300_000;
19
+ const IDLE_TRIP = "idle-trip";
20
+ const CALLER_ABORTED = "caller-aborted";
21
+ /**
22
+ * Drain an event stream, failing with {@link StreamIdleTimeoutError} when no
23
+ * event arrives within `idleTimeoutMs`. Caller aborts propagate as the
24
+ * stream's own abort outcome, never masked as an idle timeout.
25
+ */
26
+ export async function consumeStreamWithIdleTimeout(stream, options) {
27
+ const iterator = stream[Symbol.asyncIterator]();
28
+ const { idleTimeoutMs, abort, onEvent, signal } = options;
29
+ let removeAbortListener;
30
+ let callerAbortPromise;
31
+ if (signal !== undefined) {
32
+ if (signal.aborted) {
33
+ void iterator.return?.();
34
+ return;
35
+ }
36
+ const { promise, resolve } = Promise.withResolvers();
37
+ const onAbort = () => resolve(CALLER_ABORTED);
38
+ signal.addEventListener("abort", onAbort, { once: true });
39
+ removeAbortListener = () => signal.removeEventListener("abort", onAbort);
40
+ callerAbortPromise = promise;
41
+ }
42
+ try {
43
+ while (true) {
44
+ const { promise: idlePromise, resolve: resolveIdle } = Promise.withResolvers();
45
+ const timer = setTimeout(() => resolveIdle(IDLE_TRIP), idleTimeoutMs);
46
+ timer.unref?.();
47
+ const contenders = [
48
+ iterator.next(),
49
+ idlePromise,
50
+ ];
51
+ if (callerAbortPromise)
52
+ contenders.push(callerAbortPromise);
53
+ let result;
54
+ try {
55
+ result = await Promise.race(contenders);
56
+ }
57
+ finally {
58
+ clearTimeout(timer);
59
+ }
60
+ if (result === IDLE_TRIP) {
61
+ abort();
62
+ void iterator.return?.();
63
+ throw new StreamIdleTimeoutError(idleTimeoutMs);
64
+ }
65
+ if (result === CALLER_ABORTED) {
66
+ void iterator.return?.();
67
+ return;
68
+ }
69
+ if (result.done)
70
+ return;
71
+ onEvent?.(result.value);
72
+ }
73
+ }
74
+ finally {
75
+ removeAbortListener?.();
76
+ }
77
+ }
78
+ //# sourceMappingURL=stream-watchdog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-watchdog.js","sourceRoot":"","sources":["../../../src/core/compaction/stream-watchdog.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAEhD,YAAY,aAAqB;QAChC,KAAK,CAAC,wDAAwD,aAAa,kCAAkC,CAAC,CAAC;QAC/G,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACpC,CAAC;CACD;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qCAAqC,GAAG,OAAO,CAAC;AAY7D,MAAM,SAAS,GAAG,WAAoB,CAAC;AACvC,MAAM,cAAc,GAAG,gBAAyB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CACjD,MAAwB,EACxB,OAA+C;IAE/C,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;IAChD,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC1D,IAAI,mBAA6C,CAAC;IAClD,IAAI,kBAA8D,CAAC;IACnE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,KAAK,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YACzB,OAAO;QACR,CAAC;QACD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAyB,CAAC;QAC5E,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,mBAAmB,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzE,kBAAkB,GAAG,OAAO,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC;QACJ,OAAO,IAAI,EAAE,CAAC;YACb,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,aAAa,EAAoB,CAAC;YACjG,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,CAAC;YACtE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAChB,MAAM,UAAU,GAAiF;gBAChG,QAAQ,CAAC,IAAI,EAAE;gBACf,WAAW;aACX,CAAC;YACF,IAAI,kBAAkB;gBAAE,UAAU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAC5D,IAAI,MAAoE,CAAC;YACzE,IAAI,CAAC;gBACJ,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzC,CAAC;oBAAS,CAAC;gBACV,YAAY,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;YACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC1B,KAAK,EAAE,CAAC;gBACR,KAAK,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;gBACzB,MAAM,IAAI,sBAAsB,CAAC,aAAa,CAAC,CAAC;YACjD,CAAC;YACD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;gBAC/B,KAAK,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;gBACzB,OAAO;YACR,CAAC;YACD,IAAI,MAAM,CAAC,IAAI;gBAAE,OAAO;YACxB,OAAO,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACF,CAAC;YAAS,CAAC;QACV,mBAAmB,EAAE,EAAE,CAAC;IACzB,CAAC;AACF,CAAC","sourcesContent":["/**\n * Idle watchdog for compaction summarization streams.\n *\n * A provider connection can stall — open but silent — for far longer than any\n * user will wait, and compaction previously had no bound at all: the session\n * sat on \"Compacting…\" until ESC aborted it. The agent loop's main-turn\n * reader already has this shape of protection (`StreamIdleTimeoutError` in\n * packages/agent); this brings the same guarantee to summarization requests.\n */\n\nexport class StreamIdleTimeoutError extends Error {\n\treadonly idleTimeoutMs: number;\n\tconstructor(idleTimeoutMs: number) {\n\t\tsuper(`Summarization stream stalled: no provider events for ${idleTimeoutMs}ms; treating the request as dead`);\n\t\tthis.name = \"StreamIdleTimeoutError\";\n\t\tthis.idleTimeoutMs = idleTimeoutMs;\n\t}\n}\n\n/** Matches the agent stream idle-timeout default (`httpIdleTimeoutMs`). */\nexport const DEFAULT_SUMMARIZATION_IDLE_TIMEOUT_MS = 300_000;\n\nexport interface ConsumeStreamWithIdleTimeoutOptions<T> {\n\t/** Silence budget per read; the timer resets on every event. */\n\treadonly idleTimeoutMs: number;\n\t/** Tear down the underlying request (abort the request-local controller). */\n\treadonly abort: () => void;\n\treadonly onEvent?: (event: T) => void;\n\t/** Caller cancellation; an abort here ends the wait without an idle error. */\n\treadonly signal?: AbortSignal;\n}\n\nconst IDLE_TRIP = \"idle-trip\" as const;\nconst CALLER_ABORTED = \"caller-aborted\" as const;\n\n/**\n * Drain an event stream, failing with {@link StreamIdleTimeoutError} when no\n * event arrives within `idleTimeoutMs`. Caller aborts propagate as the\n * stream's own abort outcome, never masked as an idle timeout.\n */\nexport async function consumeStreamWithIdleTimeout<T>(\n\tstream: AsyncIterable<T>,\n\toptions: ConsumeStreamWithIdleTimeoutOptions<T>,\n): Promise<void> {\n\tconst iterator = stream[Symbol.asyncIterator]();\n\tconst { idleTimeoutMs, abort, onEvent, signal } = options;\n\tlet removeAbortListener: (() => void) | undefined;\n\tlet callerAbortPromise: Promise<typeof CALLER_ABORTED> | undefined;\n\tif (signal !== undefined) {\n\t\tif (signal.aborted) {\n\t\t\tvoid iterator.return?.();\n\t\t\treturn;\n\t\t}\n\t\tconst { promise, resolve } = Promise.withResolvers<typeof CALLER_ABORTED>();\n\t\tconst onAbort = () => resolve(CALLER_ABORTED);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\tremoveAbortListener = () => signal.removeEventListener(\"abort\", onAbort);\n\t\tcallerAbortPromise = promise;\n\t}\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { promise: idlePromise, resolve: resolveIdle } = Promise.withResolvers<typeof IDLE_TRIP>();\n\t\t\tconst timer = setTimeout(() => resolveIdle(IDLE_TRIP), idleTimeoutMs);\n\t\t\ttimer.unref?.();\n\t\t\tconst contenders: Array<Promise<IteratorResult<T> | typeof IDLE_TRIP | typeof CALLER_ABORTED>> = [\n\t\t\t\titerator.next(),\n\t\t\t\tidlePromise,\n\t\t\t];\n\t\t\tif (callerAbortPromise) contenders.push(callerAbortPromise);\n\t\t\tlet result: IteratorResult<T> | typeof IDLE_TRIP | typeof CALLER_ABORTED;\n\t\t\ttry {\n\t\t\t\tresult = await Promise.race(contenders);\n\t\t\t} finally {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\tif (result === IDLE_TRIP) {\n\t\t\t\tabort();\n\t\t\t\tvoid iterator.return?.();\n\t\t\t\tthrow new StreamIdleTimeoutError(idleTimeoutMs);\n\t\t\t}\n\t\t\tif (result === CALLER_ABORTED) {\n\t\t\t\tvoid iterator.return?.();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result.done) return;\n\t\t\tonEvent?.(result.value);\n\t\t}\n\t} finally {\n\t\tremoveAbortListener?.();\n\t}\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ExtensionAPI } from "../../types.ts";
2
+ export default function btwExtension(pi: ExtensionAPI): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/btw/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAcrE,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EAAE,EAAE,YAAY,QAmHpD"}
@@ -0,0 +1,120 @@
1
+ import { convertToLlm, filterContextExcludedMessages } from "../../../messages.js";
2
+ import { buildSessionContext } from "../../../session-manager.js";
3
+ import { BtwPanel } from "./panel.js";
4
+ import { buildSideQueryContext, runSideQuery } from "./side-query.js";
5
+ const WIDGET_KEY = "btw";
6
+ const ESCAPE = "";
7
+ export default function btwExtension(pi) {
8
+ let active;
9
+ function dismiss(ctx, options) {
10
+ const current = active;
11
+ if (!current)
12
+ return;
13
+ active = undefined;
14
+ if (options.abort)
15
+ current.controller.abort();
16
+ current.unsubscribeEscape?.();
17
+ if (current.panel)
18
+ ctx.ui.setWidget(WIDGET_KEY, undefined);
19
+ }
20
+ pi.on("session_before_switch", (_event, ctx) => {
21
+ dismiss(ctx, { abort: true });
22
+ });
23
+ pi.on("session_before_fork", (_event, ctx) => {
24
+ dismiss(ctx, { abort: true });
25
+ });
26
+ pi.on("session_shutdown", (_event, ctx) => {
27
+ dismiss(ctx, { abort: true });
28
+ });
29
+ pi.on("input", (_event, ctx) => {
30
+ if (active?.settled)
31
+ dismiss(ctx, { abort: false });
32
+ });
33
+ pi.registerCommand("btw", {
34
+ description: "Ask a side question in parallel without touching the main session",
35
+ argumentHint: "<question>",
36
+ handler: async (args, ctx) => {
37
+ const question = args.trim();
38
+ if (!question) {
39
+ ctx.ui.notify("Usage: /btw <question>", "warning");
40
+ return;
41
+ }
42
+ const model = ctx.model;
43
+ if (!model) {
44
+ ctx.ui.notify("No active model available for /btw.", "error");
45
+ return;
46
+ }
47
+ const snapshot = buildSessionContext(ctx.sessionManager.getEntries(), ctx.sessionManager.getLeafId());
48
+ const history = convertToLlm(filterContextExcludedMessages(snapshot.messages));
49
+ const systemPrompt = ctx.getSystemPrompt();
50
+ const thinkingLevel = pi.getThinkingLevel();
51
+ const sessionId = ctx.sessionManager.getSessionId();
52
+ const context = buildSideQueryContext({ systemPrompt, history, question });
53
+ dismiss(ctx, { abort: true });
54
+ const controller = new AbortController();
55
+ const entry = { controller, panel: undefined, unsubscribeEscape: undefined, settled: false };
56
+ active = entry;
57
+ if (ctx.mode === "tui" && ctx.hasUI) {
58
+ ctx.ui.setWidget(WIDGET_KEY, (tui, theme) => {
59
+ const panel = new BtwPanel(question, tui, theme);
60
+ entry.panel = panel;
61
+ return panel.component;
62
+ });
63
+ entry.unsubscribeEscape = ctx.ui.onTerminalInput((data) => {
64
+ if (active !== entry || data !== ESCAPE)
65
+ return undefined;
66
+ dismiss(ctx, { abort: true });
67
+ return undefined;
68
+ });
69
+ }
70
+ const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
71
+ if (!auth.ok) {
72
+ if (active !== entry)
73
+ return;
74
+ dismiss(ctx, { abort: false });
75
+ ctx.ui.notify(`/btw: ${auth.error}`, "error");
76
+ return;
77
+ }
78
+ try {
79
+ const { replyText } = await runSideQuery({
80
+ model,
81
+ auth: { apiKey: auth.apiKey, headers: auth.headers, extraBody: auth.extraBody },
82
+ sessionId,
83
+ thinkingLevel: thinkingLevel === "off" ? undefined : thinkingLevel,
84
+ }, context, {
85
+ signal: controller.signal,
86
+ onTextDelta: (delta) => {
87
+ if (active === entry)
88
+ entry.panel?.appendText(delta);
89
+ },
90
+ });
91
+ if (active !== entry)
92
+ return;
93
+ entry.settled = true;
94
+ if (entry.panel) {
95
+ entry.panel.markDone();
96
+ }
97
+ else {
98
+ ctx.ui.notify(replyText, "info");
99
+ }
100
+ }
101
+ catch (error) {
102
+ if (active !== entry)
103
+ return;
104
+ entry.settled = true;
105
+ const message = error instanceof Error ? error.message : String(error);
106
+ if (controller.signal.aborted) {
107
+ entry.panel?.markAborted();
108
+ return;
109
+ }
110
+ if (entry.panel) {
111
+ entry.panel.markError(message);
112
+ }
113
+ else {
114
+ ctx.ui.notify(`/btw failed: ${message}`, "error");
115
+ }
116
+ }
117
+ },
118
+ });
119
+ }
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/btw/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { convertToLlm, filterContextExcludedMessages } from \"../../../messages.ts\";\nimport { buildSessionContext } from \"../../../session-manager.ts\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { BtwPanel } from \"./panel.ts\";\nimport { buildSideQueryContext, runSideQuery } from \"./side-query.ts\";\n\nconst WIDGET_KEY = \"btw\";\nconst ESCAPE = \"\u001b\";\n\ninterface ActiveBtw {\n\tcontroller: AbortController;\n\tpanel: BtwPanel | undefined;\n\tunsubscribeEscape: (() => void) | undefined;\n\tsettled: boolean;\n}\n\nexport default function btwExtension(pi: ExtensionAPI) {\n\tlet active: ActiveBtw | undefined;\n\n\tfunction dismiss(ctx: ExtensionContext, options: { abort: boolean }): void {\n\t\tconst current = active;\n\t\tif (!current) return;\n\t\tactive = undefined;\n\t\tif (options.abort) current.controller.abort();\n\t\tcurrent.unsubscribeEscape?.();\n\t\tif (current.panel) ctx.ui.setWidget(WIDGET_KEY, undefined);\n\t}\n\n\tpi.on(\"session_before_switch\", (_event, ctx) => {\n\t\tdismiss(ctx, { abort: true });\n\t});\n\n\tpi.on(\"session_before_fork\", (_event, ctx) => {\n\t\tdismiss(ctx, { abort: true });\n\t});\n\n\tpi.on(\"session_shutdown\", (_event, ctx) => {\n\t\tdismiss(ctx, { abort: true });\n\t});\n\n\tpi.on(\"input\", (_event, ctx) => {\n\t\tif (active?.settled) dismiss(ctx, { abort: false });\n\t});\n\n\tpi.registerCommand(\"btw\", {\n\t\tdescription: \"Ask a side question in parallel without touching the main session\",\n\t\targumentHint: \"<question>\",\n\t\thandler: async (args, ctx) => {\n\t\t\tconst question = args.trim();\n\t\t\tif (!question) {\n\t\t\t\tctx.ui.notify(\"Usage: /btw <question>\", \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst model = ctx.model;\n\t\t\tif (!model) {\n\t\t\t\tctx.ui.notify(\"No active model available for /btw.\", \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst snapshot = buildSessionContext(ctx.sessionManager.getEntries(), ctx.sessionManager.getLeafId());\n\t\t\tconst history = convertToLlm(filterContextExcludedMessages(snapshot.messages));\n\t\t\tconst systemPrompt = ctx.getSystemPrompt();\n\t\t\tconst thinkingLevel = pi.getThinkingLevel();\n\t\t\tconst sessionId = ctx.sessionManager.getSessionId();\n\t\t\tconst context = buildSideQueryContext({ systemPrompt, history, question });\n\n\t\t\tdismiss(ctx, { abort: true });\n\t\t\tconst controller = new AbortController();\n\t\t\tconst entry: ActiveBtw = { controller, panel: undefined, unsubscribeEscape: undefined, settled: false };\n\t\t\tactive = entry;\n\n\t\t\tif (ctx.mode === \"tui\" && ctx.hasUI) {\n\t\t\t\tctx.ui.setWidget(WIDGET_KEY, (tui, theme) => {\n\t\t\t\t\tconst panel = new BtwPanel(question, tui, theme);\n\t\t\t\t\tentry.panel = panel;\n\t\t\t\t\treturn panel.component;\n\t\t\t\t});\n\t\t\t\tentry.unsubscribeEscape = ctx.ui.onTerminalInput((data) => {\n\t\t\t\t\tif (active !== entry || data !== ESCAPE) return undefined;\n\t\t\t\t\tdismiss(ctx, { abort: true });\n\t\t\t\t\treturn undefined;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (!auth.ok) {\n\t\t\t\tif (active !== entry) return;\n\t\t\t\tdismiss(ctx, { abort: false });\n\t\t\t\tctx.ui.notify(`/btw: ${auth.error}`, \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst { replyText } = await runSideQuery(\n\t\t\t\t\t{\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tauth: { apiKey: auth.apiKey, headers: auth.headers, extraBody: auth.extraBody },\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tthinkingLevel: thinkingLevel === \"off\" ? undefined : thinkingLevel,\n\t\t\t\t\t},\n\t\t\t\t\tcontext,\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t\tonTextDelta: (delta) => {\n\t\t\t\t\t\t\tif (active === entry) entry.panel?.appendText(delta);\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (active !== entry) return;\n\t\t\t\tentry.settled = true;\n\t\t\t\tif (entry.panel) {\n\t\t\t\t\tentry.panel.markDone();\n\t\t\t\t} else {\n\t\t\t\t\tctx.ui.notify(replyText, \"info\");\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (active !== entry) return;\n\t\t\t\tentry.settled = true;\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tif (controller.signal.aborted) {\n\t\t\t\t\tentry.panel?.markAborted();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (entry.panel) {\n\t\t\t\t\tentry.panel.markError(message);\n\t\t\t\t} else {\n\t\t\t\t\tctx.ui.notify(`/btw failed: ${message}`, \"error\");\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import { Container, type TUI } from "@earendil-works/pi-tui";
2
+ import type { Theme } from "../../../../modes/interactive/theme/theme.ts";
3
+ export type BtwPanelStatus = "streaming" | "done" | "error" | "aborted";
4
+ export declare class BtwPanel {
5
+ private readonly container;
6
+ private readonly body;
7
+ private readonly question;
8
+ private readonly tui;
9
+ private readonly theme;
10
+ private answer;
11
+ private status;
12
+ private detail;
13
+ constructor(question: string, tui: TUI, theme: Theme);
14
+ get component(): Container;
15
+ appendText(delta: string): void;
16
+ markDone(): void;
17
+ markError(message: string): void;
18
+ markAborted(): void;
19
+ private repaint;
20
+ }
21
+ //# sourceMappingURL=panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/btw/panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAQ,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8CAA8C,CAAC;AAE1E,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAExE,qBAAa,QAAQ;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAAM;IAEpB,YAAY,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAUnD;IAED,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG9B;IAED,QAAQ,IAAI,IAAI,CAGf;IAED,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI/B;IAED,WAAW,IAAI,IAAI,CAGlB;IAED,OAAO,CAAC,OAAO;CAsBf"}
@@ -0,0 +1,61 @@
1
+ import { Container, Text } from "@earendil-works/pi-tui";
2
+ import { DynamicBorder } from "../../../../modes/interactive/components/dynamic-border.js";
3
+ export class BtwPanel {
4
+ constructor(question, tui, theme) {
5
+ this.answer = "";
6
+ this.status = "streaming";
7
+ this.detail = "";
8
+ this.question = question;
9
+ this.tui = tui;
10
+ this.theme = theme;
11
+ this.container = new Container();
12
+ this.container.addChild(new DynamicBorder((s) => this.theme.fg("muted", s)));
13
+ this.body = new Text("", 1, 0);
14
+ this.container.addChild(this.body);
15
+ this.container.addChild(new DynamicBorder((s) => this.theme.fg("muted", s)));
16
+ this.repaint();
17
+ }
18
+ get component() {
19
+ return this.container;
20
+ }
21
+ appendText(delta) {
22
+ this.answer += delta;
23
+ this.repaint();
24
+ }
25
+ markDone() {
26
+ this.status = "done";
27
+ this.repaint();
28
+ }
29
+ markError(message) {
30
+ this.status = "error";
31
+ this.detail = message;
32
+ this.repaint();
33
+ }
34
+ markAborted() {
35
+ this.status = "aborted";
36
+ this.repaint();
37
+ }
38
+ repaint() {
39
+ const thm = this.theme;
40
+ const header = thm.fg("accent", thm.bold("btw: ")) + thm.fg("text", this.question);
41
+ const answer = this.answer ? `\n${this.answer}` : "";
42
+ let footer;
43
+ switch (this.status) {
44
+ case "streaming":
45
+ footer = thm.fg("dim", "\nanswering… (Esc to cancel)");
46
+ break;
47
+ case "done":
48
+ footer = thm.fg("dim", "\n(dismisses on next message)");
49
+ break;
50
+ case "error":
51
+ footer = thm.fg("error", `\nerror: ${this.detail}`);
52
+ break;
53
+ case "aborted":
54
+ footer = thm.fg("dim", "\n(dismissed)");
55
+ break;
56
+ }
57
+ this.body.setText(header + answer + footer);
58
+ this.tui.requestRender();
59
+ }
60
+ }
61
+ //# sourceMappingURL=panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/btw/panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { Container, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport { DynamicBorder } from \"../../../../modes/interactive/components/dynamic-border.ts\";\nimport type { Theme } from \"../../../../modes/interactive/theme/theme.ts\";\n\nexport type BtwPanelStatus = \"streaming\" | \"done\" | \"error\" | \"aborted\";\n\nexport class BtwPanel {\n\tprivate readonly container: Container;\n\tprivate readonly body: Text;\n\tprivate readonly question: string;\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate answer = \"\";\n\tprivate status: BtwPanelStatus = \"streaming\";\n\tprivate detail = \"\";\n\n\tconstructor(question: string, tui: TUI, theme: Theme) {\n\t\tthis.question = question;\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.container = new Container();\n\t\tthis.container.addChild(new DynamicBorder((s: string) => this.theme.fg(\"muted\", s)));\n\t\tthis.body = new Text(\"\", 1, 0);\n\t\tthis.container.addChild(this.body);\n\t\tthis.container.addChild(new DynamicBorder((s: string) => this.theme.fg(\"muted\", s)));\n\t\tthis.repaint();\n\t}\n\n\tget component(): Container {\n\t\treturn this.container;\n\t}\n\n\tappendText(delta: string): void {\n\t\tthis.answer += delta;\n\t\tthis.repaint();\n\t}\n\n\tmarkDone(): void {\n\t\tthis.status = \"done\";\n\t\tthis.repaint();\n\t}\n\n\tmarkError(message: string): void {\n\t\tthis.status = \"error\";\n\t\tthis.detail = message;\n\t\tthis.repaint();\n\t}\n\n\tmarkAborted(): void {\n\t\tthis.status = \"aborted\";\n\t\tthis.repaint();\n\t}\n\n\tprivate repaint(): void {\n\t\tconst thm = this.theme;\n\t\tconst header = thm.fg(\"accent\", thm.bold(\"btw: \")) + thm.fg(\"text\", this.question);\n\t\tconst answer = this.answer ? `\\n${this.answer}` : \"\";\n\t\tlet footer: string;\n\t\tswitch (this.status) {\n\t\t\tcase \"streaming\":\n\t\t\t\tfooter = thm.fg(\"dim\", \"\\nanswering… (Esc to cancel)\");\n\t\t\t\tbreak;\n\t\t\tcase \"done\":\n\t\t\t\tfooter = thm.fg(\"dim\", \"\\n(dismisses on next message)\");\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tfooter = thm.fg(\"error\", `\\nerror: ${this.detail}`);\n\t\t\t\tbreak;\n\t\t\tcase \"aborted\":\n\t\t\t\tfooter = thm.fg(\"dim\", \"\\n(dismissed)\");\n\t\t\t\tbreak;\n\t\t}\n\t\tthis.body.setText(header + answer + footer);\n\t\tthis.tui.requestRender();\n\t}\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import type { Context, Message, Model, StreamFunction, ThinkingLevel } from "@earendil-works/pi-ai/compat";
2
+ export declare const SIDE_QUERY_INSTRUCTION: string;
3
+ export declare const DEFAULT_ESTABLISHMENT_TIMEOUT_MS = 30000;
4
+ export interface SideQueryContextInput {
5
+ systemPrompt: string;
6
+ history: readonly Message[];
7
+ question: string;
8
+ }
9
+ export declare function buildSideQueryContext(input: SideQueryContextInput): Context;
10
+ export interface SideQueryAuth {
11
+ apiKey?: string;
12
+ headers?: Record<string, string>;
13
+ extraBody?: Record<string, unknown>;
14
+ }
15
+ export interface SideQueryDeps {
16
+ model: Model<any>;
17
+ auth: SideQueryAuth;
18
+ sessionId: string;
19
+ thinkingLevel?: ThinkingLevel;
20
+ streamFn?: StreamFunction;
21
+ establishmentTimeoutMs?: number;
22
+ }
23
+ export interface SideQueryCallbacks {
24
+ onTextDelta?: (delta: string) => void;
25
+ signal?: AbortSignal;
26
+ }
27
+ export interface SideQueryResult {
28
+ replyText: string;
29
+ }
30
+ export declare function runSideQuery(deps: SideQueryDeps, context: Context, callbacks?: SideQueryCallbacks): Promise<SideQueryResult>;
31
+ //# sourceMappingURL=side-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-query.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/btw/side-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,OAAO,EACP,OAAO,EACP,KAAK,EAEL,cAAc,EACd,aAAa,EACb,MAAM,8BAA8B,CAAC;AAGtC,eAAO,MAAM,sBAAsB,QAIxB,CAAC;AAEZ,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAM3E;AAED,MAAM,WAAW,aAAa;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IAClC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,YAAY,CACjC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,OAAO,EAChB,SAAS,GAAE,kBAAuB,GAChC,OAAO,CAAC,eAAe,CAAC,CA+C1B"}
@@ -0,0 +1,68 @@
1
+ import { streamSimple } from "@earendil-works/pi-ai/compat";
2
+ export const SIDE_QUERY_INSTRUCTION = [
3
+ "The user is asking a side question about the conversation so far, outside the main task.",
4
+ "Answer it directly and concisely from the context above.",
5
+ "Do not continue any task, do not modify anything, and do not treat this as new work.",
6
+ ].join(" ");
7
+ export const DEFAULT_ESTABLISHMENT_TIMEOUT_MS = 30_000;
8
+ export function buildSideQueryContext(input) {
9
+ return {
10
+ systemPrompt: `${input.systemPrompt}\n\n${SIDE_QUERY_INSTRUCTION}`,
11
+ messages: [...input.history, { role: "user", content: input.question, timestamp: Date.now() }],
12
+ tools: [],
13
+ };
14
+ }
15
+ export async function runSideQuery(deps, context, callbacks = {}) {
16
+ callbacks.signal?.throwIfAborted();
17
+ const streamFn = deps.streamFn ?? streamSimple;
18
+ const establishment = new AbortController();
19
+ const signal = callbacks.signal ? AbortSignal.any([callbacks.signal, establishment.signal]) : establishment.signal;
20
+ const timeoutMs = deps.establishmentTimeoutMs ?? DEFAULT_ESTABLISHMENT_TIMEOUT_MS;
21
+ const timeoutError = new Error(`/btw provider did not produce an event within ${Math.round(timeoutMs / 1000)}s`);
22
+ let timer;
23
+ try {
24
+ const options = {
25
+ apiKey: deps.auth.apiKey,
26
+ headers: deps.auth.headers,
27
+ extraBody: deps.auth.extraBody,
28
+ sessionId: `${deps.sessionId}:btw:${crypto.randomUUID()}`,
29
+ reasoning: deps.thinkingLevel,
30
+ signal,
31
+ };
32
+ timer = setTimeout(() => establishment.abort(timeoutError), timeoutMs);
33
+ timer.unref?.();
34
+ const stream = await streamFn(deps.model, context, options);
35
+ let established = false;
36
+ let replyText = "";
37
+ for await (const event of stream) {
38
+ if (!established && event.type !== "start") {
39
+ established = true;
40
+ clearTimeout(timer);
41
+ timer = undefined;
42
+ }
43
+ if (event.type === "text_delta") {
44
+ replyText += event.delta;
45
+ callbacks.onTextDelta?.(event.delta);
46
+ }
47
+ else if (event.type === "done") {
48
+ break;
49
+ }
50
+ else if (event.type === "error") {
51
+ throw new Error(event.error.errorMessage || "Side query failed");
52
+ }
53
+ }
54
+ signal.throwIfAborted();
55
+ return { replyText };
56
+ }
57
+ catch (error) {
58
+ if (establishment.signal.aborted && !callbacks.signal?.aborted) {
59
+ throw timeoutError;
60
+ }
61
+ throw error;
62
+ }
63
+ finally {
64
+ if (timer)
65
+ clearTimeout(timer);
66
+ }
67
+ }
68
+ //# sourceMappingURL=side-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-query.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/btw/side-query.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tContext,\n\tMessage,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tThinkingLevel,\n} from \"@earendil-works/pi-ai/compat\";\nimport { streamSimple } from \"@earendil-works/pi-ai/compat\";\n\nexport const SIDE_QUERY_INSTRUCTION = [\n\t\"The user is asking a side question about the conversation so far, outside the main task.\",\n\t\"Answer it directly and concisely from the context above.\",\n\t\"Do not continue any task, do not modify anything, and do not treat this as new work.\",\n].join(\" \");\n\nexport const DEFAULT_ESTABLISHMENT_TIMEOUT_MS = 30_000;\n\nexport interface SideQueryContextInput {\n\tsystemPrompt: string;\n\thistory: readonly Message[];\n\tquestion: string;\n}\n\nexport function buildSideQueryContext(input: SideQueryContextInput): Context {\n\treturn {\n\t\tsystemPrompt: `${input.systemPrompt}\\n\\n${SIDE_QUERY_INSTRUCTION}`,\n\t\tmessages: [...input.history, { role: \"user\", content: input.question, timestamp: Date.now() }],\n\t\ttools: [],\n\t};\n}\n\nexport interface SideQueryAuth {\n\tapiKey?: string;\n\theaders?: Record<string, string>;\n\textraBody?: Record<string, unknown>;\n}\n\nexport interface SideQueryDeps {\n\tmodel: Model<any>;\n\tauth: SideQueryAuth;\n\tsessionId: string;\n\tthinkingLevel?: ThinkingLevel;\n\tstreamFn?: StreamFunction;\n\testablishmentTimeoutMs?: number;\n}\n\nexport interface SideQueryCallbacks {\n\tonTextDelta?: (delta: string) => void;\n\tsignal?: AbortSignal;\n}\n\nexport interface SideQueryResult {\n\treplyText: string;\n}\n\nexport async function runSideQuery(\n\tdeps: SideQueryDeps,\n\tcontext: Context,\n\tcallbacks: SideQueryCallbacks = {},\n): Promise<SideQueryResult> {\n\tcallbacks.signal?.throwIfAborted();\n\tconst streamFn = deps.streamFn ?? streamSimple;\n\tconst establishment = new AbortController();\n\tconst signal = callbacks.signal ? AbortSignal.any([callbacks.signal, establishment.signal]) : establishment.signal;\n\tconst timeoutMs = deps.establishmentTimeoutMs ?? DEFAULT_ESTABLISHMENT_TIMEOUT_MS;\n\tconst timeoutError = new Error(`/btw provider did not produce an event within ${Math.round(timeoutMs / 1000)}s`);\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\ttry {\n\t\tconst options: SimpleStreamOptions = {\n\t\t\tapiKey: deps.auth.apiKey,\n\t\t\theaders: deps.auth.headers,\n\t\t\textraBody: deps.auth.extraBody,\n\t\t\tsessionId: `${deps.sessionId}:btw:${crypto.randomUUID()}`,\n\t\t\treasoning: deps.thinkingLevel,\n\t\t\tsignal,\n\t\t};\n\t\ttimer = setTimeout(() => establishment.abort(timeoutError), timeoutMs);\n\t\ttimer.unref?.();\n\t\tconst stream = await streamFn(deps.model, context, options);\n\t\tlet established = false;\n\t\tlet replyText = \"\";\n\t\tfor await (const event of stream) {\n\t\t\tif (!established && event.type !== \"start\") {\n\t\t\t\testablished = true;\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimer = undefined;\n\t\t\t}\n\t\t\tif (event.type === \"text_delta\") {\n\t\t\t\treplyText += event.delta;\n\t\t\t\tcallbacks.onTextDelta?.(event.delta);\n\t\t\t} else if (event.type === \"done\") {\n\t\t\t\tbreak;\n\t\t\t} else if (event.type === \"error\") {\n\t\t\t\tthrow new Error(event.error.errorMessage || \"Side query failed\");\n\t\t\t}\n\t\t}\n\t\tsignal.throwIfAborted();\n\t\treturn { replyText };\n\t} catch (error) {\n\t\tif (establishment.signal.aborted && !callbacks.signal?.aborted) {\n\t\t\tthrow timeoutError;\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tif (timer) clearTimeout(timer);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAgB,YAAY,EAA+C,MAAM,gBAAgB,CAAC;AA+I9G,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA2VlE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAgB,YAAY,EAA+C,MAAM,gBAAgB,CAAC;AAgJ9G,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA8XlE"}
@@ -9,7 +9,7 @@ import * as cap from "./per-turn-cap.js";
9
9
  import * as policy from "./policy.js";
10
10
  import { repairOrphanedToolResults } from "./repair-tool-pairs.js";
11
11
  import * as restoration from "./restoration-tracker.js";
12
- import { applyGeneratedCompaction, createSpeculativeCompactionSnapshot, getPromptVariant, hardLimitEmergencyPrune, runExtensionCompaction, } from "./speculative.js";
12
+ import { applyGeneratedCompaction, createSpeculativeCompactionSnapshot, getPromptVariant, hardLimitEmergencyPrune, runExtensionCompaction, SummaryGenerationError, } from "./speculative.js";
13
13
  import { createInitialState, resetTurnCounter } from "./state.js";
14
14
  import * as todoBridge from "./todo-bridge.js";
15
15
  const DEFAULT_CONTEXT_WINDOW = 200_000;
@@ -214,7 +214,18 @@ export default function compactionExtension(pi) {
214
214
  endCompactionFeedback(ctx, feedbackSignal, result);
215
215
  return result;
216
216
  }
217
- const compaction = await runExtensionCompaction(ctx, snapshot, feedbackSignal, (delta) => ctx.updateCompaction?.({ reason: "extension", delta }));
217
+ let compaction;
218
+ try {
219
+ compaction = await runExtensionCompaction(ctx, snapshot, feedbackSignal, (delta) => ctx.updateCompaction?.({ reason: "extension", delta }));
220
+ }
221
+ catch (error) {
222
+ // Auto-path parity: summary-generation failures (missing credentials,
223
+ // text-less response) degrade to "unavailable" exactly as before
224
+ // instead of erroring the turn; the precise reason still surfaces on
225
+ // the session_before_compact route.
226
+ if (!(error instanceof SummaryGenerationError))
227
+ throw error;
228
+ }
218
229
  const result = await applyGeneratedCompaction(ctx, snapshot, () => speculativeGeneration, compaction);
219
230
  endCompactionFeedback(ctx, feedbackSignal, result);
220
231
  return result;
@@ -231,10 +242,23 @@ export default function compactionExtension(pi) {
231
242
  }
232
243
  pi.on("session_before_compact", async (event, ctx) => {
233
244
  invalidateSpeculativeCompaction();
234
- if (cap.shouldRejectByCap(state, { reason: event.reason }).cancel)
235
- return { cancel: true };
236
- if (breaker.isTripped(state, Date.now()) && !breaker.shouldBypass(state, { reason: event.reason }))
237
- return { cancel: true };
245
+ if (cap.shouldRejectByCap(state, { reason: event.reason }).cancel) {
246
+ return {
247
+ cancel: true,
248
+ rejectionCause: "per-turn-cap",
249
+ reason: "per-turn compaction cap reached for this turn",
250
+ };
251
+ }
252
+ const now = Date.now();
253
+ if (breaker.isTripped(state, now) && !breaker.shouldBypass(state, { reason: event.reason })) {
254
+ const remainingMs = state.trippedAt !== null ? Math.max(0, state.trippedAt + breaker.COOLDOWN_MS - now) : 0;
255
+ const remainingSec = Math.ceil(remainingMs / 1000);
256
+ return {
257
+ cancel: true,
258
+ rejectionCause: "circuit-breaker",
259
+ reason: `compaction circuit breaker cooling down (${remainingSec}s left)`,
260
+ };
261
+ }
238
262
  capturePendingMetadata(event.requestId, ctx);
239
263
  const model = ctx.model;
240
264
  if (!model)
@@ -263,14 +287,24 @@ export default function compactionExtension(pi) {
263
287
  // limit) instead of letting it degrade into a bare "Compaction
264
288
  // cancelled". Cancel rather than fall back: the core route would
265
289
  // re-send the same conversation and burn tokens on the same failure.
266
- const message = error instanceof Error ? error.message : String(error);
267
- ctx.ui.notify(`Compaction failed: ${message}`, "error");
290
+ // The reason threads into compaction_end.errorMessage so the UI shows
291
+ // the real provider message; ctx.ui.notify would be a duplicate toast.
268
292
  pendingMetadata.delete(event.requestId);
269
- return { cancel: true };
293
+ if (error instanceof SummaryGenerationError) {
294
+ return { cancel: true, reason: error.message };
295
+ }
296
+ const message = error instanceof Error ? error.message : String(error);
297
+ return { cancel: true, reason: `compaction generator failed: ${message}` };
270
298
  }
271
299
  if (!compaction) {
272
300
  pendingMetadata.delete(event.requestId);
273
- return { cancel: true };
301
+ if (event.signal.aborted) {
302
+ // User abort: returning no reason lets agent-session's aborted branch
303
+ // render the plain "Compaction cancelled" instead of a misleading
304
+ // "returned no summary" rejection.
305
+ return { cancel: true };
306
+ }
307
+ return { cancel: true, reason: "compaction generator returned no summary" };
274
308
  }
275
309
  return {
276
310
  compaction,
@@ -311,8 +345,10 @@ export default function compactionExtension(pi) {
311
345
  }
312
346
  return;
313
347
  }
348
+ // Rejection feedback is emitted by core via compaction_end.errorMessage;
349
+ // duplicating it as a ctx.ui.notify toast produces double surfaces while
350
+ // the compaction status indicator is still animating (plan §1 Q3).
314
351
  state = breaker.recordFailure(state, Date.now(), { route: event.reason });
315
- ctx.ui.notify(`Compaction rejected: ${event.rejectionCause ?? "unknown"}`, "warning");
316
352
  });
317
353
  pi.on("before_agent_start", async (event, ctx) => {
318
354
  let systemPrompt = event.systemPrompt;