visionclaw 0.1.219-beta.0 → 0.1.219-dev.codex-issue-2805-worker-runtime.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 (524) hide show
  1. package/dist/agent/api-proxy.d.ts +0 -16
  2. package/dist/agent/api-proxy.d.ts.map +1 -1
  3. package/dist/agent/api-proxy.js +9 -8
  4. package/dist/agent/api-proxy.js.map +1 -1
  5. package/dist/agent/browser-launcher.d.ts +3 -0
  6. package/dist/agent/browser-launcher.d.ts.map +1 -1
  7. package/dist/agent/browser-launcher.js +101 -43
  8. package/dist/agent/browser-launcher.js.map +1 -1
  9. package/dist/agent/coding-conventions.d.ts +8 -0
  10. package/dist/agent/coding-conventions.d.ts.map +1 -0
  11. package/dist/agent/coding-conventions.js +19 -0
  12. package/dist/agent/coding-conventions.js.map +1 -0
  13. package/dist/agent/command-handlers.d.ts.map +1 -1
  14. package/dist/agent/command-handlers.js +4 -16
  15. package/dist/agent/command-handlers.js.map +1 -1
  16. package/dist/agent/context-action-restart-fallback.d.ts.map +1 -1
  17. package/dist/agent/context-action-restart-fallback.js +9 -3
  18. package/dist/agent/context-action-restart-fallback.js.map +1 -1
  19. package/dist/agent/context-refresh.d.ts.map +1 -1
  20. package/dist/agent/context-refresh.js +0 -7
  21. package/dist/agent/context-refresh.js.map +1 -1
  22. package/dist/agent/context.d.ts +2 -4
  23. package/dist/agent/context.d.ts.map +1 -1
  24. package/dist/agent/context.js +12 -21
  25. package/dist/agent/context.js.map +1 -1
  26. package/dist/agent/engine-fallback.d.ts +0 -35
  27. package/dist/agent/engine-fallback.d.ts.map +1 -1
  28. package/dist/agent/engine-fallback.js +4 -3
  29. package/dist/agent/engine-fallback.js.map +1 -1
  30. package/dist/agent/engine-switch.d.ts +19 -38
  31. package/dist/agent/engine-switch.d.ts.map +1 -1
  32. package/dist/agent/engine-switch.js +46 -111
  33. package/dist/agent/engine-switch.js.map +1 -1
  34. package/dist/agent/engines/browser-tool-policy.d.ts +12 -1
  35. package/dist/agent/engines/browser-tool-policy.d.ts.map +1 -1
  36. package/dist/agent/engines/browser-tool-policy.js +17 -2
  37. package/dist/agent/engines/browser-tool-policy.js.map +1 -1
  38. package/dist/agent/engines/claude/executor-shell-groups.d.ts +11 -0
  39. package/dist/agent/engines/claude/executor-shell-groups.d.ts.map +1 -0
  40. package/dist/agent/engines/claude/executor-shell-groups.js +22 -0
  41. package/dist/agent/engines/claude/executor-shell-groups.js.map +1 -0
  42. package/dist/agent/engines/claude/session.d.ts +13 -4
  43. package/dist/agent/engines/claude/session.d.ts.map +1 -1
  44. package/dist/agent/engines/claude/session.js +165 -84
  45. package/dist/agent/engines/claude/session.js.map +1 -1
  46. package/dist/agent/engines/pi/shared/usage.d.ts +6 -8
  47. package/dist/agent/engines/pi/shared/usage.d.ts.map +1 -1
  48. package/dist/agent/engines/pi/shared/usage.js +24 -7
  49. package/dist/agent/engines/pi/shared/usage.js.map +1 -1
  50. package/dist/agent/engines/pi/tools.d.ts +3 -10
  51. package/dist/agent/engines/pi/tools.d.ts.map +1 -1
  52. package/dist/agent/engines/pi/tools.js +6 -20
  53. package/dist/agent/engines/pi/tools.js.map +1 -1
  54. package/dist/agent/engines/pi-coding/executor-shell.d.ts +4 -0
  55. package/dist/agent/engines/pi-coding/executor-shell.d.ts.map +1 -0
  56. package/dist/agent/engines/pi-coding/executor-shell.js +175 -0
  57. package/dist/agent/engines/pi-coding/executor-shell.js.map +1 -0
  58. package/dist/agent/engines/pi-coding/session.d.ts +4 -4
  59. package/dist/agent/engines/pi-coding/session.d.ts.map +1 -1
  60. package/dist/agent/engines/pi-coding/session.js +118 -66
  61. package/dist/agent/engines/pi-coding/session.js.map +1 -1
  62. package/dist/agent/engines/pi-coding/tools.d.ts +2 -5
  63. package/dist/agent/engines/pi-coding/tools.d.ts.map +1 -1
  64. package/dist/agent/engines/pi-coding/tools.js +7 -5
  65. package/dist/agent/engines/pi-coding/tools.js.map +1 -1
  66. package/dist/agent/engines/session-types.d.ts +8 -8
  67. package/dist/agent/engines/session-types.d.ts.map +1 -1
  68. package/dist/agent/external-context/interrupt.d.ts +0 -2
  69. package/dist/agent/external-context/interrupt.d.ts.map +1 -1
  70. package/dist/agent/external-context/interrupt.js +0 -1
  71. package/dist/agent/external-context/interrupt.js.map +1 -1
  72. package/dist/agent/external-context/registry.d.ts +0 -2
  73. package/dist/agent/external-context/registry.d.ts.map +1 -1
  74. package/dist/agent/external-context/registry.js +2 -4
  75. package/dist/agent/external-context/registry.js.map +1 -1
  76. package/dist/agent/external-context/runtime.d.ts.map +1 -1
  77. package/dist/agent/external-context/runtime.js +15 -14
  78. package/dist/agent/external-context/runtime.js.map +1 -1
  79. package/dist/agent/external-context/types.d.ts +0 -2
  80. package/dist/agent/external-context/types.d.ts.map +1 -1
  81. package/dist/agent/fast-responder.d.ts +4 -20
  82. package/dist/agent/fast-responder.d.ts.map +1 -1
  83. package/dist/agent/fast-responder.js +28 -42
  84. package/dist/agent/fast-responder.js.map +1 -1
  85. package/dist/agent/interrupt-handler.d.ts +4 -18
  86. package/dist/agent/interrupt-handler.d.ts.map +1 -1
  87. package/dist/agent/interrupt-handler.js +52 -283
  88. package/dist/agent/interrupt-handler.js.map +1 -1
  89. package/dist/agent/lab-run-system-prompt.d.ts.map +1 -1
  90. package/dist/agent/lab-run-system-prompt.js +4 -1
  91. package/dist/agent/lab-run-system-prompt.js.map +1 -1
  92. package/dist/agent/lifecycle-trace.d.ts.map +1 -1
  93. package/dist/agent/lifecycle-trace.js +6 -5
  94. package/dist/agent/lifecycle-trace.js.map +1 -1
  95. package/dist/agent/loop.d.ts +9 -3
  96. package/dist/agent/loop.d.ts.map +1 -1
  97. package/dist/agent/loop.js +288 -157
  98. package/dist/agent/loop.js.map +1 -1
  99. package/dist/agent/memory-protocol.d.ts +2 -2
  100. package/dist/agent/memory-protocol.d.ts.map +1 -1
  101. package/dist/agent/memory-protocol.js +3 -15
  102. package/dist/agent/memory-protocol.js.map +1 -1
  103. package/dist/agent/memory-store.d.ts +58 -0
  104. package/dist/agent/memory-store.d.ts.map +1 -0
  105. package/dist/agent/memory-store.js +152 -0
  106. package/dist/agent/memory-store.js.map +1 -0
  107. package/dist/agent/model-provider.d.ts +18 -5
  108. package/dist/agent/model-provider.d.ts.map +1 -1
  109. package/dist/agent/model-provider.js +58 -18
  110. package/dist/agent/model-provider.js.map +1 -1
  111. package/dist/agent/nightly-maintenance/dreaming-batch.d.ts +184 -0
  112. package/dist/agent/nightly-maintenance/dreaming-batch.d.ts.map +1 -0
  113. package/dist/agent/nightly-maintenance/dreaming-batch.js +192 -0
  114. package/dist/agent/nightly-maintenance/dreaming-batch.js.map +1 -0
  115. package/dist/agent/nightly-maintenance/dreaming-files.d.ts +48 -0
  116. package/dist/agent/nightly-maintenance/dreaming-files.d.ts.map +1 -0
  117. package/dist/agent/nightly-maintenance/dreaming-files.js +109 -0
  118. package/dist/agent/nightly-maintenance/dreaming-files.js.map +1 -0
  119. package/dist/agent/nightly-maintenance/dreaming-ledger.d.ts +62 -0
  120. package/dist/agent/nightly-maintenance/dreaming-ledger.d.ts.map +1 -0
  121. package/dist/agent/nightly-maintenance/dreaming-ledger.js +146 -0
  122. package/dist/agent/nightly-maintenance/dreaming-ledger.js.map +1 -0
  123. package/dist/agent/nightly-maintenance/dreaming-planner.d.ts +86 -0
  124. package/dist/agent/nightly-maintenance/dreaming-planner.d.ts.map +1 -0
  125. package/dist/agent/nightly-maintenance/dreaming-planner.js +304 -0
  126. package/dist/agent/nightly-maintenance/dreaming-planner.js.map +1 -0
  127. package/dist/agent/nightly-maintenance/dreaming-runner.d.ts +93 -0
  128. package/dist/agent/nightly-maintenance/dreaming-runner.d.ts.map +1 -0
  129. package/dist/agent/nightly-maintenance/dreaming-runner.js +156 -0
  130. package/dist/agent/nightly-maintenance/dreaming-runner.js.map +1 -0
  131. package/dist/agent/nightly-maintenance/dreaming-sources.d.ts +115 -0
  132. package/dist/agent/nightly-maintenance/dreaming-sources.d.ts.map +1 -0
  133. package/dist/agent/nightly-maintenance/dreaming-sources.js +270 -0
  134. package/dist/agent/nightly-maintenance/dreaming-sources.js.map +1 -0
  135. package/dist/agent/nightly-maintenance/index.d.ts +28 -8
  136. package/dist/agent/nightly-maintenance/index.d.ts.map +1 -1
  137. package/dist/agent/nightly-maintenance/index.js +42 -15
  138. package/dist/agent/nightly-maintenance/index.js.map +1 -1
  139. package/dist/agent/nightly-maintenance/skill-learning-gate.js +1 -1
  140. package/dist/agent/nightly-maintenance/skill-learning-gate.js.map +1 -1
  141. package/dist/agent/nightly-maintenance/vocabulary-processor.d.ts +1 -1
  142. package/dist/agent/nightly-maintenance/vocabulary-processor.d.ts.map +1 -1
  143. package/dist/agent/product-identity.d.ts +5 -4
  144. package/dist/agent/product-identity.d.ts.map +1 -1
  145. package/dist/agent/product-identity.js +7 -6
  146. package/dist/agent/product-identity.js.map +1 -1
  147. package/dist/agent/public-activity.js +1 -1
  148. package/dist/agent/public-activity.js.map +1 -1
  149. package/dist/agent/reply-watchdog.d.ts +5 -3
  150. package/dist/agent/reply-watchdog.d.ts.map +1 -1
  151. package/dist/agent/reply-watchdog.js +6 -4
  152. package/dist/agent/reply-watchdog.js.map +1 -1
  153. package/dist/agent/runtime-context.d.ts +27 -0
  154. package/dist/agent/runtime-context.d.ts.map +1 -0
  155. package/dist/agent/runtime-context.js +60 -0
  156. package/dist/agent/runtime-context.js.map +1 -0
  157. package/dist/agent/runtime-disclosure-policy.d.ts +6 -0
  158. package/dist/agent/runtime-disclosure-policy.d.ts.map +1 -0
  159. package/dist/agent/runtime-disclosure-policy.js +16 -0
  160. package/dist/agent/runtime-disclosure-policy.js.map +1 -0
  161. package/dist/agent/runtime-surface.d.ts +15 -4
  162. package/dist/agent/runtime-surface.d.ts.map +1 -1
  163. package/dist/agent/runtime-surface.js +0 -1
  164. package/dist/agent/runtime-surface.js.map +1 -1
  165. package/dist/agent/session-manager.d.ts +30 -126
  166. package/dist/agent/session-manager.d.ts.map +1 -1
  167. package/dist/agent/session-manager.js +60 -484
  168. package/dist/agent/session-manager.js.map +1 -1
  169. package/dist/agent/state.d.ts +42 -2
  170. package/dist/agent/state.d.ts.map +1 -1
  171. package/dist/agent/state.js +21 -11
  172. package/dist/agent/state.js.map +1 -1
  173. package/dist/agent/stream-handler.d.ts +6 -13
  174. package/dist/agent/stream-handler.d.ts.map +1 -1
  175. package/dist/agent/stream-handler.js +8 -62
  176. package/dist/agent/stream-handler.js.map +1 -1
  177. package/dist/agent/system-prompt.d.ts +2 -0
  178. package/dist/agent/system-prompt.d.ts.map +1 -1
  179. package/dist/agent/system-prompt.js +21 -20
  180. package/dist/agent/system-prompt.js.map +1 -1
  181. package/dist/agent/tool-usage.d.ts.map +1 -1
  182. package/dist/agent/tool-usage.js +0 -1
  183. package/dist/agent/tool-usage.js.map +1 -1
  184. package/dist/agent/transcript/transcript-backfill.js +3 -3
  185. package/dist/agent/transcript/transcript-backfill.js.map +1 -1
  186. package/dist/agent/transcript/transcript-indexer.d.ts +3 -31
  187. package/dist/agent/transcript/transcript-indexer.d.ts.map +1 -1
  188. package/dist/agent/transcript/transcript-indexer.js +58 -57
  189. package/dist/agent/transcript/transcript-indexer.js.map +1 -1
  190. package/dist/agent/transcript-parsers/trivial-tools.d.ts.map +1 -1
  191. package/dist/agent/transcript-parsers/trivial-tools.js +0 -2
  192. package/dist/agent/transcript-parsers/trivial-tools.js.map +1 -1
  193. package/dist/agent/transcript-parsers/types.d.ts +1 -1
  194. package/dist/agent/transcript-summarizer.d.ts +14 -0
  195. package/dist/agent/transcript-summarizer.d.ts.map +1 -1
  196. package/dist/agent/transcript-summarizer.js +69 -45
  197. package/dist/agent/transcript-summarizer.js.map +1 -1
  198. package/dist/agent/usage/usage-report-queue.d.ts.map +1 -1
  199. package/dist/agent/usage/usage-report-queue.js +53 -52
  200. package/dist/agent/usage/usage-report-queue.js.map +1 -1
  201. package/dist/agent/usage/usage-report-types.d.ts +1 -1
  202. package/dist/agent/usage/usage-report-types.d.ts.map +1 -1
  203. package/dist/agent/vocabulary-glossary.d.ts +3 -3
  204. package/dist/agent/wake-cycle-runner.d.ts +14 -17
  205. package/dist/agent/wake-cycle-runner.d.ts.map +1 -1
  206. package/dist/agent/wake-cycle-runner.js +121 -290
  207. package/dist/agent/wake-cycle-runner.js.map +1 -1
  208. package/dist/builtin-skills/owner-manual/SKILL.md +2 -2
  209. package/dist/calendar/occurrence-ownership.d.ts.map +1 -1
  210. package/dist/calendar/occurrence-ownership.js +6 -5
  211. package/dist/calendar/occurrence-ownership.js.map +1 -1
  212. package/dist/calendar/scheduler.d.ts.map +1 -1
  213. package/dist/calendar/scheduler.js +4 -3
  214. package/dist/calendar/scheduler.js.map +1 -1
  215. package/dist/channels/interface.d.ts +8 -2
  216. package/dist/channels/interface.d.ts.map +1 -1
  217. package/dist/channels/interface.js +8 -1
  218. package/dist/channels/interface.js.map +1 -1
  219. package/dist/channels/manager.d.ts.map +1 -1
  220. package/dist/channels/manager.js +5 -1
  221. package/dist/channels/manager.js.map +1 -1
  222. package/dist/channels/queue.d.ts.map +1 -1
  223. package/dist/channels/queue.js +8 -0
  224. package/dist/channels/queue.js.map +1 -1
  225. package/dist/channels/tui.d.ts +14 -1
  226. package/dist/channels/tui.d.ts.map +1 -1
  227. package/dist/channels/tui.js +64 -2
  228. package/dist/channels/tui.js.map +1 -1
  229. package/dist/cli/index.d.ts +2 -2
  230. package/dist/cli/index.d.ts.map +1 -1
  231. package/dist/cli/index.js +22 -53
  232. package/dist/cli/index.js.map +1 -1
  233. package/dist/config/index.d.ts +13 -7
  234. package/dist/config/index.d.ts.map +1 -1
  235. package/dist/config/index.js +51 -64
  236. package/dist/config/index.js.map +1 -1
  237. package/dist/config/types.d.ts +28 -7
  238. package/dist/config/types.d.ts.map +1 -1
  239. package/dist/config/types.js +22 -20
  240. package/dist/config/types.js.map +1 -1
  241. package/dist/conversations/lazy-runtime.d.ts +5 -0
  242. package/dist/conversations/lazy-runtime.d.ts.map +1 -0
  243. package/dist/conversations/lazy-runtime.js +12 -0
  244. package/dist/conversations/lazy-runtime.js.map +1 -0
  245. package/dist/conversations/runtime.d.ts +17 -0
  246. package/dist/conversations/runtime.d.ts.map +1 -0
  247. package/dist/conversations/runtime.js +92 -0
  248. package/dist/conversations/runtime.js.map +1 -0
  249. package/dist/conversations/scheduler.d.ts +57 -0
  250. package/dist/conversations/scheduler.d.ts.map +1 -0
  251. package/dist/conversations/scheduler.js +175 -0
  252. package/dist/conversations/scheduler.js.map +1 -0
  253. package/dist/data-processing/pipeline.d.ts +0 -2
  254. package/dist/data-processing/pipeline.d.ts.map +1 -1
  255. package/dist/data-processing/pipeline.js +19 -24
  256. package/dist/data-processing/pipeline.js.map +1 -1
  257. package/dist/data-processing/restructure.d.ts +0 -2
  258. package/dist/data-processing/restructure.d.ts.map +1 -1
  259. package/dist/data-processing/restructure.js +6 -9
  260. package/dist/data-processing/restructure.js.map +1 -1
  261. package/dist/data-processing/types.d.ts +2 -9
  262. package/dist/data-processing/types.d.ts.map +1 -1
  263. package/dist/data-processing/types.js +2 -13
  264. package/dist/data-processing/types.js.map +1 -1
  265. package/dist/email/email-route-store.d.ts.map +1 -1
  266. package/dist/email/email-route-store.js +6 -5
  267. package/dist/email/email-route-store.js.map +1 -1
  268. package/dist/i18n/messages.d.ts +26 -2
  269. package/dist/i18n/messages.d.ts.map +1 -1
  270. package/dist/i18n/messages.js +30 -5
  271. package/dist/i18n/messages.js.map +1 -1
  272. package/dist/index.js.map +1 -1
  273. package/dist/logger.d.ts +11 -0
  274. package/dist/logger.d.ts.map +1 -1
  275. package/dist/logger.js +49 -1
  276. package/dist/logger.js.map +1 -1
  277. package/dist/obs/mini-app/status.d.ts.map +1 -1
  278. package/dist/obs/mini-app/status.js +0 -1
  279. package/dist/obs/mini-app/status.js.map +1 -1
  280. package/dist/onboarding/onboarding-service-client.d.ts +1 -0
  281. package/dist/onboarding/onboarding-service-client.d.ts.map +1 -1
  282. package/dist/onboarding/onboarding-service-client.js.map +1 -1
  283. package/dist/onboarding/remote-set-owner.d.ts.map +1 -1
  284. package/dist/onboarding/remote-set-owner.js +0 -1
  285. package/dist/onboarding/remote-set-owner.js.map +1 -1
  286. package/dist/onboarding/set-owner.d.ts +1 -1
  287. package/dist/onboarding/set-owner.d.ts.map +1 -1
  288. package/dist/onboarding/set-owner.js +3 -6
  289. package/dist/onboarding/set-owner.js.map +1 -1
  290. package/dist/reconfigure.d.ts.map +1 -1
  291. package/dist/reconfigure.js +1 -32
  292. package/dist/reconfigure.js.map +1 -1
  293. package/dist/reset.d.ts.map +1 -1
  294. package/dist/reset.js +3 -1
  295. package/dist/reset.js.map +1 -1
  296. package/dist/threads/active-threads-store.d.ts.map +1 -1
  297. package/dist/threads/active-threads-store.js +8 -27
  298. package/dist/threads/active-threads-store.js.map +1 -1
  299. package/dist/threads/dreaming-execution.d.ts +10 -0
  300. package/dist/threads/dreaming-execution.d.ts.map +1 -0
  301. package/dist/threads/dreaming-execution.js +78 -0
  302. package/dist/threads/dreaming-execution.js.map +1 -0
  303. package/dist/threads/execution-authority.d.ts +43 -0
  304. package/dist/threads/execution-authority.d.ts.map +1 -0
  305. package/dist/threads/execution-authority.js +75 -0
  306. package/dist/threads/execution-authority.js.map +1 -0
  307. package/dist/threads/execution-budget.d.ts +107 -0
  308. package/dist/threads/execution-budget.d.ts.map +1 -0
  309. package/dist/threads/execution-budget.js +257 -0
  310. package/dist/threads/execution-budget.js.map +1 -0
  311. package/dist/threads/execution-host.d.ts +17 -0
  312. package/dist/threads/execution-host.d.ts.map +1 -0
  313. package/dist/threads/execution-host.js +66 -0
  314. package/dist/threads/execution-host.js.map +1 -0
  315. package/dist/threads/execution-scheduler.d.ts +162 -0
  316. package/dist/threads/execution-scheduler.d.ts.map +1 -0
  317. package/dist/threads/execution-scheduler.js +413 -0
  318. package/dist/threads/execution-scheduler.js.map +1 -0
  319. package/dist/threads/execution-snapshot.d.ts +91 -0
  320. package/dist/threads/execution-snapshot.d.ts.map +1 -0
  321. package/dist/threads/execution-snapshot.js +146 -0
  322. package/dist/threads/execution-snapshot.js.map +1 -0
  323. package/dist/threads/execution-store.d.ts +374 -0
  324. package/dist/threads/execution-store.d.ts.map +1 -0
  325. package/dist/threads/execution-store.js +910 -0
  326. package/dist/threads/execution-store.js.map +1 -0
  327. package/dist/threads/execution-thread-error.d.ts +9 -0
  328. package/dist/threads/execution-thread-error.d.ts.map +1 -0
  329. package/dist/threads/execution-thread-error.js +12 -0
  330. package/dist/threads/execution-thread-error.js.map +1 -0
  331. package/dist/threads/executor-exit.d.ts +18 -0
  332. package/dist/threads/executor-exit.d.ts.map +1 -0
  333. package/dist/threads/executor-exit.js +21 -0
  334. package/dist/threads/executor-exit.js.map +1 -0
  335. package/dist/threads/foreground-task.d.ts +91 -0
  336. package/dist/threads/foreground-task.d.ts.map +1 -0
  337. package/dist/threads/foreground-task.js +191 -0
  338. package/dist/threads/foreground-task.js.map +1 -0
  339. package/dist/threads/foreman-business.d.ts +9 -0
  340. package/dist/threads/foreman-business.d.ts.map +1 -0
  341. package/dist/threads/foreman-business.js +117 -0
  342. package/dist/threads/foreman-business.js.map +1 -0
  343. package/dist/threads/foreman-client.d.ts +18 -0
  344. package/dist/threads/foreman-client.d.ts.map +1 -0
  345. package/dist/threads/foreman-client.js +51 -0
  346. package/dist/threads/foreman-client.js.map +1 -0
  347. package/dist/threads/foreman-delivery.d.ts +5 -0
  348. package/dist/threads/foreman-delivery.d.ts.map +1 -0
  349. package/dist/threads/foreman-delivery.js +21 -0
  350. package/dist/threads/foreman-delivery.js.map +1 -0
  351. package/dist/threads/foreman-execution.d.ts +32 -0
  352. package/dist/threads/foreman-execution.d.ts.map +1 -0
  353. package/dist/threads/foreman-execution.js +90 -0
  354. package/dist/threads/foreman-execution.js.map +1 -0
  355. package/dist/threads/foreman-host.d.ts +77 -0
  356. package/dist/threads/foreman-host.d.ts.map +1 -0
  357. package/dist/threads/foreman-host.js +891 -0
  358. package/dist/threads/foreman-host.js.map +1 -0
  359. package/dist/threads/foreman-protocol.d.ts +242 -0
  360. package/dist/threads/foreman-protocol.d.ts.map +1 -0
  361. package/dist/threads/foreman-protocol.js +116 -0
  362. package/dist/threads/foreman-protocol.js.map +1 -0
  363. package/dist/threads/foreman-store.d.ts +151 -0
  364. package/dist/threads/foreman-store.d.ts.map +1 -0
  365. package/dist/threads/foreman-store.js +299 -0
  366. package/dist/threads/foreman-store.js.map +1 -0
  367. package/dist/threads/generic-execution.d.ts +25 -0
  368. package/dist/threads/generic-execution.d.ts.map +1 -0
  369. package/dist/threads/generic-execution.js +86 -0
  370. package/dist/threads/generic-execution.js.map +1 -0
  371. package/dist/threads/init-thread-dir.d.ts +2 -2
  372. package/dist/threads/init-thread-dir.d.ts.map +1 -1
  373. package/dist/threads/init-thread-dir.js +6 -6
  374. package/dist/threads/init-thread-dir.js.map +1 -1
  375. package/dist/threads/ipc.d.ts +108 -2
  376. package/dist/threads/ipc.d.ts.map +1 -1
  377. package/dist/threads/ipc.js +14 -2
  378. package/dist/threads/ipc.js.map +1 -1
  379. package/dist/threads/lab-run-thread.d.ts +3 -5
  380. package/dist/threads/lab-run-thread.d.ts.map +1 -1
  381. package/dist/threads/lab-run-thread.js +3 -5
  382. package/dist/threads/lab-run-thread.js.map +1 -1
  383. package/dist/threads/lab-runtime-policy.d.ts +26 -21
  384. package/dist/threads/lab-runtime-policy.d.ts.map +1 -1
  385. package/dist/threads/lab-runtime-policy.js +31 -126
  386. package/dist/threads/lab-runtime-policy.js.map +1 -1
  387. package/dist/threads/process-group.d.ts +41 -0
  388. package/dist/threads/process-group.d.ts.map +1 -0
  389. package/dist/threads/process-group.js +161 -0
  390. package/dist/threads/process-group.js.map +1 -0
  391. package/dist/threads/relay-adapter.d.ts +8 -0
  392. package/dist/threads/relay-adapter.d.ts.map +1 -1
  393. package/dist/threads/relay-adapter.js +26 -1
  394. package/dist/threads/relay-adapter.js.map +1 -1
  395. package/dist/threads/supervisor.d.ts +191 -57
  396. package/dist/threads/supervisor.d.ts.map +1 -1
  397. package/dist/threads/supervisor.js +766 -427
  398. package/dist/threads/supervisor.js.map +1 -1
  399. package/dist/threads/task-workspace.d.ts +8 -0
  400. package/dist/threads/task-workspace.d.ts.map +1 -0
  401. package/dist/threads/task-workspace.js +52 -0
  402. package/dist/threads/task-workspace.js.map +1 -0
  403. package/dist/threads/worker-entry.d.ts.map +1 -1
  404. package/dist/threads/worker-entry.js +314 -34
  405. package/dist/threads/worker-entry.js.map +1 -1
  406. package/dist/threads/worker-execution-runtime.d.ts +75 -0
  407. package/dist/threads/worker-execution-runtime.d.ts.map +1 -0
  408. package/dist/threads/worker-execution-runtime.js +142 -0
  409. package/dist/threads/worker-execution-runtime.js.map +1 -0
  410. package/dist/threads/worker-execution.d.ts +35 -0
  411. package/dist/threads/worker-execution.d.ts.map +1 -0
  412. package/dist/threads/worker-execution.js +2 -0
  413. package/dist/threads/worker-execution.js.map +1 -0
  414. package/dist/threads/worker-runtime-policy.d.ts +42 -0
  415. package/dist/threads/worker-runtime-policy.d.ts.map +1 -0
  416. package/dist/threads/worker-runtime-policy.js +98 -0
  417. package/dist/threads/worker-runtime-policy.js.map +1 -0
  418. package/dist/tools/adapter-tool.d.ts +12 -0
  419. package/dist/tools/adapter-tool.d.ts.map +1 -0
  420. package/dist/tools/adapter-tool.js +2 -0
  421. package/dist/tools/adapter-tool.js.map +1 -0
  422. package/dist/tools/data-service.d.ts +2 -2
  423. package/dist/tools/delegation.d.ts +121 -0
  424. package/dist/tools/delegation.d.ts.map +1 -0
  425. package/dist/tools/delegation.js +106 -0
  426. package/dist/tools/delegation.js.map +1 -0
  427. package/dist/tools/dream-memory.d.ts +122 -0
  428. package/dist/tools/dream-memory.d.ts.map +1 -0
  429. package/dist/tools/dream-memory.js +513 -0
  430. package/dist/tools/dream-memory.js.map +1 -0
  431. package/dist/tools/email.d.ts +1 -1
  432. package/dist/tools/execution-control.d.ts +31 -0
  433. package/dist/tools/execution-control.d.ts.map +1 -0
  434. package/dist/tools/execution-control.js +71 -0
  435. package/dist/tools/execution-control.js.map +1 -0
  436. package/dist/tools/index.d.ts +5 -7
  437. package/dist/tools/index.d.ts.map +1 -1
  438. package/dist/tools/index.js +7 -13
  439. package/dist/tools/index.js.map +1 -1
  440. package/dist/tools/mcp-manager.d.ts +1 -1
  441. package/dist/tools/memory.d.ts +1 -1
  442. package/dist/tools/memory.d.ts.map +1 -1
  443. package/dist/tools/memory.js +69 -45
  444. package/dist/tools/memory.js.map +1 -1
  445. package/dist/tools/notify.d.ts +5 -0
  446. package/dist/tools/notify.d.ts.map +1 -1
  447. package/dist/tools/notify.js +45 -10
  448. package/dist/tools/notify.js.map +1 -1
  449. package/dist/tools/skill.d.ts +1 -1
  450. package/dist/tools/totp.d.ts +1 -1
  451. package/dist/tui/client.d.ts +1 -16
  452. package/dist/tui/client.d.ts.map +1 -1
  453. package/dist/tui/client.js +0 -4
  454. package/dist/tui/client.js.map +1 -1
  455. package/dist/tui/index.d.ts.map +1 -1
  456. package/dist/tui/index.js +0 -41
  457. package/dist/tui/index.js.map +1 -1
  458. package/dist/tui/protocol.d.ts +2 -1
  459. package/dist/tui/protocol.d.ts.map +1 -1
  460. package/dist/tui/protocol.js +2 -1
  461. package/dist/tui/protocol.js.map +1 -1
  462. package/dist/tui/renderer.d.ts.map +1 -1
  463. package/dist/tui/renderer.js +0 -5
  464. package/dist/tui/renderer.js.map +1 -1
  465. package/dist/tui/request-store.d.ts +1 -1
  466. package/dist/tui/request-store.d.ts.map +1 -1
  467. package/dist/tui/request-store.js +2 -2
  468. package/dist/tui/request-store.js.map +1 -1
  469. package/dist/tui/server.d.ts.map +1 -1
  470. package/dist/tui/server.js +137 -25
  471. package/dist/tui/server.js.map +1 -1
  472. package/dist/utils/claude-transcripts.d.ts +6 -0
  473. package/dist/utils/claude-transcripts.d.ts.map +1 -1
  474. package/dist/utils/claude-transcripts.js +8 -2
  475. package/dist/utils/claude-transcripts.js.map +1 -1
  476. package/dist/utils/restart.d.ts.map +1 -1
  477. package/dist/utils/restart.js +6 -0
  478. package/dist/utils/restart.js.map +1 -1
  479. package/dist-agent/bundle.cjs +2 -2
  480. package/package.json +1 -1
  481. package/dist/agent/mailbox.d.ts +0 -50
  482. package/dist/agent/mailbox.d.ts.map +0 -1
  483. package/dist/agent/mailbox.js +0 -124
  484. package/dist/agent/mailbox.js.map +0 -1
  485. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.d.ts +0 -77
  486. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.d.ts.map +0 -1
  487. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.js +0 -158
  488. package/dist/agent/nightly-maintenance/memory-dreaming-sweep.js.map +0 -1
  489. package/dist/agent/nightly-maintenance/memory-dreaming.d.ts +0 -116
  490. package/dist/agent/nightly-maintenance/memory-dreaming.d.ts.map +0 -1
  491. package/dist/agent/nightly-maintenance/memory-dreaming.js +0 -458
  492. package/dist/agent/nightly-maintenance/memory-dreaming.js.map +0 -1
  493. package/dist/threads/task-contracts.d.ts +0 -194
  494. package/dist/threads/task-contracts.d.ts.map +0 -1
  495. package/dist/threads/task-contracts.js +0 -82
  496. package/dist/threads/task-contracts.js.map +0 -1
  497. package/dist/threads/task-sidecar.d.ts +0 -145
  498. package/dist/threads/task-sidecar.d.ts.map +0 -1
  499. package/dist/threads/task-sidecar.js +0 -311
  500. package/dist/threads/task-sidecar.js.map +0 -1
  501. package/dist/threads/task-store.d.ts +0 -172
  502. package/dist/threads/task-store.d.ts.map +0 -1
  503. package/dist/threads/task-store.js +0 -599
  504. package/dist/threads/task-store.js.map +0 -1
  505. package/dist/threads/thread-task-context.d.ts +0 -40
  506. package/dist/threads/thread-task-context.d.ts.map +0 -1
  507. package/dist/threads/thread-task-context.js +0 -160
  508. package/dist/threads/thread-task-context.js.map +0 -1
  509. package/dist/threads/thread-task-controller.d.ts +0 -122
  510. package/dist/threads/thread-task-controller.d.ts.map +0 -1
  511. package/dist/threads/thread-task-controller.js +0 -276
  512. package/dist/threads/thread-task-controller.js.map +0 -1
  513. package/dist/threads/thread-task-runtime.d.ts +0 -354
  514. package/dist/threads/thread-task-runtime.d.ts.map +0 -1
  515. package/dist/threads/thread-task-runtime.js +0 -917
  516. package/dist/threads/thread-task-runtime.js.map +0 -1
  517. package/dist/tools/switch-session.d.ts +0 -15
  518. package/dist/tools/switch-session.d.ts.map +0 -1
  519. package/dist/tools/switch-session.js +0 -88
  520. package/dist/tools/switch-session.js.map +0 -1
  521. package/dist/tools/thread-tasks.d.ts +0 -23
  522. package/dist/tools/thread-tasks.d.ts.map +0 -1
  523. package/dist/tools/thread-tasks.js +0 -122
  524. package/dist/tools/thread-tasks.js.map +0 -1
