mixdog 1.3.1 → 1.3.3

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 (468) hide show
  1. package/README.md +8 -4
  2. package/package.json +8 -8
  3. package/scripts/native-release-status.mjs +238 -0
  4. package/scripts/verify-runtime-dependency-versions.mjs +158 -0
  5. package/src/agents/reviewer/AGENT.md +5 -7
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +9 -1
  8. package/src/defaults/skills/browser-use/SKILL.md +6 -3
  9. package/src/defaults/skills/local-provider/SKILL.md +33 -6
  10. package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
  11. package/src/defaults/skills/setup/SKILL.md +23 -1
  12. package/src/defaults/skills/setup/references/actions.md +50 -3
  13. package/src/defaults/skills/setup/references/surfaces.md +23 -3
  14. package/src/defaults/skills/setup-guide/SKILL.md +7 -3
  15. package/src/defaults/skills/visualize/SKILL.md +9 -6
  16. package/src/defaults/skills/visualize/references/craft.md +8 -1
  17. package/src/help.mjs +1 -1
  18. package/src/lib/keychain-cjs.cjs +4 -1
  19. package/src/lib/rules-builder.cjs +14 -7
  20. package/src/rules/agent-mode/AGENT_MODE.md +8 -5
  21. package/src/rules/agent-mode/MIXY.md +6 -8
  22. package/src/rules/lead/LEAD.md +7 -10
  23. package/src/rules/shared/10-tool-workflow.md +4 -0
  24. package/src/rules/shared/20-research.md +2 -0
  25. package/src/rules/shared/45-destructive.md +5 -1
  26. package/src/rules/shared/60-verification.md +6 -4
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
  29. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
  30. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
  31. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
  32. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
  33. package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
  34. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
  35. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
  37. package/src/runtime/agent/orchestrator/config.mjs +11 -0
  38. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
  39. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
  40. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
  41. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +84 -32
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
  45. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
  46. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +84 -42
  48. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
  49. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
  50. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
  51. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
  52. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
  54. package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
  55. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
  56. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
  57. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
  59. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
  60. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
  62. package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
  64. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
  65. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
  67. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
  68. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
  69. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
  70. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
  72. package/src/runtime/agent/orchestrator/providers/registry.mjs +19 -0
  73. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
  74. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
  75. package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
  76. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
  78. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
  79. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
  81. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
  82. package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
  83. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +52 -6
  85. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +35 -13
  86. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
  87. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +8 -3
  90. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
  92. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
  93. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
  94. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -2
  95. package/src/runtime/agent/orchestrator/session/agent-room.mjs +196 -45
  96. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
  97. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
  99. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +45 -19
  100. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
  101. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
  102. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +185 -37
  103. package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +6 -2
  107. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +4 -1
  108. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  109. package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
  110. package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +240 -0
  111. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +102 -35
  112. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
  113. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +19 -9
  114. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
  115. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
  116. package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
  117. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
  118. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +199 -109
  119. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
  120. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
  121. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
  123. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
  124. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
  125. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
  126. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -0
  127. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
  128. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +33 -8
  129. package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
  130. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +27 -0
  131. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
  132. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
  133. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
  134. package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
  135. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
  136. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
  137. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
  138. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +27 -14
  139. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +14 -0
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
  143. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
  144. package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +115 -0
  145. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
  146. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
  148. package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
  150. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
  151. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
  155. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
  156. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +4 -9
  157. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +14 -1
  158. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
  160. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
  161. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +52 -11
  163. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +126 -12
  166. package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
  167. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +16 -3
  168. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
  169. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
  170. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
  171. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
  172. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +15 -5
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +49 -1
  178. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +80 -1
  179. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
  180. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
  181. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
  182. package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
  183. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
  184. package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
  185. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
  186. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
  189. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
  190. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +47 -14
  191. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +6 -3
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
  196. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +10 -12
  200. package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
  201. package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
  202. package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
  203. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
  204. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +42 -23
  206. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
  207. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
  208. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
  209. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
  210. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
  211. package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
  212. package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
  213. package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
  214. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
  215. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
  216. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
  217. package/src/runtime/attachments/attachment-reference.mjs +155 -0
  218. package/src/runtime/attachments/legacy-office.mjs +110 -0
  219. package/src/runtime/attachments/limits.mjs +5 -1
  220. package/src/runtime/attachments/office-extract.mjs +3 -6
  221. package/src/runtime/attachments/pdf-extract.mjs +84 -10
  222. package/src/runtime/attachments/prompt-restore.mjs +70 -0
  223. package/src/runtime/attachments/store.mjs +109 -33
  224. package/src/runtime/browser-bridge/client.mjs +73 -20
  225. package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
  226. package/src/runtime/channels/lib/scheduler.mjs +14 -7
  227. package/src/runtime/channels/lib/state-file.mjs +15 -15
  228. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
  229. package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
  230. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
  231. package/src/runtime/channels/lib/worker-main.mjs +3 -2
  232. package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
  233. package/src/runtime/effort-judge/judge-client.mjs +66 -16
  234. package/src/runtime/effort-judge/model-install.mjs +47 -7
  235. package/src/runtime/local-provider/asset-installer.mjs +10 -4
  236. package/src/runtime/local-provider/catalog.mjs +5 -2
  237. package/src/runtime/local-provider/registered-models.mjs +64 -27
  238. package/src/runtime/local-provider/server.mjs +2 -3
  239. package/src/runtime/media/adapters/image-api.mjs +89 -0
  240. package/src/runtime/media/auth.mjs +64 -1
  241. package/src/runtime/media/catalog.mjs +66 -4
  242. package/src/runtime/media/jobs.mjs +4 -0
  243. package/src/runtime/media/lanes.mjs +46 -5
  244. package/src/runtime/media/media-usage.mjs +17 -0
  245. package/src/runtime/media/renditions.mjs +15 -15
  246. package/src/runtime/media/store.mjs +36 -35
  247. package/src/runtime/media/tool.mjs +8 -1
  248. package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
  249. package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
  250. package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
  251. package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
  252. package/src/runtime/memory/lib/pg/process.mjs +8 -4
  253. package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
  254. package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
  255. package/src/runtime/office/core/journal.mjs +7 -14
  256. package/src/runtime/office/design/library/design-library-core.mjs +4 -16
  257. package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
  258. package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
  259. package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
  260. package/src/runtime/office/pdf/pdf-render.mjs +30 -18
  261. package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
  262. package/src/runtime/office/portable/portable-soffice.mjs +135 -29
  263. package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
  264. package/src/runtime/shared/agent-avatar.mjs +3 -2
  265. package/src/runtime/shared/agent-kind-migration.mjs +200 -0
  266. package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
  267. package/src/runtime/shared/agent-message-envelope.mjs +44 -0
  268. package/src/runtime/shared/agent-reap-state.d.mts +4 -0
  269. package/src/runtime/shared/agent-room-host.d.mts +31 -0
  270. package/src/runtime/shared/agent-room-host.mjs +58 -0
  271. package/src/runtime/shared/agent-store.mjs +24 -7
  272. package/src/runtime/shared/agent-task-starts.mjs +27 -0
  273. package/src/runtime/shared/atomic-file.d.mts +50 -0
  274. package/src/runtime/shared/atomic-file.mjs +394 -132
  275. package/src/runtime/shared/background-tasks.mjs +7 -4
  276. package/src/runtime/shared/bot-hops.mjs +35 -0
  277. package/src/runtime/shared/bot-split-migration.mjs +1 -1
  278. package/src/runtime/shared/bounded-download.mjs +4 -2
  279. package/src/runtime/shared/config.mjs +39 -9
  280. package/src/runtime/shared/defaults-separation.mjs +6 -2
  281. package/src/runtime/shared/delegated-approval-host.mjs +74 -0
  282. package/src/runtime/shared/err-text.mjs +4 -0
  283. package/src/runtime/shared/error-presentation.mjs +22 -4
  284. package/src/runtime/shared/file-has-data.mjs +28 -0
  285. package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
  286. package/src/runtime/shared/pending-agent-work.mjs +54 -0
  287. package/src/runtime/shared/process-lifecycle.mjs +8 -12
  288. package/src/runtime/shared/projects.mjs +50 -41
  289. package/src/runtime/shared/provider-accounts.mjs +17 -12
  290. package/src/runtime/shared/redact-directories.mjs +18 -0
  291. package/src/runtime/shared/remove-directory.mjs +28 -0
  292. package/src/runtime/shared/routine-trigger.d.mts +6 -1
  293. package/src/runtime/shared/routine-trigger.mjs +14 -6
  294. package/src/runtime/shared/run-child.d.mts +3 -0
  295. package/src/runtime/shared/run-child.mjs +24 -3
  296. package/src/runtime/shared/session-baseline-store.mjs +8 -2
  297. package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
  298. package/src/runtime/shared/session-sidebar-host.mjs +16 -3
  299. package/src/runtime/shared/singleton-owner.mjs +7 -6
  300. package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
  301. package/src/runtime/shared/staged-update.mjs +4 -2
  302. package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
  303. package/src/runtime/shared/tool-execution-contract.mjs +10 -0
  304. package/src/runtime/shared/tool-work-units.mjs +12 -9
  305. package/src/runtime/shared/transcript-metadata.mjs +28 -3
  306. package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
  307. package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
  308. package/src/runtime/shared/turn-snapshot.mjs +277 -124
  309. package/src/runtime/shared/user-cwd.mjs +9 -4
  310. package/src/runtime/shared/user-data-guard.mjs +92 -61
  311. package/src/runtime/shared/utf8-cut.mjs +10 -0
  312. package/src/runtime/shared/worktrees/activity-gate.mjs +251 -61
  313. package/src/runtime/shared/worktrees/contract.mjs +11 -3
  314. package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
  315. package/src/runtime/shared/worktrees/manager.mjs +419 -52
  316. package/src/runtime/shared/worktrees/registry.mjs +29 -27
  317. package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
  318. package/src/runtime/tidy/core-install.mjs +26 -4
  319. package/src/runtime/tidy/install.mjs +91 -23
  320. package/src/runtime/tidy/process.mjs +41 -8
  321. package/src/runtime/tidy/resolve.mjs +10 -7
  322. package/src/runtime/web-search/lib/config.mjs +4 -16
  323. package/src/session-runtime/agent-home-delivery.mjs +542 -204
  324. package/src/session-runtime/agent-profile-changes.mjs +16 -0
  325. package/src/session-runtime/agent-room-delivery.mjs +81 -35
  326. package/src/session-runtime/agent-task-sessions.mjs +811 -179
  327. package/src/session-runtime/agent-tool-routing.mjs +1 -0
  328. package/src/session-runtime/boot/apis.mjs +48 -24
  329. package/src/session-runtime/boot/config.mjs +1 -0
  330. package/src/session-runtime/boot/facade.mjs +16 -7
  331. package/src/session-runtime/boot/infrastructure.mjs +14 -2
  332. package/src/session-runtime/boot/providers.mjs +2 -2
  333. package/src/session-runtime/boot/shared.mjs +12 -6
  334. package/src/session-runtime/boot/tools.mjs +23 -3
  335. package/src/session-runtime/bot-status.mjs +432 -0
  336. package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
  337. package/src/session-runtime/config-lifecycle.mjs +60 -55
  338. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
  339. package/src/session-runtime/held-requests.mjs +31 -33
  340. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
  341. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
  342. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +24 -26
  343. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  344. package/src/session-runtime/lifecycle/teardown.mjs +11 -3
  345. package/src/session-runtime/mcp-glue/connect.mjs +100 -186
  346. package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
  347. package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
  348. package/src/session-runtime/media-api.mjs +5 -2
  349. package/src/session-runtime/model-recency.mjs +1 -0
  350. package/src/session-runtime/model-route/route-tuning.mjs +4 -1
  351. package/src/session-runtime/model-route/set-route.mjs +61 -1
  352. package/src/session-runtime/owned-automation-run.mjs +8 -1
  353. package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
  354. package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
  355. package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
  356. package/src/session-runtime/route-resolution.mjs +16 -8
  357. package/src/session-runtime/route-state.mjs +1 -59
  358. package/src/session-runtime/routine-home-turn.mjs +5 -3
  359. package/src/session-runtime/runtime-bootstrap.mjs +5 -3
  360. package/src/session-runtime/runtime-paths.mjs +11 -5
  361. package/src/session-runtime/runtime-review-api.mjs +4 -1
  362. package/src/session-runtime/runtime-tunables.mjs +6 -0
  363. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
  364. package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
  365. package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
  366. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
  367. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
  368. package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
  369. package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
  370. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +7 -0
  371. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
  372. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
  373. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
  374. package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
  375. package/src/session-runtime/services/agent-tool.mjs +6 -0
  376. package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
  377. package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
  378. package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
  379. package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
  380. package/src/session-runtime/services/plugin-admin.mjs +26 -26
  381. package/src/session-runtime/services/provider-admin.mjs +26 -6
  382. package/src/session-runtime/services/schedule-access.mjs +33 -4
  383. package/src/session-runtime/services/seeds.mjs +4 -3
  384. package/src/session-runtime/services/usage-dashboard.mjs +1 -1
  385. package/src/session-runtime/services/usage-stats-model.mjs +2 -1
  386. package/src/session-runtime/services/worktree-access.mjs +27 -0
  387. package/src/session-runtime/session-create/materialize.mjs +2 -3
  388. package/src/session-runtime/session-create/session-options.mjs +15 -2
  389. package/src/session-runtime/session-hooks.mjs +9 -17
  390. package/src/session-runtime/settings-builtin-tools-api.mjs +65 -1
  391. package/src/session-runtime/settings-compaction-api.mjs +86 -39
  392. package/src/session-runtime/setup-tool/executor.mjs +12 -2
  393. package/src/session-runtime/setup-tool/settings-contract.mjs +34 -1
  394. package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
  395. package/src/session-runtime/skills-api.mjs +12 -5
  396. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +349 -0
  397. package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
  398. package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
  399. package/src/session-runtime/tool-policy/policy-stage.mjs +183 -0
  400. package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
  401. package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
  402. package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
  403. package/src/session-runtime/tool-policy-refresh.mjs +48 -369
  404. package/src/session-runtime/tool-surface.mjs +10 -4
  405. package/src/session-runtime/turn/session-ops.mjs +8 -0
  406. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
  407. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  408. package/src/session-runtime/turn/turn-run.mjs +7 -2
  409. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
  410. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +527 -333
  411. package/src/session-runtime/workflow-agents-api/agent-route.mjs +85 -63
  412. package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
  413. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
  414. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
  415. package/src/session-runtime/workspace/transition-steps.mjs +1 -18
  416. package/src/session-runtime/workspace/transitions.mjs +279 -67
  417. package/src/session-runtime/workspace/workspace-state.mjs +7 -6
  418. package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
  419. package/src/standalone/daemon-agent-control.mjs +4 -1
  420. package/src/standalone/daemon-lag-profiler.mjs +3 -1
  421. package/src/standalone/daemon-session-control.mjs +173 -15
  422. package/src/standalone/daemon-telemetry.mjs +9 -0
  423. package/src/standalone/daemon.mjs +33 -10
  424. package/src/standalone/local-session-runtime.mjs +33 -16
  425. package/src/standalone/session-client.mjs +7 -2
  426. package/src/standalone/session-protocol.mjs +8 -0
  427. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
  428. package/src/standalone/session-service/agent-route-follow.mjs +69 -0
  429. package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
  430. package/src/standalone/session-service.mjs +21 -0
  431. package/src/standalone/session-state-projection.mjs +19 -9
  432. package/src/standalone/session-tool-output.mjs +36 -9
  433. package/src/standalone/staged-import.mjs +47 -0
  434. package/src/tui/App.jsx +2 -0
  435. package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
  436. package/src/tui/app/message-selector.mjs +15 -2
  437. package/src/tui/app/model-options.mjs +16 -2
  438. package/src/tui/app/model-picker.mjs +2 -1
  439. package/src/tui/app/route-pickers.mjs +3 -1
  440. package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
  441. package/src/tui/app/slash-commands.mjs +1 -1
  442. package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
  443. package/src/tui/dist/index.mjs +617 -369
  444. package/src/tui/paste-attachments.mjs +0 -1
  445. package/src/tui/paste-text-policy.mjs +4 -5
  446. package/src/tui/prompt-history-store.mjs +16 -21
  447. package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
  448. package/src/tui/session/context-state.mjs +4 -0
  449. package/src/tui/session/notice-surface.mjs +3 -0
  450. package/src/tui/session/session-api/intake/abort.mjs +52 -18
  451. package/src/tui/session/session-api/intake/rewind.mjs +39 -4
  452. package/src/tui/session/session-api/media.mjs +2 -1
  453. package/src/tui/session/session-api/routes-agent-definitions.mjs +76 -0
  454. package/src/tui/session/session-api/routes-write.mjs +203 -0
  455. package/src/tui/session/session-api/routes.mjs +23 -247
  456. package/src/tui/session/session-api/settings.mjs +14 -1
  457. package/src/tui/session/session-flow/drain.mjs +28 -3
  458. package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
  459. package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
  460. package/src/tui/session/session-flow/steering.mjs +8 -3
  461. package/src/tui/session/tool-approval.mjs +142 -14
  462. package/src/tui/session/transcript-intake.mjs +2 -0
  463. package/src/tui/session/turn.mjs +23 -14
  464. package/src/tui/transcript-tool-failures.mjs +8 -2
  465. package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
  466. package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
  467. package/src/rules/agent-mode/ROUTINE.md +0 -6
  468. package/src/session-runtime/room-member-gate.mjs +0 -48
