mixdog 1.1.2 → 1.2.1

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 (424) hide show
  1. package/README.md +8 -5
  2. package/package.json +2 -1
  3. package/scripts/lib/run-node-tests.mjs +9 -0
  4. package/scripts/prune-desktop-runtime.mjs +3 -0
  5. package/scripts/test-direct.mjs +4 -2
  6. package/src/defaults/shipped-history.json +10 -0
  7. package/src/defaults/skills/pptx/SKILL.md +6 -6
  8. package/src/defaults/skills/pptx/references/review.md +6 -4
  9. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  10. package/src/defaults/skills/setup/references/actions.md +18 -5
  11. package/src/defaults/skills/visualize/SKILL.md +160 -0
  12. package/src/defaults/skills/visualize/references/craft.md +88 -0
  13. package/src/headless-command.mjs +56 -3
  14. package/src/headless-exec.mjs +17 -1
  15. package/src/help.mjs +2 -0
  16. package/src/rules/shared/60-verification.md +3 -1
  17. package/src/rules/shared/70-delivery.md +4 -2
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
  21. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  22. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
  24. package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +19 -5
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +133 -15
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +55 -8
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +86 -8
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +474 -164
  33. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  34. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  35. package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
  36. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
  37. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  38. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
  40. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -12
  41. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
  42. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  43. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  45. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  50. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +21 -6
  51. package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
  52. package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
  53. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  54. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  55. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  56. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
  57. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
  58. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
  59. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
  60. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  61. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +82 -0
  62. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +556 -0
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
  64. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
  65. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
  66. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +15 -0
  67. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  68. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
  72. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +15 -4
  73. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
  77. package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -7
  78. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
  79. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
  80. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -11
  81. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  82. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  83. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +278 -84
  85. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  86. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  87. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  88. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
  90. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
  91. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
  92. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  93. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
  94. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  95. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  96. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
  97. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +24 -13
  98. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
  99. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
  100. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
  101. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  102. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  103. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  104. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  105. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  106. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  107. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  108. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  109. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
  111. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
  112. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
  113. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
  114. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +5 -3
  115. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -4
  116. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +21 -10
  117. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  118. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
  120. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -3
  121. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +22 -12
  122. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
  123. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +9 -3
  124. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
  125. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
  126. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
  127. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
  128. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
  131. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
  133. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  136. package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
  137. package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
  138. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +33 -22
  139. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  140. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
  141. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  142. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
  143. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
  144. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
  145. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +36 -0
  146. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +23 -12
  147. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  148. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +202 -374
  149. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
  150. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  151. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +48 -9
  153. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +161 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  155. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  156. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
  157. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
  158. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
  159. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  160. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  161. package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
  162. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +203 -33
  163. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
  164. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  165. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
  166. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
  167. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -68
  168. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
  169. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +20 -3
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
  173. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
  174. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
  175. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
  176. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  177. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  179. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
  180. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
  181. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  182. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
  184. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  185. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  186. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  187. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  188. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  189. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  190. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
  191. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
  192. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  193. package/src/runtime/attachments/store.d.mts +3 -0
  194. package/src/runtime/attachments/store.mjs +38 -0
  195. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  196. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  197. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  199. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  200. package/src/runtime/memory/lib/memory.mjs +1 -1
  201. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  202. package/src/runtime/shared/atomic-file.mjs +33 -6
  203. package/src/runtime/shared/best-effort-stderr.mjs +8 -0
  204. package/src/runtime/shared/code-graph-state.mjs +12 -0
  205. package/src/runtime/shared/defaults-separation.mjs +2 -0
  206. package/src/runtime/shared/extension-scopes.mjs +5 -3
  207. package/src/runtime/shared/file-lock.mjs +37 -11
  208. package/src/runtime/shared/git-runner-worker.mjs +3 -2
  209. package/src/runtime/shared/git-runner.mjs +4 -3
  210. package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
  211. package/src/runtime/shared/llm/default-context-window.mjs +6 -0
  212. package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
  213. package/src/runtime/shared/llm/model-catalog.mjs +240 -130
  214. package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
  215. package/src/runtime/shared/llm/provider-catalog-registry.mjs +162 -0
  216. package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
  217. package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
  218. package/src/runtime/shared/model-proxy-mode.mjs +19 -0
  219. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  220. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  221. package/src/runtime/shared/pristine-execution.mjs +28 -4
  222. package/src/runtime/shared/provider-accounts.mjs +125 -21
  223. package/src/runtime/shared/provider-api-key.mjs +33 -1
  224. package/src/runtime/shared/schedule-model-ref.mjs +11 -2
  225. package/src/runtime/shared/session-usage-totals.mjs +19 -0
  226. package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
  227. package/src/runtime/shared/shell-display.mjs +9 -3
  228. package/src/runtime/shared/singleton-owner.mjs +36 -6
  229. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  230. package/src/runtime/shared/skill-mentions.mjs +133 -0
  231. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  232. package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
  233. package/src/runtime/shared/tool-primitives.mjs +35 -2
  234. package/src/runtime/shared/tool-surface.mjs +7 -0
  235. package/src/runtime/shared/tool-work-units.mjs +14 -0
  236. package/src/runtime/shared/transcript-metadata.mjs +17 -1
  237. package/src/runtime/shared/turn-changes.mjs +791 -0
  238. package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
  239. package/src/runtime/shared/turn-snapshot.mjs +690 -81
  240. package/src/runtime/shared/turn-worktree-snapshot.mjs +185 -15
  241. package/src/runtime/shared/worker-requests.mjs +15 -2
  242. package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
  243. package/src/runtime/shared/worktrees/contract.mjs +551 -0
  244. package/src/runtime/shared/worktrees/disk.mjs +57 -0
  245. package/src/runtime/shared/worktrees/git.mjs +247 -0
  246. package/src/runtime/shared/worktrees/include.mjs +480 -0
  247. package/src/runtime/shared/worktrees/lock.mjs +46 -0
  248. package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
  249. package/src/runtime/shared/worktrees/manager.mjs +1215 -0
  250. package/src/runtime/shared/worktrees/merge.mjs +182 -0
  251. package/src/runtime/shared/worktrees/owner.mjs +46 -0
  252. package/src/runtime/shared/worktrees/paths.mjs +62 -0
  253. package/src/runtime/shared/worktrees/registry.mjs +110 -0
  254. package/src/runtime/shared/worktrees/settings.mjs +84 -0
  255. package/src/runtime/shared/worktrees/slug.mjs +62 -0
  256. package/src/runtime/shared/worktrees/test-support.mjs +96 -0
  257. package/src/runtime/visualize-bridge/client.mjs +181 -0
  258. package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
  259. package/src/session-runtime/automation-agents.mjs +8 -2
  260. package/src/session-runtime/boot/apis.mjs +90 -0
  261. package/src/session-runtime/boot/config.mjs +7 -2
  262. package/src/session-runtime/boot/facade.mjs +21 -0
  263. package/src/session-runtime/boot/infrastructure.mjs +30 -18
  264. package/src/session-runtime/boot/session.mjs +1 -0
  265. package/src/session-runtime/boot/tools.mjs +4 -0
  266. package/src/session-runtime/config-lifecycle.mjs +10 -1
  267. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  268. package/src/session-runtime/conversation-import/service.mjs +369 -0
  269. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +21 -6
  270. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  271. package/src/session-runtime/global-extensions.mjs +2 -2
  272. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
  273. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
  274. package/src/session-runtime/internal-tool-executor.mjs +9 -1
  275. package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
  276. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
  277. package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
  278. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
  279. package/src/session-runtime/mcp-glue/connect.mjs +68 -16
  280. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  281. package/src/session-runtime/mcp-glue/server-catalog.mjs +122 -33
  282. package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
  283. package/src/session-runtime/mcp-glue.mjs +22 -2
  284. package/src/session-runtime/model-route/route-persist.mjs +3 -0
  285. package/src/session-runtime/model-route/set-route.mjs +15 -2
  286. package/src/session-runtime/new-session-config.mjs +3 -2
  287. package/src/session-runtime/notification-bus.mjs +18 -3
  288. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  289. package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
  290. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  291. package/src/session-runtime/provider-readiness.mjs +16 -10
  292. package/src/session-runtime/resource-extension-sync.mjs +45 -7
  293. package/src/session-runtime/resource-mcp-api.mjs +121 -84
  294. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  295. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  296. package/src/session-runtime/resource-skills-api.mjs +23 -2
  297. package/src/session-runtime/route-resolution.mjs +10 -1
  298. package/src/session-runtime/route-state.mjs +16 -2
  299. package/src/session-runtime/runtime-core.mjs +5 -0
  300. package/src/session-runtime/runtime-facade.mjs +8 -0
  301. package/src/session-runtime/runtime-review-api.mjs +9 -0
  302. package/src/session-runtime/schedule-session-run.mjs +1 -1
  303. package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
  304. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
  305. package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
  306. package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
  307. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
  308. package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
  310. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
  311. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  312. package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
  313. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
  314. package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
  315. package/src/session-runtime/services/agent-tool.mjs +1 -0
  316. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  317. package/src/session-runtime/services/daemon-candidate.mjs +3 -2
  318. package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
  319. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  320. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  321. package/src/session-runtime/services/provider-admin.mjs +64 -18
  322. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  323. package/src/session-runtime/session-create/session-options.mjs +10 -1
  324. package/src/session-runtime/session-turn-api.mjs +1 -0
  325. package/src/session-runtime/settings-api.mjs +4 -2
  326. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
  327. package/src/session-runtime/settings-worktree-api.mjs +17 -0
  328. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  329. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  330. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -1
  331. package/src/session-runtime/setup-tool/tool-defs.mjs +38 -4
  332. package/src/session-runtime/skills-api.mjs +7 -3
  333. package/src/session-runtime/turn/agent-ops.mjs +12 -1
  334. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +14 -3
  335. package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
  336. package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
  337. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
  338. package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
  339. package/src/session-runtime/turn/turn-run.mjs +6 -7
  340. package/src/session-runtime/webhook-session-run.mjs +16 -4
  341. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
  342. package/src/session-runtime/workspace/admission-gate.mjs +197 -0
  343. package/src/session-runtime/workspace/project-branches.mjs +136 -0
  344. package/src/session-runtime/workspace/transition-steps.mjs +364 -0
  345. package/src/session-runtime/workspace/transitions.mjs +651 -0
  346. package/src/session-runtime/workspace/workspace-state.mjs +112 -0
  347. package/src/skill-script-entry.mjs +36 -0
  348. package/src/standalone/channel-transport/http-routes.mjs +17 -0
  349. package/src/standalone/channel-transport.mjs +13 -1
  350. package/src/standalone/daemon-desktop-runtime.mjs +1 -0
  351. package/src/standalone/daemon-owner.mjs +372 -0
  352. package/src/standalone/daemon-stored-session-views.mjs +15 -4
  353. package/src/standalone/daemon.mjs +179 -8
  354. package/src/standalone/desktop-service-registry.mjs +20 -0
  355. package/src/standalone/local-session-runtime.mjs +11 -0
  356. package/src/standalone/session-client/attachment-calls.mjs +3 -1
  357. package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
  358. package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
  359. package/src/standalone/session-client.mjs +104 -13
  360. package/src/standalone/session-protocol.mjs +21 -0
  361. package/src/standalone/session-proxy.mjs +3 -0
  362. package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
  363. package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
  364. package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
  365. package/src/standalone/session-service/projection/revisions.mjs +2 -0
  366. package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
  367. package/src/standalone/session-service/projection/workspace.mjs +14 -0
  368. package/src/standalone/session-service/session-calls/session-action.mjs +17 -4
  369. package/src/standalone/session-transport/call-route.mjs +13 -0
  370. package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
  371. package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
  372. package/src/standalone/session-transport/client-registry.mjs +20 -3
  373. package/src/standalone/session-transport/routes.mjs +79 -2
  374. package/src/standalone/session-transport/stack.mjs +2 -0
  375. package/src/standalone/session-transport.mjs +24 -1
  376. package/src/tui/App.jsx +9 -1
  377. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  378. package/src/tui/app/app-view.jsx +6 -0
  379. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  380. package/src/tui/app/message-selector.mjs +2 -1
  381. package/src/tui/app/model-options.mjs +37 -5
  382. package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
  383. package/src/tui/app/model-picker.mjs +4 -2
  384. package/src/tui/app/skill-mention-palette.mjs +88 -0
  385. package/src/tui/app/slash-palette.mjs +23 -7
  386. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  387. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  388. package/src/tui/app/use-prompt-state.mjs +5 -0
  389. package/src/tui/components/Message.jsx +22 -1
  390. package/src/tui/components/PromptInput.jsx +21 -3
  391. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  392. package/src/tui/components/TranscriptItem.jsx +9 -1
  393. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  394. package/src/tui/components/user-message-skills.mjs +38 -0
  395. package/src/tui/dist/index.mjs +839 -207
  396. package/src/tui/index.jsx +10 -2
  397. package/src/tui/session/compaction-view.mjs +147 -0
  398. package/src/tui/session/context-state.mjs +6 -0
  399. package/src/tui/session/initial-state.mjs +3 -0
  400. package/src/tui/session/queue-helpers.mjs +7 -2
  401. package/src/tui/session/quota-resume.mjs +2 -1
  402. package/src/tui/session/session-api/commands.mjs +10 -2
  403. package/src/tui/session/session-api/controls.mjs +4 -0
  404. package/src/tui/session/session-api/extensions.mjs +4 -2
  405. package/src/tui/session/session-api/intake/rewind.mjs +2 -1
  406. package/src/tui/session/session-api/integrations.mjs +17 -0
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
  408. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
  409. package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
  410. package/src/tui/session/session-api/routes.mjs +10 -1
  411. package/src/tui/session/session-api/settings.mjs +9 -0
  412. package/src/tui/session/session-api/worktree.mjs +60 -0
  413. package/src/tui/session/session-api.mjs +2 -0
  414. package/src/tui/session/session-flow/auto-clear.mjs +31 -12
  415. package/src/tui/session/session-flow/drain.mjs +27 -3
  416. package/src/tui/session/session-flow/session-reset.mjs +4 -3
  417. package/src/tui/session/session-flow.mjs +2 -0
  418. package/src/tui/session/transcript-intake.mjs +14 -5
  419. package/src/tui/session/tui-steering-persist.mjs +25 -9
  420. package/src/tui/session/turn-stream.mjs +32 -4
  421. package/src/tui/session/turn-tool-cards.mjs +10 -2
  422. package/src/tui/session/turn.mjs +56 -10
  423. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  424. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
