mixdog 1.2.1 → 1.2.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 (557) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/scripts/provider-pingpong-live.mjs +509 -0
  6. package/src/agents/advisor/AGENT.md +1 -1
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +3 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +6 -0
  11. package/src/defaults/skills/setup/SKILL.md +6 -1
  12. package/src/defaults/skills/setup/references/actions.md +44 -22
  13. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  14. package/src/headless-exec.mjs +15 -8
  15. package/src/lib/keychain-cjs.cjs +7 -4
  16. package/src/output-styles/common.md +11 -10
  17. package/src/repl/slash-commands.mjs +16 -1
  18. package/src/rules/agent/AGENT.md +5 -5
  19. package/src/rules/lead/LEAD.md +5 -5
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  22. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  23. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  33. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  36. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  37. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  38. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  39. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  40. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  41. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  44. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  45. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
  46. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  47. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  48. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
  49. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
  50. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  51. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  54. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
  58. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  63. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  65. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  71. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  72. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
  73. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
  74. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
  75. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  76. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
  77. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  79. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  80. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
  81. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  83. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
  84. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  85. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  86. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
  87. package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
  88. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  89. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  90. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  91. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  92. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  93. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
  94. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
  96. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
  97. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  99. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  100. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  102. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
  103. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
  105. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
  106. package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
  107. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  109. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
  110. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  113. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  114. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  115. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  116. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  117. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  118. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  120. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  121. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  122. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  123. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  124. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  125. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  126. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  127. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  128. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  129. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  138. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  140. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  141. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  142. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
  143. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
  144. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  145. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  147. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
  148. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  150. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
  151. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
  153. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
  154. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
  155. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
  156. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
  157. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  158. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  159. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  160. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
  161. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  163. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
  164. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  165. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
  166. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  167. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  168. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  169. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  170. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
  171. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
  172. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  173. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
  174. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
  175. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  176. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  177. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  178. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  179. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  180. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  181. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  182. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  183. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  184. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  185. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  186. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  187. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  188. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
  189. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  190. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  191. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  192. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
  193. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  195. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
  196. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  197. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  198. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  199. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  200. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  201. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  202. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  203. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  204. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  205. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  206. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  207. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  208. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  210. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  211. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  212. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  213. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  214. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  215. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  216. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  217. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  218. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  219. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  220. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  221. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  222. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
  223. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  224. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  225. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  226. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  227. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  228. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  229. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  230. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  231. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  232. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  233. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  234. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  235. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  236. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  237. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  238. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  239. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  240. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
  241. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  242. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  243. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  244. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  245. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  246. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  248. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  249. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  250. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  251. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
  252. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  253. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  254. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  255. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  256. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  257. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  258. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
  259. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  260. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  261. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  262. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  263. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  264. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  265. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  266. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  267. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
  268. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  269. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  270. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  271. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  272. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  273. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  274. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  275. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  276. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  277. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  278. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  279. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  280. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  281. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
  282. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
  283. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
  284. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  285. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  286. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  287. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  288. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  289. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  290. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  291. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  292. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  293. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  294. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  295. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  296. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  297. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  298. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  299. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  300. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  301. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  302. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  303. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  304. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  305. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  306. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  307. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  308. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  309. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  310. package/src/runtime/github/tool.mjs +92 -2
  311. package/src/runtime/memory/index.mjs +1 -0
  312. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  313. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  314. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  315. package/src/runtime/memory/lib/pg/process.mjs +65 -50
  316. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  317. package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
  318. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  319. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  320. package/src/runtime/office/README.md +2 -2
  321. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  322. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  323. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  324. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  325. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  326. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  327. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  328. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  329. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  330. package/src/runtime/office/core/office-sessions.mjs +5 -0
  331. package/src/runtime/office/core/office-transactions.mjs +3 -0
  332. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  333. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  334. package/src/runtime/office/index.mjs +30 -0
  335. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  336. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  337. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  338. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  339. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  340. package/src/runtime/office/shared/values.mjs +0 -5
  341. package/src/runtime/shared/background-tasks.mjs +92 -14
  342. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  343. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  344. package/src/runtime/shared/buffered-appender.mjs +18 -0
  345. package/src/runtime/shared/config.mjs +78 -18
  346. package/src/runtime/shared/err-text.mjs +31 -0
  347. package/src/runtime/shared/error-presentation.mjs +159 -19
  348. package/src/runtime/shared/file-permissions.d.mts +6 -1
  349. package/src/runtime/shared/file-permissions.mjs +54 -6
  350. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  351. package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
  352. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  353. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  354. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  355. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  356. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  357. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  358. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  359. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  360. package/src/runtime/shared/loopback-listener.mjs +9 -0
  361. package/src/runtime/shared/model-display.mjs +13 -0
  362. package/src/runtime/shared/provider-api-key.mjs +2 -0
  363. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  364. package/src/runtime/shared/review-diff.mjs +52 -0
  365. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  366. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  367. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  368. package/src/runtime/shared/slow-span.mjs +114 -0
  369. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  370. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  371. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  372. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  373. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  374. package/src/runtime/shared/tool-card-model.mjs +5 -2
  375. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  376. package/src/runtime/shared/tool-primitives.mjs +13 -0
  377. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  378. package/src/runtime/shared/tool-surface.mjs +18 -3
  379. package/src/runtime/shared/tool-work-units.mjs +40 -4
  380. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  381. package/src/runtime/shared/transcript-writer.mjs +10 -2
  382. package/src/runtime/shared/turn-changes.mjs +670 -274
  383. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  384. package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
  385. package/src/runtime/shared/turn-snapshot.mjs +986 -690
  386. package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
  387. package/src/runtime/shared/user-data-guard.mjs +262 -49
  388. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  389. package/src/runtime/shared/worktrees/contract.mjs +34 -24
  390. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  391. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  392. package/src/runtime/shared/worktrees/git.mjs +8 -3
  393. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  394. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  395. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  396. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  397. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  398. package/src/runtime/terminal-bridge/client.mjs +44 -11
  399. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  400. package/src/runtime/tidy/apply.mjs +47 -2
  401. package/src/runtime/tidy/run-engines.mjs +11 -5
  402. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  403. package/src/session-runtime/boot/apis.mjs +19 -5
  404. package/src/session-runtime/boot/facade.mjs +1 -0
  405. package/src/session-runtime/boot/infrastructure.mjs +12 -1
  406. package/src/session-runtime/boot/session.mjs +0 -1
  407. package/src/session-runtime/boot/tools.mjs +4 -1
  408. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  409. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  410. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  411. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  412. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  413. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  414. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  415. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  416. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
  417. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  418. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  419. package/src/session-runtime/lifecycle/teardown.mjs +73 -8
  420. package/src/session-runtime/lifecycle-api.mjs +1 -0
  421. package/src/session-runtime/mcp-glue/connect.mjs +46 -14
  422. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  423. package/src/session-runtime/mcp-glue.mjs +3 -0
  424. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  425. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  426. package/src/session-runtime/model-route/set-route.mjs +85 -17
  427. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  428. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  429. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  430. package/src/session-runtime/native-web-search.mjs +10 -1
  431. package/src/session-runtime/new-session-config.mjs +4 -2
  432. package/src/session-runtime/provider-auth/login.mjs +4 -0
  433. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  434. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  435. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  436. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  437. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  438. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  439. package/src/session-runtime/runtime-review-api.mjs +21 -2
  440. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  441. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  442. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  443. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  444. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  445. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  446. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  447. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  448. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  449. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  450. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  451. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  452. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  453. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  454. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  455. package/src/session-runtime/services/agent-tool.mjs +3 -0
  456. package/src/session-runtime/services/channel-admin.mjs +19 -3
  457. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  458. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  459. package/src/session-runtime/services/provider-admin.mjs +81 -15
  460. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  461. package/src/session-runtime/session-turn-api.mjs +14 -5
  462. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  463. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  464. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  465. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  466. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  467. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  468. package/src/session-runtime/skills-api.mjs +3 -5
  469. package/src/session-runtime/tool-surface.mjs +5 -1
  470. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  471. package/src/session-runtime/turn/session-ops.mjs +7 -5
  472. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  473. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  474. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  475. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  476. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  477. package/src/session-runtime/turn/turn-run.mjs +25 -9
  478. package/src/session-runtime/usage-stats-api.mjs +43 -11
  479. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  480. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  481. package/src/session-runtime/workspace/transitions.mjs +190 -15
  482. package/src/standalone/daemon-agent-control.mjs +9 -1
  483. package/src/standalone/daemon-drain-policy.mjs +8 -0
  484. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  485. package/src/standalone/daemon-owner.mjs +17 -4
  486. package/src/standalone/daemon-pg-stop.mjs +51 -0
  487. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  488. package/src/standalone/daemon-stop-budget.mjs +18 -0
  489. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  490. package/src/standalone/daemon-telemetry.mjs +74 -0
  491. package/src/standalone/daemon.mjs +64 -8
  492. package/src/standalone/desktop-service-registry.mjs +5 -0
  493. package/src/standalone/local-session-runtime.mjs +70 -19
  494. package/src/standalone/session-client.mjs +42 -0
  495. package/src/standalone/session-protocol.mjs +14 -0
  496. package/src/standalone/session-proxy/projection.mjs +41 -4
  497. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  498. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  499. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  500. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  501. package/src/standalone/session-service/agent-tree.mjs +12 -0
  502. package/src/standalone/session-service/quota-resume.mjs +8 -0
  503. package/src/standalone/session-service/retention/busy.mjs +15 -1
  504. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  505. package/src/standalone/session-service-api.mjs +11 -1
  506. package/src/standalone/session-service.mjs +1 -0
  507. package/src/standalone/session-state-patch.d.mts +2 -1
  508. package/src/standalone/session-state-patch.mjs +41 -1
  509. package/src/tui/App.jsx +25 -0
  510. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  511. package/src/tui/app/app-view.jsx +1 -0
  512. package/src/tui/app/btw-controller.mjs +118 -0
  513. package/src/tui/app/create-app-pickers.mjs +6 -0
  514. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  515. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  516. package/src/tui/app/extension-pickers.mjs +2 -1
  517. package/src/tui/app/model-options.mjs +11 -16
  518. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  519. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  520. package/src/tui/app/slash-commands.mjs +20 -5
  521. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  522. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  523. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  524. package/src/tui/app/use-global-key-input.mjs +5 -12
  525. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  526. package/src/tui/components/BtwPanel.jsx +53 -0
  527. package/src/tui/components/QuestionPanel.jsx +275 -0
  528. package/src/tui/components/StatusLine.jsx +2 -0
  529. package/src/tui/components/question-panel-model.mjs +156 -0
  530. package/src/tui/components/status-line/local-line.mjs +5 -2
  531. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  532. package/src/tui/dist/index.mjs +3221 -1500
  533. package/src/tui/session/context-state.mjs +4 -2
  534. package/src/tui/session/quota-resume.mjs +46 -14
  535. package/src/tui/session/session-api/commands.mjs +43 -24
  536. package/src/tui/session/session-api/controls.mjs +2 -2
  537. package/src/tui/session/session-api/extensions.mjs +22 -0
  538. package/src/tui/session/session-api/integrations.mjs +16 -2
  539. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  540. package/src/tui/session/session-api/lifecycle.mjs +7 -2
  541. package/src/tui/session/session-api/routes.mjs +71 -7
  542. package/src/tui/session/session-api/settings.mjs +11 -14
  543. package/src/tui/session/session-api.mjs +1 -0
  544. package/src/tui/session/session-flow/drain.mjs +7 -1
  545. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  546. package/src/tui/session/tool-approval.mjs +10 -7
  547. package/src/tui/session/transcript-spill.mjs +14 -7
  548. package/src/tui/session/turn-stream.mjs +174 -31
  549. package/src/tui/session/turn.mjs +46 -16
  550. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  551. package/src/ui/statusline-agents.mjs +15 -4
  552. package/src/ui/statusline.mjs +7 -3
  553. package/src/ui/streaming-markdown-heal.mjs +34 -3
  554. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  555. package/src/workflows/default/WORKFLOW.md +3 -1
  556. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  557. 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,48 +100,79 @@ 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;
