mixdog 1.2.3 → 1.2.4

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 (465) hide show
  1. package/package.json +1 -1
  2. package/scripts/gate-local.mjs +6 -4
  3. package/scripts/lib/gate-scheduler.mjs +29 -11
  4. package/scripts/probe-provider-catalog.mjs +31 -0
  5. package/scripts/provider-pingpong-live.mjs +128 -38
  6. package/scripts/session-sweep.mjs +5 -25
  7. package/src/agents/maintainer/AGENT.md +1 -1
  8. package/src/agents/maintainer/agent.json +1 -1
  9. package/src/agents/reviewer/AGENT.md +2 -4
  10. package/src/agents/security/AGENT.md +1 -2
  11. package/src/agents/writer/AGENT.md +2 -3
  12. package/src/defaults/shipped-history.json +6 -1
  13. package/src/defaults/skills/image/SKILL.md +21 -23
  14. package/src/lib/keychain-cjs.cjs +13 -11
  15. package/src/rules/agent/AGENT.md +7 -5
  16. package/src/rules/lead/LEAD.md +7 -9
  17. package/src/rules/shared/45-destructive.md +4 -0
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  20. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  21. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  22. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  24. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  25. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  29. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  30. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  31. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  32. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  33. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  34. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  35. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  36. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  37. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  38. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  40. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  41. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  46. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  47. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  48. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  49. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  50. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  51. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  52. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  53. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  54. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  55. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  56. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  57. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  58. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  59. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  60. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  61. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  62. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  63. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  64. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  65. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  66. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  67. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  68. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  78. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  79. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  80. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  82. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  84. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  86. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  87. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  88. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  89. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  90. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  91. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  92. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  93. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  94. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  95. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  96. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  97. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  99. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  100. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  101. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  102. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  103. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  106. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  107. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  108. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  109. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  110. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  111. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  112. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  113. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  114. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  115. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  116. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  117. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  118. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  119. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  120. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  121. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  122. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  123. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  124. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  125. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  126. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  128. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  129. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  130. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  131. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  132. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  133. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  134. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  135. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  137. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  138. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  139. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  146. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  148. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  150. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  157. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  158. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  159. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  160. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  161. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  162. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  163. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  164. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  165. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  167. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  169. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  170. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  171. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  172. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  177. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  179. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
  180. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  181. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  182. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  184. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  185. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  186. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  187. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  188. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  189. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  190. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  191. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  192. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  195. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  196. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  198. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  200. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  206. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  208. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  209. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  210. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  211. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  212. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  216. package/src/runtime/attachments/store.d.mts +9 -0
  217. package/src/runtime/attachments/store.mjs +80 -9
  218. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  219. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  220. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  221. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  222. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  223. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  224. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  225. package/src/runtime/github/tool.mjs +118 -17
  226. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  227. package/src/runtime/media/catalog.mjs +4 -4
  228. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  229. package/src/runtime/media/defaults.mjs +37 -0
  230. package/src/runtime/media/jobs.mjs +12 -2
  231. package/src/runtime/media/lanes.mjs +12 -0
  232. package/src/runtime/media/tool-defs.mjs +15 -4
  233. package/src/runtime/media/tool.mjs +41 -12
  234. package/src/runtime/media/upstream-error.mjs +72 -6
  235. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  236. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  237. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  238. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  239. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  240. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  242. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  243. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  244. package/src/runtime/office/index.mjs +2 -3
  245. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  246. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  247. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  248. package/src/runtime/shared/atomic-file.d.mts +1 -1
  249. package/src/runtime/shared/background-tasks.mjs +6 -1
  250. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  251. package/src/runtime/shared/browser-launch.mjs +15 -0
  252. package/src/runtime/shared/err-text.mjs +42 -4
  253. package/src/runtime/shared/file-lock.mjs +6 -5
  254. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  255. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  256. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  257. package/src/runtime/shared/model-route-chain.mjs +48 -0
  258. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  259. package/src/runtime/shared/pid-liveness.mjs +12 -0
  260. package/src/runtime/shared/provider-api-key.mjs +6 -0
  261. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  262. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  263. package/src/runtime/shared/quiet-progress.mjs +101 -0
  264. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  265. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  266. package/src/runtime/shared/remote-intent.mjs +2 -42
  267. package/src/runtime/shared/slow-span.mjs +8 -1
  268. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  269. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  270. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  271. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  272. package/src/runtime/shared/tool-status.mjs +3 -2
  273. package/src/runtime/shared/tool-surface.mjs +2 -3
  274. package/src/runtime/shared/tool-work-units.mjs +22 -15
  275. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  276. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  277. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  278. package/src/runtime/shared/transcript-writer.mjs +14 -4
  279. package/src/runtime/shared/turn-changes.mjs +2 -1
  280. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  281. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  282. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  283. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  284. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  285. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  286. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  287. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  288. package/src/runtime/shared/worktrees/include.mjs +125 -7
  289. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  290. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  291. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  292. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  293. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  294. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  295. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  296. package/src/runtime/terminal-bridge/client.mjs +14 -10
  297. package/src/session-runtime/boot/apis.mjs +7 -1
  298. package/src/session-runtime/boot/config.mjs +2 -0
  299. package/src/session-runtime/boot/facade.mjs +3 -0
  300. package/src/session-runtime/boot/session.mjs +3 -2
  301. package/src/session-runtime/boot/tools.mjs +3 -0
  302. package/src/session-runtime/conversation-import/service.mjs +1 -1
  303. package/src/session-runtime/goal-facade-api.mjs +2 -2
  304. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  305. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  306. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  307. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  308. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  309. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  310. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  311. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  312. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  313. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  314. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  315. package/src/session-runtime/media-api.mjs +8 -0
  316. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  317. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  318. package/src/session-runtime/model-route/set-route.mjs +114 -34
  319. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  320. package/src/session-runtime/model-route-api.mjs +4 -2
  321. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  322. package/src/session-runtime/native-web-search.mjs +9 -8
  323. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  324. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  325. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  326. package/src/session-runtime/provider-models.mjs +1 -0
  327. package/src/session-runtime/provider-usage.mjs +4 -0
  328. package/src/session-runtime/route-resolution.mjs +3 -1
  329. package/src/session-runtime/runtime-core.mjs +4 -0
  330. package/src/session-runtime/runtime-facade.mjs +6 -0
  331. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  332. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  333. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  334. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  335. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  336. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  337. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  338. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  339. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  340. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  341. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  343. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  344. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  345. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  346. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  347. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  348. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  349. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  350. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  351. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  352. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  353. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  354. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  355. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  356. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  357. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  358. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  359. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  360. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  361. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  362. package/src/session-runtime/services/agent-tool.mjs +4 -0
  363. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  364. package/src/session-runtime/services/provider-admin.mjs +77 -0
  365. package/src/session-runtime/session-create/session-options.mjs +7 -5
  366. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  367. package/src/session-runtime/session-transcript.mjs +4 -5
  368. package/src/session-runtime/session-turn-api.mjs +3 -9
  369. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  370. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  371. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  372. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  373. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  374. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  375. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  376. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  377. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  378. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  379. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  380. package/src/session-runtime/turn/turn-run.mjs +1 -36
  381. package/src/session-runtime/usage-stats-api.mjs +4 -1
  382. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  383. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  384. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  385. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  386. package/src/session-runtime/workspace/transitions.mjs +248 -68
  387. package/src/standalone/channel-transport.mjs +3 -4
  388. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  389. package/src/standalone/daemon-pg-stop.mjs +1 -3
  390. package/src/standalone/daemon-session-control.mjs +88 -0
  391. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  392. package/src/standalone/daemon.mjs +2 -0
  393. package/src/standalone/local-session-runtime.mjs +11 -12
  394. package/src/standalone/session-protocol.mjs +7 -0
  395. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  396. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  397. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  398. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  399. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  400. package/src/standalone/session-service/agent-tree.mjs +28 -2
  401. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  402. package/src/standalone/session-service/entries.mjs +1 -0
  403. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  404. package/src/standalone/session-service/quota-resume.mjs +28 -13
  405. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  406. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  407. package/src/standalone/session-tool-output.mjs +82 -0
  408. package/src/tui/app/app-view.jsx +2 -1
  409. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  410. package/src/tui/app/provider-setup-picker.mjs +15 -3
  411. package/src/tui/app/slash-commands.mjs +6 -0
  412. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  413. package/src/tui/components/Spinner.jsx +4 -0
  414. package/src/tui/components/SpinnerByline.jsx +21 -2
  415. package/src/tui/components/status-line/local-line.mjs +10 -2
  416. package/src/tui/dist/index.mjs +478 -251
  417. package/src/tui/session/active-tool-summary.mjs +1 -1
  418. package/src/tui/session/context-state.mjs +0 -3
  419. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  420. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  421. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  422. package/src/tui/session/quota-resume.mjs +140 -61
  423. package/src/tui/session/session-api/commands.mjs +4 -10
  424. package/src/tui/session/session-api/controls.mjs +12 -0
  425. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  426. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  427. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  428. package/src/tui/session/session-api/media.mjs +2 -0
  429. package/src/tui/session/session-api/routes.mjs +81 -57
  430. package/src/tui/session/session-api/settings.mjs +3 -3
  431. package/src/tui/session/session-api/worktree.mjs +3 -2
  432. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  433. package/src/tui/session/session-flow/drain.mjs +6 -4
  434. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  435. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  436. package/src/tui/session/session-flow/queue.mjs +1 -1
  437. package/src/tui/session/tool-approval.mjs +17 -8
  438. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  439. package/src/tui/session/tui-steering-persist.mjs +3 -5
  440. package/src/tui/session/turn-quiet.mjs +53 -0
  441. package/src/tui/session/turn-stream.mjs +5 -1
  442. package/src/tui/session/turn.mjs +38 -31
  443. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  444. package/src/tui/spinner-meta.mjs +10 -0
  445. package/src/tui/spinner-verbs.mjs +3 -0
  446. package/src/ui/statusline.mjs +13 -3
  447. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  448. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  449. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  450. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  451. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  452. package/src/session-runtime/turn/share-ops.mjs +0 -77
  453. package/src/tui/session/cross-surface-share.mjs +0 -406
  454. package/src/tui/session/live-share/delta.mjs +0 -153
  455. package/src/tui/session/live-share/mirror.mjs +0 -106
  456. package/src/tui/session/live-share/owner.mjs +0 -254
  457. package/src/tui/session/live-share/retry.mjs +0 -54
  458. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  459. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  460. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  461. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  462. package/src/tui/session/live-share/viewer.mjs +0 -99
  463. package/src/tui/session/live-share/wire.mjs +0 -44
  464. package/src/tui/session/live-share.mjs +0 -154
  465. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -23,7 +23,14 @@ import { reloadProviderApiKey, resolveProviderApiKey } from '../../../shared/pro