@@ -1,13 +1,14 @@
1
1
  /**
2
- * WakeCycleRunner — encapsulates the inner session-switch loop, Claude
2
+ * WakeCycleRunner — encapsulates the wake loop, Claude
3
3
  * stream processing, error classification / retry logic, transcript
4
4
  * sanitization, and post-cycle transcript memory indexing.
5
5
  *
6
6
  * Extracted from loop.ts so the main loop is a thin orchestrator.
7
7
  */
8
- import { isEmailChannel, normalizeChannelName, presentsAssistantText } from "../channels/interface.js";
8
+ import { isEmailChannel, presentsAssistantText } from "../channels/interface.js";
9
9
  import { isCalendarInterruptMessage } from "./owner-initiated-eligibility.js";
10
10
  import { emailAddressesMatch } from "../utils/email.js";
11
+ import { EXTERNAL_WAKE_KIND } from "../channels/queue.js";
11
12
  import { nextRecoveryPhase } from "./lifecycle-transitions.js";
12
13
  import { COMPACTION_FAILURE_CONTINUATION, CompactionFailureError } from "./compaction-failure.js";
13
14
  import { ToolOutputRepairError } from "./transcript-output-repair.js";
@@ -32,36 +33,7 @@ import path from "path";
32
33
  import { randomUUID } from "node:crypto";