@@ -20,12 +20,19 @@ import { createHash } from 'node:crypto';
20
20
  import { resolvePluginData } from '../plugin-paths.mjs';
21
21
  import { writeJsonAtomicSync } from '../atomic-file.mjs';
22
22
  import {
23
+ capabilityFlag,
24
+ rosterRowMetadata,
23
25
  providerCachedModelMetadataSync,
24
- providerUsesEndpointScopedLimits,
25
26
  providerPricingModelSync,
26
27
  cachedProviderModelListsSync,
27
28
  providerCachedModelsSync,
28
29
  } from './provider-catalog-cache.mjs';
30
+ import {
31
+ modelsDevProviderId,
32
+ providerCatalogEntry,
33
+ providerMetadataCorrection,
34
+ providerSeedRow,
35
+ } from './provider-catalog-registry.mjs';
29
36
  import { litellmMediaPricing, litellmPricing, modelsDevPricing, PRICING_RATE_KEYS } from './model-pricing-rates.mjs';
30
37
  // Both overlays are narrowed to their read surface before becoming resident;
31
38
  // the disk caches below still receive the full payload.
@@ -45,34 +52,21 @@ const MODELSDEV_CACHE_FILE = 'modelsdev-catalog.json';
45
52
  export const PRICING_CATALOG_REFRESH_MS = 6 * 60 * 60 * 1000;