23
23
  const PROVIDER = 'opencode-go';
24
24
 
25
25
  /** The generateContent request body for a built Gemini request. */
26
- export function openCodeGoGeminiBody({ contents, systemInstruction, geminiTools, toolConfig, generationConfig, safetySettings }) {
26
+ export function openCodeGoGeminiBody({
27
+ contents,
28
+ systemInstruction,
29
+ geminiTools,
30
+ toolConfig,
31
+ generationConfig,
32
+ safetySettings,
33
+ }) {
27
34
  return {
28
35
  contents,
29
36
  ...(systemInstruction ? { systemInstruction: { parts: [{ text: systemInstruction }] } } : {}),
@@ -84,7 +91,11 @@ export class OpenCodeGoGeminiEngine extends GeminiProvider {
84
91
  }
85
92
 
86
93
  async _openGatewayStream(url, body, opts, attemptSignal) {
87
- const openFirstByte = createTimeoutSignal(attemptSignal, GEMINI_FIRST_BYTE_TIMEOUT_MS, 'OpenCode Go Gemini first byte');
94
+ const openFirstByte = createTimeoutSignal(
95
+ attemptSignal,
96
+ GEMINI_FIRST_BYTE_TIMEOUT_MS,
97
+ 'OpenCode Go Gemini first byte'
98
+ );
88
99
  let res;
89
100
  try {
90
101
  res = await this._fetch(url, {
@@ -162,7 +162,10 @@ export class OpenCodeGoProvider {
162
162
  this.gemini = new OpenCodeGoGeminiEngine({
163
163
  ...this.config,
164
164
  baseURL: this.openai.baseURL,
165
- extraHeaders: { ...(OPENAI_COMPAT_PRESETS['opencode-go'].extraHeaders || {}), ...(this.config.extraHeaders || {}) },
165
+ extraHeaders: {
166
+ ...(OPENAI_COMPAT_PRESETS['opencode-go'].extraHeaders || {}),
167
+ ...(this.config.extraHeaders || {}),
168
+ },
166
169
  });
167
170
  }
168
171
  return this.gemini;
@@ -69,7 +69,6 @@ export class OpenRouterProvider extends WireGatewayProvider {
69
69
  );
70
70
  // The roster's output ceiling is `top_provider.max_completion_tokens`.
71
71
  const fetchItems = this.openai._fetchModelItems.bind(this.openai);
72
- this.openai._fetchModelItems = async (options) =>
73
- (await fetchItems(options)).map(withTopProviderOutputCeiling);
72
+ this.openai._fetchModelItems = async (options) => (await fetchItems(options)).map(withTopProviderOutputCeiling);
74
73
  }
75
74
  }
@@ -517,7 +517,10 @@ const IN_FLIGHT_BUDGET_MAX_WAIT_MS = 60_000;
517
517
  function inFlightAdviceMs(err) {
518
518
  const advised = retryAfterMsFromError(err);
519
519
  if (advised != null) return advised;
520
- for (const [name, unitMs] of [['retry-after-ms', 1], ['retry-after', 1000]]) {
520
+ for (const [name, unitMs] of [
521
+ ['retry-after-ms', 1],
522
+ ['retry-after', 1000],
523
+ ]) {
521
524
  const value = errorHeaderValue(err, name);
522
525
  const n = Number(value);
523
526
  if (value != null && String(value).trim() !== '' && Number.isFinite(n) && n >= 0) return n * unitMs;
@@ -650,7 +653,6 @@ export function providerErrorKind(err, options = {}) {
650
653
  // Validated account-pool evidence and boundary-stamped re-auth decide first.
651
654
  if (err.quotaExhausted && typeof err.quotaExhausted === 'object') return describe('quota_exhausted');
652
655
  if (chain.some((item) => item?.reauthRequired === true)) return describe('auth');
653
-
654
656
  if (isInFlightBudget402(chain, status, inFlightAdviceMs(err))) return describe('transient', IN_FLIGHT_BUDGET);
655
657
  // Every other 402 is a billing refusal, whatever generic retryable code
656
658
  // (server_error, rate_limit_exceeded) its body also carries.
@@ -661,8 +663,7 @@ export function providerErrorKind(err, options = {}) {
661
663
  // generic rate-limit code or status; they never turn an overload (or a more
662
664
  // specific refusal) into quota.
663
665
  const quotaFlagged =
664
- options.quotaFlags !== false &&
665
- chain.some((item) => item?.providerQuota === true || item?.quotaExceeded === true);
666
+ options.quotaFlags !== false && chain.some((item) => item?.providerQuota === true || item?.quotaExceeded === true);
666
667
  if (quotaFlagged && (!kind || kind === 'rate_limited')) kind = 'quota_exhausted';
667
668
  // Wordings, for untyped errors only (a typed code always decides).
668
669
  const text = options.text !== false && (!kind || kind === 'invalid_request') ? messageOf(err, chain) : '';
@@ -24,7 +24,7 @@ const signatures = new Map();
24
24
  // preservation guard and the getProvider self-heal read it through these two
25
25
  // helpers so "usable right now" and "genuinely gone" are answered identically
26
26
  // in both places.
27
- const OAUTH_PROVIDER_NAMES = new Set([
27
+ export const OAUTH_PROVIDER_NAMES = new Set([
28
28
  'anthropic-oauth',
29
29
  'openai-oauth',
30
30
  'grok-oauth',
@@ -498,6 +498,14 @@ export function providerInputExcludesCache(name) {
498
498
  export function providerNativePdf(name) {
499
499
  return providerTakesNativePdf(providers.get(String(name || '').toLowerCase()));
500
500
  }
501
+ /**
502
+ * Whether the named provider's adapter declares `consumesReadWindows`: it
503
+ * needs the structured clip report of read results. A pure lookup; a proxy
504
+ * stand-in carries the PC adapter's declared trait.
505
+ */
506
+ export function providerConsumesReadWindows(name) {
507
+ return providers.get(String(name || '').toLowerCase())?.consumesReadWindows === true;
508
+ }
501
509
  export function getAllProviders() {
502
510
  // Defensive copy — callers must not mutate the live registry or retain
503
511
  // stale entries across re-init (initProviders rebuilds the map in place).
@@ -476,7 +476,8 @@ export function isContextOverflowError(err, _depth = 0) {
476
476
  const sizeTyped =
477
477
  typeof err === 'object' &&
478
478
  boundedCauseChain(err).some(
479
- (item) => item && typeof item === 'object' && providerErrorKind(item, { text: false }).kind === REQUEST_TOO_LARGE_KIND
479
+ (item) =>
480
+ item && typeof item === 'object' && providerErrorKind(item, { text: false }).kind === REQUEST_TOO_LARGE_KIND
480
481
  );
481
482
  const patterns = sizeTyped ? TOKEN_CONTEXT_OVERFLOW_PATTERNS : CONTEXT_OVERFLOW_PATTERNS;
482
483
  const msg = (typeof err === 'string' ? err : err?.message) || '';
@@ -15,7 +15,9 @@ import { resolveWireRoute, sendOnRoute } from './wire-route.mjs';
15
15
  function hasFileIdImage(value, depth = 0) {
16
16
  if (!value || typeof value !== 'object' || depth > 6) return false;
17
17
  if (Array.isArray(value)) return value.some((entry) => hasFileIdImage(entry, depth + 1));
18
- const fileId = value.type === 'input_image' ? value.file_id : value.type === 'image' && value.source?.type === 'file' ? value.source.file_id : null;
18
+ let fileId = null;
19
+ if (value.type === 'input_image') fileId = value.file_id;
20
+ else if (value.type === 'image' && value.source?.type === 'file') fileId = value.source.file_id;
19
21
  if (typeof fileId === 'string' && fileId) return true;
20
22
  return hasFileIdImage(value.content, depth + 1);
21
23
  }
@@ -32,9 +34,12 @@ function hasFileIdImage(value, depth = 0) {
32
34
  */
33
35
  export function gatewayMessagesOpts(config, model, messages, opts) {
34
36
  const out = { ...(opts || {}) };
35
- const ceiling = Math.floor(Number(typeof config?.modelMaxOutputTokens === 'function' ? config.modelMaxOutputTokens(model) : 0));
37
+ const ceiling = Math.floor(
38
+ Number(typeof config?.modelMaxOutputTokens === 'function' ? config.modelMaxOutputTokens(model) : 0)
39
+ );
36
40
  if (ceiling > 0 && out.modelMaxOutputTokens === undefined) out.modelMaxOutputTokens = ceiling;
37
- if (typeof config?.messagesEffortProjection === 'function') out.messagesEffortProjection = config.messagesEffortProjection;
41
+ if (typeof config?.messagesEffortProjection === 'function')
42
+ out.messagesEffortProjection = config.messagesEffortProjection;
38
43
  if (config?.fileIdImageBeta && hasFileIdImage(messages)) {
39
44
  out.requestHeaders = { 'anthropic-beta': config.fileIdImageBeta, ...(out.requestHeaders || {}) };
40
45
  }
@@ -115,7 +120,9 @@ export class WireGatewayProvider {
115
120
 
116
121
  // The model's output ceiling: the gateway roster, else the shared catalog.
117
122
  _modelMaxOutputTokens(model) {
118
- const declared = Number(this.getCachedModelInfo(model)?.outputTokens ?? getModelMetadataSync(model, this.name)?.outputTokens);
123
+ const declared = Number(
124
+ this.getCachedModelInfo(model)?.outputTokens ?? getModelMetadataSync(model, this.name)?.outputTokens
125
+ );
119
126
  return Number.isFinite(declared) && declared > 0 ? declared : null;
120
127
  }
121
128
 
@@ -157,7 +157,7 @@ const NATIVE_DEFERRED_FAMILY = Object.freeze({ messages: 'anthropic', responses:
157
157
  * verified support, or a wire with no native contract (Chat, Gemini).
158
158
  */
159
159
  export function nativeDeferredFamilyForRoute(provider, route) {
160
- if (!route || route.nativeDeferredTools !== true) return '';
160
+ if (route?.nativeDeferredTools !== true) return '';
161
161
  const name = String(provider || '')
162
162
  .trim()
163
163
  .toLowerCase();
@@ -220,7 +220,11 @@ export function resolveWireRoute(
220
220
  if (known === false) return unknown();
221
221
  // The wire a pre-table session started on, while the model still offers
222
222
  // it; otherwise the fresh resolution below (never an unadvertised wire).
223
- const legacyWire = profile.legacy({ model: id, catalogWire: usable(catalogWire) ? catalogWire : null, endpoints: advertised });
223
+ const legacyWire = profile.legacy({
224
+ model: id,
225
+ catalogWire: usable(catalogWire) ? catalogWire : null,
226
+ endpoints: advertised,
227
+ });
224
228
  if (usable(legacyWire)) return route(legacyWire, 'legacy');
225
229
  }
226
230
  if (override && usable(override)) return route(override, 'override');
@@ -255,7 +259,8 @@ export async function sendWireRoute(provider, model, tools, sendOpts, messages =
255
259
  // 403), quota / billing (402, 429) and server errors never qualify.
256
260
  const ENDPOINT_STATUSES = new Set([405, 501]);
257
261
  const REJECTION_STATUSES = new Set([400, 404, 415, 422]);
258
- const ENDPOINT_WORDS = /\b(?:endpoints?|routes?)\b|\/(?:v1\/)?(?:messages|responses|chat\/completions)\b|chat completions/i;
262
+ const ENDPOINT_WORDS =
263
+ /\b(?:endpoints?|routes?)\b|\/(?:v1\/)?(?:messages|responses|chat\/completions)\b|chat completions/i;
259
264
  const UNSUPPORTED_WORDS =
260
265
  /\bunsupported\b|not (?:be )?(?:supported|available|served|implemented)|(?:does not|doesn't|do not|don't) (?:support|serve)|only (?:available|supported|served)|wrong endpoint|use (?:the )?\/?(?:v1\/)?(?:messages|responses|chat\/completions)\b/i;
261
266
  // A typed code / type that names an auth, quota, billing or parameter failure
@@ -507,6 +512,11 @@ export async function pinSessionWireRoute(session, provider) {
507
512
  // The route changed while resolving: the newer route pins on its own turn.
508
513
  if (session.provider !== providerName || session.model !== model) return null;
509
514
  const nativeDeferred = !answered && wireSupportsNativeDeferredTools(providerName, route.wire);
510
- session.wireRoute = { provider: providerName, model, ...route, ...(nativeDeferred ? { nativeDeferredTools: true } : {}) };
515
+ session.wireRoute = {
516
+ provider: providerName,
517
+ model,
518
+ ...route,
519
+ ...(nativeDeferred ? { nativeDeferredTools: true } : {}),
520
+ };
511
521
  return session.wireRoute;
512
522
  }
@@ -106,8 +106,16 @@ export function serverSearchEvents(model = 'grok-4') {
106
106
  }
107
107
 
108
108
  export const SESSION_TOOLS = [
109
- { name: 'Read', description: 'Read a file', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
110
- { name: 'load_tool', description: 'Load tools', inputSchema: { type: 'object', properties: { names: { type: 'array' } } } },
109
+ {
110
+ name: 'Read',
111
+ description: 'Read a file',
112
+ inputSchema: { type: 'object', properties: { path: { type: 'string' } } },
113
+ },
114
+ {
115
+ name: 'load_tool',
116
+ description: 'Load tools',
117
+ inputSchema: { type: 'object', properties: { names: { type: 'array' } } },
118
+ },
111
119
  ];
112
120
  export const DEFERRED_TOOLS = [
113
121
  ...SESSION_TOOLS,
@@ -168,7 +176,11 @@ export async function captureBodies(history, tools, { config = {}, opts = {} } =
168
176
  await sendXaiResponses(http.provider, history, 'grok-4', tools, { sessionId: 'sess-1', ...opts });
169
177
  const before = ws.bodies.length;
170
178
  const socket = xaiProvider(config);
171
- await sendXaiResponsesWebSocket(socket.provider, history, 'grok-4', tools, { sessionId: 'sess-1', iteration: 1, ...opts });
179
+ await sendXaiResponsesWebSocket(socket.provider, history, 'grok-4', tools, {
180
+ sessionId: 'sess-1',
181
+ iteration: 1,
182
+ ...opts,
183
+ });
172
184
  return { http: http.requests[0], ws: ws.bodies[before] };
173
185
  }
174
186
 
@@ -6,7 +6,8 @@ export const ASK_USER_TOOL_DEFS = Object.freeze([
6
6
  {
7
7
  name: 'ask_user',
8
8
  title: 'Ask User',
9
- trigger: 'Ask the user 1–4 multiple-choice questions and wait; when a plan needs the user to pick between clear options, instead of listing them in chat.',
9
+ trigger:
10
+ 'Ask the user 1–4 multiple-choice questions and wait; when a plan needs the user to pick between clear options, instead of listing them in chat.',
10
11
  description:
11
12
  'Ask the user multiple-choice questions and wait. Only while planning, for a decision only the user can make with clear options; open questions, minor choices and plan approval go in chat. Do not repeat the options in your message.',
12
13
  annotations: {
@@ -92,7 +93,10 @@ export function validateAskUserQuestions(args) {
92
93
  if (labels.has(option.label)) throw new Error(`${at} has duplicate option label "${option.label}"`);
93
94
  labels.add(option.label);
94
95
  }
95
- if (q.recommended != null && (!Number.isInteger(q.recommended) || q.recommended < 0 || q.recommended >= q.options.length)) {
96
+ if (
97
+ q.recommended != null &&
98
+ (!Number.isInteger(q.recommended) || q.recommended < 0 || q.recommended >= q.options.length)
99
+ ) {
96
100
  throw new Error(`${at} recommended must be an index below ${q.options.length}`);
97
101
  }
98
102
  });
@@ -189,18 +189,20 @@ const AUTO_CLEAR_DEFAULT_IDLE_MS = 60 * 60 * 1000;
189
189
  // rewrite the accumulated tail. Anthropic agent tails are 5m and compact once
190
190
  // expired; their terminal reap keeps this 1h window so a completed agent stays
191
191
  // reusable. Gemini, xAI and Mistral
192
- // caches run ~1h, Groq's implicit cache persists ~2h, OpenAI/DeepSeek
193
- // key-prefix/implicit caches persist far longer (~24h), and OpenAI OAuth
194
- // (Codex backend) guarantees a 30-minute minimum prompt-cache TTL on
195
- // GPT-5.6+ models (prompt_cache_options.ttl=30m, refreshed on use), so the
196
- // sweep matches that window to avoid clearing a still-warm cache.
192
+ // caches run ~1h, Groq's implicit cache persists ~2h, and DeepSeek's
193
+ // implicit cache is evicted after "a few hours to a few days" (kept at 24h).
194
+ // OpenAI (direct and OAuth/Codex) guarantees a 30-minute minimum prompt-cache
195
+ // TTL on GPT-5.6+ (refreshed on use; no 24h retention there), so the sweep
196
+ // matches that window. Older OpenAI models that still take
197
+ // prompt_cache_retention='24h' are not distinguished: these call sites only
198
+ // know the provider, not the model, so 30m applies to the whole provider.
197
199
  // Unknown/unrecognized providers fall back to the 'default' 1h entry.
198
200
  const AUTO_CLEAR_PROVIDER_IDLE_MS = Object.freeze({
199
201
  anthropic: 60 * 60 * 1000,
200
202
  'anthropic-oauth': 60 * 60 * 1000,
201
203
  gemini: 60 * 60 * 1000,
202
204
  groq: 2 * 60 * 60 * 1000,
203
- openai: 24 * 60 * 60 * 1000,
205
+ openai: 30 * 60 * 1000,
204
206
  deepseek: 24 * 60 * 60 * 1000,
205
207
  xai: 60 * 60 * 1000,
206
208
  'openai-oauth': 30 * 60 * 1000,
@@ -8,7 +8,10 @@ export function sessionAllowlistExcludes(session, name) {
8
8
 
9
9
  /** The session's denied tools name `name`. */
10
10
  export function sessionDisallows(session, name) {
11
- return Array.isArray(session?.disallowedTools) && session.disallowedTools.some((denied) => lowerName(denied) === lowerName(name));
11
+ return (
12
+ Array.isArray(session?.disallowedTools) &&
13
+ session.disallowedTools.some((denied) => lowerName(denied) === lowerName(name))
14
+ );
12
15
  }
13
16
 
14
17
  /**
@@ -86,7 +86,7 @@ export function createGoalStore(ctx) {
86
86
  }
87
87
  };
88
88
 
89
- const commit = async (sessionId, goal) => {
89
+ const commit = async (sessionId, goal, { isCurrent, accept } = {}) => {
90
90
  const id = assertSessionId(sessionId);
91
91
  const previous = goal ? readRecord(id).goal : null;
92
92
  let committedGoal = null;
@@ -101,7 +101,35 @@ export function createGoalStore(ctx) {
101
101
  ? previous.revision + Number(revisionStateKey(previous) !== revisionStateKey(committedGoal))
102
102
  : 1;
103
103
  }
104
- await storage.write(id, { version: GOAL_FILE_VERSION, goal: committedGoal });
104
+ const rollback = async () => {
105
+ try {
106
+ await storage.write(id, { version: GOAL_FILE_VERSION, goal: previous });
107
+ } catch (error) {
108
+ error.quotaResumeRollbackFailed = true;
109
+ throw error;
110
+ }
111
+ ctx.deadlines.armDeadline(id);
112
+ };
113
+ try {
114
+ await storage.write(id, { version: GOAL_FILE_VERSION, goal: committedGoal });
115
+ } catch (error) {
116
+ if (isCurrent || accept) await rollback();
117
+ throw error;
118
+ }
119
+ if (isCurrent || accept) {
120
+ let accepted = false;
121
+ let admissionError = null;
122
+ try {
123
+ accepted = (!isCurrent || isCurrent()) && (!accept || accept() === true);
124
+ } catch (error) {
125
+ admissionError = error;
126
+ }
127
+ if (!accepted) {
128
+ await rollback();
129
+ if (admissionError) throw admissionError;
130
+ return null;
131
+ }
132
+ }
105
133
  ctx.deadlines.armDeadline(id);
106
134
  emit(id);
107
135
  return publicGoal(committedGoal, now());
@@ -171,8 +171,9 @@ export function createGoalTurnLifecycle(ctx) {
171
171
  // A quota resume revives exactly the Goal its failure suspended, and only
172
172
  // while that Goal is still waiting on the limit: a Goal the user paused,
173
173
  // stopped, replaced or completed meanwhile stays as it is.
174
- reactivateUsageLimited(sessionId, goalId) {
174
+ reactivateUsageLimited(sessionId, goalId, options = {}) {
175
175
  return withMutation(sessionId, async (id) => {
176
+ if (options.isCurrent && !options.isCurrent()) return null;
176
177
  const goal = readRecord(id).goal;
177
178
  if (!goal || goal.archivedAt || goal.id !== clean(goalId) || goal.status !== 'usage_limited') return null;
178
179
  try {
@@ -180,7 +181,7 @@ export function createGoalTurnLifecycle(ctx) {
180
181
  } catch {
181
182
  return null;
182
183
  }
183
- return commit(id, goal);
184
+ return commit(id, goal, options);
184
185
  });
185
186
  },
186
187
  continuation(sessionId, { agentStatus = null } = {}) {
@@ -5,9 +5,10 @@ const BATCHING = {
5
5
  self-contained supporting work, one agent per role; batch related tasks
6
6
  rather than splitting them for parallelism.`,
7
7
  balanced: `Delegate independent work by coherent feature or module, one agent per
8
- scope. Batch related tasks within the same change scope rather than
9
- splitting every file or step.`,
10
- swarm: `Delegate every independent scope to its own agent. Treat disjoint file or
8
+ scope; a scope is one verifiable deliverable. Batch related tasks within the
9
+ same change scope rather than splitting every file or step.`,
10
+ swarm: `Delegate every independent scope to its own agent; a scope is one
11
+ verifiable deliverable, not a bundle of steps. Treat disjoint file or
11
12
  module sets as independent and merge scopes only on a true output
12
13
  dependency. Prefer parallel scopes over sequential slices in one agent.`,
13
14
  };
@@ -38,6 +39,10 @@ scopes does not change this.
38
39
 
39
40
  Dispatch all ready independent scopes in one turn. Only a scope that requires
40
41
  another's output waits. Brief each agent as the Lead rules describe.
42
+ A running agent receives only changes within its own scope; a new independent
43
+ need goes to a new agent. When scopes touch the same file, name one owner for
44
+ that file in each brief. Agents run only the checks covering their own change;
45
+ Lead runs the full suite once after integration.
41
46
  Use only available agents; when none fits a role, Lead does that work itself
42
47
  and never changes settings to enable one. If the reviewer is disabled or
43
48
  unavailable, Lead alone reviews the result against the approved scope and
@@ -59,7 +59,9 @@ export function loadSkillToolDependencies(envelope, session, mode) {
59
59
  `Required tools loaded: ${direct.join(', ')}. Their full definitions are available on your next request; use them directly without load_tool.`,
60
60
  ]
61
61
  : []),
62
- ...(direct.length && isToolBridgeEnabled(session) ? [`Required tools available directly: ${direct.join(', ')}.`] : []),
62
+ ...(direct.length && isToolBridgeEnabled(session)
63
+ ? [`Required tools available directly: ${direct.join(', ')}.`]
64
+ : []),
63
65
  ...(bridged.length
64
66
  ? [
65
67
  `Required tools available through call_tool: ${bridged.join(', ')}. Read a definition with load_tool, then run it with call_tool {name, arguments}.`,
@@ -0,0 +1,6 @@
1
+ export const BRIDGE_NAME_MAX_CHARS = 256;
2
+ const META_NAMES = new Set(['load_tool', 'call_tool', 'tool_search']);
3
+
4
+ export function isBridgeMetaTool(name) {
5
+ return typeof name === 'string' && META_NAMES.has(name.toLowerCase());
6
+ }
@@ -7,6 +7,7 @@
7
7
  // execution permission; continuation tokens only carry a position and grant
8
8
  // no authority.
9
9
  import { createHash } from 'node:crypto';
10
+ import { BRIDGE_NAME_MAX_CHARS, isBridgeMetaTool } from './tool-bridge-contract.mjs';
10
11
  import { clean } from './session-text.mjs';
11
12
  import { isDeferredToolAvailable } from './deferred-tool-availability.mjs';
12
13
  import {
@@ -26,16 +27,13 @@ export { isToolBridgeEnabled } from './tool-exposure.mjs';
26
27
 
27
28
  export const BRIDGE_LOAD_TOOL_NAME = 'load_tool';
28
29
  export const BRIDGE_CALL_TOOL_NAME = 'call_tool';
29
- // Names call_tool may never target and search never lists.
30
- const BRIDGE_META_TOOL_NAMES = new Set(['load_tool', 'call_tool', 'tool_search']);
31
-
32
30
  const DESCRIBE_MAX_NAMES = 8;
33
31
  // Most definitions one request resolves to: every name an alias of the widest
34
32
  // alias. A token naming more was not issued by this tool.
35
33
  const MAX_ALIAS_MEMBERS = Math.max(1, ...Object.values(DEFERRED_SELECT_ALIASES).map((members) => members.length));
36
34
 
37
35
  export const BRIDGE_LIMITS = Object.freeze({
38
- nameMaxChars: 256,
36
+ nameMaxChars: BRIDGE_NAME_MAX_CHARS,
39
37
  continuationMaxChars: 4096,
40
38
  continuationMaxTargets: DESCRIBE_MAX_NAMES * MAX_ALIAS_MEMBERS,
41
39
  describeMaxNames: DESCRIBE_MAX_NAMES,
@@ -300,7 +298,7 @@ function searchKeywords(session, keywords, mode, available) {
300
298
  const name = clean(tool?.name);
301
299
  return (
302
300
  !eagerNames.has(name) &&
303
- !BRIDGE_META_TOOL_NAMES.has(name.toLowerCase()) &&
301
+ !isBridgeMetaTool(name) &&
304
302
  toolSearchMatches(tool, keyword) &&
305
303
  !bridgeBlockReason(session, tool, mode, eagerNames)
306
304
  );
@@ -343,17 +341,19 @@ function largestChunk(text, offset, buildPage) {
343
341
  }
344
342
 
345
343
  export function describeBridgeTools(session, args = {}, { mode } = {}) {
344
+ const syntaxHint = ' Use load_tool {"names":["exact_tool_name"]}; the required key is names, not name.';
346
345
  const invalid = unknownKeysError(args, DESCRIBE_KEYS, BRIDGE_LOAD_TOOL_NAME);
347
346
  if (invalid) {
348
347
  const hint = isPlainObject(args) && 'query' in args ? ' Pass exact names; the deferred tool list names them.' : '';
349
- return bridgeError(invalid.error.code, `${invalid.error.message}${hint}`);
348
+ return bridgeError(invalid.error.code, `${invalid.error.message}${hint}${syntaxHint}`);
350
349
  }
351
350
  // A continuation token resumes an earlier request. It travels alone: names
352
351
  // is split exactly as for a lookup, and a token beside any other value is
353
352
  // refused rather than read as a missing name.
354
353
  const raw = args.names;
355
- const strings =
356
- typeof raw === 'string' ? [raw] : Array.isArray(raw) && raw.every((item) => typeof item === 'string') ? raw : [];
354
+ let strings = [];
355
+ if (typeof raw === 'string') strings = [raw];
356
+ else if (Array.isArray(raw) && raw.every((item) => typeof item === 'string')) strings = raw;
357
357
  let continuation = null;
358
358
  if (strings.some((item) => item.includes(BRIDGE_CONTINUATION_PREFIX))) {
359
359
  if (strings.length !== 1 || !CONTINUATION_TOKEN_PATTERN.test(strings[0])) {
@@ -375,7 +375,7 @@ export function describeBridgeTools(session, args = {}, { mode } = {}) {
375
375
  if (!names) {
376
376
  return bridgeError(
377
377
  'INVALID_ARGUMENTS',
378
- `names must be 1-${BRIDGE_LIMITS.describeMaxNames} exact tool names of at most ${BRIDGE_LIMITS.nameMaxChars} characters.`
378
+ `names must be 1-${BRIDGE_LIMITS.describeMaxNames} exact tool names of at most ${BRIDGE_LIMITS.nameMaxChars} characters.${syntaxHint}`
379
379
  );
380
380
  }
381
381
  ({ targets, missing, blocked } = resolveDescribeTargets(session, names, mode, available));
@@ -478,7 +478,7 @@ export function resolveBridgeTarget(session, rawName) {
478
478
  if (!name || name.length > BRIDGE_LIMITS.nameMaxChars) {
479
479
  return bridgeError('INVALID_ARGUMENTS', `name must be 1-${BRIDGE_LIMITS.nameMaxChars} characters.`);
480
480
  }
481
- if (BRIDGE_META_TOOL_NAMES.has(name.toLowerCase())) {
481
+ if (isBridgeMetaTool(name)) {
482
482
  return bridgeError('BRIDGE_RECURSION', `call_tool cannot run the bridge tool "${name}"; call it directly.`);
483
483
  }
484
484
  const eager = lookupByName(Array.isArray(session?.tools) ? session.tools : [], name);
@@ -800,7 +800,9 @@ function pendingAndFailedMcpServers(mcpStatus) {
800
800
  */
801
801
  function resolvableCatalog(session) {
802
802
  const union = deferredCatalogUnion(session);
803
- return filterSessionToolPolicy(union.length ? union : Array.isArray(session?.tools) ? session.tools : [], session);
803
+ let tools = union;
804
+ if (!union.length) tools = Array.isArray(session?.tools) ? session.tools : [];
805
+ return filterSessionToolPolicy(tools, session);
804
806
  }
805
807
 
806
808
  // Pure loader. Input is exact deferred-tool names/aliases; output reports
@@ -67,14 +67,14 @@ export const SESSION_TOOL = {
67
67
  annotations: {
68
68
  title: 'Session',
69
69
  readOnlyHint: false,
70
- destructiveHint: false,
70
+ destructiveHint: true,
71
71
  idempotentHint: false,
72
72
  openWorldHint: false,
73
73
  agentHidden: true,
74
74
  },
75
- trigger: 'Session status, rename the title, compact, fork into a new session, switch Project, worktrees.',
75
+ trigger: 'Session lookup/control, title, compact, fork, Project and worktrees.',
76
76
  description:
77
- 'Manage the current session. status shows session id, title, Project and model; rename sets the session title; compact runs after this turn ends; fork copies this conversation into a new session. set-project switches the active Project; list-projects returns the registered projects (name, path); a project name instead of a path → list-projects first, then set-project with the matching path, ask only if several match. path must be an existing directory. A shell-local cd does not change the Project. Worktree actions act on this session’s git worktree only when the user explicitly asks.',
77
+ 'Inspect sessions or control another by exact ID, never a guessed one. send acknowledges queue intake, not completion. Cancel/delete and worktree actions require the user’s request. Other actions affect only the current session.',
78
78
  inputSchema: {
79
79
  type: 'object',
80
80
  properties: {
@@ -82,6 +82,11 @@ export const SESSION_TOOL = {
82
82
  type: 'string',
83
83
  enum: [
84
84
  'status',
85
+ 'list',
86
+ 'read',
87
+ 'send',
88
+ 'cancel',
89
+ 'delete',
85
90
  'rename',
86
91
  'compact',
87
92
  'fork',
@@ -95,14 +100,47 @@ export const SESSION_TOOL = {
95
100
  'prune-worktrees',
96
101
  ],
97
102
  description:
98
- 'status (default without path) shows the session; rename sets title; compact schedules a compaction right after this turn; fork creates a new session copying this conversation (returns its sessionId; this session stays current); set-project switches to path; list-projects returns registered projects; favorite/archive set this session’s sidebar flag to value; merge-worktree merges this session’s worktree into the project folder’s checked-out branch, remove-worktree deletes it (returning to the project folder; call again if it reports WORKTREE_REMOVAL_INCOMPLETE); list-worktrees lists every managed worktree and who retains it; prune-worktrees removes clean, merged ones no session retains.',
103
+ 'status defaults to current; list pages sessions; read returns latest items; send queues prompt; cancel stops the turn; delete removes the session. compact runs after this turn; fork copies it without switching. merge-worktree merges into the Project’s checked-out branch; remove-worktree returns to the Project (repeat on WORKTREE_REMOVAL_INCOMPLETE); list-worktrees includes retaining sessions; prune-worktrees removes only clean, merged, unretained worktrees.',
104
+ },
105
+ title: { type: 'string', description: 'rename: new current-session title.' },
106
+ session_id: {
107
+ type: 'string',
108
+ description:
109
+ 'ID from list; required for read/send/cancel/delete, optional for status. send/cancel/delete cannot target the caller.',
110
+ },
111
+ prompt: { type: 'string', description: 'send: message to enqueue; loads a cold session.' },
112
+ limit: {
113
+ type: 'integer',
114
+ minimum: 1,
115
+ maximum: 100,
116
+ description:
117
+ 'list/read: maximum rows, default 25. Output: 8KiB per page, 12KiB for initial read tail; follow nextOffset/nextTextOffset for more.',
118
+ },
119
+ cursor: { type: 'string', description: 'list: returned nextCursor.' },
120
+ offset: {
121
+ type: 'integer',
122
+ minimum: 0,
123
+ description:
124
+ 'read: newest items to skip, default 0 (tail). Use nextOffset for older pages; appends/rewinds shift positions.',
125
+ },
126
+ text_offset: {
127
+ type: 'integer',
128
+ minimum: 0,
129
+ description: 'read: UTF-16 text position from nextTextOffset; requires offset, limit:1, item_id.',
130
+ },
131
+ item_id: {
132
+ type: 'string',
133
+ description: 'read: returned item id; rejects a shifted position instead of reading another item.',
134
+ },
135
+ path: {
136
+ type: 'string',
137
+ description:
138
+ 'Existing directory; implies set-project. Resolve names with list-projects first. Shell cd does not switch Project.',
99
139
  },
100
- title: { type: 'string', description: 'rename: the new session title.' },
101
- path: { type: 'string', description: 'Existing directory to switch to (implies action=set-project).' },
102
- compact: { type: 'boolean', description: 'fork: compact the copied conversation.' },
140
+ compact: { type: 'boolean', description: 'fork: compact the copy.' },
103
141
  force: {
104
142
  type: 'boolean',
105
- description: 'remove-worktree: delete even with uncommitted or unmerged work (only when the user says so).',
143
+ description: 'remove-worktree: allow uncommitted/unmerged work only when explicitly requested.',
106
144
  },
107
145
  value: { type: 'boolean', description: 'favorite/archive: on or off.' },
108
146
  },
@@ -7,6 +7,7 @@ import { normalizeEffortInput } from './effort.mjs';
7
7
  import { isLikelyRawModelId } from './config-helpers.mjs';
8
8
  import { configuredAgentRouteCandidates } from '../../../shared/agent-route-config.mjs';
9
9
  import { normalizeContextTokens } from '../../../shared/llm/default-context-window.mjs';
10
+ import { canonicalRouteProvider, normalizeRouteChain } from '../../../shared/model-route-chain.mjs';
10
11
  import { normalizeAgentId, normalizeWorkflowId } from './workflow-ids.mjs';
11
12
  import { createWorkflowPacks } from './workflow/packs.mjs';
12
13
  import { createWorkflowAgents } from './workflow/agents.mjs';
@@ -38,12 +39,6 @@ const WEB_SEARCH_PROVIDER_FAMILIES = new Map([
38
39
  ]);
39
40
  export const WEB_SEARCH_DEFAULT_PROVIDER = 'default';
40
41
  export const WEB_SEARCH_DEFAULT_MODEL = 'default';
41
- const WEB_SEARCH_PROVIDER_ALIASES = Object.freeze({
42
- 'openai-api': 'openai',
43
- 'xai-api': 'xai',
44
- 'gemini-api': 'gemini',
45
- 'anthropic-api': 'anthropic',
46
- });
47
42
 
48
43
  export function workflowPresetId(slot) {
49
44
  return `workflow-${slot}`;
@@ -121,8 +116,7 @@ export function createWorkflowHelpers({ rootDir, dataDir, readMarkdownDocument,
121
116
  }
122
117
 
123
118
  export function normalizeWebSearchProviderId(provider) {
124
- const id = clean(provider);
125
- return WEB_SEARCH_PROVIDER_ALIASES[id] || id;
119
+ return canonicalRouteProvider(provider);
126
120
  }
127
121
 
128
122
  export function isDefaultWebSearchRouteConfig(routeLike = {}) {
@@ -141,6 +135,10 @@ export function isWebSearchCapableProvider(provider) {
141
135
  }
142
136
 
143
137
  export function normalizeWebSearchRouteConfig(routeLike, fallback = {}) {
138
+ return normalizeRouteChain(routeLike, normalizeWebSearchRouteLeaf, fallback);
139
+ }
140
+
141
+ function normalizeWebSearchRouteLeaf(routeLike, fallback = {}) {
144
142
  const provider = normalizeWebSearchProviderId(routeLike?.provider || fallback.provider);
145
143
  const model = clean(routeLike?.model || fallback.model);
146
144
  if (!provider || !model) return null;
@@ -178,6 +176,10 @@ export function webSearchRouteOrDefault(...routeLikes) {
178
176
  }
179
177
 
180
178
  export function normalizeWorkflowRoute(routeLike, fallback = {}) {
179
+ return normalizeRouteChain(routeLike, normalizeWorkflowRouteLeaf, fallback);
180
+ }
181
+
182
+ function normalizeWorkflowRouteLeaf(routeLike, fallback = {}) {
181
183
  const provider = clean(routeLike?.provider) || clean(fallback.provider);
182
184
  const model = clean(routeLike?.model) || clean(fallback.model);
183
185
  if (!provider || !model) return null;