@@ -10,6 +10,7 @@
10
10
  * anthropic-turn-result.mjs); nothing here touches the socket.
11
11
  */
12
12
  import { prepareAnthropicImages } from './lib/anthropic-image-input.mjs';
13
+ import { anthropicPrefixFingerprint, recordAnthropicPrefix } from './lib/anthropic-prefix-trace.mjs';
13
14
  import { buildAnthropicBetaHeaders, supportsAnthropicFastMode } from './anthropic-betas.mjs';
14
15
  import { applyAnthropicServerFallback } from './anthropic-server-fallback.mjs';
15
16
  import { fastModeAvailable } from './anthropic-fast-mode.mjs';
@@ -17,6 +18,7 @@ import { applyAnthropicEffortToBody, shouldIncludeEffortBeta } from './anthropic
17
18
  import { isCustomProviderName, resolveCustomReasoning } from './custom-reasoning.mjs';
18
19
  import {
19
20
  anthropicThinkingActive,
21
+ appendAnthropicTailReminder,
20
22
  applyAnthropicCacheMarkers,
21
23
  clampAnthropicThinkingBudget as clampThinkingBudgetTokens,
22
24
  resolveAnthropicCacheTtls as resolveCacheTtls,
@@ -24,6 +26,7 @@ import {
24
26
  sharedCachePrefixBoundary,
25
27
  toAnthropicToolChoice,
26
28
  } from './lib/anthropic-request-utils.mjs';
29
+ import { splitTailReminder } from './lib/tail-reminder-split.mjs';
27
30
  import {
28
31
  buildSystemBlocks,
29
32
  resolveMaxTokens,
@@ -50,7 +53,7 @@ import {
50
53
  export async function buildAnthropicApiRequest({
51
54
  name,
52
55
  config,
53
- messages,
56
+ messages: requestMessages,
54
57
  useModel,
55
58
  tools,
56
59
  opts,
@@ -67,7 +70,11 @@ export async function buildAnthropicApiRequest({
67
70
  // the global by-model-id capability index and the Claude-id ladders are
68
71
  // first-party knowledge and must not leak onto (or from) a custom endpoint.
69
72
  const isCustom = isCustomProviderName(name);
70
- const maxTokens = resolveMaxTokens(capabilityModel, { modelMaxOutputTokens });
73
+ const { messages, reminder } = splitTailReminder(requestMessages);
74
+ const maxTokens = resolveMaxTokens(capabilityModel, {
75
+ modelMaxOutputTokens,
76
+ override: opts?.maxOutputTokensOverride,
77
+ });
71
78
  const effortOptions = { ...config, ...opts, disableBetaHeaders: config?.disableBetaHeaders };
72
79
  const gatewayEffort = typeof config?.messagesEffort === 'function' ? config.messagesEffort(opts) : null;
73
80
  const effortProjection = projectEffortConfiguration(messages, name, useModel, effortOptions);
@@ -108,7 +115,9 @@ export async function buildAnthropicApiRequest({
108
115
  model: useModel,
109
116
  max_tokens: maxTokens,
110
117
  system: systemBlocks.length ? systemBlocks : undefined,
111
- messages: await prepareAnthropicImages(anthropicMessages, { signal: opts.signal }),
118
+ messages: await prepareAnthropicImages(appendAnthropicTailReminder(anthropicMessages, reminder), {
119
+ signal: opts.signal,
120
+ }),
112
121
  };
113
122
  // Server-side fallback and fast mode are decided from Claude model ids:
114
123
  // first-party knowledge, never applied to a custom endpoint.
@@ -135,6 +144,55 @@ export async function buildAnthropicApiRequest({
135
144
  .map((t) => (t && typeof t.name === 'string' ? t.name : null))
136
145
  .filter(Boolean)
137
146
  );
147
+ applyRequestReasoning(params, {
148
+ isCustom,
149
+ name,
150
+ config,
151
+ opts,
152
+ modelInfo,
153
+ capabilityModel,
154
+ maxTokens,
155
+ gatewayEffort,
156
+ effortProjection,
157
+ });
158
+ if (params.tools) resolveRequestToolChoice(params, opts, config);
159
+ // Fast mode → speed: "fast" on models Anthropic marks as speed-capable.
160
+ // Suppressed while the fast capacity pool is cooling down.
161
+ let fastLatched = fastModeLatched;
162
+ if (!isCustom && opts.fast === true && supportsAnthropicFastMode(useModel) && fastModeAvailable()) {
163
+ params.speed = 'fast';
164
+ fastLatched = true;
165
+ }
166
+ // NOTE: do NOT sanitize here. params.messages was already sanitized
167
+ // once inside toAnthropicMessages and then had cache markers applied.
168
+ // Re-sanitizing after marking could drop/reorder a marked block and
169
+ // move the provider-visible cache breakpoint off the cached one — the
170
+ // exact COLD-turn bug this change fixes. Order: build → sanitize
171
+ // (once) → mark → prepare image bytes → send.
172
+ params.stream = true;
173
+ // Diagnostic: per-block prefix hashes of exactly what is sent.
174
+ recordAnthropicPrefix(opts.sessionId || opts.session?.id || null, anthropicPrefixFingerprint(params));
175
+
176
+ const requestHeaders = requestHeadersFor(params, {
177
+ config,
178
+ opts,
179
+ isCustom,
180
+ fastLatched,
181
+ hasDeferredTools,
182
+ capabilityModel,
183
+ effortProjection,
184
+ });
185
+
186
+ return { params, requestHeaders, knownToolNames, fastModeLatched: fastLatched };
187
+ }
188
+
189
+ /** The turn's thinking/effort fields on `params` (in place): a custom
190
+ * provider's from its own model row, else the turn effort (or a gateway's
191
+ * own `messagesEffort`; 'none' sends no thinking at all). */
192
+ function applyRequestReasoning(
193
+ params,
194
+ { isCustom, name, config, opts, modelInfo, capabilityModel, maxTokens, gatewayEffort, effortProjection }
195
+ ) {
138
196
  if (isCustom) {
139
197
  const { fields } = resolveCustomReasoning({
140
198
  protocol: 'anthropic',
@@ -156,32 +214,29 @@ export async function buildAnthropicApiRequest({
156
214
  progressUpdates: config?.disableBetaHeaders !== true,
157
215
  });
158
216
  }
159
- if (params.tools) {
160
- const toolChoice = toAnthropicToolChoice(opts.toolChoice, {
161
- thinking: anthropicThinkingActive(params),
162
- disableParallelToolUse: opts.disableParallelToolUse === true,
163
- // A gateway that cannot honour disable_parallel_tool_use declares so.
164
- supportsDisableParallelToolUse: config?.supportsDisableParallelToolUse !== false,
165
- onThinkingConflict: opts.toolChoiceThinkingConflict,
166
- });
167
- if (toolChoice) params.tool_choice = toolChoice;
168
- else delete params.tool_choice;
169
- }
170
- // Fast mode → speed: "fast" on models Anthropic marks as speed-capable.
171
- // Suppressed while the fast capacity pool is cooling down.
172
- let fastLatched = fastModeLatched;
173
- if (!isCustom && opts.fast === true && supportsAnthropicFastMode(useModel) && fastModeAvailable()) {
174
- params.speed = 'fast';
175
- fastLatched = true;
176
- }
177
- // NOTE: do NOT sanitize here. params.messages was already sanitized
178
- // once inside toAnthropicMessages and then had cache markers applied.
179
- // Re-sanitizing after marking could drop/reorder a marked block and
180
- // move the provider-visible cache breakpoint off the cached one — the
181
- // exact COLD-turn bug this change fixes. Order: build → sanitize
182
- // (once) → mark → prepare image bytes → send.
183
- params.stream = true;
217
+ }
184
218
 
219
+ /** The reserved `tool_choice` of a request with tools, resolved once
220
+ * thinking is known (forced any/tool is invalid while thinking is on);
221
+ * dropped when none applies. */
222
+ function resolveRequestToolChoice(params, opts, config) {
223
+ const toolChoice = toAnthropicToolChoice(opts.toolChoice, {
224
+ thinking: anthropicThinkingActive(params),
225
+ disableParallelToolUse: opts.disableParallelToolUse === true,
226
+ // A gateway that cannot honour disable_parallel_tool_use declares so.
227
+ supportsDisableParallelToolUse: config?.supportsDisableParallelToolUse !== false,
228
+ onThinkingConflict: opts.toolChoiceThinkingConflict,
229
+ });
230
+ if (toolChoice) params.tool_choice = toolChoice;
231
+ else delete params.tool_choice;
232
+ }
233
+
234
+ /** The per-request headers of the final body `params`: the anthropic-beta
235
+ * set it needs, then the caller's `opts.requestHeaders`; null when none. */
236
+ function requestHeadersFor(
237
+ params,
238
+ { config, opts, isCustom, fastLatched, hasDeferredTools, capabilityModel, effortProjection }
239
+ ) {
185
240
  // Per-call headers override the client defaultHeaders, so the
186
241
  // constructor-level disableBetaHeaders opt-out must be honoured here
187
242
  // too — otherwise opencode-go's anthropic-compatible routing
@@ -205,8 +260,5 @@ export async function buildAnthropicApiRequest({
205
260
  ].filter(Boolean);
206
261
  if (betas.length) betaHeaders = { 'anthropic-beta': betas.join(',') };
207
262
  }
208
- const requestHeaders =
209
- betaHeaders || opts.requestHeaders ? { ...(betaHeaders || {}), ...(opts.requestHeaders || {}) } : null;
210
-
211
- return { params, requestHeaders, knownToolNames, fastModeLatched: fastLatched };
263
+ return betaHeaders || opts.requestHeaders ? { ...(betaHeaders || {}), ...(opts.requestHeaders || {}) } : null;
212
264
  }
@@ -59,16 +59,11 @@ function sharedCatalogOutputTokens(model) {
59
59
  return Number.isFinite(declared) && declared > 0 ? declared : null;
60
60
  }
61
61
 
62
- // catalogLookup(model) -> number|null. Providers supply their own strategy
63
- // for sourcing the catalog array (in-memory mirror + disk fallback for OAuth,
64
- // plain disk read for the API-key twin — see anthropic.mjs).
65
- //
66
- // `modelMaxOutputTokens` (number|null): a gateway-supplied model limit. When
67
- // positive it takes precedence over every catalog lookup. A declared model
68
- // maximum is a ceiling: it is never raised to the floor, and the env override
69
- // is capped by it.
70
- export function resolveAnthropicMaxTokens(model, { catalogLookup, modelMaxOutputTokens = null } = {}) {
71
- const isLimit = (value) => Number.isFinite(value) && value > 0;
62
+ const isLimit = (value) => Number.isFinite(value) && value > 0;
63
+
64
+ // The model's declared output limit (gateway value, then catalogs), unclamped
65
+ // by the safety cap; null when nothing declares one.
66
+ function declaredOutputLimit(model, { catalogLookup, modelMaxOutputTokens }) {
72
67
  let declared = Number(modelMaxOutputTokens);
73
68
  if (!isLimit(declared)) {
74
69
  declared = null;
@@ -81,7 +76,39 @@ export function resolveAnthropicMaxTokens(model, { catalogLookup, modelMaxOutput
81
76
  }
82
77
  if (!isLimit(declared)) declared = sharedCatalogOutputTokens(model);
83
78
  }
84
- declared = isLimit(declared) ? Math.floor(declared) : null;
79
+ return isLimit(declared) ? Math.floor(declared) : null;
80
+ }
81
+
82
+ /**
83
+ * The larger max_tokens to retry a turn with after it spent the whole normal
84
+ * budget: the model's declared output limit when it exceeds what a normal
85
+ * request carries, else null (nothing higher to try). An explicit env override
86
+ * is the user's chosen ceiling and is never escalated past.
87
+ */
88
+ export function resolveAnthropicEscalatedMaxTokens(model, { catalogLookup, modelMaxOutputTokens = null } = {}) {
89
+ if (envAnthropicMaxOutputOverride() != null) return null;
90
+ const declared = declaredOutputLimit(model, { catalogLookup, modelMaxOutputTokens });
91
+ if (declared == null) return null;
92
+ const current = resolveAnthropicMaxTokens(model, { catalogLookup, modelMaxOutputTokens });
93
+ return declared > current ? declared : null;
94
+ }
95
+
96
+ // catalogLookup(model) -> number|null. Providers supply their own strategy
97
+ // for sourcing the catalog array (in-memory mirror + disk fallback for OAuth,
98
+ // plain disk read for the API-key twin — see anthropic.mjs).
99
+ //
100
+ // `modelMaxOutputTokens` (number|null): a gateway-supplied model limit. When
101
+ // positive it takes precedence over every catalog lookup. A declared model
102
+ // maximum is a ceiling: it is never raised to the floor, and the env override
103
+ // is capped by it.
104
+ //
105
+ // `override` (number|null): a one-shot request for a specific max_tokens (the
106
+ // loop's output-limit escalation). When positive it wins outright; the caller
107
+ // derives it from resolveAnthropicEscalatedMaxTokens, which already respects
108
+ // the declared model limit.
109
+ export function resolveAnthropicMaxTokens(model, { catalogLookup, modelMaxOutputTokens = null, override = null } = {}) {
110
+ if (isLimit(Number(override))) return Math.floor(Number(override));
111
+ const declared = declaredOutputLimit(model, { catalogLookup, modelMaxOutputTokens });
85
112
  const envOverride = envAnthropicMaxOutputOverride();
86
113
  if (envOverride != null) return declared == null ? envOverride : Math.min(envOverride, declared);
87
114
  if (declared != null) return Math.min(declared, DEFAULT_SAFETY_CAP);
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'node:module';
3
3
  import { effortValuesForModel, thinkingTypesFromCapabilities } from './anthropic-effort.mjs';
4
4
  import { makeModelCache } from './model-cache.mjs';
5
- import { resolveAnthropicMaxTokens } from './anthropic-max-tokens.mjs';
5
+ import { resolveAnthropicEscalatedMaxTokens, resolveAnthropicMaxTokens } from './anthropic-max-tokens.mjs';
6
6
  import {
7
7
  deferredAnthropicTools as sharedDeferredAnthropicTools,
8
8
  requestAnthropicTools as sharedRequestAnthropicTools,
@@ -130,8 +130,20 @@ function _catalogOutputTokensFromSharedCache(model) {
130
130
  }
131
131
  }
132
132
 
133
- export function resolveMaxTokens(model, { modelMaxOutputTokens = null } = {}) {
134
- return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokensFromSharedCache, modelMaxOutputTokens });
133
+ export function resolveMaxTokens(model, { modelMaxOutputTokens = null, override = null } = {}) {
134
+ return resolveAnthropicMaxTokens(model, {
135
+ catalogLookup: _catalogOutputTokensFromSharedCache,
136
+ modelMaxOutputTokens,
137
+ override,
138
+ });
139
+ }
140
+
141
+ // The higher max_tokens an output-limit retry may use for `model`, or null.
142
+ export function resolveEscalatedMaxTokens(model, { modelMaxOutputTokens = null } = {}) {
143
+ return resolveAnthropicEscalatedMaxTokens(model, {
144
+ catalogLookup: _catalogOutputTokensFromSharedCache,
145
+ modelMaxOutputTokens,
146
+ });
135
147
  }
136
148
 
137
149
  // Test-only escape hatch for the provider contract scripts
@@ -149,7 +149,7 @@ function _markLatestByFamily(models) {
149
149
  for (const m of byFamily.values()) m.latest = true;
150
150
  }
151
151
 
152
- function _compareVersion(a, b) {
152
+ export function _compareVersion(a, b) {
153
153
  const na = (a.match(/^claude-[a-z]+-(\d+)(?:-(\d+))?/i) || []).slice(1).map(Number);
154
154
  const nb = (b.match(/^claude-[a-z]+-(\d+)(?:-(\d+))?/i) || []).slice(1).map(Number);
155
155
  for (let i = 0; i < Math.max(na.length, nb.length); i++) {
@@ -10,7 +10,7 @@ import { createNpmVersionSource, maxSemver } from './npm-cli-version.mjs';
10
10
  // source release just to advance the user-agent version.
11
11
  // Claude Opus 5.5 requires 2.1.280 or newer. The release workflow raises this
12
12
  // to the published CLI version (scripts/sync-client-version-floors.mjs).
13
- export const DEFAULT_CLI_VERSION = '2.1.304';
13
+ export const DEFAULT_CLI_VERSION = '2.1.308';
14
14
  export const CLAUDE_CLI_NPM_PACKAGE = '@anthropic-ai/claude-code';
15
15
 
16
16
  const CACHE_SCHEMA_VERSION = 1;
@@ -6,8 +6,13 @@
6
6
  * from anthropic.mjs. agent-trace instrumented.
7
7
  */
8
8
  import { traceAgentSse, traceAgentUsage } from '../agent-trace.mjs';
9
+ import {
10
+ anthropicPrefixFingerprint,
11
+ latestAnthropicPrefix,
12
+ recordAnthropicPrefix,
13
+ } from './lib/anthropic-prefix-trace.mjs';
9
14
  import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
10
- import { resolveAnthropicMaxTokens } from './anthropic-max-tokens.mjs';
15
+ import { resolveAnthropicEscalatedMaxTokens, resolveAnthropicMaxTokens } from './anthropic-max-tokens.mjs';
11
16
  import { MODELS } from './lib/anthropic-models.mjs';
12
17
  import { systemBlockItems, systemBlockTtl } from './lib/anthropic-system-blocks.mjs';
13
18
  import { prepareAnthropicImages } from './lib/anthropic-image-input.mjs';
@@ -56,6 +61,7 @@ import { ANTHROPIC_EFFORT_LEVELS, withEffortRejectionFallback } from './effort-r
56
61
  import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
57
62
  import {
58
63
  anthropicThinkingActive,
64
+ appendAnthropicTailReminder,
59
65
  applyAnthropicCacheMarkers,
60
66
  clampAnthropicThinkingBudget as clampThinkingBudgetTokens,
61
67
  deferredAnthropicTools as sharedDeferredAnthropicTools,
@@ -67,6 +73,7 @@ import {
67
73
  toAnthropicMessages,
68
74
  toAnthropicToolChoice,
69
75
  } from './lib/anthropic-request-utils.mjs';
76
+ import { splitTailReminder } from './lib/tail-reminder-split.mjs';
70
77
  import {
71
78
  EFFORT_CONFIGURATION_BETA,
72
79
  isEffortConfigurationRejection,
@@ -169,8 +176,8 @@ function buildSystemBlocks(systemMsgs, systemTtl, tier3Ttl) {
169
176
  // clamped to [MAX_TOKENS_FLOOR, safetyCap].
170
177
  // 3. Shared model catalog outputTokens, then the floor, when the live
171
178
  // roster has no entry for this model.
172
- function resolveMaxTokens(model, { modelMaxOutputTokens = null } = {}) {
173
- return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokens, modelMaxOutputTokens });
179
+ function resolveMaxTokens(model, { modelMaxOutputTokens = null, override = null } = {}) {
180
+ return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokens, modelMaxOutputTokens, override });
174
181
  }
175
182
 
176
183
  // --- Message conversion ---
@@ -189,11 +196,15 @@ function requestAnthropicTools(tools, messages, opts) {
189
196
  // the tier3 1h cache_control to that block; BP1/BP2 take the system TTL. No
190
197
  // `<system-reminder>` user message / sentinel scan is involved anymore.
191
198
 
192
- function buildRequestBody(messages, model, tools, sendOpts) {
199
+ function buildRequestBody(requestMessages, model, tools, sendOpts) {
200
+ const { messages, reminder } = splitTailReminder(requestMessages);
193
201
  const systemMsgs = messages.filter((m) => m.role === 'system');
194
202
  const chatMsgs = messages.filter((m) => m.role !== 'system');
195
203
  const opts = sendOpts || {};
196
- const maxTokens = resolveMaxTokens(model, { modelMaxOutputTokens: opts.modelMaxOutputTokens });
204
+ const maxTokens = resolveMaxTokens(model, {
205
+ modelMaxOutputTokens: opts.modelMaxOutputTokens,
206
+ override: opts.maxOutputTokensOverride,
207
+ });
197
208
  const effortProjection = projectEffortConfiguration(messages, 'anthropic-oauth', model, opts);
198
209
  const ttls = resolveCacheTtls(opts);
199
210
  // Each system message becomes its own Anthropic content block with its own
@@ -229,7 +240,7 @@ function buildRequestBody(messages, model, tools, sendOpts) {
229
240
  const body = {
230
241
  model,
231
242
  max_tokens: maxTokens,
232
- messages: anthropicMessages,
243
+ messages: appendAnthropicTailReminder(anthropicMessages, reminder),
233
244
  stream: true,
234
245
  };
235
246
  applyAnthropicServerFallback(body, model, {
@@ -304,6 +315,16 @@ export class AnthropicOAuthProvider {
304
315
  preconnect('https://api.anthropic.com');
305
316
  }
306
317
 
318
+ // The larger max_tokens the loop may retry a max_tokens-truncated turn with
319
+ // (one-shot, via opts.maxOutputTokensOverride), or null when the model has
320
+ // nothing above the normal request.
321
+ escalatedMaxTokens(model, opts = {}) {
322
+ return resolveAnthropicEscalatedMaxTokens(model, {
323
+ catalogLookup: _catalogOutputTokens,
324
+ modelMaxOutputTokens: opts.modelMaxOutputTokens,
325
+ });
326
+ }
327
+
307
328
  async ensureAuth({ forceRefresh = false, reason = 'preemptive' } = {}) {
308
329
  await warmCliVersion();
309
330
  if (!this.credentials) {
@@ -463,6 +484,8 @@ export class AnthropicOAuthProvider {
463
484
  const useModel = model || (await ensureLatestAnthropicModel(this));
464
485
  const body = buildRequestBody(messages, useModel, tools, sendOpts);
465
486
  body.messages = await prepareAnthropicImages(body.messages, { signal: externalSignal });
487
+ // Diagnostic: per-block prefix hashes of exactly what is sent.
488
+ recordAnthropicPrefix(opts.sessionId || null, anthropicPrefixFingerprint(body));
466
489
  if (body.speed === 'fast') {
467
490
  this.fastModeBetaHeaderLatched = true;
468
491
  }
@@ -544,42 +567,15 @@ export class AnthropicOAuthProvider {
544
567
  let maxTokensAdjusted = false;
545
568
  try {
546
569
  for (let attemptIndex = 0; attemptIndex <= ANTHROPIC_MAX_MIDSTREAM_RETRIES; attemptIndex++) {
547
- let response, controller, cancelHandler;
548
- ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
549
-
550
- // Refresh on 401, and only Anthropic's exact official revoked-token
551
- // 403 signature. Ordinary permission/policy 403s are terminal.
552
- let rejectedAuthBody = null;
553
- if (response.status === 401 || response.status === 403) {
554
- rejectedAuthBody = await response.text().catch(() => '');
555
- }
556
- if (isRefreshableAuthRejection(response.status, rejectedAuthBody)) {
557
- process.stderr.write(`[anthropic-oauth] ${response.status} — forcing refresh and retrying once\n`);
558
- cleanupCancelHandler(cancelHandler);
559
- // Body was drained above; abort closes any remaining transport
560
- // resources before the credential-refresh replay.
561
- try {
562
- controller?.abort?.();
563
- } catch {}
564
- auth.creds = await this.ensureAuth({ forceRefresh: true, reason: String(response.status) });
565
- ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
566
- rejectedAuthBody = null;
567
- }
568
-
569
- // "input length and max_tokens exceed context limit": shrink max_tokens
570
- // to what the context has room for and replay once.
571
- if (response.status === 400 && !maxTokensAdjusted) {
572
- rejectedAuthBody = await response.text().catch(() => '');
573
- if (adjustMaxTokensForContextOverflow(body, 400, rejectedAuthBody)) {
574
- maxTokensAdjusted = true;
575
- cleanupCancelHandler(cancelHandler);
576
- try {
577
- controller?.abort?.();
578
- } catch {}
579
- ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
580
- rejectedAuthBody = null;
581
- }
582
- }
570
+ const opened = await this._openResponse({
571
+ requestWithRetry,
572
+ cleanupCancelHandler,
573
+ auth,
574
+ body,
575
+ maxTokensAdjusted,
576
+ });
577
+ const { response, controller, cancelHandler, rejectedAuthBody } = opened;
578
+ maxTokensAdjusted = opened.maxTokensAdjusted;
583
579
  if (!response.ok) {
584
580
  cleanupCancelHandler(cancelHandler);
585
581
  return await this._resendAfterRejection({
@@ -657,6 +653,51 @@ export class AnthropicOAuthProvider {
657
653
  }
658
654
  }
659
655
 
656
+ // One attempt's initial response: a 401 (or Anthropic's exact revoked-token
657
+ // 403) refreshes the credentials in `auth` and replays once; a context
658
+ // overflow 400 shrinks `body.max_tokens` and replays once per send
659
+ // (`maxTokensAdjusted`). `rejectedAuthBody`: the drained text of a final
660
+ // rejected response, null when none was read.
661
+ async _openResponse({ requestWithRetry, cleanupCancelHandler, auth, body, maxTokensAdjusted }) {
662
+ let response, controller, cancelHandler;
663
+ ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
664
+
665
+ // Refresh on 401, and only Anthropic's exact official revoked-token
666
+ // 403 signature. Ordinary permission/policy 403s are terminal.
667
+ let rejectedAuthBody = null;
668
+ if (response.status === 401 || response.status === 403) {
669
+ rejectedAuthBody = await response.text().catch(() => '');
670
+ }
671
+ if (isRefreshableAuthRejection(response.status, rejectedAuthBody)) {
672
+ process.stderr.write(`[anthropic-oauth] ${response.status} — forcing refresh and retrying once\n`);
673
+ cleanupCancelHandler(cancelHandler);
674
+ // Body was drained above; abort closes any remaining transport
675
+ // resources before the credential-refresh replay.
676
+ try {
677
+ controller?.abort?.();
678
+ } catch {}
679
+ auth.creds = await this.ensureAuth({ forceRefresh: true, reason: String(response.status) });
680
+ ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
681
+ rejectedAuthBody = null;
682
+ }
683
+
684
+ // "input length and max_tokens exceed context limit": shrink max_tokens
685
+ // to what the context has room for and replay once.
686
+ if (response.status === 400 && !maxTokensAdjusted) {
687
+ rejectedAuthBody = await response.text().catch(() => '');
688
+ if (adjustMaxTokensForContextOverflow(body, 400, rejectedAuthBody)) {
689
+ maxTokensAdjusted = true;
690
+ cleanupCancelHandler(cancelHandler);
691
+ try {
692
+ controller?.abort?.();
693
+ } catch {}
694
+ ({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
695
+ rejectedAuthBody = null;
696
+ }
697
+ }
698
+ return { response, controller, cancelHandler, rejectedAuthBody, maxTokensAdjusted };
699
+ }
700
+
660
701
  // A non-OK initial response: quota errors surface as-is; a CLI-version
661
702
  // floor or an unknown/retired model replays the turn ONCE through send().
662
703
  async _resendAfterRejection({ response, rejectedAuthBody, messages, model, useModel, tools, opts, onStageChange }) {
@@ -780,6 +821,7 @@ export class AnthropicOAuthProvider {
780
821
  rawUsage: result.usage?.raw || null,
781
822
  provider: 'anthropic-oauth',
782
823
  requestKind,
824
+ prefixBlocks: latestAnthropicPrefix(sessionId),
783
825
  });
784
826
 
785
827
  // Phase I: if the live response surfaced a model id we don't know
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import { traceAgentUsage } from '../agent-trace.mjs';
13
13
  import { reportedCostUsd } from './lib/usage-primitives.mjs';
14
+ import { latestAnthropicPrefix } from './lib/anthropic-prefix-trace.mjs';
14
15
 
15
16
  /**
16
17
  * @param {object} parseResult the assembled turn (streaming or normalized non-streaming)
@@ -47,6 +48,7 @@ export function buildAnthropicTurnResult(parseResult, { provider, useModel, opts
47
48
  // Anthropic usage is additive at this inner transport
48
49
  // boundary, even when OpenCode Go supplies the provider id.
49
50
  inputTokensInclusive: false,
51
+ prefixBlocks: latestAnthropicPrefix(opts.sessionId || opts.session?.id || null),
50
52
  });
51
53
  }
52
54
 
@@ -27,7 +27,12 @@ import { enrichModels } from './model-catalog.mjs';
27
27
  import { sanitizeModelList } from './model-list-sanitize.mjs';
28
28
  import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
29
29
 
30
- import { loadAnthropic, _normalizeAnthropicModel, _setApiKeyCatalogMirror } from './anthropic-messages.mjs';
30
+ import {
31
+ loadAnthropic,
32
+ resolveEscalatedMaxTokens,
33
+ _normalizeAnthropicModel,
34
+ _setApiKeyCatalogMirror,
35
+ } from './anthropic-messages.mjs';
31
36
  import { ANTHROPIC_VERSION, MODELS } from './lib/anthropic-models.mjs';
32
37
  import { streamCallbacks } from './lib/send-callbacks.mjs';
33
38
  import { preparePdfTextForProvider } from './media-normalization.mjs';
@@ -92,6 +97,14 @@ export class AnthropicProvider {
92
97
  _capabilityModel(model) {
93
98
  return model;
94
99
  }
100
+ // The larger max_tokens the loop may retry a max_tokens-truncated turn with
101
+ // (one-shot, via opts.maxOutputTokensOverride), or null when the model has
102
+ // nothing above the normal request.
103
+ escalatedMaxTokens(model, opts = {}) {
104
+ return resolveEscalatedMaxTokens(this._capabilityModel(model), {
105
+ modelMaxOutputTokens: opts.modelMaxOutputTokens ?? null,
106
+ });
107
+ }
95
108
  reloadApiKey() {
96
109
  try {
97
110
  const newKey = reloadProviderApiKey(this.name, this.config);
@@ -3,6 +3,7 @@ import { createProviderReplay, providerReplayItems } from './lib/provider-replay
3
3
  import { toGeminiContents, toGeminiRequestTools, toGeminiToolConfig } from './gemini-schema.mjs';
4
4
  import { geminiThinkingConfig } from './gemini-thinking.mjs';
5
5
  import { isGeminiFamilyModel } from './gemini-family.mjs';
6
+ import { splitTailReminder } from './lib/tail-reminder-split.mjs';
6
7
 
7
8
  const THOUGHT_SIGNATURE_SENTINEL = 'skip_thought_signature_validator';
8
9
  const CLAUDE_MAX_OUTPUT_TOKENS = 64000;
@@ -219,7 +220,10 @@ function antigravityGeminiThinkingConfig(model, opts) {
219
220
  });
220
221
  }
221
222
 
222
- export function buildAntigravityRequest(messages, model, tools, opts = {}, projectId) {
223
+ export function buildAntigravityRequest(requestMessages, model, tools, opts = {}, projectId) {
224
+ // The tail reminder is not history: the tool-loop closure below must see the
225
+ // real tail, so the reminder is appended to the wire contents last.
226
+ const { messages, reminder } = splitTailReminder(requestMessages);
223
227
  const systemText = messages
224
228
  .filter((message) => message.role === 'system')
225
229
  .map((message) => message.content)
@@ -234,7 +238,7 @@ export function buildAntigravityRequest(messages, model, tools, opts = {}, proje
234
238
  ...(claude ? { maxOutputTokens: CLAUDE_MAX_OUTPUT_TOKENS } : {}),
235
239
  ...(thinkingConfig ? { thinkingConfig } : {}),
236
240
  };
237
- const request = { contents };
241
+ const request = { contents: reminder ? [...contents, { role: 'user', parts: [{ text: reminder }] }] : contents };
238
242
  if (systemText) request.systemInstruction = { role: 'user', parts: [{ text: systemText }] };
239
243
  const requestTools = claude
240
244
  ? claudeRequestTools(tools, opts.nativeTools, opts.onToolExcluded)
@@ -3,24 +3,43 @@
3
3
  // Every turn starts again from the base, so a run of hard turns never
4
4
  // ratchets the effort upward.
5
5
  //
6
- // The base is `medium` on every model: raised only when the request needs it,
7
- // lowered when it is easy. The ladder is the model's supported efforts from
6
+ // The base is the global "Auto reasoning base" setting (`autoEffortBase` in the
7
+ // agent config; low / medium / high, default `medium`), the same on every model
8
+ // and independent of the effort last chosen: raised only when the request needs
9
+ // it, lowered when it is easy. The ladder is the model's supported efforts from
8
10
  // `low` up to the tier below the top: `none`/`minimal` switch thinking off and
9
- // `max`/`ultra` are reserved for an explicit user choice, so auto never picks
10
- // them. A chosen `max`/`ultra` is left untouched.
11
+ // `max`/`ultra` are reserved for an explicit (fixed, Auto off) user choice, so
12
+ // auto never picks them. A base the model does not offer is clamped to the
13
+ // nearest ladder level.
11
14
 
12
15
  const EFFORT_ORDER = Object.freeze(['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra']);
13
16
  const FLOOR_INDEX = EFFORT_ORDER.indexOf('low');
14
17
  const RESERVED_TOP = new Set(['max', 'ultra']);
15
18
 
16
19
  export const AUTO_EFFORT_BASE = 'medium';
20
+ /** The "Auto reasoning base" choices: the levels Auto can work around. */
21
+ export const AUTO_EFFORT_BASES = Object.freeze(['low', 'medium', 'high']);
17
22
 
18
- /** The effort auto moves from: `medium`, unless the user chose `max`/`ultra`. */
19
- export function autoEffortBase(chosen) {
20
- const effort = String(chosen ?? '')
23
+ /** The effort auto moves from: the global "Auto reasoning base" setting
24
+ * (`autoEffortBase` in the agent config); absent or invalid is `medium`. */
25
+ export function autoEffortBase(setting) {
26
+ const effort = String(setting ?? '')
21
27
  .trim()
22
28
  .toLowerCase();
23
- return RESERVED_TOP.has(effort) ? effort : AUTO_EFFORT_BASE;
29
+ return AUTO_EFFORT_BASES.includes(effort) ? effort : AUTO_EFFORT_BASE;
30
+ }
31
+
32
+ /** The base on the model's ladder: the setting itself, else the nearest
33
+ * ladder level (the lower one on a tie); null when the ladder is empty. */
34
+ export function clampAutoEffortBase({ base, options }) {
35
+ const ladder = autoEffortLadder(options);
36
+ if (!ladder.length) return null;
37
+ const want = EFFORT_ORDER.indexOf(autoEffortBase(base));
38
+ let best = ladder[0];
39
+ for (const level of ladder) {
40
+ if (Math.abs(EFFORT_ORDER.indexOf(level) - want) < Math.abs(EFFORT_ORDER.indexOf(best) - want)) best = level;
41
+ }
42
+ return best;
24
43
  }
25
44
 
26
45
  export const AUTO_EFFORT_MODES = Object.freeze(['off', 'observe', 'on']);
@@ -4,7 +4,7 @@ import { createRemoteVersionSource } from './npm-cli-version.mjs';
4
4
  // documented version endpoint; the official installer script embeds the
5
5
  // current build (…/lab/<build>/…), parsed best-effort. Any format change or
6
6
  // failure falls back to the floor.
7
- export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.19-6bbf2c4';
7
+ export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.22-27dcf5f';
8
8
  const BUILD_PATTERN = /downloads\.cursor\.com\/lab\/(\d{4}\.\d{2}\.\d{2}-[0-9a-f]{6,40})\//;
9
9
  export const CURSOR_INSTALL_URL = 'https://cursor.com/install';
10
10