97
163
  }
98
164
 
99
165
  /**
100
166
  * Effort levels the wire builder sends unchanged for `model` (reserved `max`
101
167
  * excluded), from the same capability gates normalizeAnthropicEffortInput and
102
- * applyAnthropicEffortToBody use: catalog record first, regex ladder for an
103
- * absent record. A model without effort support, or whose catalog record
168
+ * applyAnthropicEffortToBody use: catalog record first, generation floor for
169
+ * an absent record. A model without effort support, or whose catalog record
104
170
  * declares none, accepts none.
105
171
  */
106
172
  export function anthropicEffortLevelsFor(model) {
107
- if (!modelSupportsEffort(model)) return [];
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 [];
108
176
  const levels = ['low', 'medium', 'high'];
109
177
  if (modelSupportsXhighEffort(model)) levels.push('xhigh');
110
178
  return levels;
@@ -123,121 +191,41 @@ const _LOGGED_EFFORT_NORMALIZATION = new Set();
123
191
  const _LOGGED_UNKNOWN_EFFORT = new Set();
124
192
  const MAX_LOGGED_UNKNOWN_EFFORTS = 100;
125
193
 
126
- function parseClaudeVersion(model) {
127
- const m = normalizeModelId(model);
128
- const triple = m.match(/^claude-(haiku|sonnet|opus|fable)-(\d+)-(\d+)/);
129
- if (triple) {
130
- return { family: triple[1], major: Number(triple[2]), minor: Number(triple[3]) };
131
- }
132
- // Bare version ids carry family + major only (claude-opus-5). opus/haiku
133
- // were missing here, so `claude-opus-5` parsed to null and fell through
134
- // every capability check as an unknown shape.
135
- const pair = m.match(/^claude-(sonnet|fable|opus|haiku)-(\d+)(?:$|[-@])/);
136
- if (pair) {
137
- return { family: pair[1], major: Number(pair[2]), minor: null };
138
- }
139
- // Legacy naming: version comes BEFORE the family (claude-3-7-sonnet,
140
- // claude-3-5-sonnet, claude-3-opus). These are manual-thinking models —
141
- // parse them so isLegacyAnthropicReasoningModel excludes them instead of
142
- // letting modelSupportsEffort's `startsWith('claude-')` fallthrough grant
143
- // them adaptive thinking + the effort beta (a hard 400).
144
- const legacy = m.match(/^claude-(\d+)-(\d+)-(haiku|sonnet|opus)/);
145
- if (legacy) {
146
- return { family: legacy[3], major: Number(legacy[1]), minor: Number(legacy[2]) };
147
- }
148
- return null;
149
- }
150
-
151
- function isLegacyAnthropicReasoningModel(model) {
152
- const parsed = parseClaudeVersion(model);
153
- if (!parsed) return false;
154
- if (parsed.family === 'haiku') return true;
155
- if (parsed.family === 'fable') return false;
156
- if (parsed.family === 'sonnet' || parsed.family === 'opus') {
157
- if (parsed.major < 4) return true;
158
- if (parsed.major === 4 && parsed.minor !== null && parsed.minor < 6) return true;
159
- // Bare major, no minor (claude-opus-4 / claude-sonnet-4): adaptive
160
- // effort only ships from 5 up, so 4.x aliases stay manual-thinking.
161
- if (parsed.minor === null && parsed.major < 5) return true;
162
- return false;
163
- }
164
- return false;
165
- }
166
-
167
- // @[MODEL LAUNCH]: extend allowlist when new Claude models ship with effort support.
168
194
  export function modelSupportsEffort(model) {
169
195
  if (isEnvTruthy(process.env.MIXDOG_ANTHROPIC_ALWAYS_ENABLE_EFFORT)) return true;
170
196
  const advertised = _catalogLevels(model);
171
197
  if (advertised) return advertised.size > 0;
172
- return _regexSupportsEffort(model);
198
+ return _floorSupportsEffort(model);
173
199
  }
174
200
 
175
- // Fallback ladder for ids the catalog does not carry. Also used by
176
- // effortValuesForModel, which BUILDS the catalog records and therefore must
177
- // never consult the index it feeds.
178
- function _regexSupportsEffort(model) {
179
- const m = normalizeModelId(model);
180
- if (!m.includes('claude')) return false;
181
- if (isLegacyAnthropicReasoningModel(model)) return false;
182
- if (isAnthropicAdaptiveOnlyModel(model)) return true;
183
- if (m.includes('opus-4-6') || m.includes('sonnet-4-6')) return true;
184
- if (m.includes('sonnet-5') || m.includes('fable-5')) return true;
185
- if (/^claude-mythos-5-1(?:-\d{8})?$/.test(m)) return true;
186
- if (/^claude-opus-4-(6|7|8)(?:$|[-@])/.test(m)) return true;
187
- if (/^claude-opus-5(?:$|[-@])/.test(m)) return true;
188
- // Fallthrough for not-yet-enumerated modern models: only grant effort when
189
- // parseClaudeVersion resolves a family with major>=4 (and not a manual-
190
- // thinking legacy already excluded above). A bare `startsWith('claude-')`
191
- // here would hand thinking:adaptive + the effort beta to legacy/unknown
192
- // IDs (e.g. claude-3-7-sonnet) → hard 400. Unknown-shape IDs (no version
193
- // parsed) fall through to false: no effort, no adaptive thinking.
194
- const parsed = parseClaudeVersion(model);
195
- if (
196
- parsed &&
197
- (parsed.family === 'sonnet' || parsed.family === 'opus' || parsed.family === 'fable') &&
198
- parsed.major >= 4
199
- ) {
200
- return true;
201
- }
202
- 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);
203
208
  }
