mixdog 1.3.5 → 1.4.1

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 (515) hide show
  1. package/NOTICE.md +2 -2
  2. package/README.md +2 -2
  3. package/package.json +2 -11
  4. package/scripts/check-voice-runtime-inputs.mjs +25 -0
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/gate-local.mjs +16 -5
  7. package/scripts/latest-guard.mjs +21 -9
  8. package/scripts/lib/isolated-test-env.mjs +10 -5
  9. package/scripts/lib/run-node-tests.mjs +37 -37
  10. package/scripts/lib/scoped-temp.d.mts +16 -0
  11. package/scripts/lib/scoped-temp.mjs +123 -0
  12. package/scripts/lib/stale-temp.mjs +44 -0
  13. package/scripts/native-release-status.mjs +2 -2
  14. package/scripts/post-release-check.mjs +1 -6
  15. package/scripts/pptx-kit-index.mjs +17 -4
  16. package/scripts/recall-history-cases.json +1 -1
  17. package/scripts/suite-health.mjs +20 -2
  18. package/scripts/test-data-dir.mjs +10 -7
  19. package/scripts/test.mjs +7 -11
  20. package/src/agents/reviewer/AGENT.md +7 -11
  21. package/src/agents/reviewer/agent.json +1 -1
  22. package/src/app.mjs +4 -0
  23. package/src/defaults/shipped-history.json +22 -1
  24. package/src/defaults/skills/browser-use/SKILL.md +62 -12
  25. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  26. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  27. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  28. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  29. package/src/defaults/skills/computer-use/SKILL.md +35 -9
  30. package/src/defaults/skills/setup/SKILL.md +22 -0
  31. package/src/defaults/skills/setup/references/actions.md +39 -5
  32. package/src/defaults/skills/setup/references/surfaces.md +11 -2
  33. package/src/defaults/skills/visualize/SKILL.md +2 -1
  34. package/src/lib/rules-builder.cjs +39 -20
  35. package/src/output-styles/common.md +2 -2
  36. package/src/output-styles/simple.md +1 -1
  37. package/src/rules/agent/AGENT.md +11 -10
  38. package/src/rules/lead/LEAD.md +23 -20
  39. package/src/rules/shared/05-tool-calls.md +5 -6
  40. package/src/rules/shared/10-tool-workflow.md +4 -0
  41. package/src/rules/shared/45-destructive.md +0 -2
  42. package/src/rules/shared/50-execution.md +2 -0
  43. package/src/rules/shared/60-verification.md +7 -5
  44. package/src/rules/shared/70-delivery.md +7 -9
  45. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
  46. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  47. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  48. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  49. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
  50. package/src/runtime/agent/orchestrator/config.mjs +17 -1
  51. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  52. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +73 -68
  53. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +57 -2
  54. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  55. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
  56. package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
  57. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
  58. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +192 -133
  59. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
  60. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
  63. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  66. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  67. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
  70. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +159 -69
  71. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  72. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +70 -33
  73. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
  74. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  75. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
  76. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  77. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
  78. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  79. package/src/runtime/agent/orchestrator/providers/cursor.mjs +25 -13
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
  81. package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
  82. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
  83. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
  84. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
  85. package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
  87. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  88. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  89. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
  90. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  91. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  92. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  93. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
  106. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
  107. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
  109. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  113. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
  116. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
  117. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  118. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  119. package/src/runtime/agent/orchestrator/providers/registry.mjs +38 -0
  120. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  121. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  122. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +49 -16
  123. package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
  124. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
  125. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
  126. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
  127. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +9 -3
  128. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
  131. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
  132. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
  133. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +798 -0
  134. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  135. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
  136. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
  137. package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
  138. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +280 -45
  139. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  140. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  141. package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
  142. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
  143. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
  144. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
  145. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
  146. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
  147. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
  148. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
  149. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
  150. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  151. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +51 -25
  153. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +37 -3
  154. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
  155. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
  157. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
  158. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +31 -3
  159. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +20 -3
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +5 -4
  162. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  163. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  164. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +49 -21
  165. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  166. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
  167. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  168. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
  172. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  173. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  174. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +24 -14
  175. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  176. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  177. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +130 -0
  178. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
  179. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +81 -8
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  181. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -8
  182. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
  183. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  184. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +9 -4
  185. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  187. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +21 -5
  188. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
  189. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +24 -9
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  191. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +150 -0
  192. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
  193. package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
  194. package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
  195. package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
  196. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
  197. package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
  198. package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
  199. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
  200. package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
  201. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
  203. package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
  207. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +81 -22
  208. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +92 -3
  209. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  210. package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
  211. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
  212. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
  213. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +79 -3
  214. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  216. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  217. package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
  218. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  221. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
  222. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
  224. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
  225. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +31 -6
  226. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +110 -26
  227. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
  228. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
  229. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
  230. package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
  231. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
  232. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
  233. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
  234. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
  235. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
  236. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
  237. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  238. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
  239. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  240. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  241. package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
  242. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
  243. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  244. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  245. package/src/runtime/browser-bridge/client.mjs +73 -8
  246. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  247. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  248. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  249. package/src/runtime/channels/lib/config.mjs +6 -61
  250. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  251. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  252. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  253. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  254. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  255. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  256. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  257. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  258. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  259. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  260. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  261. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  262. package/src/runtime/channels/lib/scheduler.mjs +33 -147
  263. package/src/runtime/channels/lib/schedules-db.mjs +34 -11
  264. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  265. package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
  266. package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
  267. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  268. package/src/runtime/channels/lib/whisper-port.mjs +10 -1
  269. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  270. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  271. package/src/runtime/channels/lib/worker-main.mjs +10 -34
  272. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  273. package/src/runtime/computer-bridge/actions.mjs +9 -1
  274. package/src/runtime/computer-bridge/client.mjs +180 -8
  275. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  276. package/src/runtime/computer-bridge/error-recovery.mjs +28 -2
  277. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
  278. package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
  279. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  280. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  281. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  282. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  283. package/src/runtime/connectors/google-mcp.mjs +10 -12
  284. package/src/runtime/local-provider/server-process.mjs +2 -1
  285. package/src/runtime/media/adapters/gemini-video.mjs +4 -1
  286. package/src/runtime/media/adapters/xai-media.mjs +2 -1
  287. package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
  288. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
  289. package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
  290. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  291. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  292. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  293. package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
  294. package/src/runtime/office/design/design-art-direction.mjs +29 -27
  295. package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
  296. package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
  297. package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
  298. package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
  299. package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
  300. package/src/runtime/office/quality/design-review.mjs +1 -5
  301. package/src/runtime/office/quality/document-brief.mjs +1 -5
  302. package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
  303. package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
  304. package/src/runtime/session-search/session-search-db.mjs +73 -9
  305. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  306. package/src/runtime/shared/abort-race.mjs +89 -0
  307. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  308. package/src/runtime/shared/agent-kind.mjs +4 -3
  309. package/src/runtime/shared/bot-owned-work.mjs +56 -0
  310. package/src/runtime/shared/bounded-download.mjs +8 -3
  311. package/src/runtime/shared/config.mjs +2 -13
  312. package/src/runtime/shared/connector-accounts.mjs +20 -10
  313. package/src/runtime/shared/connector-catalog.d.mts +29 -0
  314. package/src/runtime/shared/connector-catalog.mjs +150 -0
  315. package/src/runtime/shared/connector-triggers.mjs +22 -19
  316. package/src/runtime/shared/defaults-separation.mjs +2 -17
  317. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  318. package/src/runtime/shared/err-text.mjs +24 -15
  319. package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
  320. package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
  321. package/src/runtime/shared/file-permissions.d.mts +0 -8
  322. package/src/runtime/shared/file-permissions.mjs +0 -11
  323. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  324. package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
  325. package/src/runtime/shared/handoff-artifacts.mjs +18 -8
  326. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  327. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  328. package/src/runtime/shared/idle-auto-clear-gate.mjs +126 -0
  329. package/src/runtime/shared/llm/cost.mjs +5 -1
  330. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  331. package/src/runtime/shared/loopback-listener.mjs +25 -2
  332. package/src/runtime/shared/mixy-presence.mjs +22 -0
  333. package/src/runtime/shared/model-route-chain.d.mts +7 -2
  334. package/src/runtime/shared/model-route-chain.mjs +22 -4
  335. package/src/runtime/shared/open-url.mjs +10 -0
  336. package/src/runtime/shared/orchestration.d.mts +2 -0
  337. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  338. package/src/runtime/shared/profile-config.cjs +1 -1
  339. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  340. package/src/runtime/shared/prompt-origin.mjs +21 -0
  341. package/src/runtime/shared/provider-accounts.mjs +7 -1
  342. package/src/runtime/shared/provider-display-name.mjs +29 -0
  343. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  344. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  345. package/src/runtime/shared/routine-trigger.mjs +10 -0
  346. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  347. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  348. package/src/runtime/shared/session-activity-signal.mjs +48 -1
  349. package/src/runtime/shared/session-scratch.mjs +37 -0
  350. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  351. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  352. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  353. package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
  354. package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
  355. package/src/runtime/shared/tool-result-summary.mjs +2 -15
  356. package/src/runtime/shared/tool-surface.mjs +3 -0
  357. package/src/runtime/shared/tool-work-units.mjs +2 -0
  358. package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
  359. package/src/runtime/shared/worktrees/contract.mjs +4 -1
  360. package/src/runtime/shared/worktrees/git.mjs +15 -0
  361. package/src/runtime/shared/worktrees/manager.mjs +87 -38
  362. package/src/runtime/shared/worktrees/test-support.mjs +14 -13
  363. package/src/runtime/terminal-bridge/client.mjs +10 -1
  364. package/src/runtime/visualize-bridge/client.mjs +29 -8
  365. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  366. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  367. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  368. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  369. package/src/session-runtime/agent-home-delivery.mjs +489 -185
  370. package/src/session-runtime/agent-task-sessions.mjs +467 -229
  371. package/src/session-runtime/agent-tool-routing.mjs +8 -41
  372. package/src/session-runtime/boot/apis.mjs +9 -0
  373. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  374. package/src/session-runtime/boot/providers.mjs +3 -0
  375. package/src/session-runtime/boot/tools.mjs +11 -2
  376. package/src/session-runtime/bot-status.mjs +12 -6
  377. package/src/session-runtime/bot-target.mjs +38 -0
  378. package/src/session-runtime/channel-config-api.mjs +6 -1
  379. package/src/session-runtime/config-lifecycle.mjs +6 -0
  380. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  381. package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
  382. package/src/session-runtime/conversation-import/discovery.mjs +271 -25
  383. package/src/session-runtime/conversation-import/service.mjs +26 -5
  384. package/src/session-runtime/handoff-attachments.mjs +82 -31
  385. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +144 -41
  386. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -0
  387. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
  388. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
  389. package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
  390. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  391. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  392. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  393. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  394. package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
  395. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  396. package/src/session-runtime/mixy-heartbeat.mjs +153 -33
  397. package/src/session-runtime/model-route/set-route.mjs +11 -2
  398. package/src/session-runtime/notification-bus.mjs +31 -117
  399. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  400. package/src/session-runtime/notification-listeners.mjs +76 -0
  401. package/src/session-runtime/owned-automation-run.mjs +2 -1
  402. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  403. package/src/session-runtime/provider-catalog-cache.mjs +82 -36
  404. package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
  405. package/src/session-runtime/provider-models.mjs +4 -2
  406. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  407. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  408. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  409. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  410. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  411. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  412. package/src/session-runtime/resource-recall-api.mjs +6 -1
  413. package/src/session-runtime/routine-owner.mjs +40 -9
  414. package/src/session-runtime/runtime-feature-gates.mjs +5 -1
  415. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  416. package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
  417. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
  418. package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
  419. package/src/session-runtime/services/agent-tool/render.mjs +71 -17
  420. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +13 -4
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  422. package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
  423. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  424. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  425. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  426. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  427. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  428. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  429. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  430. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  431. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  432. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  433. package/src/session-runtime/services/channel-admin.mjs +7 -13
  434. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  435. package/src/session-runtime/services/provider-admin.mjs +2 -1
  436. package/src/session-runtime/services/seeds.mjs +0 -28
  437. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  438. package/src/session-runtime/session-create/session-options.mjs +1 -0
  439. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  440. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  441. package/src/session-runtime/settings-system-api.mjs +13 -1
  442. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  443. package/src/session-runtime/setup-tool/executor.mjs +145 -22
  444. package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
  445. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  446. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
  447. package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
  448. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  449. package/src/session-runtime/tool-policy/policy-stage.mjs +17 -2
  450. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  451. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
  452. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
  453. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
  454. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  455. package/src/session-runtime/workspace/transitions.mjs +25 -0
  456. package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
  457. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  458. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  459. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  460. package/src/standalone/channel-transport.mjs +1 -1
  461. package/src/standalone/daemon-channels-loader.mjs +10 -8
  462. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  463. package/src/standalone/daemon-session-control/request.mjs +51 -0
  464. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  465. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  466. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  467. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  468. package/src/standalone/daemon-session-control.mjs +142 -190
  469. package/src/standalone/daemon.mjs +26 -3
  470. package/src/standalone/session-client.mjs +7 -3
  471. package/src/standalone/session-protocol.mjs +5 -0
  472. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  473. package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
  474. package/src/standalone/session-service/quota-resume.mjs +3 -0
  475. package/src/standalone/session-service/retention/busy.mjs +65 -1
  476. package/src/standalone/session-service/session-calls/session-action.mjs +30 -2
  477. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  478. package/src/standalone/session-tool-output.mjs +15 -7
  479. package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
  480. package/src/tui/app/app-view/floating-panel.jsx +7 -4
  481. package/src/tui/app/model-options.mjs +3 -28
  482. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
  483. package/src/tui/app/model-picker/route-selection.mjs +5 -6
  484. package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
  485. package/src/tui/app/provider-setup/provider-items.mjs +8 -2
  486. package/src/tui/app/provider-setup-picker.mjs +9 -5
  487. package/src/tui/components/QuestionPanel.jsx +13 -4
  488. package/src/tui/dist/index.mjs +133 -92
  489. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  490. package/src/tui/session/initial-state.mjs +3 -0
  491. package/src/tui/session/notice-surface.mjs +7 -1
  492. package/src/tui/session/queue-helpers.mjs +3 -42
  493. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  494. package/src/tui/session/session-api/routes-write.mjs +5 -1
  495. package/src/tui/session/session-api/routes.mjs +1 -0
  496. package/src/tui/session/session-api/settings.mjs +17 -1
  497. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  498. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  499. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  500. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  501. package/src/tui/session/session-flow/drain.mjs +118 -149
  502. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  503. package/src/tui/session/session-flow/queue/take-entries.mjs +16 -2
  504. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  505. package/src/tui/session/tool-approval-request.mjs +39 -0
  506. package/src/tui/session/tool-approval-settle.mjs +62 -0
  507. package/src/tui/session/tool-approval.mjs +69 -115
  508. package/src/tui/session/tui-steering-persist.mjs +8 -1
  509. package/src/tui/session/turn-stream.mjs +19 -2
  510. package/src/tui/session/turn.mjs +1 -0
  511. package/src/ui/statusline-agents.mjs +1 -3
  512. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  513. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  514. package/scripts/code-graph-description-contract.mjs +0 -188
  515. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ACCOUNT_PROVIDERS,
