mixdog 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/README.md +7 -5
  2. package/package.json +1 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/src/agents/reviewer/AGENT.md +3 -3
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +5 -0
  8. package/src/defaults/skills/pptx/SKILL.md +6 -6
  9. package/src/defaults/skills/pptx/references/review.md +6 -4
  10. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  11. package/src/defaults/skills/setup/references/actions.md +13 -3
  12. package/src/defaults/skills/visualize/SKILL.md +12 -9
  13. package/src/repl/slash-commands.mjs +16 -1
  14. package/src/rules/shared/60-verification.md +3 -1
  15. package/src/rules/shared/70-delivery.md +4 -2
  16. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  17. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  18. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  19. package/src/runtime/agent/orchestrator/config.mjs +10 -4
  20. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  21. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  22. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  23. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
  24. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
  25. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
  26. package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
  27. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  28. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  29. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  30. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  31. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  32. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  33. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  36. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
  41. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  42. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  46. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  49. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  50. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  51. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
  53. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  58. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  59. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
  60. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
  61. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
  63. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  65. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  66. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
  68. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
  73. package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
  74. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  75. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
  76. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
  78. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
  79. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  80. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  81. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  82. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  83. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
  84. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
  85. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
  86. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
  87. package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
  88. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  89. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
  90. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  91. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  92. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  93. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  94. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
  95. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
  96. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  97. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
  98. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  108. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
  115. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
  116. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
  117. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  119. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
  120. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  122. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  125. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
  127. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  128. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
  130. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  132. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  133. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  135. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
  136. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
  137. package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
  138. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  139. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
  140. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  141. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  142. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  143. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  146. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  147. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  148. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  149. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  150. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +268 -181
  151. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  154. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
  156. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  157. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  158. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
  159. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  160. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  161. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  162. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  163. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  164. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  165. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  166. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  167. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
  169. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
  170. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
  171. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
  172. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  173. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
  174. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
  175. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
  176. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
  177. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
  178. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
  179. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  182. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  183. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
  184. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
  185. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  186. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  187. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  188. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  189. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  190. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +819 -0
  191. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
  192. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
  193. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  194. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
  195. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  196. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  197. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
  198. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
  199. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  200. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  201. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  202. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  203. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  205. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  206. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  208. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
  209. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
  210. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  211. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  212. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  213. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  214. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  216. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  217. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  219. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  220. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  221. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  222. package/src/runtime/attachments/store.d.mts +3 -0
  223. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  224. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  225. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  226. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  227. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  228. package/src/runtime/memory/lib/memory.mjs +1 -1
  229. package/src/runtime/memory/lib/pg/process.mjs +34 -24
  230. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
  231. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  232. package/src/runtime/office/README.md +1 -1
  233. package/src/runtime/office/shared/values.mjs +0 -5
  234. package/src/runtime/shared/atomic-file.mjs +25 -4
  235. package/src/runtime/shared/background-tasks.mjs +92 -14
  236. package/src/runtime/shared/err-text.mjs +25 -0
  237. package/src/runtime/shared/error-presentation.mjs +159 -19
  238. package/src/runtime/shared/extension-scopes.mjs +5 -3
  239. package/src/runtime/shared/file-lock.mjs +37 -11
  240. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  241. package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
  242. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  243. package/src/runtime/shared/llm/model-catalog.mjs +53 -52
  244. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  245. package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
  246. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  247. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  248. package/src/runtime/shared/model-display.mjs +13 -0
  249. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  250. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  251. package/src/runtime/shared/pristine-execution.mjs +28 -4
  252. package/src/runtime/shared/provider-accounts.mjs +124 -20
  253. package/src/runtime/shared/provider-api-key.mjs +12 -0
  254. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  255. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  256. package/src/runtime/shared/shell-display.mjs +9 -3
  257. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  258. package/src/runtime/shared/skill-mentions.mjs +133 -0
  259. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  260. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  261. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  262. package/src/runtime/shared/tool-primitives.mjs +35 -2
  263. package/src/runtime/shared/turn-changes.mjs +447 -219
  264. package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
  265. package/src/runtime/shared/turn-snapshot.mjs +170 -48
  266. package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
  267. package/src/runtime/shared/worker-requests.mjs +15 -2
  268. package/src/runtime/shared/worktrees/contract.mjs +0 -24
  269. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  270. package/src/session-runtime/automation-agents.mjs +8 -2
  271. package/src/session-runtime/boot/apis.mjs +61 -0
  272. package/src/session-runtime/boot/config.mjs +5 -2
  273. package/src/session-runtime/boot/facade.mjs +1 -0
  274. package/src/session-runtime/boot/infrastructure.mjs +35 -18
  275. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  276. package/src/session-runtime/conversation-import/service.mjs +369 -0
  277. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
  278. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  279. package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
  280. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  281. package/src/session-runtime/mcp-glue/connect.mjs +83 -16
  282. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  283. package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
  284. package/src/session-runtime/mcp-glue.mjs +25 -2
  285. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  286. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  287. package/src/session-runtime/model-route/set-route.mjs +83 -15
  288. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  289. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  290. package/src/session-runtime/new-session-config.mjs +3 -2
  291. package/src/session-runtime/notification-bus.mjs +9 -2
  292. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  293. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  294. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  295. package/src/session-runtime/provider-readiness.mjs +16 -10
  296. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  297. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  298. package/src/session-runtime/resource-extension-sync.mjs +24 -5
  299. package/src/session-runtime/resource-mcp-api.mjs +198 -78
  300. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  301. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  302. package/src/session-runtime/resource-skills-api.mjs +23 -2
  303. package/src/session-runtime/runtime-review-api.mjs +13 -0
  304. package/src/session-runtime/schedule-session-run.mjs +1 -1
  305. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  306. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  307. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  308. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  310. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  311. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  312. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  313. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  314. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  315. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  316. package/src/session-runtime/services/provider-admin.mjs +64 -18
  317. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  318. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  319. package/src/session-runtime/setup-tool/executor.mjs +12 -1
  320. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  321. package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
  322. package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
  323. package/src/session-runtime/skills-api.mjs +7 -3
  324. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  325. package/src/session-runtime/webhook-session-run.mjs +16 -4
  326. package/src/skill-script-entry.mjs +36 -0
  327. package/src/standalone/daemon-drain-policy.mjs +8 -0
  328. package/src/standalone/daemon-stored-session-views.mjs +11 -3
  329. package/src/standalone/daemon-telemetry.mjs +55 -0
  330. package/src/standalone/daemon.mjs +44 -11
  331. package/src/standalone/session-protocol.mjs +12 -0
  332. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  333. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  334. package/src/standalone/session-service/agent-tree.mjs +12 -0
  335. package/src/standalone/session-service/quota-resume.mjs +8 -0
  336. package/src/standalone/session-service/retention/busy.mjs +15 -1
  337. package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
  338. package/src/standalone/session-service-api.mjs +5 -0
  339. package/src/standalone/session-service.mjs +1 -0
  340. package/src/tui/App.jsx +9 -1
  341. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  342. package/src/tui/app/app-view.jsx +7 -0
  343. package/src/tui/app/create-app-pickers.mjs +4 -0
  344. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  345. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  346. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  347. package/src/tui/app/extension-pickers.mjs +2 -1
  348. package/src/tui/app/model-options.mjs +13 -16
  349. package/src/tui/app/skill-mention-palette.mjs +88 -0
  350. package/src/tui/app/slash-commands.mjs +7 -2
  351. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  352. package/src/tui/app/slash-palette.mjs +23 -7
  353. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  354. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  355. package/src/tui/app/use-prompt-state.mjs +5 -0
  356. package/src/tui/components/Message.jsx +22 -1
  357. package/src/tui/components/PromptInput.jsx +21 -3
  358. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  359. package/src/tui/components/StatusLine.jsx +2 -0
  360. package/src/tui/components/TranscriptItem.jsx +9 -1
  361. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  362. package/src/tui/components/status-line/local-line.mjs +5 -2
  363. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  364. package/src/tui/components/user-message-skills.mjs +38 -0
  365. package/src/tui/dist/index.mjs +1323 -214
  366. package/src/tui/session/queue-helpers.mjs +7 -2
  367. package/src/tui/session/quota-resume.mjs +46 -14
  368. package/src/tui/session/session-api/commands.mjs +33 -24
  369. package/src/tui/session/session-api/extensions.mjs +26 -2
  370. package/src/tui/session/session-api/integrations.mjs +7 -0
  371. package/src/tui/session/session-api/lifecycle.mjs +5 -1
  372. package/src/tui/session/session-api/routes.mjs +71 -7
  373. package/src/tui/session/session-api/settings.mjs +12 -14
  374. package/src/tui/session/session-flow/drain.mjs +21 -5
  375. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  376. package/src/tui/session/tui-steering-persist.mjs +25 -9
  377. package/src/tui/session/turn.mjs +55 -15
  378. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  379. package/src/ui/statusline-agents.mjs +15 -4
  380. package/src/ui/statusline.mjs +7 -3
  381. package/src/ui/streaming-markdown-heal.mjs +34 -3
  382. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  383. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  384. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
  385. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  386. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -2,11 +2,13 @@