33
34
  import { runContextRefresh } from "./context-refresh.js";
34
35
  import { loadToolAbortRecoveryChain, saveToolAbortRecoveryChain } from "./recovery-chain.js";
35
- import { RECONCILE_WAIT_MS, buildThreadTaskContext, executionEvents, isTaskRelevantMessage, reconcileThreadTasks, recordExecutionEvent, } from "../threads/thread-task-runtime.js";
36
- import { isThreadTaskContextBlock } from "../threads/thread-task-context.js";
37
- /**
38
- * Session memos are internal working text (handoff instructions, worktree
39
- * paths, "do not notify" constraints). They must never be sent as owner chat.
40
- *
41
- * Last-resort ping when a coding completion was armed and this wake never
42
- * successfully notified (PR #839: do not silently drop the result). The
43
- * body is a fixed human line — never the memo, never a paraphrase of it.
44
- */
45
- async function deliverCodingCompletionFallbackPing(ownerConfig) {
46
- const message = t("coding.completion_unnotified", resolveLocale(ownerConfig.language));
47
- try {
48
- const result = await sendUserNotification({ message, purpose: "completion" });
49
- if (result.isError) {
50
- const text = result.content
51
- .map((c) => "text" in c ? c.text : "")
52
- .filter((s) => s.length > 0)
53
- .join(" ");
54
- logger.warn(`Coding completion notification failed: ${text || "unknown error"}`);
55
- return false;
56
- }
57
- logger.system("Delivered coding completion fallback ping (generic; not the session memo)");
58
- return true;
59
- }
60
- catch (err) {
61
- logger.warn(`Coding completion notification threw: ${err instanceof Error ? err.message : String(err)}`);
62
- return false;
63
- }
64
- }
36
+ import { getWorkerExecutionRuntime } from "../threads/worker-execution-runtime.js";
65
37
  const AUTH_PATTERNS = /\b(401|402|403|authentication|billing|unauthorized|forbidden|api.?key)\b/i;