3
+ MAX_ACCOUNTS,
3
4
  accountScopedSessionId,
4
5
  readProviderAccountPool,
5
6
  chooseProviderAccount,
@@ -243,6 +244,17 @@ function sessionAccountId(providerName, key, messages, options) {
243
244
  return null;
244
245
  }
245
246
 
247
+ /** The account a send of `model` for `sessionId` would try first right now —
248
+ * the session's binding and the choice poolSend makes for its first attempt
249
+ * — or null when the provider has no roster account or none is eligible. */
250
+ export function plannedAccountId(providerName, { sessionId = null, messages = [], providerState, model = '' } = {}) {
251
+ const pool = readProviderAccountPool(providerName);
252
+ if (!pool.accounts.length) return null;
253
+ const sessionKey = sessionId ? `${providerName}:${sessionId}` : null;
254
+ const boundId = sessionAccountId(providerName, sessionKey, messages, { providerState });
255
+ return chooseProviderAccount(pool, new Set(), Date.now(), model, { sessionAccountId: boundId })?.id || null;
256
+ }
257
+
246
258
  // Stamp the serving account on the answer, independent of transport state,
247
259
  // with the account the session stays bound to (`bindingId`).
248
260
  function recordServingAccount(providerName, result, id, bindingId) {
@@ -358,110 +370,182 @@ async function accountQuotaExhausted(providerName, row, model, error, account) {
358
370
  evidence = providerAccountExhausted(providerAccountWithBlocks(entry), Date.now(), model, options);
359
371
  exhausted = exhausted || evidence || providerAccountExhausted(entry, Date.now(), model, options);
360
372
  }
361
- return { exhausted, delay, evidence, ...(exhausted ? blockUntil(evidence, evidence ? 'quota' : 'unknown') : {}) };
373
+ const reason = evidence ? 'quota' : 'unknown';
374
+ return { exhausted, delay, evidence, ...(exhausted ? blockUntil(evidence, reason) : {}) };
375
+ }
376
+
377
+ // Record an exhausted verdict on the roster. An account-level block holds
378
+ // every model, so it carries no model or limit scope.
379
+ function blockRefusedAccount(providerName, accountId, model, error, verdict) {
380
+ const { evidence, until, source, reset, accountBlocked } = verdict;
381
+ return blockProviderAccount(providerName, accountId, until, accountBlocked ? '' : model, source, {
382
+ quota: evidence === true,
383
+ reset: reset === true,
384
+ limit: accountBlocked ? '' : quotaLimitOf(error),
385
+ });
386
+ }
387
+
388
+ /**
389
+ * A refusal `error` that account `accountId` gave outside the pool's send (a
390
+ * cache warm, which never rotates): judged and recorded on the roster exactly
391
+ * as the send would, with `instance` as that account's provider. Resolves
392
+ * whether the account was blocked.
393
+ */
394
+ export async function recordAccountRefusal(providerName, accountId, model, error, instance) {
395
+ const row = readProviderAccountPool(providerName).accounts.find((entry) => entry.id === accountId);
396
+ if (!row) return false;
397
+ const verdict = await accountQuotaExhausted(providerName, row, model, error, () => instance);
398
+ if (!verdict.exhausted) return false;
399
+ await blockRefusedAccount(providerName, row.id, model, error, verdict);
400
+ return true;
401
+ }
402
+
403
+ // Whether every account in `ids` (default: the roster) is exhausted with quota
404
+ // evidence: observed in this send (`evidenced`), or a full window.
405
+ function rosterExhaustion(providerName, model, evidenced, ids) {
406
+ const pool = readProviderAccountPool(providerName);
407
+ // Manual policy: the eligible set is the selected account alone.
408
+ const scope = ids || (providerAccountPolicy(pool) === 'manual' ? [pool.selectedId] : null);
409
+ const rows = scope ? pool.accounts.filter((entry) => scope.includes(entry.id)) : pool.accounts;
410
+ const opts = { useCredits: pool.useCredits === true };
411
+ const now = Date.now();
412
+ const all =
413
+ rows.length > 0 &&
414
+ rows.every((entry) =>
415
+ providerAccountExhausted(
416
+ evidenced.has(entry.id) ? entry : providerAccountWithBlocks(entry, (block) => block.blockedQuota === true),
417
+ now,
418
+ model,
419
+ opts
420
+ )
421
+ );
422
+ return { rows, opts, now, all };
423
+ }
424
+
425
+ // Mark `error` only when every account in `ids` is exhausted with quota
426
+ // evidence (`rosterExhaustion`). Without an error of its own, the send reports
427
+ // quota exhaustion only on that evidence, and a rate-limit cooldown otherwise.
428
+ function exhaustedSendError(providerName, model, evidenced, error, ids) {
429
+ const { rows, opts, now, all } = rosterExhaustion(providerName, model, evidenced, ids);
430
+ if (all) {
431
+ return quotaExhausted(error || accountsExhaustedError(opts.useCredits), providerName, model, rows, opts);
432
+ }
433
+ return error || accountsCoolingDownError(rows, now, model);
434
+ }
435
+
436
+ // The provider's bound on the time one send spends waiting for cooldowns.
437
+ function cooldownWaitBoundMs(providerName, account, ids) {
438
+ const id = ids?.[0] || readProviderAccountPool(providerName).selectedId || 'default';
439
+ return finiteMs(cooldownPolicyOf(account(id))?.waitForCooldownMs, 0);
440
+ }
441
+
442
+ // A cooldown-only eligible set whose earliest cooldown ends inside the
443
+ // remaining wait budget is waited out; otherwise the send fails as before.
444
+ // `ledger` is the send's own record of the roster (see `poolSend`).
445
+ async function waitOutCooldownOrThrow(request, ledger, error, ids) {
446
+ const { providerName, model, account, options } = request;
447
+ const { rows, now, all } = rosterExhaustion(providerName, model, ledger.evidenced, ids);
448
+ const bound = cooldownWaitBoundMs(providerName, account, ids);
449
+ // Persisting a short cooldown can outlast its deadline. Release only
450
+ // attempts cooled by this send, and only under an enabled wait policy.
451
+ const expired = bound > 0 && rows.some((row) => ledger.cooled.has(row.id) && !(coolingUntil(row, model) > now));
452
+ let wait = null;
453
+ if (!all) wait = expired ? 0 : earliestCooldownMs(rows, now, model);
454
+ if (wait == null || ledger.waitedMs + wait > bound) {
455
+ throw exhaustedSendError(providerName, model, ledger.evidenced, error, ids);
456
+ }
457
+ options.onStageChange?.('reconnecting', {
458
+ message: `Rate limited — every account is cooling down; retrying in ${Math.ceil(wait / 1000)}s`,
459
+ reason: 'rate_limited',
460
+ waitMs: wait,
461
+ retryAt: now + wait,
462
+ });
463
+ // A zero-duration sleep does not check cancellation, including on the
464
+ // final allowed send when no next loop iteration will check it either.
465
+ options.signal?.throwIfAborted();
466
+ await sleepWithAbort(wait, options.signal);
467
+ ledger.waitedMs += wait;
468
+ const lifted = Date.now();
469
+ for (const row of readProviderAccountPool(providerName).accounts) {
470
+ if (ledger.cooled.has(row.id) && !(coolingUntil(row, model) > lifted)) {
471
+ ledger.cooled.delete(row.id);
472
+ ledger.attempted.delete(row.id);
473
+ }
474
+ }
475
+ }
476
+
477
+ // No roster: with credit use off, a stored reading showing the plan's window
478
+ // spent refuses before the implicit account sends.
479
+ function throwIfPlanQuotaSpent(providerName, pool, model) {
480
+ if (pool.useCredits !== true) {
481
+ const stored = readCachedOAuthUsageSnapshot({ provider: providerName, model: '' });
482
+ // A snapshot cached before per-model gating is stale evidence.
483
+ if (stored?.quotaWindows?.length && !staleQuotaWindows(providerName, stored.quotaWindows)) {
484
+ const row = { usage: { windows: stored.quotaWindows, checkedAt: stored.cachedAt } };
485
+ if (providerAccountExhausted(row, Date.now(), model)) {
486
+ throw quotaExhausted(accountsExhaustedError(false), providerName, model, [row]);
487
+ }
488
+ }
489
+ }
490
+ }
491
+
492
+ // Headroom policy: a session's first pick, or its move off its account on a
493
+ // limit, becomes the selection; continuing on its account does not, so
494
+ // concurrent sessions never flip the selection back and forth. A move forced
495
+ // by a model-scoped limit serves this request only (`scoped`). Stamps the
496
+ // serving account on `result` and resolves whether the selection may commit.
497
+ function bindServedAccount(providerName, result, rowId, model, binding) {
498
+ const { policy, boundId, sessionKey, switched, refusalScoped } = binding;
499
+ const leftBound = Boolean(boundId) && rowId !== boundId;
500
+ const scoped = switched
501
+ ? refusalScoped
502
+ : policy === 'headroom' && leftBound && accountExhaustedForModelOnly(providerName, boundId, model);
503
+ recordServingAccount(providerName, result, rowId, scoped && boundId ? boundId : rowId);
504
+ if (sessionKey && policy === 'headroom' && !scoped) rememberSessionAccount(sessionKey, rowId);
505
+ return { scoped, commit: policy !== 'headroom' || !boundId || leftBound };
506
+ }
507
+
508
+ // A failed attempt is never re-issued once output reached the caller or the
509
+ // attempt was unsafe to retry (`unsafe`, judged by the caller and read only
510
+ // when nothing was emitted).
511
+ function attemptUnretryable(bound, error, unsafe) {
512
+ return Boolean(bound.emitted() || unsafe() || error.liveTextEmitted || error.emittedToolCall);
513
+ }
514
+
515
+ function rotationReason(evidence, accountBlocked) {
516
+ if (evidence) return 'Quota exhausted';
517
+ if (accountBlocked) return 'Account blocked';
518
+ return 'Rate limited (cooldown)';
362
519
  }