2
2
  * Anthropic "effort" (extended-thinking budget) request parameter handling.
3
3
  */
4
4
  import {
5
- assertAnthropicManualBudgetSupported,
5
+ CLAUDE_GENERATION_FLOOR,
6
+ claudeGenerationAtLeast,
6
7
  emitsAnthropicProgressUpdates,
7
- isAnthropicAdaptiveOnlyModel,
8
+ isAnthropicAdaptiveOnlyByGeneration,
8
9
  normalizeClaudeModelId as normalizeModelId,
9
10
  } from './anthropic-thinking-contract.mjs';
11
+ import { getModelMetadataSync } from './model-catalog.mjs';
10
12
 
11
13
  const EFFORT_LEVELS = Object.freeze(['low', 'medium', 'high', 'xhigh', 'max']);
12
14
  const THINKING_DISPLAYS = new Set(['summarized', 'omitted', 'updates']);
@@ -32,12 +34,47 @@ const CONTROL_EFFORT_KEYS = new Set(['supported', 'enabled', 'default']);
32
34
 
33
35
  // ── Catalog-first capability index ───────────────────────────────────────
34
36
  // The provider catalog already carries what each model advertises
35
- // (capabilities.effort → reasoningOptions:[{type:'effort',values:[…]}]), so it
36
- // — not a hardcoded regex ladder — is the source of truth for what we put on
37
- // the wire. anthropic-model-resolve feeds this whenever the in-memory catalog
38
- // moves. The regex ladder below stays as the fallback for ids the catalog does
39
- // not know (offline start, api-key provider, first run before /v1/models).
40
- const _catalogEffortLevels = new Map();
37
+ // (capabilities.effort → reasoningOptions:[{type:'effort',values:[…]}],
38
+ // capabilities.thinking.types → thinkingTypes), so it — not an id ladder — is
39
+ // the source of truth for what we put on the wire. Order for one model:
40
+ // 1. the live-roster index below (anthropic-model-resolve feeds it whenever
41
+ // the in-memory catalog moves),
42
+ // 2. the shared model catalog (cached roster / LiteLLM / models.dev),
43
+ // 3. a release-generation floor (anthropic-thinking-contract) for an id no
44
+ // catalog describes — a new release inherits it, no per-id entry.
45
+ const _catalogEntries = new Map();
46
+
47
+ /** `{adaptive?:boolean, enabled?:boolean}` a live /v1/models row declares under
48
+ * capabilities.thinking.types, or undefined when it declares neither. */
49
+ export function thinkingTypesFromCapabilities(capabilities) {
50
+ const types = capabilities?.thinking?.types;
51
+ if (!types || typeof types !== 'object') return undefined;
52
+ const out = {};
53
+ for (const key of ['adaptive', 'enabled']) {
54
+ const declared = types[key];
55
+ const supported = typeof declared === 'boolean' ? declared : declared?.supported;
56
+ if (typeof supported === 'boolean') out[key] = supported;
57
+ }
58
+ return Object.keys(out).length ? out : undefined;
59
+ }
60
+
61
+ function _effortLevelsOf(reasoningOptions) {
62
+ const option = (Array.isArray(reasoningOptions) ? reasoningOptions : []).find(
63
+ (entry) =>
64
+ String(entry?.type || '')
65
+ .trim()
66
+ .toLowerCase() === 'effort'
67
+ );
68
+ return new Set(
69
+ (Array.isArray(option?.values) ? option.values : [])
70
+ .map((value) =>
71
+ String(value || '')
72
+ .trim()
73
+ .toLowerCase()
74
+ )
75
+ .filter((value) => value && !CONTROL_EFFORT_KEYS.has(value))
76
+ );
77
+ }
41
78
 