66
38
  // Fatal environment/installation problems that won't fix themselves on retry.
67
39
  // In particular: the Claude Agent SDK immediately exits with code 1 when its
@@ -304,15 +276,15 @@ export function isSharedCredentialFailure(err) {
304
276
  }
305
277
  return classifyError(err) === "provider_failed" && !isEngineScopedFailure(err);
306
278
  }
307
- function formatOwnerErrorNotice(category, consecutiveErrors, sleepMin, errMsg) {
279
+ function formatOwnerErrorNotice(category, consecutiveErrors, errMsg) {
308
280
  if (category === "fatal") {
309
- return `Agent encountered an internal runtime error. Sleeping ${sleepMin}m before retrying.`;
281
+ return "Agent encountered an internal runtime error. This wake has stopped; the next message or heartbeat will retry.";
310
282
  }
311
283
  if (category === "local") {
312
284
  // Name the cause. The old text blamed the model provider for an error the
313
285
  // provider never saw, which is what made the original alert storm
314
286
  // impossible to diagnose from the notification alone.
315
- return `Agent hit a local session-coordination error (not a provider failure): ${errMsg ?? "unknown cause"}. Sleeping ${sleepMin}m before retrying.`;
287
+ return `Agent hit a local session-coordination error (not a provider failure): ${errMsg ?? "unknown cause"}. This wake has stopped; the next message or heartbeat will retry.`;
316
288
  }
317
289
  if (category === "request_invalid") {
318
290
  return `Agent stopped this wake because the provider rejected a malformed request (${errMsg ?? "unknown cause"}).`;
@@ -323,7 +295,7 @@ function formatOwnerErrorNotice(category, consecutiveErrors, sleepMin, errMsg) {
323
295
  if (category === "empty_turn") {
324
296
  return "The assistant returned another empty turn without confirming completion. The task may be incomplete. I stopped automatic continuation to avoid repeating work; existing results should be checked before continuing.";
325
297
  }
326
- return `Agent encountered an internal model/provider error ${consecutiveErrors} times in a row. Sleeping ${sleepMin}m before retrying.`;
298
+ return `Agent encountered an internal model/provider error ${consecutiveErrors} times in a row. This wake has stopped; the next message or heartbeat will retry.`;
327
299
  }
328
300
  function isPromptTooLong(err) {
329
301
  const terminalReason = getTerminalReason(err);
@@ -391,7 +363,6 @@ export const MAX_EMPTY_TURN_RETRIES = 1;
391
363
  const ERROR_RETRY_COMPACT_USED_PCT = 0.7;
392
364
  const BASE_DELAY_MS = 5_000;
393
365
  const MAX_DELAY_MS = 5 * 60_000;
394
- const FATAL_SLEEP_MS = 5 * 60_000;
395
366
  /** Max times to retry the LLM call on stream silence timeout before aborting. */
396
367
  export const MAX_SILENCE_RETRIES = 3;
397
368
  /** Bounded retries for transient stream/network disconnects in any wake cycle. */
@@ -405,26 +376,7 @@ export const MAX_OUTPUT_RECOVERY_ATTEMPTS = 2;
405
376
  /** Escalating silence timeouts (ms) per attempt: 5min, 10min, 15min. */
406
377
  const SILENCE_TIMEOUT_SCHEDULE_MS = [300_000, 600_000, 900_000];
407
378
  /** Decreasing effort levels per attempt to reduce thinking overhead on retries. */
408
- const EFFORT_SCHEDULE = {
409
- coding: ["xhigh", "high", "medium"],
410
- general: ["xhigh", "high", "medium"],
411
- };
412
- /**
413
- * A wake retried on a reset session re-sends its first message, whose thread
414
- * task block (#1996) was built before the reset's reconcile. Swap it for a
415
- * fresh one so the new session sees exactly one, current copy. Without a
416
- * task runtime this returns the blocks unchanged.
417
- */
418
- export function withFreshThreadTaskBlock(blocks) {
419
- const fresh = buildThreadTaskContext();
420
- const index = blocks.findIndex((block) => block.type === "text" && isThreadTaskContextBlock(block.text));
421
- if (index === -1)
422
- return fresh ? [...blocks, { type: "text", text: fresh }] : blocks;
423
- const rest = blocks.filter((_, i) => i !== index);
424
- if (fresh)
425
- rest.splice(index, 0, { type: "text", text: fresh });
426
- return rest;
427
- }
379
+ const EFFORT_SCHEDULE = ["xhigh", "high", "medium"];
428
380
  export class WakeCycleRunner {
429
381
  externalContextRegistry;
430
382
  deps;
@@ -448,9 +400,8 @@ export class WakeCycleRunner {
448
400
  * Watchdog recoveries span multiple queue-driven wakes, so this state lives
449
401
  * on the resident runner rather than inside a single run() invocation.
450
402
  * Attempt count is retained across clean wakes that lack finish/stop so a
451
- * recovery chain can actually reach MAX_TOOL_ABORT_RECOVERIES. Temporary
452
- * switch_session(handoff) also retains the budget; only finish, stop, or
453
- * switch_session(complete) clear it.
403
+ * recovery chain can actually reach MAX_TOOL_ABORT_RECOVERIES. Only finish
404
+ * or stop clear it.
454
405
  *
455
406
  * Ordinary threads also persist the chain, so a restart cannot refill the
456
407
  * budget. LabRun queues are process-local and stay in memory.
@@ -530,30 +481,30 @@ export class WakeCycleRunner {
530
481
  }
531
482
  }
532
483
  /**
533
- * Execute one full wake cycle: the session-switch inner loop, stream
534
- * processing, error recovery, and post-cycle transcript indexing.
484
+ * Execute one full wake cycle: the wake loop, stream processing, error
485
+ * recovery, and post-cycle transcript indexing.
535
486
  *
536
487
  * @param contentBlocks The multimodal user-message blocks for this cycle.
537
488
  * @param trigger Whether this wake was from a message or heartbeat.
538
489
  * @param messages Inbound messages (empty for heartbeat).
539
- * @param calendarSummary Calendar summary string for session-switch context.
540
490
  * @param consecutiveErrors Current error counter from previous cycles.
541
491
  * @returns Updated consecutive error count.
542
492
  */
543
- async run(contentBlocks, trigger, messages, calendarSummary, consecutiveErrors) {
493
+ async run(contentBlocks, trigger, messages, consecutiveErrors) {
544
494
  const { config, ownerConfig, session, activityTracker, interruptHandler, messageQueue } = this.deps;
545
495
  this.malformedRequestRefreshAttempted = false;
546
496
  this.emptyTurnRetries = 0;
547
497
  this.silenceRecoveryExhausted = false;
548
498
  this.recoveryPhase = "Running";
549
499
  // --- Capture transcript start lines for post-cycle indexing ---
550
- // A wake cycle can switch sessions, so anchor by transcript path instead
551
- // of using a single start line captured from whichever session was active
552
- // at cycle entry.
500
+ // Recovery can rotate the session to a new transcript, so anchor by
501
+ // transcript path instead of using a single start line captured at cycle
502
+ // entry.
553
503
  const wakeCycleId = generateWakeCycleId();
554
504
  /** Numbers model turns within this wake for their task-event keys. */
555
- let responseSeq = 0;
556
505
  let awaitingUser = false;
506
+ /** The model ended the wake with an accepted finish (not a timeout or exhausted recovery). */
507
+ let wakeFinished = false;
557
508
  let terminalError = false;
558
509
  const wakeCycleTimestampStart = new Date().toISOString();
559
510
  const transcriptAnchors = new Map();
@@ -563,17 +514,6 @@ export class WakeCycleRunner {
563
514
  transcriptAnchors.set(activeTranscript.path, await countFileLines(activeTranscript.path));
564
515
  };
565
516
  await ensureTranscriptAnchor(resolveIndexableTranscript(session.activeSession.getTranscriptInfo(), session.activeSession.getTranscriptPath()));
566
- // Session switch loop: if the agent calls switch_session, we close the
567
- // current stream, switch sessions, and re-enter with a new stream.
568
- let didSwitch = false;
569
- let switchForwardMessage = "";
570
- let pendingMemoAck = true;
571
- // Armed on a coding→general completion handoff when the coding session
572
- // did not notify the owner itself. The re-entered general session is
573
- // expected to humanize the memo via notify_user. If this wake never
574
- // successfully notifies, runtime last-resorts a fixed human ping (PR #839)
575
- // — never the memo body.
576
- let pendingCompletionFallback = null;
577
517
  // Survives premature-end continuations: a later turn that repeats the
578
518
  // answer as prose must not re-deliver after notify_user already landed.
579
519
  let notifyUserDeliveredThisWake = false;
@@ -584,7 +524,6 @@ export class WakeCycleRunner {
584
524
  let silenceCompactionDone = false;
585
525
  const externalContext = await this.externalContextRegistry.collect({
586
526
  trigger,
587
- sessionMode: session.activeMode,
588
527
  messages,
589
528
  });
590
529
  setCurrentExternalContext(externalContext.section, externalContext.digest, externalContext.providerBlocks);
@@ -600,62 +539,18 @@ export class WakeCycleRunner {
600
539
  // failover. If the session cannot be rotated, stay on the current engine
601
540
  // and try again next wake rather than replaying its history elsewhere.
602
541
  if (recovered) {
603
- if (await this.rotateSessionForEngineSwitch(session, String(activeBefore), recovered.recovered, "recovery")) {
604
- contentBlocks = withFreshThreadTaskBlock(contentBlocks);
605
- }
606
- else {
542
+ if (!await this.rotateSessionForEngineSwitch(session, String(activeBefore), recovered.recovered, "recovery")) {
607
543
  setFallbackEngine(fallbackBefore);
608
544
  }
609
545
  }
610
546
  }
611
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite switch loop
547
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional: recovery paths re-enter via continue
612
548
  wakeLoop: while (true) {
613
549
  const activeSession = session.activeSession;
614
550
  try {
615
551
  await activeSession.warmUp();
616
552
  await ensureTranscriptAnchor(resolveIndexableTranscript(activeSession.getTranscriptInfo(), activeSession.getTranscriptPath()));
617
- let messageContent;
618
- if (didSwitch) {
619
- // Handoff boundary (#1996): fold what the previous session did into
620
- // the task checkpoints before the other session reads them. Bounded.
621
- await reconcileThreadTasks("handoff", RECONCILE_WAIT_MS.handoff);
622
- const switchMemos = session.consumeMemosForActive();
623
- const switchParts = [];
624
- switchParts.push(`[Session Switch] time=${new Date().toLocaleString()} active_session=${session.activeMode}`);
625
- if (switchMemos) {
626
- switchParts.push("");
627
- switchParts.push(switchMemos);
628
- }
629
- const codingStatus = session.getCodingSessionStatus();
630
- if (codingStatus && session.activeMode === "general") {
631
- switchParts.push("");
632
- switchParts.push(`## Active Coding Task`);
633
- switchParts.push(codingStatus);
634
- }
635
- if (calendarSummary) {
636
- switchParts.push("");
637
- switchParts.push("## Upcoming Calendar Events");
638
- switchParts.push(calendarSummary);
639
- }
640
- if (switchForwardMessage) {
641
- switchParts.push("");
642
- switchParts.push(switchForwardMessage);
643
- }
644
- // The destination session has its own context: give it the
645
- // thread's tasks as they are now.
646
- const threadTaskBlock = buildThreadTaskContext();
647
- messageContent = [
648
- { type: "text", text: switchParts.join("\n") },
649
- ...(threadTaskBlock ? [{ type: "text", text: threadTaskBlock }] : []),
650
- ];
651
- didSwitch = false;
652
- switchForwardMessage = "";
653
- pendingMemoAck = true;
654
- }
655
- else {
656
- messageContent =
657
- contentBlocks;
658
- }
553
+ let messageContent = contentBlocks;
659
554
  let streamResult = {
660
555
  toolTimeout: null,
661
556
  finishCalled: false,
@@ -665,6 +560,10 @@ export class WakeCycleRunner {
665
560
  notifyUserDelivered: false,
666
561
  awaitingUser: false,
667
562
  };
563
+ // A lifecycle-only continuation may call finish without repeating the
564
+ // answer from the previous turn. Keep that answer through this wake.
565
+ let lastReplyText = "";
566
+ let lastReplyPresented = false;
668
567
  let subagentContinuations = 0;
669
568
  let prematureEndContinuations = 0;
670
569
  // turnLoop: each iteration drains one streamed turn (including all
@@ -687,23 +586,20 @@ export class WakeCycleRunner {
687
586
  if (silenceAttempt > 1) {
688
587
  activityTracker.notePublicPhase("Still working");
689
588
  }
690
- const effortSchedule = EFFORT_SCHEDULE[session.activeMode];
691
- const tierEffort = getLlmEffort(config, session.activeMode === "coding" ? "main_coding" : "main_general");
589
+ const effortSchedule = EFFORT_SCHEDULE;
590
+ const tierEffort = getLlmEffort(config, "main_general");
692
591
  const effort = tierEffort && silenceAttempt > 1
693
592
  ? getLlmRetryEffort(tierEffort, silenceAttempt - 1)
694
593
  : tierEffort ?? effortSchedule[silenceAttempt - 1];
695
594
  const queryStream = activeSession.sendAndStream(messageContent, { effort, externalContextDigest: externalContext.digest });
696
- if (pendingMemoAck) {
697
- session.ackMemosForActive();
698
- pendingMemoAck = false;
699
- }
700
595
  try {
701
- streamResult = await processAgentStream(queryStream, activeSession, activityTracker, session.dualSessionEnabled ? session : undefined, config, silenceTimeoutMs);
596
+ streamResult = await processAgentStream(queryStream, activeSession, activityTracker, config, silenceTimeoutMs);
702
597
  if (streamResult.notifyUserDelivered)
703
598
  notifyUserDeliveredThisWake = true;
704
- // One event per model turn with its complete prose; the task
705
- // sidecar folds it into progress. No-op without a task runtime.
706
- recordExecutionEvent(executionEvents.response(`${wakeCycleId}:${responseSeq++}`, streamResult.assistantText));
599
+ if (streamResult.lastAssistantText) {
600
+ lastReplyText = streamResult.lastAssistantText;
601
+ lastReplyPresented = streamResult.lastAssistantTextPresented === true;
602
+ }
707
603
  // A successful SDK envelope can still contain a legitimate empty
708
604
  // model turn. Apply the same task-state policy as SDK diagnostics.
709
605
  if (!this.deps.singleShot && streamResult.emptyTurn && !streamResult.finishCalled && !streamResult.toolTimeout) {
@@ -791,7 +687,6 @@ export class WakeCycleRunner {
791
687
  const degraded = await this.degradeActiveEngine(engineFallback, "silence_exhausted", session);
792
688
  if (degraded === "hot") {
793
689
  consecutiveErrors = 0;
794
- contentBlocks = withFreshThreadTaskBlock(contentBlocks);
795
690
  continue wakeLoop;
796
691
  }
797
692
  if (degraded === "restarting") {
@@ -810,9 +705,6 @@ export class WakeCycleRunner {
810
705
  try {
811
706
  await activeSession.requestCompaction();
812
707
  consecutiveErrors = 0;
813
- // The compacted session must see the tasks as the compaction
814
- // reconcile just left them, not the wake-start block (#1996).
815
- contentBlocks = withFreshThreadTaskBlock(contentBlocks);
816
708
  continue wakeLoop;
817
709
  }
818
710
  catch (compactErr) {
@@ -837,7 +729,18 @@ export class WakeCycleRunner {
837
729
  }
838
730
  catch (streamErr) {
839
731
  // TODO: guard retry against simultaneous stop requests and settle the failed input generator before retrying; both are rare stream/stop races.
840
- if (isTransientStreamFailure(streamErr) && transientStreamRetries < MAX_TRANSIENT_STREAM_RETRIES) {
732
+ // transientStreamRetries counts the disconnects already retried in
733
+ // this turn. Another one is Recovering; the ceiling throws, and
734
+ // the outer handler records it instead of retrying this turn.
735
+ const networkPhase = isTransientStreamFailure(streamErr)
736
+ ? nextRecoveryPhase({
737
+ from: this.recoveryPhase,
738
+ bucket: "network",
739
+ spent: transientStreamRetries,
740
+ })
741
+ : null;
742
+ if (networkPhase === "Recovering") {
743
+ this.recoveryPhase = "Recovering";
841
744
  transientStreamRetries++;
842
745
  logger.system(`Transient stream failure (retry ${transientStreamRetries}/${MAX_TRANSIENT_STREAM_RETRIES}) — retrying the current business turn...`);
843
746
  continue;
@@ -845,30 +748,10 @@ export class WakeCycleRunner {
845
748
  throw streamErr;
846
749
  }
847
750
  }
848
- // An owner-facing notification was DELIVERED this turn — any armed
849
- // coding completion fallback has been superseded by the model's own
850
- // summary. A notify_user call whose tool result errored (channel
851
- // outage, bad explicit target) must not disarm the fallback, or the
852
- // completion is silently lost.
853
- if (streamResult.notifyUserDelivered) {
854
- pendingCompletionFallback = null;
855
- }
856
751
  if (streamResult.finishCalled && streamResult.awaitingUser)
857
752
  awaitingUser = true;
858
- // The coding prompt asks the model to switch back with
859
- // reason="complete", but the generic finish tool is also available
860
- // and can be used after a successful completion notification. In
861
- // that case finish only closes the wake at the stream layer; finalize
862
- // the task here when the receipt is for this exact active task so a
863
- // later general heartbeat cannot resurrect it.
864
- const completionReceiptMatchesActiveCodingTask = session.activeMode === "coding" &&
865
- !session.pendingSwitch &&
866
- !streamResult.awaitingUser &&
867
- Boolean(this.deps.agentState.codingCompletionTaskStartedAt &&
868
- this.deps.agentState.codingCompletionTaskStartedAt === session.getActiveCodingTaskStartedAt());
869
- if (streamResult.finishCalled && completionReceiptMatchesActiveCodingTask) {
870
- session.finalizeCodingCompletionAfterFinish();
871
- }
753
+ if (streamResult.finishCalled)
754
+ wakeFinished = true;
872
755
  // A watchdog abort is scoped to the active tool. Preserve the result
873
756
  // for the next queue-driven wake rather than resuming the same provider
874
757
  // turn, which keeps lifecycle handling identical for Claude and Pi.
@@ -926,7 +809,7 @@ export class WakeCycleRunner {
926
809
  }
927
810
  // A successful SDK result only means the stream ended; it does not
928
811
  // prove the task ended intentionally. Keep the original wake context
929
- // alive until the model calls finish or requests a session switch.
812
+ // alive until the model calls finish.
930
813
  // Gated on "no subagents currently active" (not on whether a subagent
931
814
  // continuation ever fired): while subagents run, the subagent-wait
932
815
  // mechanism above owns the turn; once they are done, the explicit
@@ -934,22 +817,30 @@ export class WakeCycleRunner {
934
817
  // subagent continuation earlier.
935
818
  if (!this.deps.singleShot &&
936
819
  endedWithoutLifecycleAction &&
937
- !session.pendingSwitch &&
938
820
  runningSubagents.length === 0) {
939
- if (prematureEndContinuations < MAX_PREMATURE_END_CONTINUATIONS) {
821
+ // prematureEndContinuations counts the continuations already sent in
822
+ // this wake. One more is Recovering; the ceiling is Stopping, and
823
+ // this wake ends instead of starting another continuation.
824
+ const prematurePhase = nextRecoveryPhase({
825
+ from: this.recoveryPhase,
826
+ bucket: "premature_result",
827
+ spent: prematureEndContinuations,
828
+ });
829
+ if (prematurePhase === "Recovering") {
830
+ this.recoveryPhase = "Recovering";
940
831
  prematureEndContinuations++;
941
- logger.warn(`Turn ended without finish or switch_session — continuing in ${session.activeMode} session (${prematureEndContinuations}/${MAX_PREMATURE_END_CONTINUATIONS})`);
832
+ logger.warn(`Turn ended without finish — continuing (${prematureEndContinuations}/${MAX_PREMATURE_END_CONTINUATIONS})`);
942
833
  messageContent = [{
943
834
  type: "text",
944
835
  text: [
945
- "Your previous turn ended without an explicit finish or switch_session call, so this wake cycle is still active.",
836
+ "Your previous turn ended without an explicit finish call, so this wake cycle is still active.",
946
837
  "Inspect the transcript and existing tool results before acting. Do not repeat successful notifications, emails, uploads, or other mutations/side effects.",
947
- "If the requested work is already complete, only call finish now. Otherwise complete the remaining work, notify the user if needed, then call finish or switch_session as appropriate.",
838
+ "If the requested work is already complete, only call finish now. Otherwise complete the remaining work, notify the user if needed, then call finish.",
948
839
  ].join("\n"),
949
840
  }];
950
841
  continue turnLoop;
951
842
  }
952
- const errorMessage = `Wake cycle ended without finish or switch_session after ${MAX_PREMATURE_END_CONTINUATIONS} continuations`;
843
+ const errorMessage = `Wake cycle ended without finish after ${MAX_PREMATURE_END_CONTINUATIONS} continuations`;
953
844
  logger.err(errorMessage);
954
845
  // The alert is only actionable when the owner is actually waiting on
955
846
  // something, and it fires at most once per wake cycle — so a long run
@@ -970,7 +861,7 @@ export class WakeCycleRunner {
970
861
  const alreadyNotifiedOwner = this.deps.agentState.notifiedUserThisWake === true;
971
862
  const recoveryAlertEligible = trigger === "message" && !alreadyNotifiedOwner;
972
863
  if (recoveryAlertEligible) {
973
- void notifyOwner(`Agent wake recovery stopped after ${MAX_PREMATURE_END_CONTINUATIONS} attempts in the ${session.activeMode} session. The task may be incomplete; please ask me to resume it.`, config).catch((notifyErr) => {
864
+ void notifyOwner(`Agent wake recovery stopped after ${MAX_PREMATURE_END_CONTINUATIONS} attempts. The task may be incomplete; please ask me to resume it.`, config).catch((notifyErr) => {
974
865
  logger.warn(`Failed to notify owner about exhausted wake recovery: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
975
866
  });
976
867
  }
@@ -1003,9 +894,18 @@ export class WakeCycleRunner {
1003
894
  }
1004
895
  }
1005
896
  else {
897
+ // The persisted count is this chain's own budget. It survives
898
+ // wakes and restarts, so a new wake must not refill it.
899
+ const toolAbortPhase = nextRecoveryPhase({
900
+ from: this.recoveryPhase,
901
+ bucket: "tool_abort",
902
+ spent: this.toolAbortRecoveries,
903
+ });
1006
904
  this.toolAbortRecoveryChainId ??= randomUUID();
1007
905
  this.toolAbortRecoveries += 1;
1008
- const retryable = this.toolAbortRecoveries <= MAX_TOOL_ABORT_RECOVERIES;
906
+ const retryable = toolAbortPhase === "Recovering";
907
+ if (retryable)
908
+ this.recoveryPhase = "Recovering";
1009
909
  if (!retryable)
1010
910
  this.toolAbortRecoveryExhausted = true;
1011
911
  this.persistToolAbortRecoveryChain();
@@ -1047,12 +947,7 @@ export class WakeCycleRunner {
1047
947
  this.clearToolAbortRecoveryBudget();
1048
948
  }
1049
949
  else if (streamResult.finishCalled) {
1050
- // `finishCalled` is also set for accepted switch_session. Temporary
1051
- // handoffs must retain the budget; only a real finish tool clears
1052
- // here. switch_session(complete) clears below via reason.
1053
- if (streamResult.lifecycleTool !== "switch_session") {
1054
- this.clearToolAbortRecoveryBudget();
1055
- }
950
+ this.clearToolAbortRecoveryBudget();
1056
951
  }
1057
952
  // --- Direct assistant text delivery ---
1058
953
  // When the model writes the answer as prose, calls finish, and never
@@ -1060,44 +955,34 @@ export class WakeCycleRunner {
1060
955
  // adapters drop `assistant_text`). Send the LAST text block as a
1061
956
  // normal notify so the originating channel actually delivers it.
1062
957
  // Concatenated earlier blocks, thinking, and tool narration stay out.
1063
- // Heartbeat, switch_session, singleShot, and toolTimeout stay silent.
958
+ // Heartbeat, singleShot, and toolTimeout stay silent.
1064
959
  // Fin-App matches Telegram: live assistant_text is dropped, so this
1065
960
  // last-block notify is the courtesy delivery when finish has no
1066
961
  // notify_user. TUI still presents assistant_text in-thread.
1067
- const fallbackText = streamResult.lastAssistantText;
1068
- // An accepted switch_session always leaves a pending request here --
1069
- // `executePendingSwitch` only runs later in this wake -- so
1070
- // `pendingSwitch` already covers that exit on its own. Requiring an
1071
- // accepted `finish` below excludes it a second time.
1072
- const skipBecauseSwitch = Boolean(session.pendingSwitch);
962
+ const fallbackText = lastReplyText;
1073
963
  const skipBecauseNotified = notifyUserDeliveredThisWake || streamResult.notifyUserDelivered;
1074
964
  const finishAccepted = streamResult.lifecycleTool === "finish";
1075
965
  // Only replies to messages in the initial wake batch are eligible.
1076
966
  // Resumes, external wakes and calendars may carry a delivery target
1077
967
  // without requesting a reply. Mid-turn work uses explicit notify_user
1078
968
  // for its result; a quick acknowledgment does not enable this fallback.
1079
- const replyMessages = messages.filter((message) => isTaskRelevantMessage(message) && !isCalendarInterruptMessage(message));
969
+ const replyMessages = messages.filter((message) => message.channel !== "system" && message.meta?.kind !== EXTERNAL_WAKE_KIND && !isCalendarInterruptMessage(message));
1080
970
  const fallbackEligible = !this.deps.singleShot &&
1081
971
  !streamResult.toolTimeout &&
1082
972
  !skipBecauseNotified &&
1083
973
  fallbackText.length > 0 &&
1084
974
  trigger === "message" &&
1085
975
  finishAccepted &&
1086
- !skipBecauseSwitch &&
1087
976
  replyMessages.length > 0;
1088
977
  if (replyMessages.length === 0 && fallbackText.length > 0 && finishAccepted && !skipBecauseNotified) {
1089
978
  logger.info("Skipped finish-without-notify fallback: no reply message in the initial wake batch");
1090
979
  }
1091
- if (skipBecauseSwitch && fallbackText.length > 0 && trigger === "message") {
1092
- logger.warn(`Skipped assistant_text delivery: the turn took switch_session without notify_user, so this text was NOT delivered to the owner: ${fallbackText.slice(0, 2000)}`);
1093
- }
1094
980
  // Premature-end recovery re-prompts, so unfinished prose is deliberately
1095
981
  // not delivered (a rejected `finish` lands here too: it sets neither
1096
982
  // `finishCalled` nor `lifecycleTool`). The owner still gets the generic
1097
983
  // exhausted-recovery alert, but the text itself would vanish without a
1098
984
  // trace -- record it so the drop is diagnosable.
1099
985
  if (!finishAccepted &&
1100
- !skipBecauseSwitch &&
1101
986
  !skipBecauseNotified &&
1102
987
  !streamResult.toolTimeout &&
1103
988
  fallbackText.length > 0 &&
@@ -1107,16 +992,10 @@ export class WakeCycleRunner {
1107
992
  if (fallbackEligible) {
1108
993
  const fallbackTarget = resolveDirectAssistantFallbackTarget(replyMessages, ownerConfig.ownerEmail);
1109
994
  const livePresentedOnChat = Boolean(fallbackTarget && presentsAssistantText(fallbackTarget.channel)) &&
1110
- streamResult.lastAssistantTextPresented === true;
995
+ lastReplyPresented;
1111
996
  if (livePresentedOnChat) {
1112
997
  // Last live block actually landed in chat. Do not splice a
1113
998
  // second last-block notify into the same thread.
1114
- pendingCompletionFallback = null;
1115
- }
1116
- else if (fallbackTarget &&
1117
- normalizeChannelName(fallbackTarget.channel) === "finapp" &&
1118
- session.activeMode === "coding") {
1119
- // Coding narration never becomes a Fin-App chat bubble. TUI still last-block notifies.
1120
999
  }
1121
1000
  else if (fallbackTarget) {
1122
1001
  // Best-effort courtesy delivery: never let a fallback failure
@@ -1138,7 +1017,6 @@ export class WakeCycleRunner {
1138
1017
  }
1139
1018
  else {
1140
1019
  logger.warn(`Delivered finish-without-notify fallback via ${fallbackTarget.channel} to ${fallbackTarget.to}`);
1141
- pendingCompletionFallback = null;
1142
1020
  }
1143
1021
  }
1144
1022
  catch (err) {
@@ -1207,46 +1085,6 @@ export class WakeCycleRunner {
1207
1085
  logger.warn(`Post-query compaction failed: ${compactErr instanceof Error ? compactErr.message : String(compactErr)}`);
1208
1086
  }
1209
1087
  }
1210
- const switchResult = session.executePendingSwitch();
1211
- if (switchResult) {
1212
- // switch_session sets finishCalled, so the finishCalled branch above
1213
- // skips clearing when lifecycleTool is switch_session. Only complete
1214
- // clears here; temporary handoff retains the budget.
1215
- if (switchResult.reason === "complete") {
1216
- this.clearToolAbortRecoveryBudget();
1217
- }
1218
- didSwitch = true;
1219
- switchForwardMessage = [switchResult.workspaceNotice, switchResult.forwardMessage]
1220
- .filter(Boolean)
1221
- .join("\n\n");
1222
- // Completion handoffs are user-visible outcomes. The re-entered
1223
- // general session is expected to humanize the memo via notify_user.
1224
- // Do not dump the memo as chat (internal working text). Arm a marker:
1225
- // a later notify_user / last-block send disarms it; if the cycle
1226
- // ends with no successful owner ping, last-resort a fixed human line
1227
- // (PR #839: do not silently drop the result). Newest memo wins.
1228
- if (switchResult.target === "general" &&
1229
- switchResult.ownerNotificationRequired &&
1230
- switchResult.completionMemo) {
1231
- pendingCompletionFallback = switchResult.completionMemo;
1232
- }
1233
- // Coding already sent this task's final result. No memo was created,
1234
- // so end the wake instead of invoking general for a duplicate summary.
1235
- if (switchResult.target === "general" &&
1236
- switchResult.ownerNotificationRequired === false &&
1237
- switchResult.completionMemo) {
1238
- // reason="complete" already cleared the recovery budget above.
1239
- logger.system("Coding completion already delivered — ending wake without re-entering general");
1240
- this.deps.engineFallback.noteEngineSuccess();
1241
- this.invalidJsonBodyRecoveryCount = 0;
1242
- this.localCoordinationErrors = 0;
1243
- this.emptyTurnRetries = 0;
1244
- consecutiveErrors = 0;
1245
- break;
1246
- }
1247
- logger.system(`Re-entering wake cycle for ${switchResult.target} session`);
1248
- continue;
1249
- }
1250
1088
  this.deps.engineFallback.noteEngineSuccess();
1251
1089
  this.invalidJsonBodyRecoveryCount = 0;
1252
1090
  this.localCoordinationErrors = 0;
@@ -1272,23 +1110,14 @@ export class WakeCycleRunner {
1272
1110
  if (errorResult.kind === "continue_with_message") {
1273
1111
  consecutiveErrors = errorResult.consecutiveErrors;
1274
1112
  contentBlocks = [{ type: "text", text: errorResult.message }];
1275
- // A rebuilt session starts without the thread's tasks (#1996).
1276
- if (errorResult.newSession)
1277
- contentBlocks = withFreshThreadTaskBlock(contentBlocks);
1278
- didSwitch = false;
1279
- switchForwardMessage = "";
1280
1113
  continue;
1281
1114
  }
1282
1115
  if (errorResult.kind === "continue_with_reset") {
1283
1116
  consecutiveErrors = 0;
1284
- contentBlocks = withFreshThreadTaskBlock(contentBlocks);
1285
1117
  continue;
1286
1118
  }
1287
1119
  if (errorResult.kind === "continue_preserve_count") {
1288
1120
  consecutiveErrors = errorResult.consecutiveErrors;
1289
- // Invalid-json recovery may have compacted (#1996): resend the
1290
- // current task block. A no-op when nothing changed.
1291
- contentBlocks = withFreshThreadTaskBlock(contentBlocks);
1292
1121
  continue;
1293
1122
  }
1294
1123
  consecutiveErrors = errorResult.consecutiveErrors;
@@ -1296,17 +1125,7 @@ export class WakeCycleRunner {
1296
1125
  }
1297
1126
  }
1298
1127
  break;
1299
- } // end switch loop
1300
- // --- Coding completion last-resort ping (PR #839) ---
1301
- // The wake cycle is over and no owner notification superseded the armed
1302
- // completion (general silent, errored, or stopped). Send a fixed human
1303
- // line so the result is not silently lost. Never send the session memo
1304
- // (handoff instructions, paths, do-not-notify constraints).
1305
- if (pendingCompletionFallback) {
1306
- logger.warn("Wake cycle ended without an owner notification for a coding completion — sending a generic ping, not the session memo");
1307
- await deliverCodingCompletionFallbackPing(ownerConfig);
1308
- pendingCompletionFallback = null;
1309
- }
1128
+ } // end wake loop
1310
1129
  // --- Post-wake-cycle transcript indexing (best-effort) ---
1311
1130
  // Usage reports are no longer enqueued immediately here. Instead,
1312
1131
  // indexWakeCycle extracts and stores tool call facts, and the background
@@ -1320,9 +1139,7 @@ export class WakeCycleRunner {
1320
1139
  const wakeCycleOutcome = session.isStopRequested()
1321
1140
  ? "stopped"
1322
1141
  : !terminalError && consecutiveErrors === 0
1323
- ? didSwitch
1324
- ? "switched"
1325
- : "completed"
1142
+ ? "completed"
1326
1143
  : "error";
1327
1144
  // Always index wake cycles — including stopped/error cycles — so that
1328
1145
  // usage metering is consistent for all cycles. The outcome field records
@@ -1331,7 +1148,7 @@ export class WakeCycleRunner {
1331
1148
  const wakeCycleEndLine = await countFileLines(postCycleTranscript.path);
1332
1149
  void indexWakeCycle({
1333
1150
  wakeCycleId,
1334
- sessionType: session.activeMode,
1151
+ sessionType: "general",
1335
1152
  sourceFile: postCycleTranscript.path,
1336
1153
  sourceFormat: postCycleTranscript.format,
1337
1154
  startLine: postCycleStartLine,
@@ -1357,10 +1174,11 @@ export class WakeCycleRunner {
1357
1174
  : awaitingUser
1358
1175
  ? "waiting_user"
1359
1176
  : "completed",
1177
+ finished: wakeFinished,
1360
1178
  };
1361
1179
  }
1362
1180
  /**
1363
- * Handle an error from the session switch loop. Returns:
1181
+ * Handle an error from the wake loop. Returns:
1364
1182
  * - `continue_with_reset` for recovery paths that should retry immediately
1365
1183
  * with a clean error counter (compaction/sanitization succeeded)
1366
1184
  * - `continue_preserve_count` for normal retryable failures that should
@@ -1402,6 +1220,8 @@ export class WakeCycleRunner {
1402
1220
  // terminal facts for this run, not a reason to start conversational
1403
1221
  // recovery, notify the owner directly, sleep, or enqueue another wake.
1404
1222
  if (this.deps.singleShot) {
1223
+ // Kept for the failure report, so the caller sees the cause.
1224
+ getWorkerExecutionRuntime()?.noteError(errMsg);
1405
1225
  return { kind: "done", consecutiveErrors };
1406
1226
  }
1407
1227
  if (err instanceof CompactionFailureError ||
@@ -1463,7 +1283,6 @@ export class WakeCycleRunner {
1463
1283
  message: `${config.agentName}: invalid Pi session could not be reset`,
1464
1284
  details: {
1465
1285
  code: "INVALID_PI_SESSION_RECOVERY_FAILED",
1466
- activeSession: session.activeMode,
1467
1286
  sessionId: invalidSessionId ?? "unknown",
1468
1287
  provider: config.provider,
1469
1288
  model: reportedModel(config),
@@ -1526,7 +1345,6 @@ export class WakeCycleRunner {
1526
1345
  message: `${config.agentName}: stale session could not be reset`,
1527
1346
  details: {
1528
1347
  code: "SESSION_NOT_FOUND_RECOVERY_FAILED",
1529
- activeSession: session.activeMode,
1530
1348
  sessionId: deadSessionId ?? "unknown",
1531
1349
  provider: config.provider,
1532
1350
  model: reportedModel(config),
@@ -1613,7 +1431,7 @@ export class WakeCycleRunner {
1613
1431
  }
1614
1432
  if (recoveryCount === 2) {
1615
1433
  const oldSessionId = session.activeSession.getSessionId();
1616
- logger.warn(`Invalid JSON body repeated after compaction; resetting ${session.activeSession.mode} session before retry`);
1434
+ logger.warn("Invalid JSON body repeated after compaction; resetting session before retry");
1617
1435
  session.activeSession.resetForNewSession("Previous session was reset automatically after repeated provider `400 Invalid JSON body` errors. " +
1618
1436
  "This usually means the provider rejected the context/payload even after compaction. Continue from memory and the current user request; avoid reloading large prior tool outputs unless needed.");
1619
1437
  logger.system(`Invalid-json-body recovery reset session: old=${oldSessionId ?? "unknown"} new=${session.activeSession.getSessionId() ?? "pending"}`);
@@ -1628,7 +1446,6 @@ export class WakeCycleRunner {
1628
1446
  code: "INVALID_JSON_BODY_RECOVERY_FAILED",
1629
1447
  consecutiveInvalidJsonBodyErrors: recoveryCount,
1630
1448
  actionsAttempted: ["compaction", "session_reset", "controlled_restart"],
1631
- activeSession: session.activeSession.mode,
1632
1449
  provider: config.provider,
1633
1450
  model: reportedModel(config),
1634
1451
  },
@@ -1653,16 +1470,15 @@ export class WakeCycleRunner {
1653
1470
  return { kind: "continue_preserve_count", consecutiveErrors };
1654
1471
  }
1655
1472
  // Retries exhausted: tell the owner what actually broke, naming the
1656
- // local cause instead of blaming the model provider.
1657
- const sleepMin = FATAL_SLEEP_MS / 60_000;
1473
+ // local cause instead of blaming the model provider. The wake ends here.
1474
+ // Sleeping would keep the foreground slot busy until the timer fired.
1658
1475
  logger.warn(`Notifying owner about persistent local coordination error: ${errMsg}`);
1659
1476
  try {
1660
- await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors, sleepMin, errMsg), config);
1477
+ await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors, errMsg), config);
1661
1478
  }
1662
1479
  catch (notifyErr) {
1663
1480
  logger.warn(`Failed to send error notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
1664
1481
  }
1665
- await new Promise((r) => setTimeout(r, FATAL_SLEEP_MS));
1666
1482
  return { kind: "done", consecutiveErrors };
1667
1483
  }
1668
1484
  // --- Known malformed Responses replay ---
@@ -1701,7 +1517,7 @@ export class WakeCycleRunner {
1701
1517
  }
1702
1518
  logger.err(`Malformed Responses replay recovery failed — ending wake: ${errMsg}`);
1703
1519
  try {
1704
- await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors, 0, errMsg), config);
1520
+ await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors, errMsg), config);
1705
1521
  }
1706
1522
  catch (notifyErr) {
1707
1523
  logger.warn(`Failed to send error notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
@@ -1713,10 +1529,7 @@ export class WakeCycleRunner {
1713
1529
  // whether this wake has work that still needs an explicit resolution.
1714
1530
  if (category === "empty_turn") {
1715
1531
  const { activityTracker, interruptHandler } = this.deps;
1716
- const hasPendingWork = activityTracker.getTodos().some((todo) => todo.status === "pending" || todo.status === "in_progress") || activityTracker.getActiveSubagents().length > 0
1717
- // Paused tasks persist across wakes; they do not make an otherwise
1718
- // idle heartbeat responsible for resuming coding work.
1719
- || session.getCodingSessionState() === "in_progress";
1532
+ const hasPendingWork = activityTracker.getTodos().some((todo) => todo.status === "pending" || todo.status === "in_progress") || activityTracker.getActiveSubagents().length > 0;
1720
1533
  const idleHeartbeat = wake.trigger === "heartbeat"
1721
1534
  && wake.messages.length === 0
1722
1535
  && !interruptHandler.hasAcceptedWorkThisCycle()
@@ -1733,7 +1546,7 @@ export class WakeCycleRunner {
1733
1546
  if (phase === "Stopping") {
1734
1547
  logger.warn(`Empty-turn continuation did not confirm task completion: ${errMsg}`);
1735
1548
  try {
1736
- await notifyOwner(formatOwnerErrorNotice(category, this.emptyTurnRetries, 0, errMsg), config);
1549
+ await notifyOwner(formatOwnerErrorNotice(category, this.emptyTurnRetries, errMsg), config);
1737
1550
  }
1738
1551
  catch (notifyErr) {
1739
1552
  logger.warn(`Failed to send empty-turn notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
@@ -1745,7 +1558,7 @@ export class WakeCycleRunner {
1745
1558
  const message = [
1746
1559
  "Your previous turn ended with no additional content. This alone does not indicate whether the task is complete.",
1747
1560
  "Review the current request, task state, and existing tool results before acting. Do not repeat successful notifications, emails, uploads, or other side effects.",
1748
- "If no work remains, only call finish (or switch_session for a required handoff). Otherwise continue only the unfinished work, wait for running subagents as needed, then finish.",
1561
+ "If no work remains, only call finish. Otherwise continue only the unfinished work, wait for running subagents as needed, then finish.",
1749
1562
  "If completion cannot be verified or user input is needed, explain what remains uncertain to the user and call finish(awaiting_user=true).",
1750
1563
  ].join("\n");
1751
1564
  logger.system("Empty assistant turn with unresolved work — sending one explicit continuation");
@@ -1802,10 +1615,22 @@ export class WakeCycleRunner {
1802
1615
  logger.system("No alternate engine available for transient network failures; keeping consecutiveErrors and the cooldown");
1803
1616
  }
1804
1617
  }
1805
- if (category === "fatal" ||
1806
- consecutiveErrors >= MAX_RETRIES_BEFORE_NOTIFY) {
1807
- const sleepMin = FATAL_SLEEP_MS / 60_000;
1808
- const notice = formatOwnerErrorNotice(category, consecutiveErrors, sleepMin);
1618
+ // consecutiveErrors counts the failures already seen in this wake. The
1619
+ // notify threshold is the unknown bucket, not the network disconnect
1620
+ // ceiling. Reaching it is Stopping: notify, then end the wake. The next
1621
+ // attempt waits for a queued message or the proactive timer, not a sleep
1622
+ // that holds this slot.
1623
+ const unknownPhase = category === "fatal"
1624
+ ? "Stopping"
1625
+ : nextRecoveryPhase({
1626
+ from: this.recoveryPhase,
1627
+ bucket: "unknown",
1628
+ spent: consecutiveErrors,
1629
+ });
1630
+ if (unknownPhase === "Recovering")
1631
+ this.recoveryPhase = "Recovering";
1632
+ if (unknownPhase === "Stopping") {
1633
+ const notice = formatOwnerErrorNotice(category, consecutiveErrors);
1809
1634
  logger.warn(`Notifying owner about repeated agent error: ${errMsg}`);
1810
1635
  try {
1811
1636
  await notifyOwner(notice, config);
@@ -1814,7 +1639,6 @@ export class WakeCycleRunner {
1814
1639
  logger.warn(`Failed to send error notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
1815
1640
  }
1816
1641
  consecutiveErrors = 0;
1817
- await new Promise((r) => setTimeout(r, FATAL_SLEEP_MS));
1818
1642
  }
1819
1643
  else {
1820
1644
  try {
@@ -1854,8 +1678,8 @@ export class WakeCycleRunner {
1854
1678
  return;
1855
1679
  }
1856
1680
  // Between the failed `/compact` and the end of the cycle the session may
1857
- // have been switched (coding <-> general) or already rotated by the error
1858
- // path. Only rotate the session that actually failed to compact.
1681
+ // have already been rotated by the error path. Only rotate the session
1682
+ // that actually failed to compact.
1859
1683
  if (pending.sessionId === null || session.activeSession.getSessionId() !== pending.sessionId) {
1860
1684
  logger.system(`Post-query compaction failed terminally (${err.errorCode}) but the active session changed before the cycle ended; leaving rotation to the next check`);
1861
1685
  return;
@@ -1893,8 +1717,15 @@ export class WakeCycleRunner {
1893
1717
  // Two recovery turns total: repair, then one refresh. The second branch is
1894
1718
  // gated by the ceiling, so raising MAX_OUTPUT_RECOVERY_ATTEMPTS is what
1895
1719
  // allows another turn. Advancing before I/O keeps a failed repair from
1896
- // resetting the allowance.
1897
- if (attempts[recoveryKind] === 0) {
1720
+ // resetting the allowance. The two kinds keep separate counts.
1721
+ const outputPhase = nextRecoveryPhase({
1722
+ from: this.recoveryPhase,
1723
+ bucket: recoveryKind === "policy_refused" ? "policy_refusal" : "oversized",
1724
+ spent: attempts[recoveryKind],
1725
+ });
1726
+ if (outputPhase === "Recovering")
1727
+ this.recoveryPhase = "Recovering";
1728
+ if (attempts[recoveryKind] === 0 && outputPhase === "Recovering") {
1898
1729
  attempts[recoveryKind]++;
1899
1730
  if (!compactionAlreadyFailed) {
1900
1731
  try {
@@ -1913,7 +1744,7 @@ export class WakeCycleRunner {
1913
1744
  logger.system("SDK auto-compaction already failed — skipping same-session transcript repair and rotating context");
1914
1745
  }
1915
1746
  }
1916
- if (attempts[recoveryKind] < MAX_OUTPUT_RECOVERY_ATTEMPTS) {
1747
+ if (attempts[recoveryKind] < MAX_OUTPUT_RECOVERY_ATTEMPTS && outputPhase === "Recovering") {
1917
1748
  attempts[recoveryKind]++;
1918
1749
  const previousId = session.activeSession.getSessionId();
1919
1750
  try {