363
520
 
364
521
  // The pool's send: walks the eligible accounts until one answers, blocking
365
522
  // the ones whose quota window is exhausted along the way.
366
523
  function poolSend(providerName, account) {
367
524
  return async function send(messages, model, tools, options = {}) {
368
- const attempted = new Set();
525
+ const request = { providerName, model, account, options };
526
+ // This send's record of the roster: the accounts it tried, those it found
527
+ // exhausted with quota evidence, those it blocked on a rate-limit
528
+ // cooldown, and the time it spent waiting for cooldowns.
529
+ const ledger = { attempted: new Set(), evidenced: new Set(), cooled: new Set(), waitedMs: 0 };
369
530
  let lastError;
370
531
  let probed = false;
371
- const evidenced = new Set();
532
+ let sends = 0;
372
533
  const sessionKey = options.sessionId ? `${providerName}:${options.sessionId}` : null;
373
534
  const boundId = sessionAccountId(providerName, sessionKey, messages, options);
374
535
  // Whether this send already left an account, and whether the latest quota
375
536
  // refusal held only for this model's family.
376
537
  let switched = false;
377
538
  let refusalScoped = false;
378
- // Mark `error` only when every account in `ids` (default: the roster) is
379
- // exhausted with quota evidence: observed in this send, or a full window.
380
- // Without an error of its own, the send reports quota exhaustion only on
381
- // that evidence, and a rate-limit cooldown otherwise.
382
- const exhaustion = (ids) => {
383
- const pool = readProviderAccountPool(providerName);
384
- // Manual policy: the eligible set is the selected account alone.
385
- const scope = ids || (providerAccountPolicy(pool) === 'manual' ? [pool.selectedId] : null);
386
- const rows = scope ? pool.accounts.filter((entry) => scope.includes(entry.id)) : pool.accounts;
387
- const opts = { useCredits: pool.useCredits === true };
388
- const now = Date.now();
389
- const all =
390
- rows.length > 0 &&
391
- rows.every((entry) =>
392
- providerAccountExhausted(
393
- evidenced.has(entry.id) ? entry : providerAccountWithBlocks(entry, (block) => block.blockedQuota === true),
394
- now,
395
- model,
396
- opts
397
- )
398
- );
399
- return { rows, opts, now, all };
400
- };
401
- const markExhausted = (error, ids) => {
402
- const { rows, opts, now, all } = exhaustion(ids);
403
- if (all) {
404
- return quotaExhausted(error || accountsExhaustedError(opts.useCredits), providerName, model, rows, opts);
405
- }
406
- return error || accountsCoolingDownError(rows, now, model);
407
- };
408
- // Accounts this send blocked on a rate-limit cooldown, the time it spent
409
- // waiting for cooldowns, and the provider's wait bound.
410
- const cooled = new Set();
411
- let waitedMs = 0;
412
- let sends = 0;
413
- const waitBoundMs = (ids) => {
414
- const id = ids?.[0] || readProviderAccountPool(providerName).selectedId || 'default';
415
- return finiteMs(cooldownPolicyOf(account(id))?.waitForCooldownMs, 0);
416
- };
417
- // A cooldown-only eligible set whose earliest cooldown ends inside the
418
- // remaining wait budget is waited out; otherwise the send fails as before.
419
- const waitOrThrow = async (error, ids) => {
420
- const { rows, now, all } = exhaustion(ids);
421
- const bound = waitBoundMs(ids);
422
- // Persisting a short cooldown can outlast its deadline. Release only
423
- // attempts cooled by this send, and only under an enabled wait policy.
424
- const expired = bound > 0 && rows.some((row) => cooled.has(row.id) && !(coolingUntil(row, model) > now));
425
- let wait = null;
426
- if (!all) wait = expired ? 0 : earliestCooldownMs(rows, now, model);
427
- if (wait == null || waitedMs + wait > bound) throw markExhausted(error, ids);
428
- options.onStageChange?.('reconnecting', {
429
- message: `Rate limited — every account is cooling down; retrying in ${Math.ceil(wait / 1000)}s`,
430
- reason: 'rate_limited',
431
- waitMs: wait,
432
- retryAt: now + wait,
433
- });
434
- // A zero-duration sleep does not check cancellation, including on the
435
- // final allowed send when no next loop iteration will check it either.
436
- options.signal?.throwIfAborted();
437
- await sleepWithAbort(wait, options.signal);
438
- waitedMs += wait;
439
- const lifted = Date.now();
440
- for (const row of readProviderAccountPool(providerName).accounts) {
441
- if (cooled.has(row.id) && !(coolingUntil(row, model) > lifted)) {
442
- cooled.delete(row.id);
443
- attempted.delete(row.id);
444
- }
445
- }
446
- };
447
- while (attempted.size < 20 && sends < 20) {
539
+ // One try per connectable account at most (provider-accounts.mjs MAX_ACCOUNTS).
540
+ while (ledger.attempted.size < MAX_ACCOUNTS && sends < MAX_ACCOUNTS) {
448
541
  options.signal?.throwIfAborted();
449
542
  const pool = readProviderAccountPool(providerName);
450
543
  if (!pool.accounts.length) {
451
- if (pool.useCredits !== true) {
452
- const stored = readCachedOAuthUsageSnapshot({ provider: providerName, model: '' });
453
- // A snapshot cached before per-model gating is stale evidence.
454
- if (stored?.quotaWindows?.length && !staleQuotaWindows(providerName, stored.quotaWindows)) {
455
- const row = { usage: { windows: stored.quotaWindows, checkedAt: stored.cachedAt } };
456
- if (providerAccountExhausted(row, Date.now(), model)) {
457
- throw quotaExhausted(accountsExhaustedError(false), providerName, model, [row]);
458
- }
459
- }
460
- }
544
+ throwIfPlanQuotaSpent(providerName, pool, model);
461
545
  return account('default').send(messages, model, tools, options);
462
546
  }
463
547
  const policy = providerAccountPolicy(pool);
464
- const row = chooseProviderAccount(pool, attempted, Date.now(), model, { sessionAccountId: boundId });
548
+ const row = chooseProviderAccount(pool, ledger.attempted, Date.now(), model, { sessionAccountId: boundId });
465
549
  if (!row) {
466
550
  // Once per send: a refusal built on a stale meter must not outlive the
467
551
  // meter. Re-measuring can only widen the roster, so it is tried before
@@ -470,26 +554,22 @@ function poolSend(providerName, account) {
470
554
  probed = true;
471
555
  if (await probeRefusedAccounts(providerName, pool, model, account)) continue;
472
556
  }
473
- await waitOrThrow(lastError);
557
+ await waitOutCooldownOrThrow(request, ledger, lastError);
474
558
  continue;
475
559
  }
476
- attempted.add(row.id);
560
+ ledger.attempted.add(row.id);
477
561
  sends += 1;
478
562
  const bound = boundAccountSend(providerName, row, messages, options);
479
563
  try {
480
564
  const result = await account(row.id).send(bound.history, model, tools, bound.opts);
481
565
  quotaStrikes.delete(`${providerName}:${row.id}`);
482
- // Headroom policy: a session's first pick, or its move off its account
483
- // on a limit, becomes the selection; continuing on its account does
484
- // not, so concurrent sessions never flip the selection back and forth.
485
- // A move forced by a model-scoped limit serves this request only.
486
- const leftBound = Boolean(boundId) && row.id !== boundId;
487
- const scoped = switched
488
- ? refusalScoped
489
- : policy === 'headroom' && leftBound && accountExhaustedForModelOnly(providerName, boundId, model);
490
- recordServingAccount(providerName, result, row.id, scoped && boundId ? boundId : row.id);
491
- if (sessionKey && policy === 'headroom' && !scoped) rememberSessionAccount(sessionKey, row.id);
492
- const commit = policy !== 'headroom' || !boundId || leftBound;
566
+ const { scoped, commit } = bindServedAccount(providerName, result, row.id, model, {
567
+ policy,
568
+ boundId,
569
+ sessionKey,
570
+ switched,
571
+ refusalScoped,
572
+ });
493
573
  if (commit && (await commitFallbackAccount(providerName, pool, row, model, scoped, policy))) {
494
574
  // Publish only a committed selection, never a speculative retry or
495
575
  // one superseded by a manual switch. The existing progress channel
@@ -508,62 +588,41 @@ function poolSend(providerName, account) {
508
588
  } catch (error) {
509
589
  if (options.signal?.aborted) throw error;
510
590
  if (error?.reauthRequired === true) {
511
- if (
512
- policy === 'manual' ||
513
- bound.emitted() ||
514
- error.unsafeToRetry ||
515
- error.liveTextEmitted ||
516
- error.emittedToolCall
517
- )
518
- throw error;
591
+ if (policy === 'manual' || attemptUnretryable(bound, error, () => error.unsafeToRetry)) throw error;
519
592
  lastError = error;
520
593
  switched = true;
521
594
  refusalScoped = false;
522
595
  options.onStageChange?.('reconnecting', { message: 'Sign-in expired — switching to the next account' });
523
596
  continue;
524
597
  }
525
- const { exhausted, evidence, until, source, reset, accountBlocked } = await accountQuotaExhausted(
526
- providerName,
527
- row,
528
- model,
529
- error,
530
- account
531
- );
598
+ const verdict = await accountQuotaExhausted(providerName, row, model, error, account);
599
+ const { exhausted, evidence, accountBlocked } = verdict;
532
600
  if (options.signal?.aborted || !exhausted) throw error;
533
- if (evidence) evidenced.add(row.id);
534
- else cooled.add(row.id);
535
- // An account-level block holds every model, so it carries no model or
536
- // limit scope.
537
- await blockProviderAccount(providerName, row.id, until, accountBlocked ? '' : model, source, {
538
- quota: evidence === true,
539
- reset: reset === true,
540
- limit: accountBlocked ? '' : quotaLimitOf(error),
541
- });
601
+ if (evidence) ledger.evidenced.add(row.id);
602
+ else ledger.cooled.add(row.id);
603
+ await blockRefusedAccount(providerName, row.id, model, error, verdict);
542
604
  // An account block is unsafe to re-issue on THAT account only; with no
543
605
  // output emitted, the next account may serve the same request.
544
- if (
545
- bound.emitted() ||
546
- (error.unsafeToRetry && accountBlocked !== true) ||
547
- error.liveTextEmitted ||
548
- error.emittedToolCall
549
- )
550
- throw error;
606
+ if (attemptUnretryable(bound, error, () => error.unsafeToRetry && accountBlocked !== true)) throw error;
551
607
  // Manual policy: the eligible set is the selected account alone.
552
608
  if (policy === 'manual') {
553
- await waitOrThrow(error, [row.id]);
609
+ await waitOutCooldownOrThrow(request, ledger, error, [row.id]);
554
610
  lastError = error;
555
611
  continue;
556
612
  }
557
613
  lastError = error;
558
614
  switched = true;
559
615
  refusalScoped = accountExhaustedForModelOnly(providerName, row.id, model);
560
- let reason = 'Rate limited (cooldown)';
561
- if (evidence) reason = 'Quota exhausted';
562
- else if (accountBlocked) reason = 'Account blocked';
616
+ const reason = rotationReason(evidence, accountBlocked);
563
617
  options.onStageChange?.('reconnecting', { message: `${reason} — switching to the next account` });
564
618
  }
565
619
  }
566
- throw markExhausted(lastError || new Error('Provider account attempts exhausted.'));
620
+ throw exhaustedSendError(
621
+ providerName,
622
+ model,
623
+ ledger.evidenced,
624
+ lastError || new Error('Provider account attempts exhausted.')
625
+ );
567
626
  };
568
627
  }
569
628
 
@@ -264,7 +264,9 @@ export class ProviderAdmissionScheduler {
264
264
  running.parentAbort = () => {
265
265
  try {
266
266
  controller.abort(item.signal.reason);
267
- } catch {}
267
+ } catch {
268
+ // the controller may already be aborted
269
+ }
268
270
  };
269
271
  item.signal.addEventListener('abort', running.parentAbort, { once: true });
270
272
  }
@@ -301,7 +303,9 @@ export class ProviderAdmissionScheduler {
301
303
  if (running.parentAbort && running.parentSignal) {
302
304
  try {
303
305
  running.parentSignal.removeEventListener('abort', running.parentAbort);
304
- } catch {}
306
+ } catch {
307
+ // the abort listener may already be gone
308
+ }
305
309
  }
306
310
  this.running.delete(running);
307
311
  lane.active -= 1;
@@ -312,6 +316,32 @@ export class ProviderAdmissionScheduler {
312
316
  if (this._canDeleteLane(lane)) this._deleteLane(key, lane);
313
317
  }
314
318
 
319
+ /**
320
+ * Why a request that must not wait (a cache warm) cannot start on lane
321
+ * `key` now, or null: the lane's rate-limit cooldown, or a lane throttled
322
+ * after a 429 that would queue it.
323
+ */
324
+ immediateBlock(key) {
325
+ if (this.closedReason) return 'provider scheduler closed';
326
+ const lane = this.lanes.get(String(key || ''));
327
+ if (!lane) return null;
328
+ if (lane.adaptive && lane.cooldownUntil > this.now()) return 'rate-limit cooldown';
329
+ if (lane.queue.length > 0 || lane.active >= lane.limit) return 'account throttled';
330
+ return null;
331
+ }
332
+
333
+ /** Record a rate limit a request outside `run` (a cache warm) received on
334
+ * lane `key`, into the same cooldown state (and broadcast) as a send's. */
335
+ recordRateLimit(key, error) {
336
+ const laneKey = String(key || '');
337
+ if (!laneKey || this.closedReason) return false;
338
+ const lane = this.lanes.get(laneKey) || createAdmissionLane(laneKey, this.concurrency);
339
+ this.lanes.set(laneKey, lane);
340
+ const recorded = this._recordFailure(laneKey, lane, error);
341
+ if (this._canDeleteLane(lane)) this._deleteLane(laneKey, lane);
342
+ return recorded;
343
+ }
344
+
315
345
  snapshot() {
316
346
  const now = this.now();
317
347
  return {
@@ -428,7 +458,9 @@ export class ProviderAdmissionScheduler {
428
458
  if (item.onAbort && item.signal) {
429
459
  try {
430
460
  item.signal.removeEventListener('abort', item.onAbort);
431
- } catch {}
461
+ } catch {
462
+ // the abort listener may already be gone
463
+ }
432
464
  item.onAbort = null;
433
465
  }
434
466
  }
@@ -453,7 +485,9 @@ export class ProviderAdmissionScheduler {
453
485
  for (const running of this.running) {
454
486
  try {
455
487
  running.controller.abort(this.closedReason);
456
- } catch {}
488
+ } catch {
489
+ // the controller may already be aborted
490
+ }
457
491
  }
458
492
  }
459
493
  }
@@ -476,7 +510,7 @@ function digest(value) {
476
510
  .digest('hex');
477
511
  }
478
512
 
479
- function providerAdmissionKey(providerName, provider) {
513
+ export function providerAdmissionKey(providerName, provider) {
480
514
  const name = String(providerName || provider?.name || 'provider');
481
515
  const stableAnthropicOAuthPath =
482
516
  name.toLowerCase() === 'anthropic-oauth'
@@ -556,7 +590,9 @@ export function wrapProviderAdmission(provider, providerName, scheduler = provid
556
590
  // time. Provider-local retry remains the sole retry owner.
557
591
  try {
558
592
  opts.onStageChange?.('requesting');
559
- } catch {}
593
+ } catch {
594
+ // the stage observer is advisory
595
+ }
560
596
  const admittedOpts = {
561
597
  ...opts,
562
598
  signal: admissionSignal,
@@ -52,7 +52,7 @@ export function createAnthropicApiRecovery({
52
52
  : PROVIDER_NONSTREAM_TOTAL_TIMEOUT_MS;
53
53
  const lifetime = createTimeoutSignal(totalSignal, timeoutMs, `${label} Anthropic non-streaming fallback`);
54
54
  try {
55
- const message = await transport.requestNonStreamingMessage(nonStreamingParams, lifetime.signal);
55
+ const message = await transport.requestNonStreamingMessage(nonStreamingParams, lifetime.signal, timeoutMs);
56
56
  return buildTurnResult(normalizeAnthropicNonStreamingResponse(message, useModel));
57
57
  } catch (error) {
58
58
  if (error instanceof AnthropicFallbackTriggeredError || totalSignal?.aborted) throw error;
@@ -10,7 +10,11 @@
10
10
  * anthropic-turn-result.mjs); nothing here touches the socket.
11
11
  */
12
12
  import { prepareAnthropicImages } from './lib/anthropic-image-input.mjs';
13
- import { anthropicPrefixFingerprint, recordAnthropicPrefix } from './lib/anthropic-prefix-trace.mjs';
13
+ import {
14
+ anthropicPrefixFingerprint,
15
+ anthropicPrefixSessionId,
16
+ recordAnthropicPrefix,
17
+ } from './lib/anthropic-prefix-trace.mjs';
14
18
  import { buildAnthropicBetaHeaders, supportsAnthropicFastMode } from './anthropic-betas.mjs';
15
19
  import { applyAnthropicServerFallback } from './anthropic-server-fallback.mjs';
16
20
  import { fastModeAvailable } from './anthropic-fast-mode.mjs';
@@ -93,7 +97,7 @@ export async function buildAnthropicApiRequest({
93
97
  // Tools are resolved BEFORE the messages: the lowering needs the final
94
98
  // tool list to drop tool_reference blocks whose tool no longer ships
95
99
  // in this request (otherwise the API rejects the whole turn).
96
- const requestTools = requestAnthropicTools(tools, chatMsgs, opts, name);
100
+ const requestTools = requestAnthropicTools(tools, chatMsgs, opts, name, config);
97
101
  // Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is
98
102
  // shared with anthropic-oauth — see resolveAnthropicMessageCacheSlots.
99
103
  const messageCacheSlots = resolveAnthropicMessageCacheSlots(systemBlocks, ttls, { tools: requestTools });
@@ -183,7 +187,7 @@ export async function buildAnthropicApiRequest({
183
187
  // (once) → mark → prepare image bytes → send.
184
188
  params.stream = true;
185
189
  // Diagnostic: per-block prefix hashes of exactly what is sent.
186
- recordAnthropicPrefix(opts.sessionId || opts.session?.id || null, anthropicPrefixFingerprint(params));
190
+ recordAnthropicPrefix(anthropicPrefixSessionId(opts), anthropicPrefixFingerprint(params));
187
191
 
188
192
  const requestHeaders = requestHeadersFor(params, {
189
193
  config,
@@ -215,12 +215,18 @@ export function createAnthropicApiTransport({
215
215
  }
216
216
  };
217
217
 
218
- const requestNonStreamingMessage = (nonStreamingParams, signal) =>
218
+ // `timeoutMs` is the replay's own lifetime, handed to the SDK as the request
219
+ // timeout: without an explicit one the SDK refuses any stream:false body
220
+ // whose max_tokens it estimates past 10 minutes before sending it.
221
+ const requestNonStreamingMessage = (nonStreamingParams, signal, timeoutMs) =>
219
222
  withRetry(
220
223
  withBodyRecovery(nonStreamingParams, async ({ signal: attemptSignal }) => {
221
224
  noteRequestServiceTier(nonStreamingParams.speed);
222
225
  try {
223
- return await client.messages.create(nonStreamingParams, requestOptions(attemptSignal));
226
+ return await client.messages.create(nonStreamingParams, {
227
+ ...requestOptions(attemptSignal),
228
+ timeout: timeoutMs,
229
+ });
224
230
  } catch (err) {
225
231
  throw annotateHttpFailure(err);
226
232
  }