mixdog 1.2.3 → 1.2.5

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 (469) 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/mobile-release.mjs +5 -4
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +128 -38
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/maintainer/AGENT.md +1 -1
  9. package/src/agents/maintainer/agent.json +1 -1
  10. package/src/agents/reviewer/AGENT.md +2 -4
  11. package/src/agents/security/AGENT.md +1 -2
  12. package/src/agents/writer/AGENT.md +2 -3
  13. package/src/defaults/shipped-history.json +7 -1
  14. package/src/defaults/skills/image/SKILL.md +21 -23
  15. package/src/lib/keychain-cjs.cjs +13 -11
  16. package/src/output-styles/common.md +2 -1
  17. package/src/rules/agent/AGENT.md +7 -5
  18. package/src/rules/lead/LEAD.md +13 -13
  19. package/src/rules/shared/45-destructive.md +4 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  21. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  22. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  23. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  24. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  25. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  26. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  31. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  32. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  34. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  35. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  36. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  37. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  38. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  41. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  46. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  48. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  50. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  51. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  52. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  53. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  54. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  55. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  56. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  57. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  59. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  60. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  61. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  62. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  63. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  64. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  65. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  66. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  67. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  68. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  69. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  70. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  80. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  82. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  86. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  87. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  88. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  89. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  90. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  92. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  93. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  96. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  97. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  98. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  99. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  100. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  101. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  102. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  103. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  109. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  110. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  111. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  112. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  113. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  114. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  115. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  117. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  118. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  119. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  120. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  121. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  123. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  124. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  125. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  126. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  128. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  129. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  130. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  131. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  132. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  133. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  134. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  135. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  141. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  146. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  147. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  148. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  149. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  150. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  151. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  155. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  157. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  158. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  161. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  162. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  163. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  164. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  165. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  167. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  169. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  173. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  174. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  178. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  179. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  181. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +160 -212
  182. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  183. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  184. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  185. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  186. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  187. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  188. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  189. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  190. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  191. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  192. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  193. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  194. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  197. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  199. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  200. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  208. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  209. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  210. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  211. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  212. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  216. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  217. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  218. package/src/runtime/attachments/store.d.mts +9 -0
  219. package/src/runtime/attachments/store.mjs +80 -9
  220. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  221. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  222. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  223. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  224. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  225. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  226. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  227. package/src/runtime/github/tool.mjs +118 -17
  228. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  229. package/src/runtime/media/catalog.mjs +4 -4
  230. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  231. package/src/runtime/media/defaults.mjs +37 -0
  232. package/src/runtime/media/jobs.mjs +12 -2
  233. package/src/runtime/media/lanes.mjs +12 -0
  234. package/src/runtime/media/tool-defs.mjs +15 -4
  235. package/src/runtime/media/tool.mjs +41 -12
  236. package/src/runtime/media/upstream-error.mjs +72 -6
  237. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  238. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  240. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  242. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  243. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  244. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  245. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  246. package/src/runtime/office/index.mjs +2 -3
  247. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  248. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  249. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  250. package/src/runtime/shared/atomic-file.d.mts +1 -1
  251. package/src/runtime/shared/background-tasks.mjs +6 -1
  252. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  253. package/src/runtime/shared/browser-launch.mjs +15 -0
  254. package/src/runtime/shared/err-text.mjs +42 -4
  255. package/src/runtime/shared/file-lock.mjs +6 -5
  256. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  257. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  258. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  259. package/src/runtime/shared/model-route-chain.mjs +48 -0
  260. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  261. package/src/runtime/shared/pid-liveness.mjs +12 -0
  262. package/src/runtime/shared/provider-api-key.mjs +6 -0
  263. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  264. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  265. package/src/runtime/shared/quiet-progress.mjs +101 -0
  266. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  267. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  268. package/src/runtime/shared/remote-intent.mjs +2 -42
  269. package/src/runtime/shared/slow-span.mjs +8 -1
  270. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  271. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  272. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  273. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  274. package/src/runtime/shared/tool-status.mjs +3 -2
  275. package/src/runtime/shared/tool-surface.mjs +2 -3
  276. package/src/runtime/shared/tool-work-units.mjs +22 -15
  277. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  278. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  279. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  280. package/src/runtime/shared/transcript-writer.mjs +14 -4
  281. package/src/runtime/shared/turn-changes.mjs +2 -1
  282. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  283. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  284. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  285. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  286. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  287. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  288. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  289. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  290. package/src/runtime/shared/worktrees/include.mjs +125 -7
  291. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  292. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  293. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  294. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  295. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  296. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  297. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  298. package/src/runtime/terminal-bridge/client.mjs +14 -10
  299. package/src/session-runtime/boot/apis.mjs +7 -1
  300. package/src/session-runtime/boot/config.mjs +2 -0
  301. package/src/session-runtime/boot/facade.mjs +3 -0
  302. package/src/session-runtime/boot/session.mjs +3 -2
  303. package/src/session-runtime/boot/tools.mjs +3 -0
  304. package/src/session-runtime/conversation-import/service.mjs +1 -1
  305. package/src/session-runtime/goal-facade-api.mjs +2 -2
  306. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  307. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  308. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  309. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  310. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  311. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  312. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  313. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  314. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  315. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  316. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  317. package/src/session-runtime/media-api.mjs +8 -0
  318. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  319. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  320. package/src/session-runtime/model-route/set-route.mjs +114 -34
  321. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  322. package/src/session-runtime/model-route-api.mjs +4 -2
  323. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  324. package/src/session-runtime/native-web-search.mjs +9 -8
  325. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  326. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  327. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  328. package/src/session-runtime/provider-models.mjs +1 -0
  329. package/src/session-runtime/provider-usage.mjs +4 -0
  330. package/src/session-runtime/route-resolution.mjs +3 -1
  331. package/src/session-runtime/runtime-core.mjs +4 -0
  332. package/src/session-runtime/runtime-facade.mjs +6 -0
  333. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  334. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  335. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  336. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  337. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  338. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  339. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  340. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  341. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  343. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  344. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  345. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  346. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  347. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  348. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  349. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  350. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  351. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  352. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  353. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  354. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  355. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  356. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  357. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  358. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  359. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  360. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  361. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  362. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  363. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  364. package/src/session-runtime/services/agent-tool.mjs +4 -0
  365. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  366. package/src/session-runtime/services/provider-admin.mjs +77 -0
  367. package/src/session-runtime/session-create/session-options.mjs +7 -5
  368. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  369. package/src/session-runtime/session-transcript.mjs +4 -5
  370. package/src/session-runtime/session-turn-api.mjs +3 -9
  371. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  372. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  373. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  374. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  375. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  376. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  377. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  378. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  379. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  380. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  381. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  382. package/src/session-runtime/turn/turn-run.mjs +1 -36
  383. package/src/session-runtime/usage-stats-api.mjs +4 -1
  384. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  385. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  386. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  387. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  388. package/src/session-runtime/workspace/transitions.mjs +248 -68
  389. package/src/standalone/channel-transport.mjs +3 -4
  390. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  391. package/src/standalone/daemon-pg-stop.mjs +1 -3
  392. package/src/standalone/daemon-session-control.mjs +88 -0
  393. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  394. package/src/standalone/daemon.mjs +2 -0
  395. package/src/standalone/desktop-service-registry.mjs +32 -5
  396. package/src/standalone/local-session-runtime.mjs +11 -12
  397. package/src/standalone/session-protocol.mjs +7 -0
  398. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  399. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  400. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  401. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  402. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  403. package/src/standalone/session-service/agent-tree.mjs +28 -2
  404. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  405. package/src/standalone/session-service/entries.mjs +1 -0
  406. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  407. package/src/standalone/session-service/quota-resume.mjs +28 -13
  408. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  409. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  410. package/src/standalone/session-tool-output.mjs +82 -0
  411. package/src/tui/app/app-view.jsx +2 -1
  412. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  413. package/src/tui/app/provider-setup-picker.mjs +15 -3
  414. package/src/tui/app/slash-commands.mjs +6 -0
  415. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  416. package/src/tui/components/Spinner.jsx +4 -0
  417. package/src/tui/components/SpinnerByline.jsx +21 -2
  418. package/src/tui/components/status-line/local-line.mjs +10 -2
  419. package/src/tui/dist/index.mjs +529 -270
  420. package/src/tui/session/active-tool-summary.mjs +1 -1
  421. package/src/tui/session/context-state.mjs +0 -3
  422. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  423. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  424. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  425. package/src/tui/session/quota-resume.mjs +140 -61
  426. package/src/tui/session/session-api/commands.mjs +4 -10
  427. package/src/tui/session/session-api/controls.mjs +12 -0
  428. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  429. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  430. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  431. package/src/tui/session/session-api/media.mjs +2 -0
  432. package/src/tui/session/session-api/routes.mjs +81 -57
  433. package/src/tui/session/session-api/settings.mjs +3 -3
  434. package/src/tui/session/session-api/worktree.mjs +3 -2
  435. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  436. package/src/tui/session/session-flow/drain.mjs +6 -4
  437. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  438. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  439. package/src/tui/session/session-flow/queue.mjs +1 -1
  440. package/src/tui/session/tool-approval.mjs +17 -8
  441. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  442. package/src/tui/session/tui-steering-persist.mjs +3 -5
  443. package/src/tui/session/turn-quiet.mjs +53 -0
  444. package/src/tui/session/turn-stream.mjs +5 -1
  445. package/src/tui/session/turn.mjs +38 -31
  446. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  447. package/src/tui/spinner-meta.mjs +10 -0
  448. package/src/tui/spinner-verbs.mjs +3 -0
  449. package/src/ui/statusline.mjs +13 -3
  450. package/src/ui/streaming-markdown-heal.mjs +70 -18
  451. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  452. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  453. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  454. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  455. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  456. package/src/session-runtime/turn/share-ops.mjs +0 -77
  457. package/src/tui/session/cross-surface-share.mjs +0 -406
  458. package/src/tui/session/live-share/delta.mjs +0 -153
  459. package/src/tui/session/live-share/mirror.mjs +0 -106
  460. package/src/tui/session/live-share/owner.mjs +0 -254
  461. package/src/tui/session/live-share/retry.mjs +0 -54
  462. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  463. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  464. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  465. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  466. package/src/tui/session/live-share/viewer.mjs +0 -99
  467. package/src/tui/session/live-share/wire.mjs +0 -44
  468. package/src/tui/session/live-share.mjs +0 -154
  469. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -1,6 +1,8 @@