42
79
  function _catalogKeys(model) {
43
80
  const id = normalizeModelId(model);
@@ -55,7 +92,7 @@ function _catalogKeys(model) {
55
92
  * lists carry no capability data and must not disable effort.
56
93
  */
57
94
  export function setModelEffortCapabilities(models) {
58
- _catalogEffortLevels.clear();
95
+ _catalogEntries.clear();
59
96
  if (!Array.isArray(models)) return;
60
97
  for (const model of models) {
61
98
  if (!model?.id || !Array.isArray(model.reasoningOptions)) continue;
@@ -63,37 +100,82 @@ export function setModelEffortCapabilities(models) {
63
100
  // (custom-reasoning.mjs); a same-id custom model must never reshape the
64
101
  // first-party index.
65
102
  if (String(model.provider || '').startsWith('custom-')) continue;
66
- const option = model.reasoningOptions.find(
67
- (entry) =>
68
- String(entry?.type || '')
69
- .trim()
70
- .toLowerCase() === 'effort'
71
- );
72
- const levels = new Set(
73
- (Array.isArray(option?.values) ? option.values : [])
74
- .map((value) =>
75
- String(value || '')
76
- .trim()
77
- .toLowerCase()
78
- )
79
- .filter((value) => value && !CONTROL_EFFORT_KEYS.has(value))
80
- );
103
+ const levels = _effortLevelsOf(model.reasoningOptions);
104
+ const manual = typeof model.thinkingTypes?.enabled === 'boolean' ? model.thinkingTypes.enabled : undefined;
105
+ const adaptive = typeof model.thinkingTypes?.adaptive === 'boolean' ? model.thinkingTypes.adaptive : undefined;
81
106
  for (const key of _catalogKeys(model.id)) {
82
- const existing = _catalogEffortLevels.get(key);
107
+ const existing = _catalogEntries.get(key);
83
108
  // A bare alias shared by several records keeps the richer entry.
84
- if (existing?.size && levels.size === 0) continue;
85
- _catalogEffortLevels.set(key, levels);
109
+ if (existing?.levels.size && levels.size === 0) continue;
110
+ _catalogEntries.set(key, { levels, manual, adaptive });
86
111
  }
87
112
  }
88
113
  }
89
114
 
90
- /** Advertised levels for `model`, or null when the catalog has no record. */
91
- function _catalogLevels(model) {
115
+ // Shared-catalog tier (cached roster rows, LiteLLM, models.dev) for an id the
116
+ // live index does not hold. Only an actual effort ladder counts; silence
117
+ // returns null so the generation floor decides.
118
+ function _sharedCatalogEntry(model) {
119
+ const id = normalizeModelId(model);
120
+ if (!id) return null;
121
+ const levels = _effortLevelsOf(getModelMetadataSync(id, 'anthropic')?.reasoningOptions);
122
+ return levels.size ? { levels, manual: undefined, adaptive: undefined } : null;
123
+ }
124
+
125
+ /** `{levels: Set, manual?: boolean, adaptive?: boolean}` for `model`, or null when no catalog describes it. */
126
+ function _catalogEntry(model) {
92
127
  for (const key of _catalogKeys(model)) {
93
- const levels = _catalogEffortLevels.get(key);
94
- if (levels) return levels;
128
+ const entry = _catalogEntries.get(key);
129
+ if (entry) return entry;
130
+ }
131
+ return _sharedCatalogEntry(model);
132
+ }
133
+
134
+ /** Advertised levels for `model`, or null when the catalog has no ladder for it. */
135
+ function _catalogLevels(model) {
136
+ return _catalogEntry(model)?.levels ?? null;
137
+ }
138
+
139
+ /**
140
+ * True when the model's thinking contract rejects a manual
141
+ * `thinking:{type:"enabled",budget_tokens}` request: the catalog's declared
142
+ * thinking types decide, the release-generation floor covers an undescribed id.
143
+ */
144
+ export function isAnthropicAdaptiveOnlyModel(model) {
145
+ const manual = _catalogEntry(model)?.manual;
146
+ return typeof manual === 'boolean' ? !manual : isAnthropicAdaptiveOnlyByGeneration(model);
147
+ }
148
+
149
+ // The thinking type is resolved apart from the effort ladder: a catalog can
150
+ // advertise effort levels for a model that still takes the manual budget shape
151
+ // (effort is not adaptive-thinking support). A declared `adaptive` flag decides;
152
+ // otherwise the release-generation floor does, whatever ladder the catalog holds.
153
+ function _usesAdaptiveThinking(model) {
154
+ if (isEnvTruthy(process.env.MIXDOG_ANTHROPIC_ALWAYS_ENABLE_EFFORT)) return true;
155
+ const adaptive = _catalogEntry(model)?.adaptive;
156
+ return typeof adaptive === 'boolean' ? adaptive : _floorSupportsEffort(model);
157
+ }
158
+
159
+ export function assertAnthropicManualBudgetSupported(model) {
160
+ if (isAnthropicAdaptiveOnlyModel(model)) {
161
+ throw new TypeError(`${model} does not support thinkingBudgetTokens; use effort with adaptive thinking instead.`);
95
162
  }
96
- return null;
163
+ }
164
+
165
+ /**
166
+ * Effort levels the wire builder sends unchanged for `model` (reserved `max`
167
+ * excluded), from the same capability gates normalizeAnthropicEffortInput and
168
+ * applyAnthropicEffortToBody use: catalog record first, generation floor for
169
+ * an absent record. A model without effort support, or whose catalog record
170
+ * declares none, accepts none.
171
+ */
172
+ export function anthropicEffortLevelsFor(model) {
173
+ // Only the adaptive path sends output_config effort; a manual-thinking model
174
+ // takes none, whatever ladder a catalog holds for it.
175
+ if (!modelSupportsEffort(model) || !_usesAdaptiveThinking(model)) return [];
176
+ const levels = ['low', 'medium', 'high'];
177
+ if (modelSupportsXhighEffort(model)) levels.push('xhigh');
178
+ return levels;
97
179
  }
98
180
 
99
181
  export const EFFORT_BETA_HEADER = 'effort-2025-11-24';
@@ -109,121 +191,41 @@ const _LOGGED_EFFORT_NORMALIZATION = new Set();
109
191
  const _LOGGED_UNKNOWN_EFFORT = new Set();
110
192
  const MAX_LOGGED_UNKNOWN_EFFORTS = 100;
111
193
 
112
- function parseClaudeVersion(model) {
113
- const m = normalizeModelId(model);
114
- const triple = m.match(/^claude-(haiku|sonnet|opus|fable)-(\d+)-(\d+)/);
115
- if (triple) {
116
- return { family: triple[1], major: Number(triple[2]), minor: Number(triple[3]) };
117
- }
118
- // Bare version ids carry family + major only (claude-opus-5). opus/haiku
119
- // were missing here, so `claude-opus-5` parsed to null and fell through
120
- // every capability check as an unknown shape.
121
- const pair = m.match(/^claude-(sonnet|fable|opus|haiku)-(\d+)(?:$|[-@])/);
122
- if (pair) {
123
- return { family: pair[1], major: Number(pair[2]), minor: null };
124
- }
125
- // Legacy naming: version comes BEFORE the family (claude-3-7-sonnet,
126
- // claude-3-5-sonnet, claude-3-opus). These are manual-thinking models —
127
- // parse them so isLegacyAnthropicReasoningModel excludes them instead of
128
- // letting modelSupportsEffort's `startsWith('claude-')` fallthrough grant
129
- // them adaptive thinking + the effort beta (a hard 400).
130
- const legacy = m.match(/^claude-(\d+)-(\d+)-(haiku|sonnet|opus)/);
131
- if (legacy) {
132
- return { family: legacy[3], major: Number(legacy[1]), minor: Number(legacy[2]) };
133
- }
134
- return null;
135
- }
136
-
137
- function isLegacyAnthropicReasoningModel(model) {
138
- const parsed = parseClaudeVersion(model);
139
- if (!parsed) return false;
140
- if (parsed.family === 'haiku') return true;
141
- if (parsed.family === 'fable') return false;
142
- if (parsed.family === 'sonnet' || parsed.family === 'opus') {
143
- if (parsed.major < 4) return true;
144
- if (parsed.major === 4 && parsed.minor !== null && parsed.minor < 6) return true;
145
- // Bare major, no minor (claude-opus-4 / claude-sonnet-4): adaptive
146
- // effort only ships from 5 up, so 4.x aliases stay manual-thinking.
147
- if (parsed.minor === null && parsed.major < 5) return true;
148
- return false;
149
- }
150
- return false;
151
- }
152
-
153
- // @[MODEL LAUNCH]: extend allowlist when new Claude models ship with effort support.
154
194
  export function modelSupportsEffort(model) {
155
195
  if (isEnvTruthy(process.env.MIXDOG_ANTHROPIC_ALWAYS_ENABLE_EFFORT)) return true;
156
196
  const advertised = _catalogLevels(model);
157
197
  if (advertised) return advertised.size > 0;
158
- return _regexSupportsEffort(model);
198
+ return _floorSupportsEffort(model);
159
199
  }
160
200
 
161
- // Fallback ladder for ids the catalog does not carry. Also used by
162
- // effortValuesForModel, which BUILDS the catalog records and therefore must
163
- // never consult the index it feeds.
164
- function _regexSupportsEffort(model) {
165
- const m = normalizeModelId(model);
166
- if (!m.includes('claude')) return false;
167
- if (isLegacyAnthropicReasoningModel(model)) return false;
168
- if (isAnthropicAdaptiveOnlyModel(model)) return true;
169
- if (m.includes('opus-4-6') || m.includes('sonnet-4-6')) return true;
170
- if (m.includes('sonnet-5') || m.includes('fable-5')) return true;
171
- if (/^claude-mythos-5-1(?:-\d{8})?$/.test(m)) return true;
172
- if (/^claude-opus-4-(6|7|8)(?:$|[-@])/.test(m)) return true;
173
- if (/^claude-opus-5(?:$|[-@])/.test(m)) return true;
174
- // Fallthrough for not-yet-enumerated modern models: only grant effort when
175
- // parseClaudeVersion resolves a family with major>=4 (and not a manual-
176
- // thinking legacy already excluded above). A bare `startsWith('claude-')`
177
- // here would hand thinking:adaptive + the effort beta to legacy/unknown
178
- // IDs (e.g. claude-3-7-sonnet) → hard 400. Unknown-shape IDs (no version
179
- // parsed) fall through to false: no effort, no adaptive thinking.
180
- const parsed = parseClaudeVersion(model);
181
- if (
182
- parsed &&
183
- (parsed.family === 'sonnet' || parsed.family === 'opus' || parsed.family === 'fable') &&
184
- parsed.major >= 4
185
- ) {
186
- return true;
187
- }
188
- return false;
201
+ // Generation-floor fallbacks for ids the catalog does not describe. Also used
202
+ // by effortValuesForModel, which BUILDS the catalog records and therefore must
203
+ // never consult the index it feeds. Legacy manual-thinking generations
204
+ // (claude-3-7-sonnet, claude-sonnet-4-5, claude-haiku-4-5) sit below the
205
+ // floor; non-claude ids have no generation and get nothing.
206
+ function _floorSupportsEffort(model) {
207
+ return claudeGenerationAtLeast(model, CLAUDE_GENERATION_FLOOR.adaptiveEffort);
189
208
  }
190
209
 
191
- // @[MODEL LAUNCH]: extend when new models support xhigh effort.
192
- // Per platform.claude.com/docs/en/build-with-claude/effort — xhigh is
193
- // supported by: Fable 5, Mythos 5, Opus 4.8, Opus 4.7, Sonnet 5.
194
- // NOT Opus 4.6 / Sonnet 4.6 (those support max but not xhigh).
195
210
  export function modelSupportsXhighEffort(model) {
196
211
  const advertised = _catalogLevels(model);
197
212
  if (advertised) return advertised.has('xhigh');
198
- return _regexSupportsXhighEffort(model);
213
+ return _floorSupportsXhighEffort(model);
199
214
  }
200
215
 
201
- function _regexSupportsXhighEffort(model) {
202
- const m = normalizeModelId(model);
203
- if (/^claude-opus-4-(7|8)(?:$|[-@])/.test(m)) return true;
204
- if (/^claude-opus-5(?:$|[-@])/.test(m)) return true;
205
- if (/^claude-sonnet-5(?:$|[-@])/.test(m)) return true;
206
- if (/^claude-fable-5(?:$|[-@])/.test(m)) return true;
207
- if (/^claude-mythos-5(?:$|[-@])/.test(m)) return true;
208
- if (/^claude-mythos-preview(?:$|[-@])/.test(m)) return true;
209
- return false;
216
+ function _floorSupportsXhighEffort(model) {
217
+ return claudeGenerationAtLeast(model, CLAUDE_GENERATION_FLOOR.xhighEffort);
210
218
  }
211
219
 
212
- // @[MODEL LAUNCH]: extend when new Opus models support max effort.
213
- // Max list = xhigh list PLUS Opus 4.6, Sonnet 4.6, Opus 4.5.
214
220
  export function modelSupportsMaxEffort(model) {
215
221
  const advertised = _catalogLevels(model);
216
- // xhigh support implies max support (kept from the ladder below).
222
+ // xhigh support implies max support.
217
223
  if (advertised) return advertised.has('max') || advertised.has('xhigh');
218
- return _regexSupportsMaxEffort(model);
224
+ return _floorSupportsMaxEffort(model);
219
225
  }
220
226
 
221
- function _regexSupportsMaxEffort(model) {
222
- if (_regexSupportsXhighEffort(model)) return true;
223
- const m = normalizeModelId(model);
224
- if (/^claude-opus-4-(5|6)(?:$|[-@])/.test(m)) return true;
225
- if (/^claude-sonnet-4-6(?:$|[-@])/.test(m)) return true;
226
- return false;
227
+ function _floorSupportsMaxEffort(model) {
228
+ return claudeGenerationAtLeast(model, CLAUDE_GENERATION_FLOOR.maxEffort);
227
229
  }
228
230
 
229
231
  function isEnvTruthy(value) {
@@ -276,7 +278,8 @@ export function normalizeAnthropicEffortInput(raw, model, logTag = 'anthropic')
276
278
  export function shouldIncludeEffortBeta(model, opts = {}) {
277
279
  const thinkingBudgetTokens = Number(opts.thinkingBudgetTokens);
278
280
  if (Number.isFinite(thinkingBudgetTokens) && thinkingBudgetTokens > 0) return false;
279
- return modelSupportsEffort(model);
281
+ // Only requests that carry output_config effort (adaptive path) need the beta.
282
+ return modelSupportsEffort(model) && _usesAdaptiveThinking(model);
280
283
  }
281
284
 
282
285
  /**
@@ -300,7 +303,7 @@ export function applyAnthropicEffortToBody(
300
303
 
301
304
  const normalized = normalizeAnthropicEffortInput(opts.effort, model, logTag);
302
305
 
303
- if (modelSupportsEffort(model)) {
306
+ if (modelSupportsEffort(model) && _usesAdaptiveThinking(model)) {
304
307
  if (normalized) {
305
308
  const existing = body.output_config && typeof body.output_config === 'object' ? body.output_config : {};
306
309
  body.output_config = { ...existing, effort: normalized };
@@ -372,10 +375,10 @@ export function effortValuesForModel(capabilities, modelId) {
372
375
  // the model supports effort but doesn't enumerate levels, so derive the
373
376
  // set from the known level ladder, gated by the top-tier model check.
374
377
  let levels = [...EFFORT_LEVELS];
375
- if (!_regexSupportsMaxEffort(modelId)) {
378
+ if (!_floorSupportsMaxEffort(modelId)) {
376
379
  levels = levels.filter((level) => level !== 'max');
377
380
  }
378
- if (!_regexSupportsXhighEffort(modelId)) {
381
+ if (!_floorSupportsXhighEffort(modelId)) {
379
382
  levels = levels.filter((level) => level !== 'xhigh');
380
383
  }
381
384
  return levels;
@@ -5,25 +5,61 @@ export function normalizeClaudeModelId(model) {
5
5
  .replace(/\./g, '-');
6
6
  }
7
7
 
8
- // One classification owns request shaping and manual-budget validation.
9
- export function isAnthropicAdaptiveOnlyModel(model) {
10
- const id = normalizeClaudeModelId(model);
11
- return (
12
- /^claude-(?:fable|mythos)-5(?:-|$)/.test(id) ||
13
- /^claude-(?:opus|sonnet)-5(?:-|$)/.test(id) ||
14
- /^claude-opus-4-(?:7|8)(?:-|$)/.test(id)
15
- );
8
+ // Version token after the family (claude-opus-4-8, claude-nova-9-1-20270101)
9
+ // or before it (claude-3-5-sonnet). Minor is one or two digits and never
10
+ // followed by another digit, so a release date (claude-opus-4-20250514) is
11
+ // not read as a minor version.
12
+ const FAMILY_FIRST_VERSION = /^claude-[a-z][a-z0-9]*-(\d+)(?:-(\d{1,2})(?!\d))?(?:[-@]|$)/;
13
+ const VERSION_FIRST_VERSION = /^claude-(\d+)(?:-(\d{1,2})(?!\d))?(?:[-@]|$)/;
14
+
15
+ /**
16
+ * Release generation of a Claude id as major*100 + minor (4.8 → 408), derived
17
+ * from the version token alone — no family names. A claude-* id without a
18
+ * version token is a not-yet-numbered release and ranks as the newest
19
+ * (Infinity); a non-claude id has no generation (null). A route prefix before
20
+ * the claude token (anthropic/claude-…, us.anthropic.claude-…) is skipped.
21
+ */
22
+ export function claudeGeneration(model) {
23
+ const normalized = normalizeClaudeModelId(model);
24
+ const at = normalized.indexOf('claude-');
25
+ if (at < 0) return null;
26
+ const id = normalized.slice(at);
27
+ const m = id.match(FAMILY_FIRST_VERSION) || id.match(VERSION_FIRST_VERSION);
28
+ return m ? Number(m[1]) * 100 + Number(m[2] || 0) : Infinity;
29
+ }
30
+
31
+ // Offline floors, used only for an id no catalog record describes. Each is the
32
+ // first generation whose documented API contract has the capability; later
33
+ // generations inherit it, so a new release needs no entry here.
34
+ export const CLAUDE_GENERATION_FLOOR = Object.freeze({
35
+ // adaptive thinking + output_config.effort
36
+ adaptiveEffort: 406,
37
+ // thinking:{type:"enabled",budget_tokens} is rejected from here on
38
+ manualThinkingRejected: 407,
39
+ // effort tier "xhigh"
40
+ xhighEffort: 407,
41
+ // effort tier "max"
42
+ maxEffort: 405,
43
+ });
44
+
45
+ /** Generation at/above `floor`; ids with no generation (non-claude) never qualify. */
46
+ export function claudeGenerationAtLeast(model, floor) {
47
+ const generation = claudeGeneration(model);
48
+ return generation !== null && generation >= floor;
49
+ }
50
+
51
+ // Offline classification for an id the catalog does not describe (catalog
52
+ // lookup lives in anthropic-effort.mjs: isAnthropicAdaptiveOnlyModel).
53
+ export function isAnthropicAdaptiveOnlyByGeneration(model) {
54
+ return claudeGenerationAtLeast(model, CLAUDE_GENERATION_FLOOR.manualThinkingRejected);
16
55
  }
17
56
 
18
57
  // Models that write their user-facing notes between tool calls (tool
19
58
  // preambles) as progress-update thinking blocks instead of text blocks.
59
+ // Kept as an id list: no catalog field carries it, the display value rides a
60
+ // beta-gated parameter that other models reject (a wrong "yes" is a 400), and
61
+ // a wrong "no" only leaves preambles as text — so unknown ids stay off.
20
62
  export function emitsAnthropicProgressUpdates(model) {
21
63
  const id = normalizeClaudeModelId(model);
22
64
  return /^claude-(?:opus-5-5|sonnet-5-5|fable-5-1|mythos-5-1|fable-5)(?:-\d{8})?$/.test(id);
23
65
  }
24
-
25
- export function assertAnthropicManualBudgetSupported(model) {
26
- if (isAnthropicAdaptiveOnlyModel(model)) {
27
- throw new TypeError(`${model} does not support thinkingBudgetTokens; use effort with adaptive thinking instead.`);
28
- }
29
- }
@@ -29,6 +29,7 @@ import {
29
29
  } from './provider-catalog-cache.mjs';
30
30
  import {
31
31
  modelsDevProviderId,
32
+ firstPartyModelsDevIds,
32
33
  providerCatalogEntry,
33
34
  providerMetadataCorrection,
34
35
  providerSeedRow,
@@ -60,35 +61,35 @@ const PRICING_CATALOG_RETRY_MS = 60_000;
60
61
  // name, so a provider-keyed lookup can find nothing and the route silently
61
62
  // prices at zero — indistinguishable from a genuinely free local model.
62
63
 
63
- // Which vendor actually served a relayed model, read off the model id. Only a
64
- // guess: its row fills capabilities and the effort ladder the route's own
65
- // sources left undeclared, and prices a model only when the provider-keyed
66
- // lookup found no rates, so a route with real catalog coverage is never
67
- // repriced by a name guess. Ids are matched on their leading family token
68
- // rather than a bare substring, so an unrelated model that merely mentions a
69
- // vendor is not adopted by it.
70
- const _RELAYED_MODEL_VENDORS = [
71
- [/^claude[-.]/, 'anthropic'],
72
- [/^(gpt|o[1-9]|codex)[-.]/, 'openai'],
73
- [/^gemini[-.]/, 'google'],
74
- [/^grok[-.]/, 'xai'],
75
- [/^deepseek[-.]/, 'deepseek'],
76
- [/^kimi[-.]/, 'moonshotai'],
77
- [/^glm[-.]/, 'zai'],
78
- [/^muse[-.]/, 'meta'],
79
- [/^qwen(?:\d|[-.])/, 'alibaba'],
80
- [/^minimax[-.]/, 'minimax'],
81
- [/^mimo[-.]/, 'xiaomi'],
82
- [/^longcat[-.]/, 'longcat'],
83
- ];
84
-
85
- function _relayedModelVendor(id) {
86
- const model = String(id || '').toLowerCase();
87
- if (!model) return null;
88
- for (const [pattern, vendor] of _RELAYED_MODEL_VENDORS) {
89
- if (pattern.test(model)) return vendor;
64
+ // Which vendor actually served a relayed model, read off the catalogs, in
65
+ // order of provenance that does not depend on catalog entry order:
66
+ // 1. the vendor LiteLLM lists the id under (fixed key order);
67
+ // 2. registered first-party vendors that list it in models.dev (sorted);
68
+ // 3. an unregistered models.dev provider, only when it is the sole such
69
+ // candidate — aggregators list many vendors' SKUs, so when several
70
+ // disagree there is no provenance and nothing is borrowed.
71
+ // Only a guess: its row fills capabilities and the effort ladder the route's
72
+ // own sources left undeclared, and prices a model only when the
73
+ // provider-keyed lookup found no rates, so a route with real catalog coverage
74
+ // is never repriced by it. A model no catalog lists has no vendor row to
75
+ // lend, so there is nothing to guess and no id pattern is used.
76
+ function _relayedModelVendors(id, catalog, modelsDevCatalog) {
77
+ // A vendor serves its own models: a relay or a user-defined provider listed
78
+ // in a catalog is never the vendor (and resolving it would guess again).
79
+ const isVendor = (vendor) =>
80
+ Boolean(vendor) && !String(vendor).startsWith('custom-') && !providerCatalogEntry(vendor)?.relay;
81
+ const vendors = new Set();
82
+ for (const key of [id, ..._CATALOG_SIMPLE_PREFIXES.map((prefix) => prefix + id)]) {
83
+ const vendor = modelsDevProviderId(catalog?.[key]?.litellm_provider);
84
+ if (isVendor(vendor)) vendors.add(vendor);
90
85
  }
91
- return null;
86
+ const firstParty = new Set(firstPartyModelsDevIds());
87
+ for (const vendor of firstParty) if (modelsDevCatalog?.[vendor]?.models?.[id]) vendors.add(vendor);
88
+ const unregistered = Object.entries(modelsDevCatalog || {})
89
+ .filter(([vendor, entry]) => entry?.models?.[id] && !firstParty.has(vendor) && isVendor(vendor))
90
+ .map(([vendor]) => vendor);
91
+ if (unregistered.length === 1) vendors.add(unregistered[0]);
92
+ return vendors;
92
93
  }
93
94
 
94
95
  // Provider prefix variants used by the shared catalog resolver.
@@ -523,10 +524,15 @@ const effortEntry = (options) => (Array.isArray(options) ? options.find((o) => o
523
524
  // A vendor row is a first guess for a route it does not describe (relay,
524
525
  // same-vendor other endpoint, custom provider): it fills only the capabilities
525
526
  // and effort ladder the route's own sources left undeclared. Never limits.
526
- function withVendorGuess(meta, guess, { ladder = true } = {}) {
527
+ // A relay serves the model through its own hosted tools, so the serving
528
+ // vendor's web-search flag says nothing about the relay endpoint.
529
+ function withVendorGuess(meta, guess, { ladder = true, relay = false } = {}) {
527
530
  if (!guess) return meta;
528
531
  const out = { ...(meta || _normalize({})) };
529
- for (const key of GUESSED_FLAGS) out[key] ??= guess[key];
532
+ for (const key of GUESSED_FLAGS) {
533
+ if (relay && key === 'supportsWebSearch') continue;
534
+ out[key] ??= guess[key];
535
+ }
530
536
  const effort = effortEntry(guess.reasoningOptions);
531
537
  if (ladder && effort && out.supportsReasoning !== false && !effortEntry(out.reasoningOptions)) {
532
538
  out.reasoningOptions = [...(out.reasoningOptions || []), effort];
@@ -602,11 +608,16 @@ function catalogMetadata(id, mappedProvider, catalog, modelsDevCatalog) {
602
608
 
603
609
  // The row of the vendor serving a relayed or custom model id (no vendor: a
604
610
  // bare-id catalog lookup).
605
- function servingVendorMetadata(id, vendor, catalog, modelsDevCatalog) {
606
- // Anthropic SKUs spell versions with hyphens (claude-opus-5-5); relays
607
- // may list the same SKU with dots (claude-opus-5.5).
608
- const vendorId = vendor === 'anthropic' ? id.replace(/(\d)\.(\d)/g, '$1-$2') : id;
609
- return lookupModelMetadata(vendorId, vendor, catalog, modelsDevCatalog);
611
+ function servingVendorMetadata(id, catalog, modelsDevCatalog) {
612
+ // Some vendors spell versions with hyphens (claude-opus-5-5) where relays
613
+ // list the same SKU with dots (claude-opus-5.5); the catalog decides which.
614
+ for (const candidate of new Set([id, id.replace(/(\d)\.(\d)/g, '$1-$2')])) {
615
+ for (const vendor of _relayedModelVendors(candidate, catalog, modelsDevCatalog)) {
616
+ const row = lookupModelMetadata(candidate, vendor, catalog, modelsDevCatalog);
617
+ if (row) return row;
618
+ }
619
+ }
620
+ return null;
610
621
  }
611
622
 
612
623
  // Both list enrichment and synchronous accounting use this exact resolver;
@@ -631,9 +642,9 @@ function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog, li
631
642
  const correction = source ? providerMetadataCorrection(provider, id) : null;
632
643
  if (meta && correction) meta = { ...meta, ...correction };
633
644
  let guess = null;
634
- const relayVendor = source?.relay ? _relayedModelVendor(id) : null;
645
+ const relayGuess = source?.relay ? servingVendorMetadata(id, catalog, modelsDevCatalog) : null;
635
646
  if (custom) guess = customVendorMetadata(originalId, catalog, modelsDevCatalog);
636
- else if (relayVendor) guess = servingVendorMetadata(id, relayVendor, catalog, modelsDevCatalog);
647
+ else if (relayGuess) guess = relayGuess;
637
648
  else if (source && !source.sameEndpoint) guess = mapped;
638
649
  if (source?.relay && !hasRates(meta) && hasRates(guess)) {
639
650
  meta = meta ? { ...meta, ...pricingFields(guess) } : pricingOnly(guess);
@@ -686,7 +697,10 @@ function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog, li
686
697
  const rosterLadders = [cached?.rawProviderModel, listedRow].filter(
687
698
  (row) => Array.isArray(row?.reasoningLevels) || Array.isArray(row?.reasoningOptions)
688
699
  );
689
- meta = withVendorGuess(meta, guess, { ladder: !(source?.rosterLadderFinal && rosterLadders.length) });
700
+ meta = withVendorGuess(meta, guess, {
701
+ ladder: !(source?.rosterLadderFinal && rosterLadders.length),
702
+ relay: Boolean(relayGuess),
703
+ });
690
704
  return meta
691
705
  ? {
692
706
  ...meta,
@@ -706,8 +720,7 @@ function customVendorMetadata(originalId, catalog, modelsDevCatalog) {
706
720
  const listedId = String(originalId || '');
707
721
  for (const id of new Set([listedId, listedId.slice(listedId.lastIndexOf('/') + 1)])) {
708
722
  if (!id) continue;
709
- const vendor = _relayedModelVendor(id) || modelsDevProviderId(catalog[id]?.litellm_provider);
710
- const guess = servingVendorMetadata(id, vendor, catalog, modelsDevCatalog);
723
+ const guess = servingVendorMetadata(id, catalog, modelsDevCatalog);
711
724
  if (guess) return guess;
712
725
  }
713
726
  return null;
@@ -904,7 +917,6 @@ export function pricingCatalogRevisionSync() {
904
917
  }
905
918
 
906
919
  let lastAuditedRevision = null;
907
- let lastAudit = null;
908
920
  function auditCachedModelPricing() {
909
921
  const revision = pricingCatalogRevisionSync();
910
922
  const rows = Object.entries(cachedProviderModelListsSync()).flatMap(([provider, models]) =>
@@ -919,17 +931,6 @@ function auditCachedModelPricing() {
919
931
  );
920
932
  }
921
933
  lastAuditedRevision = revision;
922
- lastAudit = { revision, rows, unpriced };
923
- return lastAudit;
924
- }
925
-
926
- /** Catalog routes without a complete list price, from the latest audit (run on demand when none is cached). */
927
- export function unpricedModelsSync() {
928
- return (lastAudit ?? auditCachedModelPricing()).unpriced.map(({ provider, model, missingRates }) => ({
929
- provider,
930
- model,
931
- missingRates: [...missingRates],
932
- }));
933
934
  }
934
935
 
935
936
  /**
@@ -13,17 +13,6 @@ export const DAYBREAK_OFF = 'off';
13
13
  export const DAYBREAK_BLUE_PROGRAM = 'daybreak_blue';
14
14
  const STANDARD_PROGRAM = 'standard';
15
15
 
16
- // Static fallback, used ONLY when a catalog row carries no access-program
17
- // list at all (an older cache or a catalog without the field). Any list the
18
- // catalog does send — empty included — decides on its own.
19
- const FALLBACK_DAYBREAK_BLUE_MODELS = new Set([
20
- 'gpt-6-sol',
21
- 'gpt-6-luna',
22
- 'gpt-5.6-sol',
23
- 'gpt-5.6-terra',
24
- 'gpt-5.6-luna',
25
- ]);
26
-
27
16
  export const DAYBREAK_PARAMETER_OPTION = Object.freeze({
28
17
  id: DAYBREAK_PARAMETER_ID,
29
18
  label: 'Daybreak Blue',
@@ -43,13 +32,12 @@ export function catalogAccessPrograms(raw) {
43
32
  }
44
33
 
45
34
  /**
46
- * Whether a model (catalog record or bare id) accepts Blue: the catalog's
47
- * access-program list when it has one, else the static fallback.
35
+ * Whether a model accepts Blue: only when the catalog's access-program list
36
+ * for it names the program. A row with no list (or a bare id) is not offered
37
+ * the toggle; the server's catalog is the only source of this entitlement.
48
38
  */
49
39
  export function daybreakBlueSupported(model) {
50
- if (Array.isArray(model?.accessPrograms)) return model.accessPrograms.includes(DAYBREAK_BLUE_PROGRAM);
51
- const id = clean(typeof model === 'string' ? model : model?.id).toLowerCase();
52
- return FALLBACK_DAYBREAK_BLUE_MODELS.has(id);
40
+ return Array.isArray(model?.accessPrograms) && model.accessPrograms.includes(DAYBREAK_BLUE_PROGRAM);
53
41
  }
54
42
 
55
43
  /**