204
209
 
205
- // @[MODEL LAUNCH]: extend when new models support xhigh effort.
206
- // Per platform.claude.com/docs/en/build-with-claude/effort — xhigh is
207
- // supported by: Fable 5, Mythos 5, Opus 4.8, Opus 4.7, Sonnet 5.
208
- // NOT Opus 4.6 / Sonnet 4.6 (those support max but not xhigh).
209
210
  export function modelSupportsXhighEffort(model) {
210
211
  const advertised = _catalogLevels(model);
211
212
  if (advertised) return advertised.has('xhigh');
212
- return _regexSupportsXhighEffort(model);
213
+ return _floorSupportsXhighEffort(model);
213
214
  }
214
215
 
215
- function _regexSupportsXhighEffort(model) {
216
- const m = normalizeModelId(model);
217
- if (/^claude-opus-4-(7|8)(?:$|[-@])/.test(m)) return true;
218
- if (/^claude-opus-5(?:$|[-@])/.test(m)) return true;
219
- if (/^claude-sonnet-5(?:$|[-@])/.test(m)) return true;
220
- if (/^claude-fable-5(?:$|[-@])/.test(m)) return true;
221
- if (/^claude-mythos-5(?:$|[-@])/.test(m)) return true;
222
- if (/^claude-mythos-preview(?:$|[-@])/.test(m)) return true;
223
- return false;
216
+ function _floorSupportsXhighEffort(model) {
217
+ return claudeGenerationAtLeast(model, CLAUDE_GENERATION_FLOOR.xhighEffort);
224
218
  }
225
219
 
226
- // @[MODEL LAUNCH]: extend when new Opus models support max effort.
227
- // Max list = xhigh list PLUS Opus 4.6, Sonnet 4.6, Opus 4.5.
228
220
  export function modelSupportsMaxEffort(model) {
229
221
  const advertised = _catalogLevels(model);
230
- // xhigh support implies max support (kept from the ladder below).
222
+ // xhigh support implies max support.
231
223
  if (advertised) return advertised.has('max') || advertised.has('xhigh');
232
- return _regexSupportsMaxEffort(model);
224
+ return _floorSupportsMaxEffort(model);
233
225
  }
234
226
 
235
- function _regexSupportsMaxEffort(model) {
236
- if (_regexSupportsXhighEffort(model)) return true;
237
- const m = normalizeModelId(model);
238
- if (/^claude-opus-4-(5|6)(?:$|[-@])/.test(m)) return true;
239
- if (/^claude-sonnet-4-6(?:$|[-@])/.test(m)) return true;
240
- return false;
227
+ function _floorSupportsMaxEffort(model) {
228
+ return claudeGenerationAtLeast(model, CLAUDE_GENERATION_FLOOR.maxEffort);
241
229
  }
242
230
 
243
231
  function isEnvTruthy(value) {
@@ -290,7 +278,8 @@ export function normalizeAnthropicEffortInput(raw, model, logTag = 'anthropic')
290
278
  export function shouldIncludeEffortBeta(model, opts = {}) {
291
279
  const thinkingBudgetTokens = Number(opts.thinkingBudgetTokens);
292
280
  if (Number.isFinite(thinkingBudgetTokens) && thinkingBudgetTokens > 0) return false;
293
- return modelSupportsEffort(model);
281
+ // Only requests that carry output_config effort (adaptive path) need the beta.
282
+ return modelSupportsEffort(model) && _usesAdaptiveThinking(model);
294
283
  }
295
284
 
296
285
  /**
@@ -302,6 +291,12 @@ export function applyAnthropicEffortToBody(
302
291
  ) {
303
292
  if (!body || typeof body !== 'object') return;
304
293
 
294
+ // A gateway that declares its own effort contract (DeepSeek ignores
295
+ // budget_tokens) projects effort itself; returning true skips the Claude rules.
296
+ if (typeof opts.messagesEffortProjection === 'function') {
297
+ if (opts.messagesEffortProjection(body, { model, effort: opts.effort }) === true) return;
298
+ }
299
+
305
300
  const thinkingBudgetTokens = Number(opts.thinkingBudgetTokens);
306
301
  if (Number.isFinite(thinkingBudgetTokens) && thinkingBudgetTokens > 0) {
307
302
  assertAnthropicManualBudgetSupported(model);
@@ -314,7 +309,7 @@ export function applyAnthropicEffortToBody(
314
309
 
315
310
  const normalized = normalizeAnthropicEffortInput(opts.effort, model, logTag);
316
311
 
317
- if (modelSupportsEffort(model)) {
312
+ if (modelSupportsEffort(model) && _usesAdaptiveThinking(model)) {
318
313
  if (normalized) {
319
314
  const existing = body.output_config && typeof body.output_config === 'object' ? body.output_config : {};
320
315
  body.output_config = { ...existing, effort: normalized };
@@ -386,10 +381,10 @@ export function effortValuesForModel(capabilities, modelId) {
386
381
  // the model supports effort but doesn't enumerate levels, so derive the
387
382
  // set from the known level ladder, gated by the top-tier model check.
388
383
  let levels = [...EFFORT_LEVELS];
389
- if (!_regexSupportsMaxEffort(modelId)) {
384
+ if (!_floorSupportsMaxEffort(modelId)) {
390
385
  levels = levels.filter((level) => level !== 'max');
391
386
  }
392
- if (!_regexSupportsXhighEffort(modelId)) {
387
+ if (!_floorSupportsXhighEffort(modelId)) {
393
388
  levels = levels.filter((level) => level !== 'xhigh');
394
389
  }
395
390
  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;
@@ -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
  /**
@@ -132,6 +132,17 @@ export function providerCatalogEntry(provider) {
132
132
  };
133
133
  }
134
134
 
135
+ /** models.dev ids of the registered non-relay providers: vendors that serve their own models. */
136
+ export function firstPartyModelsDevIds() {
137
+ return [
138
+ ...new Set(
139
+ Object.values(PROVIDER_CATALOGS)
140
+ .filter((entry) => entry.relay !== true && entry.modelsDev)
141
+ .map((entry) => entry.modelsDev)
142
+ ),
143
+ ].sort();
144
+ }
145
+
135
146
  export function modelsDevProviderId(provider) {
136
147
  return providerCatalogEntry(provider)?.modelsDev || null;
137
148
  }