1
1
  /**
2
- * set-route.mjs — select the main route: resolve and validate the request,
3
- * adopt it into config, then decide how the current session follows it
2
+ * set-route.mjs — select the runtime's route: resolve and validate the
3
+ * request, adopt it as the live route (its per-model settings saved; the main
4
+ * model only on an explicit main-model choice, keepMainModel: false), then
5
+ * decide when the current session follows it
4
6
  * (untouched, tuned, recreated, updated in place when empty, or switched in
5
7
  * place when the selection is addressed to an established conversation).
6
8
  */
@@ -21,6 +23,7 @@ import {
21
23
  shouldRecreateEmptySessionForRouteChange,
22
24
  } from '../../runtime/agent/orchestrator/runtime-core/session-route-policy.mjs';
23
25
  import { rebuildToolSurfaceForProviderWithMigration } from '../../runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs';
26
+ import { UNOWNED_LEASE, openRouteLease } from './route-ownership.mjs';
24
27
 
25
28
  /** The request, completed from the live route where the caller left gaps. */
26
29
  function completeRequest(deps, next) {
@@ -80,20 +83,26 @@ async function resolveSelectedRoute(deps, next) {
80
83
  }
81
84
 
82
85
  /** Close the empty session and materialize a fresh one for the new provider. */
83
- async function recreateEmptySession(deps) {
86
+ async function recreateEmptySession(deps, lease) {
84
87
  const { getSession, setSession, mgr, statusRoutes, createCurrentSession, invalidatePreSessionToolSurface } = deps;
85
88
  // If the boot create is still finishing SessionStart/deferred-surface
86
89
  // work, drain that promise first. Otherwise createCurrentSession()
87
90
  // would return the old in-flight promise after we tombstone/null the
88
91
  // session, racing the intended rebuild for the new provider.
89
92
  await createCurrentSession('model-switch-empty-drain');
90
- const emptySession = getSession();
91
- if (!emptySession?.id || sessionHasRouteHistory(emptySession)) return;
92
- statusRoutes?.clearGatewaySessionRoute?.(emptySession.id);
93
- mgr.closeSession?.(emptySession.id, 'cli-model-switch-empty', { tombstone: true });
94
- setSession(null);
95
- invalidatePreSessionToolSurface?.();
96
- await createCurrentSession('model-switch-empty');
93
+ const closed = lease.run(
94
+ () => {
95
+ const emptySession = getSession();
96
+ if (!emptySession?.id || sessionHasRouteHistory(emptySession)) return false;
97
+ statusRoutes?.clearGatewaySessionRoute?.(emptySession.id);
98
+ mgr.closeSession?.(emptySession.id, 'cli-model-switch-empty', { tombstone: true });
99
+ setSession(null);
100
+ invalidatePreSessionToolSurface?.();
101
+ return true;
102
+ },
103
+ () => false
104
+ );
105
+ if (closed) await createCurrentSession('model-switch-empty');
97
106
  }
98
107
 
99
108
  /** Rewrite the addressed empty session to the route it was asked to run on. */
@@ -164,7 +173,7 @@ function switchSessionInPlace(deps, session) {
164
173
  }
165
174
 
166
175
  /** Validate, persist and adopt the requested route as the runtime's route. */
167
- async function adoptRoute(deps, persist, next, options) {
176
+ async function adoptRoute(deps, persist, next, options, lease) {
168
177
  const {
169
178
  getConfig,
170
179
  getRoute,
@@ -175,15 +184,40 @@ async function adoptRoute(deps, persist, next, options) {
175
184
  scheduleStatuslineUsageRefresh,
176
185
  } = deps;
177
186
  const { selectedRoute, fastCapable, modelMeta } = await resolveSelectedRoute(deps, next);
178
- persist.saveRouteModelSettings(selectedRoute, fastCapable);
179
- // An heir opening on its source's model is not a main-model choice.
180
- const leadRoute = persist.persistAdoptedModelSettings(selectedRoute, {
181
- keepMainModel: options?.keepMainModel === true,
182
- });
183
- setRouteState(resolveRoute(getConfig(), leadRoute ? { model: workflowPresetId('lead') } : selectedRoute));
184
- await refreshRouteEffort(modelMeta);
185
- refreshStatuslineUsageSnapshot(getRoute());
186
- scheduleStatuslineUsageRefresh();
187
+ // Provider readiness may outlast the session the selection was made for.
188
+ const adopted = lease.run(
189
+ () => {
190
+ if (options?.sessionOnly === true) {
191
+ // An agent child's route belongs to that session alone: the shared
192
+ // modelSettings bucket (saved effort/Fast per model) and the main
193
+ // model (lead preset / default model) are never written.
194
+ setRouteState(resolveRoute(getConfig(), selectedRoute));
195
+ } else {
196
+ persist.saveRouteModelSettings(selectedRoute, fastCapable);
197
+ // The main model changes only on an explicit main-model choice
198
+ // (keepMainModel: false, e.g. the setup tool); every other selection
199
+ // — the session surface's model pick, an heir — keeps it.
200
+ const leadRoute = persist.persistAdoptedModelSettings(selectedRoute, {
201
+ keepMainModel: options?.keepMainModel !== false,
202
+ });
203
+ setRouteState(resolveRoute(getConfig(), leadRoute ? { model: workflowPresetId('lead') } : selectedRoute));
204
+ }
205
+ return true;
206
+ },
207
+ () => false
208
+ );
209
+ if (!adopted) return false;
210
+ // The refresh completes against the route just adopted and only while the
211
+ // selection still owns it.
212
+ await refreshRouteEffort(modelMeta, getRoute(), null, lease);
213
+ return lease.run(
214
+ () => {
215
+ refreshStatuslineUsageSnapshot(getRoute());
216
+ scheduleStatuslineUsageRefresh();
217
+ return true;
218
+ },
219
+ () => false
220
+ );
187
221
  }
188
222
 
189
223
  /**
@@ -194,17 +228,25 @@ async function adoptRoute(deps, persist, next, options) {
194
228
  * `{ modelSwitch }` with the recorded boundary (as setRoute does) so the
195
229
  * session surface shows the same live divider, or true when nothing switched.
196
230
  */
197
- export function createContinueSessionInModel(deps, persist) {
198
- const { getSession, invalidateContextStatusCache } = deps;
231
+ export function createContinueSessionInModel(deps, persist, clearPendingRoute) {
232
+ const { getSession, getSessionGeneration, invalidateContextStatusCache } = deps;
199
233
  return async function continueSessionInModel(sessionId, next) {
200
234
  const session = getSession();
201
235
  if (!sessionId || !session?.id || session.id !== sessionId) {
202
236
  throw new Error(`session ${sessionId || ''} is not the active session`);
203
237
  }
204
- await adoptRoute(deps, persist, next, {});
205
- const modelSwitch = switchSessionInPlace(deps, session);
206
- invalidateContextStatusCache();
207
- return modelSwitch ? { modelSwitch } : true;
238
+ const lease = openRouteLease(getSessionGeneration);
239
+ const adopted = await adoptRoute(deps, persist, next, {}, lease);
240
+ return lease.run(
241
+ () => {
242
+ if (!adopted) return true;
243
+ const modelSwitch = switchSessionInPlace(deps, session);
244
+ invalidateContextStatusCache();
245
+ clearPendingRoute?.();
246
+ return modelSwitch ? { modelSwitch } : true;
247
+ },
248
+ () => true
249
+ );
208
250
  };
209
251
  }
210
252
 
@@ -215,9 +257,10 @@ async function validateSelectedRoute(deps, next) {
215
257
  }
216
258
 
217
259
  export function createSetRoute(deps, persist) {
218
- const { getRoute, getSession, invalidateContextStatusCache, createCurrentSession } = deps;
260
+ const { getRoute, getSession, getSessionGeneration, invalidateContextStatusCache, createCurrentSession } = deps;
261
+ let pending = null;
219
262
 
220
- return async function setRoute(next, options = {}) {
263
+ async function setRoute(next, options = {}) {
221
264
  // Without an explicit durable address a selection is for a new/inherited
222
265
  // session and never rewrites an existing conversation's model, unless it
223
266
  // is the user's model choice for this conversation (`switchEstablished`,
@@ -225,11 +268,28 @@ export function createSetRoute(deps, persist) {
225
268
  // place while an empty one follows the unaddressed rules below.
226
269
  const applyToCurrentSession = options?.applyToCurrentSession === true;
227
270
  const switchEstablished = applyToCurrentSession || options?.switchEstablished === true;
228
- // Lets a caller prove the selection is acceptable before it does
229
- // irreversible work (compaction) ahead of the switch; changes nothing.
271
+ // Validate without persisting the selection or changing the session.
230
272
  if (options?.validateOnly === true) return validateSelectedRoute(deps, next);
231
- await adoptRoute(deps, persist, next, options);
273
+ // A selection addressed to a conversation belongs to the session
274
+ // generation it was enqueued under (the surface's enqueue boundary names
275
+ // it; a direct call is enqueued now). Once that generation has moved, every
276
+ // route or session effect is skipped by the lease and the current route
277
+ // stands.
278
+ const addressed = switchEstablished || options?.deferUntilNextTurn === true;
279
+ const lease = addressed ? openRouteLease(getSessionGeneration, options?.originGeneration) : UNOWNED_LEASE;
280
+ const adopted = await adoptRoute(deps, persist, next, options, lease);
281
+ if (!adopted) return getRoute();
282
+ return lease.run(() => followSession(options, lease, { switchEstablished, applyToCurrentSession }), getRoute);
283
+ }
284
+
285
+ /** What the adopted route does to the session it was selected for. */
286
+ async function followSession(options, lease, { switchEstablished, applyToCurrentSession }) {
232
287
  const session = getSession();
288
+ if (options.deferUntilNextTurn === true) {
289
+ pending = session?.id ? { generation: lease.token } : null;
290
+ return getRoute();
291
+ }
292
+ pending = null;
233
293
  // A session the user has already talked in or compacted keeps its route
234
294
  // unless the selection was addressed to it. A current session with no
235
295
  // model reply, no compaction summary and no in-flight first turn — empty,
@@ -240,8 +300,8 @@ export function createSetRoute(deps, persist) {
240
300
  if (!switchEstablished) return getRoute();
241
301
  const route = getRoute();
242
302
  // An addressed selection of another model switches the conversation
243
- // itself in place; the caller (session surface) refuses it while a
244
- // turn runs. A same-model update (effort/Fast) only tunes the session
303
+ // itself in place; the session surface defers it to the next turn
304
+ // instead. A same-model update (effort/Fast) only tunes the session
245
305
  // from its next turn.
246
306
  if (session && (route.provider !== session.provider || route.model !== session.model)) {
247
307
  const modelSwitch = switchSessionInPlace(deps, session);
@@ -259,7 +319,9 @@ export function createSetRoute(deps, persist) {
259
319
  session?.id &&
260
320
  typeof createCurrentSession === 'function'
261
321
  ) {
262
- await recreateEmptySession(deps);
322
+ // The recreation installs a new session itself, so nothing after it
323
+ // acts for the selection beyond dropping the stale gauge.
324
+ await recreateEmptySession(deps, lease);
263
325
  invalidateContextStatusCache();
264
326
  return getRoute();
265
327
  }
@@ -272,5 +334,23 @@ export function createSetRoute(deps, persist) {
272
334
  invalidateContextStatusCache();
273
335
  }
274
336
  return getRoute();
337
+ }
338
+ setRoute.applyPendingRoute = () => {
339
+ if (!pending) return null;
340
+ const selection = pending;
341
+ if (selection.generation !== getSessionGeneration()) {
342
+ pending = null;
343
+ return null;
344
+ }
345
+ // The live route is the latest selection: effort/Fast tuned after the
346
+ // deferred model choice replace it, so no snapshot is kept.
347
+ const modelSwitch = switchSessionInPlace(deps, getSession());
348
+ invalidateContextStatusCache();
349
+ pending = null;
350
+ return modelSwitch;
351
+ };
352
+ setRoute.clearPendingRoute = () => {
353
+ pending = null;
275
354
  };
355
+ return setRoute;
276
356
  }
@@ -6,6 +6,7 @@ import { clean, hasOwn } from '../../runtime/agent/orchestrator/runtime-core/ses
6
6
  import { coerceEffortFor } from '../../runtime/agent/orchestrator/runtime-core/effort.mjs';
7
7
  import { ensureProviderEnabled } from '../../runtime/agent/orchestrator/runtime-core/config-helpers.mjs';
8
8
  import { selectionFastCapable } from '../route-state.mjs';
9
+ import { routeChain } from '../../runtime/shared/model-route-chain.mjs';
9
10
  import {
10
11
  isDefaultWebSearchRouteConfig,
11
12
  isWebSearchCapableProvider,
@@ -93,9 +94,13 @@ export function createWebSearchRouteApi(deps) {
93
94
  if (isDefaultWebSearchRouteConfig(selectedRoute)) {
94
95
  await awaitKeychainPrewarm();
95
96
  ensureFullConfig();
96
- return saveWebSearchRoute(defaultWebSearchRoute(selectedRoute.toolType));
97
97
  }
98
- return saveWebSearchRoute(await resolveExplicitRoute(selectedRoute));
98
+ const resolved = [];
99
+ for (const entry of routeChain(selectedRoute)) {
100
+ resolved.push(isDefaultWebSearchRouteConfig(entry) ? entry : await resolveExplicitRoute(entry));
101
+ }
102
+ const [primary, ...fallbacks] = resolved;
103
+ return saveWebSearchRoute(normalizeWebSearchRouteConfig({ ...primary, fallbacks }));
99
104
  },
100
105
  };
101
106
  }
@@ -19,10 +19,12 @@ export { shouldRecreateEmptySessionForRouteChange } from '../runtime/agent/orche
19
19
 
20
20
  export function createModelRouteApi(deps) {
21
21
  const persist = createRoutePersistence(deps);
22
+ const setRoute = createSetRoute(deps, persist);
22
23
  return {
23
24
  ...createWebSearchRouteApi(deps),
24
- setRoute: createSetRoute(deps, persist),
25
- continueSessionInModel: createContinueSessionInModel(deps, persist),
25
+ setRoute,
26
+ applyPendingRoute: setRoute.applyPendingRoute,
27
+ continueSessionInModel: createContinueSessionInModel(deps, persist, setRoute.clearPendingRoute),
26
28
  ...createRouteTuning(deps, persist),
27
29
  };
28
30
  }
@@ -4,6 +4,7 @@
4
4
  * follow-Main default.
5
5
  */
6
6
  import { webSearchRouteOrDefault } from '../../runtime/agent/orchestrator/runtime-core/workflow.mjs';
7
+ import { routeChain, canonicalRouteProvider } from '../../runtime/shared/model-route-chain.mjs';
7
8
 
8
9
  export function createWebSearchRouteCandidates({
9
10
  getRoute,
@@ -50,35 +51,47 @@ export function createWebSearchRouteCandidates({
50
51
  // before the Main Model was ever consulted.
51
52
  const webSearchRoute = webSearchRouteOrDefault(cfg.webSearchRoute, getWebSearchRoute());
52
53
  setWebSearchRoute(webSearchRoute);
54
+ const candidates = [];
55
+ const seen = new Set();
56
+ for (const selected of routeChain(webSearchRoute)) {
57
+ const candidate = await resolveCandidate(selected, cfg, route);
58
+ if (!candidate) continue;
59
+ const provider = canonicalRouteProvider(candidate.provider);
60
+ if (seen.has(provider)) continue;
61
+ seen.add(provider);
62
+ candidates.push({ ...candidate, provider });
63
+ }
64
+ return candidates;
65
+ }
66
+
67
+ async function resolveCandidate(webSearchRoute, cfg, route) {
53
68
  if (isDefaultWebSearchRouteConfig(webSearchRoute)) {
54
69
  const loadedRow = route?.provider && route?.model ? await loadMainCatalogRow(cfg, route) : null;
55
70
  const mainModel = currentMainWebSearchModelMeta(loadedRow);
56
- if (!mainModel || !webSearchCapableFor(route.provider, mainModel)) return [];
57
- return [
58
- {
59
- key: `default\n${route.provider}\n${route.model}`,
60
- provider: normalizeWebSearchProviderId(route.provider),
61
- model: route.model,
62
- source: 'default-web-search-route',
63
- effort: route.effectiveEffort || route.effort || null,
64
- fast: route.fast === true,
65
- toolType: webSearchRoute.toolType || null,
66
- },
67
- ];
71
+ if (!mainModel || !webSearchCapableFor(route.provider, mainModel)) return null;
72
+ return {
73
+ key: `default\n${route.provider}\n${route.model}`,
74
+ provider: normalizeWebSearchProviderId(route.provider),
75
+ model: route.model,
76
+ source: 'default-web-search-route',
77
+ effort: route.effectiveEffort || route.effort || null,
78
+ fast: route.fast === true,
79
+ modelParameters: route.modelParameters || {},
80
+ toolType: webSearchRoute.toolType || null,
81
+ };
68
82
  }
69
83
  const providerName = normalizeWebSearchProviderId(webSearchRoute.provider);
70
- if (!isWebSearchCapableProvider(providerName)) return [];
71
- return [
72
- {
73
- key: `${providerName}\n${webSearchRoute.model}`,
74
- provider: providerName,
75
- model: webSearchRoute.model,
76
- source: 'web-search-route',
77
- effort: webSearchRoute.effort || null,
78
- fast: webSearchRoute.fast === true,
79
- toolType: webSearchRoute.toolType || null,
80
- },
81
- ];
84
+ if (!isWebSearchCapableProvider(providerName)) return null;
85
+ return {
86
+ key: `${providerName}\n${webSearchRoute.model}`,
87
+ provider: providerName,
88
+ model: webSearchRoute.model,
89
+ source: 'web-search-route',
90
+ effort: webSearchRoute.effort || null,
91
+ fast: webSearchRoute.fast === true,
92
+ modelParameters: webSearchRoute.modelParameters || {},
93
+ toolType: webSearchRoute.toolType || null,
94
+ };
82
95
  }
83
96
 
84
97
  return { currentMainWebSearchModelMeta, nativeWebSearchRoutes };
@@ -14,6 +14,7 @@ import {
14
14
  } from './native-web-search/tool-shape.mjs';
15
15
  import { createWebSearchRouteCandidates } from './native-web-search/routes.mjs';
16
16
  import { reportNativeWebSearchUsage } from './native-web-search-usage.mjs';
17
+ import { canFallbackRoute } from '../runtime/shared/model-route-fallback.mjs';
17
18
 
18
19
  export function createNativeWebSearch(deps) {
19
20
  const {
@@ -98,14 +99,14 @@ export function createNativeWebSearch(deps) {
98
99
  if (!candidates.length) throw noCandidateError();
99
100
  const errors = [];
100
101
  for (const candidate of candidates) {
101
- for (const toolType of toolTypesFor(candidate)) {
102
- try {
103
- return await sendCandidate(candidate, toolType, webSearchArgs, signal);
104
- } catch (err) {
105
- errors.push(
106
- `${candidate.provider}${candidate.model ? `/${candidate.model}` : ''}/${toolType}: ${err?.message || String(err)}`
107
- );
108
- }
102
+ const [toolType] = toolTypesFor(candidate);
103
+ try {
104
+ return await sendCandidate(candidate, toolType, webSearchArgs, signal);
105
+ } catch (err) {
106
+ if (!canFallbackRoute(err, { signal })) throw err;
107
+ errors.push(
108
+ `${candidate.provider}${candidate.model ? `/${candidate.model}` : ''}/${toolType}: ${err?.message || String(err)}`
109
+ );
109
110
  }
110
111
  }
111
112
  throw new Error(`native web search failed: ${errors.join(' | ')}`);
@@ -3,6 +3,7 @@
3
3
  // the model catalog.
4
4
  import { refreshKeychainStatus, retryKeychain } from '../../runtime/shared/config.mjs';
5
5
  import { keychainIssueFor } from '../services/provider-admin.mjs';
6
+ import { modelProxyClientMode } from '../../runtime/shared/model-proxy-mode.mjs';
6
7
 
7
8
  // The keyring alert must reflect the live state (it can lock or unlock while a
8
9
  // cached setup is served), so overlay it on every ready read.
@@ -26,6 +27,9 @@ export function createSetupApi({
26
27
  return {
27
28
  async getProviderSetup(options = {}) {
28
29
  const force = options?.force === true || options?.refresh === true;
30
+ if (modelProxyClientMode()) {
31
+ return cachedProviderSetup({ force: force || options?.recheckKeychain === true });
32
+ }
29
33
  // An unforced read never blocks: the authoritative setup waits on the OS
30
34
  // keychain, which can take seconds on a cold start and used to stall the
31
35
  // whole settings sweep behind it. Serve
@@ -2,6 +2,7 @@
2
2
  // One authoritative provider catalog load: secrets and providers ready, the
3
3
  // daemon-wide startup refresh joined (or a forced refresh run), then the shared
4
4
  // catalog flattened into deduplicated rows with per-provider profiling.
5
+ import { modelProxyClientMode } from '../../runtime/shared/model-proxy-mode.mjs';
5
6
  import { isSelectableLlmModel } from '../model-recency.mjs';
6
7
  import { sharedProviderCatalog } from '../provider-catalog-cache.mjs';
7
8
  import { NO_ENABLED_PROVIDERS } from '../../runtime/agent/orchestrator/providers/registry-errors.mjs';
@@ -49,6 +50,14 @@ export function createCatalogLoader({
49
50
  }
50
51
  const providersStartedAt = performance.now();
51
52
  try {
53
+ if (forceRefresh && modelProxyClientMode()) {
54
+ const { loadModelProxyProviderConfig } = await import(
55
+ '../../runtime/agent/orchestrator/providers/model-proxy-provider.mjs'
56
+ );
57
+ await loadModelProxyProviderConfig({ force: true });
58
+ // Rebuild even when daemon readiness already settled on the old PC set.
59
+ await reg().initProviders({});
60
+ }
52
61
  await ensureProvidersReady(config().providers || {});
53
62
  } catch (error) {
54
63
  if (error?.code === NO_ENABLED_PROVIDERS) return false;
@@ -4,6 +4,8 @@
4
4
  // the already-loaded provider rows over a provider round-trip.
5
5
  import { isSelectableLlmModel } from '../model-recency.mjs';
6
6
  import { catalogRevision } from '../provider-catalog-cache.mjs';
7
+ import { modelProxyClientMode } from '../../runtime/shared/model-proxy-mode.mjs';
8
+ import { loadModelProxyProviderConfig } from '../../runtime/agent/orchestrator/providers/model-proxy-provider.mjs';
7
9
 
8
10
  export function createWebSearchCatalog({
9
11
  caches,
@@ -14,15 +16,22 @@ export function createWebSearchCatalog({
14
16
  quickHelpers,
15
17
  normalizeWebSearchProviderId,
16
18
  isWebSearchCapableProvider,
19
+ collectProviderModels,
17
20
  ensureFullConfig,
18
21
  awaitKeychainPrewarm,
19
22
  ensureProvidersReady,
20
23
  }) {
21
24
  async function enabledWebSearchProviderConfig() {
22
- await awaitKeychainPrewarm();
23
- ensureFullConfig();
25
+ let providers;
26
+ if (modelProxyClientMode()) {
27
+ providers = await loadModelProxyProviderConfig();
28
+ } else {
29
+ await awaitKeychainPrewarm();
30
+ ensureFullConfig();
31
+ providers = config().providers;
32
+ }
24
33
  const out = {};
25
- for (const [name, providerConfig] of Object.entries(config().providers || {})) {
34
+ for (const [name, providerConfig] of Object.entries(providers || {})) {
26
35
  const providerName = normalizeWebSearchProviderId(name);
27
36
  if (!providerConfig?.enabled || !isWebSearchCapableProvider(providerName)) continue;
28
37
  out[providerName] = { ...providerConfig, enabled: true };
@@ -66,6 +75,12 @@ export function createWebSearchCatalog({
66
75
  }
67
76
 
68
77
  async function loadWebSearchProviderModelsFresh({ forceRefresh = false } = {}) {
78
+ if (modelProxyClientMode()) {
79
+ // Share the desktop-backed catalog's readiness, force refresh and retry
80
+ // semantics. Server-local quick rows cannot describe desktop accounts.
81
+ const models = await collectProviderModels({ force: forceRefresh });
82
+ return quickHelpers.webSearchRowsWithDefault(quickHelpers.webSearchModelsFromRows(models));
83
+ }
69
84
  const webSearchProviders = await enabledWebSearchProviderConfig();
70
85
  const providerNames = Object.keys(webSearchProviders);
71
86
  if (!providerNames.length) return [];
@@ -89,6 +104,11 @@ export function createWebSearchCatalog({
89
104
  }
90
105
 
91
106
  async function collectWebSearchProviderModels({ force = false } = {}) {
107
+ if (modelProxyClientMode()) {
108
+ // The main catalog owns caching in client mode, including incomplete
109
+ // loads; do not pin an empty/offline projection in a second cache.
110
+ return rows.providerModelsFromCacheRows(await loadWebSearchProviderModelsFresh({ forceRefresh: force }));
111
+ }
92
112
  const revision = meta.syncCatalogRevision();
93
113
  if (force) {
94
114
  const models = await loadWebSearchProviderModelsFresh({ forceRefresh: true });
@@ -63,6 +63,7 @@ export function createProviderModels({
63
63
  quickHelpers,
64
64
  normalizeWebSearchProviderId,
65
65
  isWebSearchCapableProvider,
66
+ collectProviderModels,
66
67
  ...readiness,
67
68
  });
68
69
  const loadProviderModelsFresh = createCatalogLoader({ caches, config, reg, meta, rows, profile, ...readiness });
@@ -5,6 +5,7 @@
5
5
  // references) and all config/registry reads flow through supplied accessors so
6
6
  // live-binding is preserved.
7
7
  import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
8
+ import { modelProxyClientMode } from '../runtime/shared/model-proxy-mode.mjs';
8
9
 
9
10
  // A post-redeem dashboard rebuild is best effort: past this budget the caller
10
11
  // gets its confirmed outcome and the surface revalidates on its own cadence.
@@ -70,6 +71,9 @@ export function createProviderUsage({
70
71
  }
71
72
 
72
73
  async function cachedProviderSetup({ force = false, quick = false } = {}) {
74
+ // The proxy owns a short, connection-generation-aware cache. A session's
75
+ // indefinite local cache would hide PC sign-ins, sign-outs and reconnects.
76
+ if (modelProxyClientMode()) return providerSetup(displayConfig(), { force });
73
77
  if (!force && caches.providerSetupCache.setup) {
74
78
  return caches.providerSetupCache.setup;
75
79
  }
@@ -35,7 +35,7 @@ export function createRouteResolution({ rt, collectProviderModels, ensureProvide
35
35
  return rt.route;
36
36
  }
37
37
 
38
- async function refreshRouteEffort(modelMetaOverride = null, expectedRoute = null, signal = null) {
38
+ async function refreshRouteEffort(modelMetaOverride = null, expectedRoute = null, signal = null, lease = null) {
39
39
  const targetRoute = expectedRoute || rt.route;
40
40
  await runAbortable(signal, () => ensureProvidersReady(ensureProviderEnabled(rt.config, targetRoute.provider)));
41
41
  const modelMeta =
@@ -43,7 +43,9 @@ export function createRouteResolution({ rt, collectProviderModels, ensureProvide
43
43
  throwIfAborted(signal);
44
44
  // A rapid second resume/model change can replace the route while provider
45
45
  // metadata is loading. Never let the older completion overwrite it.
46
+ // A selection whose session was replaced while this loaded owns nothing.
46
47
  if (expectedRoute && rt.route !== expectedRoute) return null;
48
+ if (lease && !lease.valid()) return null;
47
49
  const { effectiveEffort, fastCapable } = resolveRouteEffortState(targetRoute, modelMeta);
48
50
  const contextState = resolveRouteContextState(targetRoute, modelMeta);
49
51
  const contextValue = clean(targetRoute.modelParameters?.context);
@@ -18,6 +18,7 @@ function bootParams({
18
18
  model,
19
19
  effort,
20
20
  fast,
21
+ autoEffort,
21
22
  modelParameters,
22
23
  contextPercent,
23
24
  contextTokens,
@@ -33,12 +34,14 @@ function bootParams({
33
34
  sessionProfile = null,
34
35
  worktree = null,
35
36
  executeAgentControl = null,
37
+ executeSessionControl = null,
36
38
  } = {}) {
37
39
  return {
38
40
  provider,
39
41
  model,
40
42
  effort,
41
43
  fast,
44
+ autoEffort,
42
45
  modelParameters,
43
46
  contextPercent,
44
47
  contextTokens,
@@ -55,6 +58,7 @@ function bootParams({
55
58
  // Creation-time worktree intent (workspace/transitions.mjs creationIntent).
56
59
  worktree,
57
60
  executeAgentControl,
61
+ executeSessionControl,
58
62
  };
59
63
  }
60
64
 
@@ -31,6 +31,7 @@ export function createRuntimeFacade({
31
31
  const currentSessionId = () => state.session?.id || state.reservedSessionId || state.addressedSessionId || null;
32
32
  return {
33
33
  ...leadingApi,
34
+ isSessionTerminal: () => state.admission === 'terminal',
34
35
  /** Bind the durable address to the conversation this runtime just
35
36
  * loaded (resume / load-on-demand). Idempotent for the same id. */
36
37
  bindSessionAddress(sessionId) {
@@ -135,6 +136,11 @@ export function createRuntimeFacade({
135
136
  get session() {
136
137
  return state.session;
137
138
  },
139
+ /** Advances whenever another conversation (or none) is installed; a route
140
+ * selection captures it when enqueued (see model-route/route-ownership). */
141
+ get sessionGeneration() {
142
+ return state.sessionGeneration;
143
+ },
138
144
  contextStatus(options) {
139
145
  return getContextStatus(options);
140
146
  },
@@ -111,6 +111,7 @@ function cleanStage(value) {
111
111
  }
112
112
 
113
113
  function describeLastProgress({ stage, snapshot, runtime, silentFor, lastToolCall, now }) {
114
+ if (snapshot?.awaitingModelResponse) return 'model thinking (request sent; awaiting response headers)';
114
115
  if (snapshot?.waitingForTransport) return 'awaiting model transport';
115
116
  if (snapshot?.waitingForFirstSemantic) {
116
117
  return 'transport active; awaiting first model event';
@@ -169,6 +170,7 @@ function describeAgentDiagnostic({ taskStatus, sessionStatus, stage, snapshot, s
169
170
  if (abortErr) return `stale: ${abortErr.message.replace(/^agent /i, '')}`;
170
171
  }
171
172
 
173
+ if (snapshot?.awaitingModelResponse) return 'model thinking; request sent, response headers pending';
172
174
  if (snapshot?.waitingForTransport) return 'waiting for model transport';
173
175
  if (snapshot?.waitingForFirstSemantic) {
174
176
  return 'transport healthy; waiting for first semantic model event';
@@ -10,9 +10,6 @@ export function createCloseAll({ registry, close }) {
10
10
  const { tags, tagAgents, tagCwds } = registry;
11
11
 
12
12
  function resetLocalTagState() {
13
- for (const timer of registry.reapTimers.values()) clearTimeout(timer);
14
- registry.reapTimers.clear();
15
- registry.clearScheduledReaps();
16
13
  tags.clear();
17
14
  tagAgents.clear();
18
15
  tagCwds.clear();
@@ -58,21 +58,20 @@ export function createCloseFlow({ mgr, registry, views }) {
58
58
  if (isLeadPoolAgent(registry.getLiveSession(sessionId)?.agent)) {
59
59
  throw new Error(`agent close: target "${target}" is a Lead session`);
60
60
  }
61
- registry.cancelReap(sessionId);
62
61
  const descendantSessionIds =
63
62
  typeof mgr.descendantSessionIds === 'function' ? mgr.descendantSessionIds(sessionId) : [];
64
63
  const tag = registry.tagForSession(sessionId);
65
64
  clearAgentStatuslineRoute(sessionId);
66
65
  cancelSessionTasks(sessionId, target, scopedContext);
67
- // Close (and stamp cancelStatus) BEFORE dropping the worker row. Removing
68
- // the row first left the next pool read with only a leftover heartbeat,
69
- // which republished the session as `running`. The explicit task_id cancel
66
+ // Close (and stamp cancelStatus) BEFORE dropping the worker row, so the
67
+ // row never outlives an unrecorded cancel. The explicit task_id cancel
70
68
  // below is an idempotent no-op fallback once terminal.
71
- const ok = await mgr.closeSession(sessionId, 'cli-agent-close');
69
+ // Closing a runtime cancels its work; only explicit session deletion
70
+ // may tombstone the conversation.
71
+ const ok = await mgr.closeSession(sessionId, 'cli-agent-close', { tombstone: false });
72
72
  if (task?.taskId) cancelBackgroundTask(task.taskId, CLOSE_REASON);
73
73
  // Drop the row only once the cancellation is DURABLY recorded: a failed
74
- // close that still forgot the row left a fresh heartbeat with no cancelled
75
- // state — the exact lingering row this path exists to prevent.
74
+ // close that still forgot the row would leave no cancelled state behind.
76
75
  if (ok) {
77
76
  registry.forgetTerminalSession(tag, sessionId);
78
77
  for (const descendantSessionId of descendantSessionIds) {