46
53
  const PRICING_CATALOG_RETRY_MS = 60_000;
47
54
 
48
- // mixdog provider id → models.dev provider id. Identity for ids that already
49
- // match (opencode-go / deepseek / xai / openai / anthropic / groq /
50
- // mistral); only the OAuth aliases and gemini→google need remapping.
51
- const _MODELSDEV_PROVIDER_ALIAS = {
52
- 'anthropic-oauth': 'anthropic',
53
- 'openai-oauth': 'openai',
54
- 'grok-oauth': 'xai',
55
- 'mimo-oauth': 'xiaomi',
56
- gemini: 'google',
57
- };
58
- function _modelsDevProviderId(provider) {
59
- if (!provider) return null;
60
- const p = String(provider).toLowerCase();
61
- return _MODELSDEV_PROVIDER_ALIAS[p] || p;
62
- }
63
-
55
+ // The mixdog provider → models.dev provider mapping, relay flags, live-roster
56
+ // files and seeds live in provider-catalog-registry.mjs.
57
+ //
64
58
  // Relays sell access, not models: one subscription fronts Anthropic, Google,
65
- // OpenAI and xAI SKUs at once. No catalog lists them under the relay's own
66
- // name, so a provider-keyed lookup finds nothing and the route silently prices
67
- // at zero — indistinguishable from a genuinely free local model.
68
- const _RELAY_PROVIDERS = new Set(['cursor-oauth', 'cursor-api', 'antigravity-oauth', 'opencode-go', 'muse-code-oauth']);
69
-
70
- // Which vendor actually served a relayed model, read off the model id. This is
71
- // a LAST resort: it runs only after the provider-keyed lookup has already
72
- // failed, so a route with real catalog coverage can never be repriced by a
73
- // name guess. Ids are matched on their leading family token rather than a bare
74
- // substring, so an unrelated model that merely mentions a vendor is not
75
- // adopted by it.
59
+ // OpenAI and xAI SKUs at once. Few catalogs list them under the relay's own
60
+ // name, so a provider-keyed lookup can find nothing and the route silently
61
+ // prices at zero — indistinguishable from a genuinely free local model.
62
+
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.
76
70
  const _RELAYED_MODEL_VENDORS = [
77
71
  [/^claude[-.]/, 'anthropic'],
78
72
  [/^(gpt|o[1-9]|codex)[-.]/, 'openai'],
@@ -82,6 +76,10 @@ const _RELAYED_MODEL_VENDORS = [
82
76
  [/^kimi[-.]/, 'moonshotai'],
83
77
  [/^glm[-.]/, 'zai'],
84
78
  [/^muse[-.]/, 'meta'],
79
+ [/^qwen(?:\d|[-.])/, 'alibaba'],
80
+ [/^minimax[-.]/, 'minimax'],
81
+ [/^mimo[-.]/, 'xiaomi'],
82
+ [/^longcat[-.]/, 'longcat'],
85
83
  ];
86
84
 
87
85
  function _relayedModelVendor(id) {
@@ -93,12 +91,6 @@ function _relayedModelVendor(id) {
93
91
  return null;
94
92
  }
95
93
 
96
- /** The vendor to reprice a relayed model under, or null to leave it alone. */
97
- function _relayPricingProvider(provider, id) {
98
- if (!provider || !_RELAY_PROVIDERS.has(String(provider).toLowerCase())) return null;
99
- return _relayedModelVendor(id);
100
- }
101
-
102
94
  // Provider prefix variants used by the shared catalog resolver.
103
95
  // A provider needing a new prefix adds it here.
104
96
  // Source: LiteLLM catalog key conventions (see CATALOG_URL above).
@@ -118,7 +110,7 @@ const _CATALOG_BEDROCK_PREFIXES = ['anthropic.', 'bedrock/anthropic.'];
118
110
 
119
111
  // Provider hint → catalog prefixes to try (subset of _CATALOG_SIMPLE_PREFIXES).
120
112
  // Keyed by the *mapped* models.dev provider id
121
- // (see _modelsDevProviderId), so anthropic-oauth and anthropic share one
113
+ // (see modelsDevProviderId), so anthropic-oauth and anthropic share one
122
114
  // entry, likewise grok-oauth/xai and gemini/google. A provider missing here
123
115
  // (unknown/custom) gets bare-id lookup only — no prefix guessing across
124
116
  // unrelated providers. No provider hint at all (mappedProvider null) keeps
@@ -366,12 +358,13 @@ function _modelsDevMetadata(row) {
366
358
  max_input_tokens: row?.limit?.context,
367
359
  max_output_tokens: row?.limit?.output,
368
360
  mode: 'chat',
369
- supports_reasoning: row?.reasoning === true,
361
+ // Undeclared capabilities stay undefined (see capabilityFlag).
362
+ supports_reasoning: capabilityFlag(row?.reasoning),
370
363
  reasoning_options: Array.isArray(row?.reasoning_options) ? row.reasoning_options : [],
371
364
  reasoning_content_field: row?.interleaved?.field || null,
372
- supports_function_calling: row?.tool_call === true,
373
- supports_vision: Array.isArray(row?.modalities?.input) && row.modalities.input.includes('image'),
374
- supports_prompt_caching: c.cache_read != null,
365
+ supports_function_calling: capabilityFlag(row?.tool_call),
366
+ supports_vision: Array.isArray(row?.modalities?.input) ? row.modalities.input.includes('image') : undefined,
367
+ supports_prompt_caching: c.cache_read != null ? true : undefined,
375
368
  };
376
369
  return { ..._normalize(out), ...modelsDevPricing(c), pricingSource: row?.cost ? 'models.dev' : null };
377
370
  }
@@ -387,7 +380,7 @@ export function getModelsDevRowSync(id, provider, _test) {
387
380
  if (!_test) warmModelsDevFromDiskSync();
388
381
  const cat = _test || modelsDevSource.cache;
389
382
  if (!cat) return null;
390
- const pid = _modelsDevProviderId(provider);
383
+ const pid = modelsDevProviderId(provider);
391
384
  if (!pid) return null;
392
385
  const row = cat?.[pid]?.models?.[id];
393
386
  return row || null;
@@ -400,7 +393,7 @@ export function getModelsDevProviderModelsSync(provider, _test) {
400
393
  if (!_test) warmModelsDevFromDiskSync();
401
394
  const cat = _test || modelsDevSource.cache;
402
395
  if (!cat) return null;
403
- const pid = _modelsDevProviderId(provider);
396
+ const pid = modelsDevProviderId(provider);
404
397
  if (!pid) return null;
405
398
  const models = cat?.[pid]?.models;
406
399
  return models && typeof models === 'object' ? models : null;
@@ -486,11 +479,85 @@ function scaledRates(row, factor) {
486
479
  return Object.fromEntries(PRICING_RATE_KEYS.map((key) => [key, row?.[key] == null ? null : row[key] * factor]));
487
480
  }
488
481
 
489
- // Both list enrichment and synchronous accounting use this exact resolver.
490
- function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog) {
491
- const id = providerPricingModelSync(provider, originalId);
492
- const mappedProvider = provider ? _modelsDevProviderId(provider) : null;
493
- const providerNative = provider ? providerCachedModelMetadataSync(provider, originalId) : null;
482
+ // Pricing a catalog row can lend to a route it does not describe.
483
+ const PRICING_FIELDS = Object.freeze([
484
+ ...PRICING_RATE_KEYS,
485
+ 'pricingTiers',
486
+ 'fastPricing',
487
+ 'ultrafastPricing',
488
+ 'offPeakMultiplier',
489
+ 'outputImageCostPerM',
490
+ 'outputVideoCostPerM',
491
+ 'outputCostPerImage',
492
+ 'outputCostPerSecond',
493
+ 'outputCostPerSecondByResolution',
494
+ 'pricingSource',
495
+ 'pricingProvider',
496
+ // Decides whether a cache-read rate is required, so it travels with prices.
497
+ 'supportsPromptCaching',
498
+ ]);
499
+ const hasRates = (meta) => PRICING_RATE_KEYS.some((key) => meta?.[key] != null);
500
+
501
+ function pricingFields(meta) {
502
+ return Object.fromEntries(PRICING_FIELDS.filter((key) => meta?.[key] !== undefined).map((key) => [key, meta[key]]));
503
+ }
504
+
505
+ // A vendor row describes the vendor's own endpoint. Elsewhere it prices the
506
+ // model and lends its label; capabilities and the effort ladder come back
507
+ // only as a guess (withVendorGuess), its limits never.
508
+ function pricingOnly(meta) {
509
+ if (!meta) return null;
510
+ return { ..._normalize({}), ...pricingFields(meta), displayName: meta.displayName || null };
511
+ }
512
+
513
+ // Capabilities a vendor row may lend; fast mode is an endpoint feature.
514
+ const GUESSED_FLAGS = Object.freeze([
515
+ 'supportsVision',
516
+ 'supportsFunctionCalling',
517
+ 'supportsWebSearch',
518
+ 'supportsPromptCaching',
519
+ 'supportsReasoning',
520
+ ]);
521
+ const effortEntry = (options) => (Array.isArray(options) ? options.find((o) => o?.type === 'effort') : null) || null;
522
+
523
+ // A vendor row is a first guess for a route it does not describe (relay,
524
+ // same-vendor other endpoint, custom provider): it fills only the capabilities
525
+ // and effort ladder the route's own sources left undeclared. Never limits.
526
+ function withVendorGuess(meta, guess, { ladder = true } = {}) {
527
+ if (!guess) return meta;
528
+ const out = { ...(meta || _normalize({})) };
529
+ for (const key of GUESSED_FLAGS) out[key] ??= guess[key];
530
+ const effort = effortEntry(guess.reasoningOptions);
531
+ if (ladder && effort && out.supportsReasoning !== false && !effortEntry(out.reasoningOptions)) {
532
+ out.reasoningOptions = [...(out.reasoningOptions || []), effort];
533
+ }
534
+ return out;
535
+ }
536
+
537
+ // Offline seed: fills only what no fetched source supplied.
538
+ function withSeedFallback(meta, seed, provider) {
539
+ if (!seed) return meta;
540
+ // A capability any fetched layer declared (false included) stands; the seed
541
+ // fills only undeclared ones, and never gives a non-reasoning model a ladder.
542
+ const out = { ...(meta || _normalize({})) };
543
+ for (const key of CAPABILITY_FLAGS) out[key] ??= capabilityFlag(seed[key]);
544
+ if (!out.displayName && seed.name) out.displayName = seed.name;
545
+ if (!out.contextWindow && seed.contextWindow) out.contextWindow = seed.contextWindow;
546
+ if (!out.outputTokens && seed.outputTokens) out.outputTokens = seed.outputTokens;
547
+ if (!out.reasoningOptions?.length && seed.reasoningOptions?.length && out.supportsReasoning !== false) {
548
+ out.reasoningOptions = seed.reasoningOptions;
549
+ }
550
+ if (!hasRates(out) && hasRates(seed)) {
551
+ for (const key of PRICING_RATE_KEYS) out[key] = seed[key] ?? null;
552
+ out.pricingTiers = [];
553
+ out.pricingSource = 'seed';
554
+ out.pricingProvider = provider;
555
+ }
556
+ return out;
557
+ }
558
+
559
+ // Override → LiteLLM → models.dev rows under one catalog provider id.
560
+ function catalogMetadata(id, mappedProvider, catalog, modelsDevCatalog) {
494
561
  let meta = null;
495
562
  // 1. Manual overrides — authoritative + offline. Provider-guarded: when a
496
563
  // provider hint is given, an override is only honoured if it belongs to
@@ -498,13 +565,13 @@ function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog) {
498
565
  // deepseek-v4-pro under `deepseek` vs `opencode-go`) never leaks the
499
566
  // wrong provider's rate. Bare-id callers keep the legacy behaviour.
500
567
  const ov = PRICING_OVERRIDES[id];
501
- if (ov && (!mappedProvider || _modelsDevProviderId(ov.litellm_provider) === mappedProvider)) {
568
+ if (ov && (!mappedProvider || modelsDevProviderId(ov.litellm_provider) === mappedProvider)) {
502
569
  meta = { ..._normalize(ov), pricingSource: 'override' };
503
570
  }
504
571
  const metaFromPricingOverride = meta !== null;
505
572
  // 2. LiteLLM community catalog (broad mainstream coverage).
506
573
  if (!meta) {
507
- if (catalog[id] && (!mappedProvider || _modelsDevProviderId(catalog[id].litellm_provider) === mappedProvider)) {
574
+ if (catalog[id] && (!mappedProvider || modelsDevProviderId(catalog[id].litellm_provider) === mappedProvider)) {
508
575
  meta = { ..._normalize(catalog[id]), pricingSource: 'litellm' };
509
576
  }
510
577
  for (const prefix of _prefixesForProvider(mappedProvider, _CATALOG_SIMPLE_PREFIXES)) {
@@ -530,16 +597,49 @@ function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog) {
530
597
  });
531
598
  if (row) meta = { ...meta, displayName: modelsDevDisplayName(row) };
532
599
  }
533
- const relayVendor = _relayPricingProvider(provider, id);
534
- if (relayVendor && !PRICING_RATE_KEYS.some((key) => meta?.[key] != null)) {
535
- // Anthropic SKUs spell versions with hyphens (claude-opus-5-5); relays
536
- // may list the same SKU with dots (claude-opus-5.5).
537
- const vendorId = relayVendor === 'anthropic' ? id.replace(/(\d)\.(\d)/g, '$1-$2') : id;
538
- const relayed = lookupModelMetadata(vendorId, relayVendor, catalog, modelsDevCatalog);
539
- if (relayed) meta = { ...relayed, contextWindow: null, outputTokens: null };
600
+ return meta;
601
+ }
602
+
603
+ // The row of the vendor serving a relayed or custom model id (no vendor: a
604
+ // 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);
610
+ }
611
+
612
+ // Both list enrichment and synchronous accounting use this exact resolver;
613
+ // enrichment passes the listed row, which is the live roster just fetched.
614
+ // Precedence, for every provider (see provider-catalog-registry.mjs):
615
+ // (a) the provider's own live roster (cached row, then the listed row);
616
+ // (b) catalog rows under its models.dev id — in full when that entry is the
617
+ // same endpoint, otherwise pricing only;
618
+ // (c) verified corrections for confirmed upstream catalog gaps;
619
+ // (d) offline seed rows fill whatever nothing above supplied;
620
+ // (e) relays, same-vendor providers on another endpoint and custom
621
+ // providers take the vendor row as a first guess for capabilities and
622
+ // the effort ladder still undeclared — never its limits;
623
+ // (f) a relay model with no rates of its own borrows the vendor's pricing.
624
+ function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog, listedRow = null) {
625
+ const custom = String(provider || '').startsWith('custom-');
626
+ const id = providerPricingModelSync(provider, originalId);
627
+ const source = provider ? providerCatalogEntry(provider) : null;
628
+ const mappedProvider = source?.modelsDev || null;
629
+ const mapped = catalogMetadata(id, mappedProvider, catalog, modelsDevCatalog);
630
+ let meta = source && !source.sameEndpoint ? pricingOnly(mapped) : mapped;
631
+ const correction = source ? providerMetadataCorrection(provider, id) : null;
632
+ if (meta && correction) meta = { ...meta, ...correction };
633
+ let guess = null;
634
+ const relayVendor = source?.relay ? _relayedModelVendor(id) : null;
635
+ if (custom) guess = customVendorMetadata(originalId, catalog, modelsDevCatalog);
636
+ else if (relayVendor) guess = servingVendorMetadata(id, relayVendor, catalog, modelsDevCatalog);
637
+ else if (source && !source.sameEndpoint) guess = mapped;
638
+ if (source?.relay && !hasRates(meta) && hasRates(guess)) {
639
+ meta = meta ? { ...meta, ...pricingFields(guess) } : pricingOnly(guess);
540
640
  }
541
- const variant = PRICED_VARIANTS[String(provider || '').toLowerCase()]?.[id];
542
- if (variant && !PRICING_RATE_KEYS.some((key) => meta?.[key] != null)) {
641
+ const variant = PRICED_VARIANTS[source?.provider || '']?.[id];
642
+ if (variant && !hasRates(meta)) {
543
643
  const base = lookupModelMetadata(variant.base, provider, catalog, modelsDevCatalog);
544
644
  if (base && PRICING_RATE_KEYS.some((key) => base[key] != null)) {
545
645
  meta = {
@@ -554,38 +654,39 @@ function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog) {
554
654
  };
555
655
  }
556
656
  }
557
- const cursorRow = /^cursor-(?:oauth|api)$/.test(String(provider || '').toLowerCase()) ? CURSOR_PRICING[id] : null;
657
+ const cursorRow = /^cursor-(?:oauth|api)$/.test(source?.provider || '') ? CURSOR_PRICING[id] : null;
558
658
  if (cursorRow) {
559
- if (!PRICING_RATE_KEYS.some((key) => meta?.[key] != null)) {
659
+ if (!hasRates(meta)) {
560
660
  meta = { ...meta, ...listedRates(cursorRow), pricingSource: 'override' };
561
661
  }
562
662
  if (cursorRow.fast) meta = { ...meta, fastPricing: listedRates(cursorRow.fast) };
563
663
  }
564
- if (providerUsesEndpointScopedLimits(provider) && !providerNative && meta) {
565
- // OAuth/backend routes can expose smaller account/backend windows than
566
- // the public API SKU. External catalogs and manual overrides remain useful
567
- // for costs and capabilities, but their public-SKU limits are not
568
- // authoritative for these routes.
569
- meta = { ...meta, contextWindow: null, outputTokens: null };
570
- }
571
- if (providerNative) {
572
- // Provider cache limits are only authoritative for endpoint-scoped
573
- // routes (OAuth/backend), where the cached row reflects the live
574
- // account/backend window. For every other provider the cache is a
575
- // best-effort snapshot that can go stale, so it must NOT override the
576
- // catalog/known limits — otherwise this function returns cache limits
577
- // labelled as catalog data and downstream catalog-vs-cache staleness
578
- // checks (context-meta, statusline route-meta) compare stale-vs-stale
579
- // and can never correct an outdated cached window. Capabilities and
580
- // gap-filling (base limit null) still flow through the merge.
581
- const nativeLimitsAuthoritative = providerUsesEndpointScopedLimits(provider);
582
- meta = mergeModelMetadata(meta, providerNative, {
664
+ const cached = provider ? providerCachedModelMetadataSync(provider, originalId) : null;
665
+ const seed = source ? providerSeedRow(provider, originalId) : null;
666
+ // A listed row alone is no metadata: enrichment then keeps it as listed.
667
+ if (!meta && !cached && !seed && !guess) return null;
668
+ const listed = listedRow ? rosterRowMetadata(provider, listedRow) : null;
669
+ // A custom model known only through its vendor gets the guess alone.
670
+ if (custom && !meta && !cached) return customCatalogDefaults(withVendorGuess(listed, guess), guess);
671
+ for (const roster of [cached, listed]) {
672
+ if (!roster) continue;
673
+ // The live roster's effort ladder and capabilities win. Its limits beat
674
+ // catalog limits only where the registry marks them authoritative (the
675
+ // row reflects the live account/backend window). Elsewhere the cache is
676
+ // a best-effort snapshot that can go stale, so it must NOT override the
677
+ // catalog limits — otherwise downstream catalog-vs-cache staleness checks
678
+ // (context-meta, statusline route-meta) compare stale-vs-stale and can
679
+ // never correct an outdated cached window; it still fills missing limits.
680
+ meta = mergeModelMetadata(meta, roster, {
583
681
  preserveBaseCosts: true,
584
- preserveBaseLimits: !nativeLimitsAuthoritative,
682
+ preserveBaseLimits: !source?.rosterLimitsAuthoritative,
585
683
  });
586
684
  }
587
- if (!meta && String(provider || '').startsWith('custom-'))
588
- return customCatalogDefaults(originalId, catalog, modelsDevCatalog);
685
+ meta = withSeedFallback(meta, seed, source?.provider);
686
+ const rosterLadders = [cached?.rawProviderModel, listedRow].filter(
687
+ (row) => Array.isArray(row?.reasoningLevels) || Array.isArray(row?.reasoningOptions)
688
+ );
689
+ meta = withVendorGuess(meta, guess, { ladder: !(source?.rosterLadderFinal && rosterLadders.length) });
589
690
  return meta
590
691
  ? {
591
692
  ...meta,
@@ -595,27 +696,32 @@ function lookupModelMetadata(originalId, provider, catalog, modelsDevCatalog) {
595
696
  : null;
596
697
  }
597
698
 
598
- // A user-defined (`custom-*`) provider is in no catalog under its own id, so
599
- // its discovered models match by bare model id (as listed, then without a
600
- // `vendor/` route prefix) under the vendor the id names. Only the reasoning
601
- // capabilities become defaults for the custom row (its overrides win); prices
602
- // and limits describe the vendor's own API, not the custom endpoint.
603
- function customCatalogDefaults(originalId, catalog, modelsDevCatalog) {
604
- const listed = String(originalId || '');
605
- for (const id of new Set([listed, listed.slice(listed.lastIndexOf('/') + 1)])) {
699
+ // A user-defined (`custom-*`) provider is rarely in a catalog under its own
700
+ // id, so its discovered models match by bare model id (as listed, then without
701
+ // a `vendor/` route prefix) under the vendor the id names. That vendor row is a
702
+ // first guess for the capabilities and effort ladder the custom route leaves
703
+ // undeclared (the row's customReasoning overrides still win); prices and
704
+ // limits describe the vendor's own API, not the custom endpoint.
705
+ function customVendorMetadata(originalId, catalog, modelsDevCatalog) {
706
+ const listedId = String(originalId || '');
707
+ for (const id of new Set([listedId, listedId.slice(listedId.lastIndexOf('/') + 1)])) {
606
708
  if (!id) continue;
607
- const vendor = _relayedModelVendor(id) || _modelsDevProviderId(catalog[id]?.litellm_provider);
608
- const meta = lookupModelMetadata(id, vendor, catalog, modelsDevCatalog);
609
- if (!meta) continue;
610
- return {
611
- supportsReasoning: meta.supportsReasoning === true,
612
- reasoningOptions: Array.isArray(meta.reasoningOptions) ? meta.reasoningOptions : [],
613
- reasoningContentField: meta.reasoningContentField || null,
614
- };
709
+ const vendor = _relayedModelVendor(id) || modelsDevProviderId(catalog[id]?.litellm_provider);
710
+ const guess = servingVendorMetadata(id, vendor, catalog, modelsDevCatalog);
711
+ if (guess) return guess;
615
712
  }
616
713
  return null;
617
714
  }
618
715
 
716
+ // The defaults a vendor guess gives a custom row: capabilities and reasoning only.
717
+ function customCatalogDefaults(meta, guess) {
718
+ return {
719
+ ...Object.fromEntries(GUESSED_FLAGS.map((key) => [key, meta[key]])),
720
+ reasoningOptions: meta.reasoningOptions || [],
721
+ reasoningContentField: meta.reasoningContentField || guess.reasoningContentField || null,
722
+ };
723
+ }
724
+
619
725
  function _normalize(entry) {
620
726
  if (!entry || typeof entry !== 'object') return null;
621
727
  // OpenAI's Priority processing (since renamed Fast mode) columns.
@@ -629,18 +735,39 @@ function _normalize(entry) {
629
735
  ...(PRICING_RATE_KEYS.some((key) => fastPricing[key] != null) ? { fastPricing } : {}),
630
736
  ...(PRICING_RATE_KEYS.some((key) => ultrafastPricing[key] != null) ? { ultrafastPricing } : {}),
631
737
  ...(entry.off_peak_multiplier ? { offPeakMultiplier: entry.off_peak_multiplier } : {}),
632
- supportsVision: entry.supports_vision === true,
633
- supportsFunctionCalling: entry.supports_function_calling === true,
634
- supportsWebSearch: entry.supports_web_search === true || entry.supports_websearch === true,
635
- supportsPromptCaching: entry.supports_prompt_caching === true,
636
- supportsFastMode: entry.supports_fast_mode === true,
637
- supportsReasoning: entry.supports_reasoning === true,
738
+ // Tri-state: true/false as declared, undefined when the row is silent.
739
+ supportsVision: capabilityFlag(entry.supports_vision),
740
+ supportsFunctionCalling: capabilityFlag(entry.supports_function_calling),
741
+ supportsWebSearch:
742
+ entry.supports_web_search === true || entry.supports_websearch === true
743
+ ? true
744
+ : (capabilityFlag(entry.supports_web_search) ?? capabilityFlag(entry.supports_websearch)),
745
+ supportsPromptCaching: capabilityFlag(entry.supports_prompt_caching),
746
+ supportsFastMode: capabilityFlag(entry.supports_fast_mode),
747
+ supportsReasoning: capabilityFlag(entry.supports_reasoning),
638
748
  reasoningOptions: Array.isArray(entry.reasoning_options) ? entry.reasoning_options : [],
639
749
  reasoningContentField: entry.reasoning_content_field || null,
640
750
  mode: entry.mode || null,
641
751
  };
642
752
  }
643
753
 
754
+ const CAPABILITY_FLAGS = Object.freeze([
755
+ 'supportsVision',
756
+ 'supportsFunctionCalling',
757
+ 'supportsWebSearch',
758
+ 'supportsPromptCaching',
759
+ 'supportsFastMode',
760
+ 'supportsReasoning',
761
+ ]);
762
+
763
+ // A layer's own ladder wins; a lower layer's ladder never reaches a model the
764
+ // higher layer declares non-reasoning.
765
+ function mergedReasoningOptions(base, overlay) {
766
+ if (overlay.reasoningOptions?.length) return overlay.reasoningOptions;
767
+ if ((overlay.supportsReasoning ?? base.supportsReasoning) === false) return [];
768
+ return base.reasoningOptions || [];
769
+ }
770
+
644
771
  function mergeModelMetadata(base, overlay, opts = {}) {
645
772
  if (!base) return overlay || null;
646
773
  if (!overlay) return base;
@@ -674,13 +801,10 @@ function mergeModelMetadata(base, overlay, opts = {}) {
674
801
  !opts.preserveBaseCosts && PRICING_RATE_KEYS.some((key) => overlay[key] != null)
675
802
  ? overlay.pricingSource
676
803
  : base.pricingSource,
677
- supportsVision: base.supportsVision || overlay.supportsVision,
678
- supportsFunctionCalling: base.supportsFunctionCalling || overlay.supportsFunctionCalling,
679
- supportsWebSearch: base.supportsWebSearch || overlay.supportsWebSearch,
680
- supportsPromptCaching: base.supportsPromptCaching || overlay.supportsPromptCaching,
681
- supportsFastMode: base.supportsFastMode || overlay.supportsFastMode,
682
- supportsReasoning: base.supportsReasoning || overlay.supportsReasoning,
683
- reasoningOptions: overlay.reasoningOptions?.length ? overlay.reasoningOptions : base.reasoningOptions || [],
804
+ // The overlay is the higher layer: a capability it declares (false
805
+ // included) wins; the base fills only what the overlay leaves undeclared.
806
+ ...Object.fromEntries(CAPABILITY_FLAGS.map((key) => [key, overlay[key] ?? base[key]])),
807
+ reasoningOptions: mergedReasoningOptions(base, overlay),
684
808
  reasoningContentField: overlay.reasoningContentField || base.reasoningContentField || null,
685
809
  mode: base.mode || overlay.mode || null,
686
810
  };
@@ -695,7 +819,7 @@ export async function enrichModels(models, { fetchFn, force = false } = {}) {
695
819
  if (!Array.isArray(models)) return models;
696
820
  const catalog = await loadCatalog({ fetchFn, force });
697
821
  let modelsDevCatalog = modelsDevSource.cache;
698
- if (models.some((m) => _modelsDevProviderId(m?.provider))) {
822
+ if (models.some((m) => modelsDevProviderId(m?.provider))) {
699
823
  try {
700
824
  modelsDevCatalog = await loadModelsDevCatalog({ fetchFn, force });
701
825
  } catch {
@@ -705,7 +829,7 @@ export async function enrichModels(models, { fetchFn, force = false } = {}) {
705
829
  return models.map((m) => {
706
830
  const id = m.id || m.name;
707
831
  if (!id) return m;
708
- const meta = lookupModelMetadata(id, m.provider, catalog, modelsDevCatalog || {});
832
+ const meta = lookupModelMetadata(id, m.provider, catalog, modelsDevCatalog || {}, m);
709
833
  if (!meta) return m;
710
834
  const catalogDisplay = meta.displayName;
711
835
  return {
@@ -726,12 +850,10 @@ export async function enrichModels(models, { fetchFn, force = false } = {}) {
726
850
  pricingModel: meta.pricingModel,
727
851
  pricingProvider: meta.pricingProvider,
728
852
  pricingSource: meta.pricingSource,
729
- supportsVision: m.supportsVision === true || meta.supportsVision,
730
- supportsFunctionCalling: m.supportsFunctionCalling === true || meta.supportsFunctionCalling,
731
- supportsWebSearch: meta.supportsWebSearch || m.supportsWebSearch === true,
732
- supportsPromptCaching: m.supportsPromptCaching === true || meta.supportsPromptCaching,
733
- supportsReasoning: m.supportsReasoning === true || meta.supportsReasoning,
734
- reasoningOptions: m.reasoningOptions?.length ? m.reasoningOptions : meta.reasoningOptions || [],
853
+ // The lookup already layered the listed row as the live roster, with
854
+ // the same roster semantics as the sync path.
855
+ ...Object.fromEntries(GUESSED_FLAGS.map((key) => [key, meta[key]])),
856
+ reasoningOptions: meta.reasoningOptions || [],
735
857
  reasoningContentField: meta.reasoningContentField || m.reasoningContentField || null,
736
858
  mode: meta.mode || m.mode || null,
737
859
  };
@@ -782,7 +904,6 @@ export function pricingCatalogRevisionSync() {
782
904
  }
783
905
 
784
906
  let lastAuditedRevision = null;
785
- let lastAudit = null;
786
907
  function auditCachedModelPricing() {
787
908
  const revision = pricingCatalogRevisionSync();
788
909
  const rows = Object.entries(cachedProviderModelListsSync()).flatMap(([provider, models]) =>
@@ -797,17 +918,6 @@ function auditCachedModelPricing() {
797
918
  );
798
919
  }
799
920
  lastAuditedRevision = revision;
800
- lastAudit = { revision, rows, unpriced };
801
- return lastAudit;
802
- }
803
-
804
- /** Catalog routes without a complete list price, from the latest audit (run on demand when none is cached). */
805
- export function unpricedModelsSync() {
806
- return (lastAudit ?? auditCachedModelPricing()).unpriced.map(({ provider, model, missingRates }) => ({
807
- provider,
808
- model,
809
- missingRates: [...missingRates],
810
- }));
811
921
  }
812
922
 
813
923
  /**
@@ -2,19 +2,29 @@ import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { resolvePluginData } from '../plugin-paths.mjs';
4
4
  import { ANTIGRAVITY_MODELS, ANTIGRAVITY_PRICING_ALIASES, normalizeGrokModelId } from './provider-model-identities.mjs';
5
+ import { providerRosterFiles, rosterProviders } from './provider-catalog-registry.mjs';
5
6
 
6
- const PROVIDER_CACHE_FILES = Object.freeze({
7
- 'openai-oauth': ['openai-oauth-models.json'],
8
- 'anthropic-oauth': ['anthropic-oauth-models.json'],
9
- anthropic: ['anthropic-oauth-models.json'],
10
- gemini: ['gemini-models.json'],
11
- 'grok-oauth': ['grok-oauth-models.json'],
12
- 'antigravity-oauth': ['antigravity-oauth-models.json'],
13
- });
7
+ /** A declared capability keeps its boolean; an undeclared one stays undefined,
8
+ * so lower layers (catalogs, seeds) fill only what no source stated. */
9
+ export function capabilityFlag(value) {
10
+ return typeof value === 'boolean' ? value : undefined;
11
+ }
14
12
 
15
- export function providerUsesEndpointScopedLimits(provider) {
16
- const p = String(provider || '').toLowerCase();
17
- return p === 'openai-oauth' || p === 'anthropic-oauth' || p === 'grok-oauth';
13
+ /** Provider roster rows coerce "unknown" to `false` (`x === true`), so only a
14
+ * `true` there is a declaration; `false` leaves the field to catalogs/seeds. */
15
+ export function rosterCapabilityFlag(value) {
16
+ return value === true ? true : undefined;
17
+ }
18
+
19
+ /** A roster row's effort ladder: `reasoningOptions` when it carries an effort
20
+ * entry, else the flat `reasoningLevels` some rosters store (Antigravity). */
21
+ export function rosterReasoningOptions(row) {
22
+ const options = Array.isArray(row?.reasoningOptions) ? row.reasoningOptions : [];
23
+ // An effort entry with no values declares nothing.
24
+ const usable = options.filter((o) => o?.type !== 'effort' || (Array.isArray(o.values) && o.values.length > 0));
25
+ if (usable.some((o) => o?.type === 'effort')) return usable;
26
+ const levels = Array.isArray(row?.reasoningLevels) ? row.reasoningLevels.filter((v) => typeof v === 'string') : [];
27
+ return levels.length ? [...usable, { type: 'effort', values: levels }] : usable;
18
28
  }
19
29
 
20
30
  function num(value) {
@@ -34,8 +44,7 @@ function readModelsFromCacheFile(fileName) {
34
44
  }
35
45
 
36
46
  export function providerCachedModelsSync(provider) {
37
- const p = String(provider || '').toLowerCase();
38
- const files = PROVIDER_CACHE_FILES[p] || [];
47
+ const files = providerRosterFiles(provider);
39
48
  const rows = [];
40
49
  const seen = new Set();
41
50
  for (const fileName of files) {
@@ -50,11 +59,7 @@ export function providerCachedModelsSync(provider) {
50
59
  }
51
60
 
52
61
  export function cachedProviderModelListsSync() {
53
- return Object.fromEntries(
54
- Object.keys(PROVIDER_CACHE_FILES)
55
- .filter((provider) => provider !== 'anthropic')
56
- .map((provider) => [provider, providerCachedModelsSync(provider)])
57
- );
62
+ return Object.fromEntries(rosterProviders().map((provider) => [provider, providerCachedModelsSync(provider)]));
58
63
  }
59
64
 
60
65
  /** Only explicit catalog wire mappings establish an alias. Never strip an
@@ -86,8 +91,7 @@ function rowId(row) {
86
91
  }
87
92
 
88
93
  function getProviderCachedModelSync(provider, model) {
89
- const p = String(provider || '').toLowerCase();
90
- const files = PROVIDER_CACHE_FILES[p] || [];
94
+ const files = providerRosterFiles(provider);
91
95
  if (!files.length || !model) return null;
92
96
  const aliases = new Set(modelAliases(model));
93
97
  for (const fileName of files) {
@@ -101,9 +105,13 @@ function getProviderCachedModelSync(provider, model) {
101
105
  }
102
106
 
103
107
  export function providerCachedModelMetadataSync(provider, model) {
104
- const p = String(provider || '').toLowerCase();
105
108
  const row = getProviderCachedModelSync(provider, model);
106
- if (!row) return null;
109
+ return row ? rosterRowMetadata(provider, row) : null;
110
+ }
111
+
112
+ /** Metadata layer of one live-roster row (cached or just listed). */
113
+ export function rosterRowMetadata(provider, row) {
114
+ const p = String(provider || '').toLowerCase();
107
115
  return {
108
116
  contextWindow: num(
109
117
  row.contextWindow ?? row.context_window ?? row.maxContextWindow ?? row.max_context_window ?? row.max_input_tokens
@@ -115,12 +123,12 @@ export function providerCachedModelMetadataSync(provider, model) {
115
123
  p === 'grok-oauth'
116
124
  ? null
117
125
  : num(row.outputTokens ?? row.maxOutputTokens ?? row.max_output_tokens ?? row.output_token_limit),
118
- supportsVision: row.supportsVision === true,
119
- supportsFunctionCalling: row.supportsFunctionCalling === true,
120
- supportsWebSearch: row.supportsWebSearch === true,
121
- supportsPromptCaching: row.supportsPromptCaching === true,
122
- supportsReasoning: row.supportsReasoning === true,
123
- reasoningOptions: Array.isArray(row.reasoningOptions) ? row.reasoningOptions : [],
126
+ supportsVision: rosterCapabilityFlag(row.supportsVision),
127
+ supportsFunctionCalling: rosterCapabilityFlag(row.supportsFunctionCalling),
128
+ supportsWebSearch: rosterCapabilityFlag(row.supportsWebSearch),
129
+ supportsPromptCaching: rosterCapabilityFlag(row.supportsPromptCaching),
130
+ supportsReasoning: rosterCapabilityFlag(row.supportsReasoning),
131
+ reasoningOptions: rosterReasoningOptions(row),
124
132
  reasoningContentField: row.reasoningContentField || null,
125
133
  mode: row.mode || null,
126
134
  displayName: row.displayName || row.display || row.name || null,