@bitkyc08/opencodex 2.86.0 → 2.88.0

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 (400) hide show
  1. package/gui/dist/assets/App-CHC89EXQ.js +58 -0
  2. package/gui/dist/assets/App-wT3mXqFz.css +1 -0
  3. package/gui/dist/assets/{Tray-DyR9yBee.js → Tray-B5bC7AWL.js} +1 -1
  4. package/gui/dist/assets/index-B5bsvxor.js +94 -0
  5. package/gui/dist/assets/index-DPeB9HpV.css +1 -0
  6. package/gui/dist/assets/quota-summary-D8y2wTsB.js +1 -0
  7. package/gui/dist/index.html +2 -2
  8. package/package.json +1 -1
  9. package/src/adapters/anthropic/beta-allowlist.ts +9 -8
  10. package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
  11. package/src/adapters/anthropic/passthrough.ts +7 -23
  12. package/src/adapters/anthropic-progress.ts +84 -0
  13. package/src/adapters/anthropic-rejection-memo.ts +71 -0
  14. package/src/adapters/anthropic-replay.ts +135 -0
  15. package/src/adapters/anthropic-tool-catalog.ts +11 -0
  16. package/src/adapters/anthropic.ts +151 -33
  17. package/src/adapters/base.ts +2 -0
  18. package/src/adapters/claude-cli/adapter.ts +111 -23
  19. package/src/adapters/claude-cli/profiles.ts +2 -1
  20. package/src/adapters/claude-cli/stable-replay.ts +108 -0
  21. package/src/adapters/claude-cli/usage-admission.ts +230 -0
  22. package/src/adapters/coding-agent/protocol.ts +1 -1
  23. package/src/adapters/coding-agent/turn.ts +18 -2
  24. package/src/adapters/dsh-account.ts +97 -0
  25. package/src/adapters/google-progress-history.ts +53 -0
  26. package/src/adapters/google.ts +52 -9
  27. package/src/adapters/openai-chat/messages.ts +4 -3
  28. package/src/adapters/openai-chat/passthrough.ts +8 -2
  29. package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
  30. package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
  31. package/src/adapters/openai-responses/passthrough.ts +57 -125
  32. package/src/adapters/openai-responses/request-strips.ts +25 -3
  33. package/src/adapters/openai-responses/transport.ts +81 -0
  34. package/src/adapters/qoder/adapter.ts +4 -2
  35. package/src/adapters/registry.ts +5 -0
  36. package/src/adapters/zed.ts +26 -1
  37. package/src/advisor/activity.ts +55 -0
  38. package/src/advisor/budget.ts +62 -0
  39. package/src/advisor/consult.ts +4 -1
  40. package/src/advisor/context.ts +16 -4
  41. package/src/advisor/evidence-tool.ts +21 -0
  42. package/src/advisor/evidence.ts +117 -0
  43. package/src/advisor/runtime.ts +79 -31
  44. package/src/advisor/settings.ts +11 -2
  45. package/src/bridge/errors.ts +19 -1
  46. package/src/bridge/internal.ts +7 -1
  47. package/src/bridge/response-json.ts +18 -3
  48. package/src/bridge/sse.ts +59 -8
  49. package/src/bridge/terminal-refusal.ts +59 -0
  50. package/src/claude/desktop-3p-library.ts +32 -7
  51. package/src/claude/desktop-3p.ts +55 -13
  52. package/src/claude/desktop-first-party.ts +1 -1
  53. package/src/claude/desktop-picker-platform.ts +4 -0
  54. package/src/claude/desktop-picker.ts +15 -8
  55. package/src/claude/desktop-system-proxy.ts +50 -4
  56. package/src/claude/inbound-content-options.ts +77 -0
  57. package/src/claude/inbound.ts +33 -0
  58. package/src/claude/intercept/picker-ca-startup.ts +2 -1
  59. package/src/claude/intercept/picker-runtime.ts +6 -5
  60. package/src/claude/intercept/picker-trust-windows.ts +338 -0
  61. package/src/claude/intercept/picker-trust.ts +19 -0
  62. package/src/claude/intercept/port-policy.ts +30 -0
  63. package/src/claude/intercept/runtime.ts +97 -94
  64. package/src/claude/outbound.ts +46 -13
  65. package/src/cli/account-api.ts +1 -0
  66. package/src/cli/account-policy-dto.ts +6 -0
  67. package/src/cli/account-policy.ts +34 -5
  68. package/src/cli/account-preservation.ts +44 -0
  69. package/src/cli/account.ts +8 -2
  70. package/src/cli/advisor.ts +17 -3
  71. package/src/cli/capabilities-accounts.ts +20 -1
  72. package/src/cli/capabilities-agents-routing.ts +5 -2
  73. package/src/cli/capabilities-base.ts +38 -10
  74. package/src/cli/capabilities-observe-system.ts +63 -3
  75. package/src/cli/capabilities-provider-models.ts +11 -0
  76. package/src/cli/codex-cli-update.ts +151 -41
  77. package/src/cli/codex-provider.ts +44 -0
  78. package/src/cli/combo-input.ts +10 -1
  79. package/src/cli/combo-result.ts +1 -1
  80. package/src/cli/combo.ts +2 -1
  81. package/src/cli/cross-home-owner.ts +33 -16
  82. package/src/cli/dispatch.ts +25 -4
  83. package/src/cli/doctor.ts +6 -1
  84. package/src/cli/ensure-desktop-cold-start.ts +60 -7
  85. package/src/cli/help.ts +3 -2
  86. package/src/cli/index.ts +1 -1
  87. package/src/cli/integration-plan-dto.ts +1 -0
  88. package/src/cli/log-history.ts +172 -0
  89. package/src/cli/loopback-family.ts +31 -0
  90. package/src/cli/models-runtime-subcommands.ts +1 -0
  91. package/src/cli/models-runtime.ts +72 -8
  92. package/src/cli/observe-stream.ts +2 -0
  93. package/src/cli/observe.ts +16 -4
  94. package/src/cli/provider.ts +27 -5
  95. package/src/cli/registry.ts +28 -8
  96. package/src/cli/runtime-api.ts +5 -3
  97. package/src/cli/system-command.ts +40 -8
  98. package/src/cli/uninstall-client-state.ts +32 -0
  99. package/src/cli/usage-compare.ts +309 -0
  100. package/src/cli/usage-model-search.ts +4 -4
  101. package/src/cli/usage-report.ts +2 -2
  102. package/src/cli/v2.ts +1 -1
  103. package/src/client/machine-listener.ts +1 -3
  104. package/src/client/runtime.ts +1 -0
  105. package/src/clients/client-path.ts +51 -0
  106. package/src/clients/config-export/contracts.ts +2 -1
  107. package/src/clients/config-export.ts +18 -44
  108. package/src/clients/gentle-shell-path.ts +87 -0
  109. package/src/codex/account-auto-switch.ts +2 -0
  110. package/src/codex/account-identity.ts +29 -0
  111. package/src/codex/account-label.ts +1 -1
  112. package/src/codex/account-lifecycle.ts +21 -5
  113. package/src/codex/account-preservation.ts +28 -0
  114. package/src/codex/account-use-remaining.ts +23 -0
  115. package/src/codex/app-server-processes.ts +97 -7
  116. package/src/codex/app-server-restart-service.ts +55 -4
  117. package/src/codex/auth-api/account-list.ts +4 -0
  118. package/src/codex/auth-api/account-pause-group.ts +6 -50
  119. package/src/codex/auth-api/account-preservation.ts +57 -0
  120. package/src/codex/auth-api/routes.ts +8 -0
  121. package/src/codex/auth-api/use-remaining-route.ts +36 -0
  122. package/src/codex/auth-api.ts +0 -1
  123. package/src/codex/auth-context.ts +2 -2
  124. package/src/codex/catalog/auto-review.ts +20 -3
  125. package/src/codex/catalog/build-entries.ts +9 -1
  126. package/src/codex/catalog/combo-member.ts +14 -5
  127. package/src/codex/catalog/configured-tiers.ts +1 -1
  128. package/src/codex/catalog/gather-capture.ts +2 -0
  129. package/src/codex/catalog/metadata.ts +11 -9
  130. package/src/codex/catalog/model-hints.ts +21 -16
  131. package/src/codex/catalog/model-visibility.ts +3 -1
  132. package/src/codex/catalog/parsing.ts +30 -86
  133. package/src/codex/catalog/provider-models.ts +36 -34
  134. package/src/codex/catalog/routed-gather.ts +14 -13
  135. package/src/codex/cli-install-provenance.ts +105 -17
  136. package/src/codex/cli-update-plan.ts +545 -0
  137. package/src/codex/config-write-lock.ts +23 -2
  138. package/src/codex/desktop-app/picker-freshness.ts +96 -0
  139. package/src/codex/desktop-app-restart.ts +21 -0
  140. package/src/codex/desktop-compatibility/installed-build.ts +24 -6
  141. package/src/codex/desktop-compatibility/routing-preflight.ts +1 -1
  142. package/src/codex/desktop-compatibility/runtime.ts +12 -3
  143. package/src/codex/desktop-compatibility/windows-key-protection.ts +115 -9
  144. package/src/codex/features.ts +85 -45
  145. package/src/codex/inject/history-failure.ts +27 -0
  146. package/src/codex/inject/restore.ts +24 -2
  147. package/src/codex/inject/routing-classify.ts +4 -3
  148. package/src/codex/inject.ts +18 -27
  149. package/src/codex/main-account-hard-lock.ts +30 -1
  150. package/src/codex/native-profile-startup.ts +1 -1
  151. package/src/codex/ocx-compaction-history.ts +12 -10
  152. package/src/codex/paths.ts +86 -1
  153. package/src/codex/provider-routing.ts +174 -0
  154. package/src/codex/refresh.ts +2 -2
  155. package/src/codex/routing/health-store.ts +1 -1
  156. package/src/codex/routing/selection.ts +4 -3
  157. package/src/codex/routing/thread-affinity.ts +1 -1
  158. package/src/codex/signed-in-identity.ts +43 -0
  159. package/src/codex/subagent-model-fallback.ts +1 -1
  160. package/src/codex/sync.ts +6 -1
  161. package/src/codex/user-identity.ts +16 -5
  162. package/src/codex/websocket-activity.ts +161 -0
  163. package/src/codex/websocket-registry.ts +25 -1
  164. package/src/codex/windows-local-appdata.ts +84 -0
  165. package/src/combos/failover.ts +6 -1
  166. package/src/combos/index.ts +1 -0
  167. package/src/combos/resolve.ts +46 -10
  168. package/src/combos/types.ts +15 -0
  169. package/src/config/diagnostics.ts +33 -6
  170. package/src/config/live-reconcile.ts +38 -2
  171. package/src/config/load-degrade.ts +17 -0
  172. package/src/config/opencode-wire-upgrade.ts +54 -0
  173. package/src/config/opencode-zen-upgrade.ts +53 -0
  174. package/src/config/owner-registry.ts +22 -17
  175. package/src/config/provider-validation.ts +45 -2
  176. package/src/config/schema/config-schema.ts +22 -0
  177. package/src/config/schema/leaf-validators.ts +38 -9
  178. package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
  179. package/src/config/schema/native-reasoning-retention.ts +26 -0
  180. package/src/config.ts +2 -0
  181. package/src/generated/compatibility-version.json +657 -297
  182. package/src/grok/sync.ts +1 -1
  183. package/src/images/loop.ts +116 -27
  184. package/src/integrations/catalog-refresh.ts +1 -1
  185. package/src/integrations/mutation-plan.ts +1 -0
  186. package/src/integrations/registry.ts +8 -0
  187. package/src/lib/codex-restart-contract.ts +15 -0
  188. package/src/lib/desktop-upstream-tunnel.ts +18 -53
  189. package/src/lib/empty-tool-catalog.ts +62 -0
  190. package/src/lib/errors.ts +19 -3
  191. package/src/lib/gcp-adc.ts +96 -9
  192. package/src/lib/gcp-credential-input.ts +12 -0
  193. package/src/lib/lab-live-route-production.ts +5 -0
  194. package/src/lib/opaque-proxy-tunnel.ts +217 -0
  195. package/src/lib/redact.ts +2 -2
  196. package/src/lib/request-failure-model.ts +2 -0
  197. package/src/oauth/account-quota-rank.ts +69 -2
  198. package/src/oauth/anthropic-account-refusal.ts +20 -2
  199. package/src/oauth/anthropic-oauth-definitions.ts +3 -1
  200. package/src/oauth/anthropic-routing.ts +1 -21
  201. package/src/oauth/anthropic.ts +38 -7
  202. package/src/oauth/callback-server.ts +27 -1
  203. package/src/oauth/chatgpt-device.ts +1 -1
  204. package/src/oauth/chatgpt-shared.ts +83 -0
  205. package/src/oauth/chatgpt.ts +8 -72
  206. package/src/oauth/dsh.ts +203 -0
  207. package/src/oauth/generic-account-failover.ts +40 -11
  208. package/src/oauth/generic-session-affinity.ts +125 -0
  209. package/src/oauth/index.ts +184 -109
  210. package/src/oauth/local-token-detect.ts +21 -1
  211. package/src/oauth/login-cli-errors.ts +44 -0
  212. package/src/oauth/login-cli.ts +69 -7
  213. package/src/oauth/login-flow-state.ts +371 -23
  214. package/src/oauth/meta-muse-errors.ts +41 -0
  215. package/src/oauth/meta-muse-keychain.ts +52 -0
  216. package/src/oauth/meta-muse.ts +51 -84
  217. package/src/oauth/model-discovery-auth.ts +3 -0
  218. package/src/oauth/pool-settings-capability.ts +4 -2
  219. package/src/oauth/refresh-flight-retirement.ts +48 -0
  220. package/src/oauth/session-affinity-key.ts +23 -0
  221. package/src/oauth/store-anthropic-instance.ts +9 -2
  222. package/src/oauth/store.ts +12 -5
  223. package/src/protocols/encoders/adapter-events.ts +6 -5
  224. package/src/protocols/encoders/messages.ts +9 -6
  225. package/src/protocols/provider-summary.ts +2 -1
  226. package/src/providers/api-key-cooldowns.ts +49 -0
  227. package/src/providers/api-key-resolve.ts +11 -6
  228. package/src/providers/api-key-response-ownership.ts +57 -0
  229. package/src/providers/api-key-selection.ts +31 -6
  230. package/src/providers/api-keys.ts +214 -3
  231. package/src/providers/claude-cli-usage.ts +96 -0
  232. package/src/providers/dsh-account-destination.ts +31 -0
  233. package/src/providers/dsh-account-models.ts +41 -0
  234. package/src/providers/gcp-credential-cleanup.ts +59 -0
  235. package/src/providers/key-failover.ts +54 -50
  236. package/src/providers/key-store.ts +7 -2
  237. package/src/providers/model-rename-fields.ts +3 -0
  238. package/src/providers/model-rename-migration.ts +2 -2
  239. package/src/providers/openai-tiers-destination.ts +11 -2
  240. package/src/providers/openai-tiers.ts +5 -12
  241. package/src/providers/opencode-go-transport.ts +3 -1
  242. package/src/providers/opencode-zen-rate-limit.ts +7 -2
  243. package/src/providers/quota/account-cache.ts +6 -5
  244. package/src/providers/quota/account-row.ts +34 -0
  245. package/src/providers/quota/antigravity.ts +28 -7
  246. package/src/providers/quota/dsh-account.ts +70 -0
  247. package/src/providers/quota/vendor-probes-oauth.ts +1 -93
  248. package/src/providers/quota-types.ts +2 -0
  249. package/src/providers/quota.ts +14 -20
  250. package/src/providers/registry/entries-core.ts +37 -8
  251. package/src/providers/registry/types.ts +1 -1
  252. package/src/providers/request-pacing.ts +77 -19
  253. package/src/providers/routed-config.ts +339 -0
  254. package/src/providers/service-tier.ts +2 -1
  255. package/src/quota/window-mapping.ts +5 -2
  256. package/src/responses/anthropic-progress.ts +34 -0
  257. package/src/responses/assistant-replay.ts +35 -0
  258. package/src/responses/compaction-history-framing.ts +65 -0
  259. package/src/responses/compaction.ts +6 -1
  260. package/src/responses/incomplete-reason.ts +31 -0
  261. package/src/responses/parser.ts +50 -5
  262. package/src/responses/reasoning-envelope.ts +4 -0
  263. package/src/responses/reasoning-replay-cache.ts +74 -6
  264. package/src/responses/reasoning-retention.ts +173 -0
  265. package/src/responses/retained-compaction.ts +46 -0
  266. package/src/responses/schema.ts +23 -0
  267. package/src/router.ts +8 -321
  268. package/src/routing/analytics.ts +7 -15
  269. package/src/routing/health.ts +37 -22
  270. package/src/routing/history/indexer.ts +6 -5
  271. package/src/routing/history/ingest.ts +6 -2
  272. package/src/routing/profile.ts +1 -1
  273. package/src/server/admission-model-scope.ts +17 -0
  274. package/src/server/auth-cors.ts +11 -0
  275. package/src/server/chat-completions.ts +7 -1
  276. package/src/server/chat-native-reasoning.ts +123 -0
  277. package/src/server/chat-native-sse.ts +110 -7
  278. package/src/server/chat-native.ts +76 -17
  279. package/src/server/claude-messages.ts +56 -414
  280. package/src/server/effort-policy.ts +1 -1
  281. package/src/server/images.ts +15 -2
  282. package/src/server/index/live-sideband.ts +3 -2
  283. package/src/server/index/model-alias-id.ts +36 -0
  284. package/src/server/index/optional-listeners.ts +2 -0
  285. package/src/server/index/serve-options.ts +20 -6
  286. package/src/server/index/startup-warnings.ts +2 -0
  287. package/src/server/index/websocket-handler.ts +18 -4
  288. package/src/server/index.ts +8 -8
  289. package/src/server/inference/advisor-diagnostics.ts +31 -0
  290. package/src/server/lifecycle.ts +13 -1
  291. package/src/server/management/advisor-routes.ts +15 -4
  292. package/src/server/management/claude-desktop-picker-routes.ts +1 -1
  293. package/src/server/management/combo-routes.ts +176 -50
  294. package/src/server/management/companion-routes.ts +1 -1
  295. package/src/server/management/config-routes.ts +75 -4
  296. package/src/server/management/cursor-integration-routes.ts +1 -1
  297. package/src/server/management/model-routes.ts +11 -6
  298. package/src/server/management/model-rows.ts +14 -0
  299. package/src/server/management/native-integration-routes.ts +2 -7
  300. package/src/server/management/native-reasoning-retention-routes.ts +41 -0
  301. package/src/server/management/oauth-account-routes.ts +87 -14
  302. package/src/server/management/provider-gcp-credential-routes.ts +29 -0
  303. package/src/server/management/provider-key-pacing-routes.ts +31 -0
  304. package/src/server/management/provider-overwrite-carry.ts +7 -0
  305. package/src/server/management/provider-routes.ts +25 -30
  306. package/src/server/management/route-registry.ts +10 -1
  307. package/src/server/management-api.ts +3 -1
  308. package/src/server/messages-native-tool-guard.ts +185 -0
  309. package/src/server/messages-native.ts +117 -24
  310. package/src/server/messages-shared.ts +431 -0
  311. package/src/server/relay.ts +1 -1
  312. package/src/server/request-log-terminal-status.ts +1 -1
  313. package/src/server/request-log.ts +6 -1
  314. package/src/server/responses/account-change-state.ts +8 -2
  315. package/src/server/responses/adapter-continuation.ts +47 -19
  316. package/src/server/responses/adapter-delivery.ts +72 -12
  317. package/src/server/responses/adapter-dispatch.ts +46 -3
  318. package/src/server/responses/advisor-retention.ts +117 -0
  319. package/src/server/responses/advisor-slot.ts +73 -41
  320. package/src/server/responses/anthropic-thinking-recovery.ts +153 -0
  321. package/src/server/responses/codex-ws-wire.ts +15 -8
  322. package/src/server/responses/combo-stream-preflight.ts +3 -2
  323. package/src/server/responses/compact.ts +303 -125
  324. package/src/server/responses/compaction-recovery.ts +20 -10
  325. package/src/server/responses/compaction-retention.ts +61 -0
  326. package/src/server/responses/context-overflow.ts +11 -6
  327. package/src/server/responses/core-auth.ts +6 -0
  328. package/src/server/responses/core-codex-account.ts +11 -1
  329. package/src/server/responses/core-combo-failure.ts +2 -0
  330. package/src/server/responses/core-combo.ts +121 -36
  331. package/src/server/responses/core-errors.ts +3 -3
  332. package/src/server/responses/core-lifetime.ts +8 -4
  333. package/src/server/responses/core-opaque-recovery.ts +35 -0
  334. package/src/server/responses/core-options.ts +7 -0
  335. package/src/server/responses/core-pipeline.ts +141 -0
  336. package/src/server/responses/core-replay.ts +23 -3
  337. package/src/server/responses/core.ts +2 -115
  338. package/src/server/responses/fetch-helpers.ts +73 -19
  339. package/src/server/responses/main-hard-lock-routing.ts +109 -0
  340. package/src/server/responses/native-response-control.ts +4 -2
  341. package/src/server/responses/passthrough-delivery.ts +3 -1
  342. package/src/server/responses/passthrough-dispatch.ts +15 -13
  343. package/src/server/responses/passthrough-execution.ts +3 -2
  344. package/src/server/responses/request-prepare.ts +77 -12
  345. package/src/server/responses/request-sidecar-auth.ts +2 -2
  346. package/src/server/responses/request-transport.ts +104 -27
  347. package/src/server/responses/response-effects.ts +2 -0
  348. package/src/server/responses/response-tool-ownership.ts +21 -0
  349. package/src/server/responses/run-turn-execution.ts +96 -30
  350. package/src/server/responses/sidecar-execution.ts +63 -9
  351. package/src/server/responses/sidecar-send-budget.ts +2 -2
  352. package/src/server/responses/terminal-guard.ts +2 -16
  353. package/src/server/responses-undeclared-tool-guard.ts +1 -1
  354. package/src/server/ws-bridge.ts +2 -0
  355. package/src/service/auth-preflight.ts +71 -0
  356. package/src/service/cli.ts +4 -2
  357. package/src/service/definition.ts +97 -0
  358. package/src/service/guards.ts +1 -61
  359. package/src/service/health-sentinel-linux.ts +112 -0
  360. package/src/service/health-sentinel-main.ts +76 -57
  361. package/src/service/health.ts +5 -89
  362. package/src/service/launchd.ts +27 -7
  363. package/src/service/logging.ts +72 -9
  364. package/src/service/repair.ts +2 -1
  365. package/src/service/state.ts +7 -8
  366. package/src/service/systemd.ts +1 -1
  367. package/src/service/windows-guarded-manager.ts +2 -1
  368. package/src/service/windows-ops.ts +1 -1
  369. package/src/service/windows-scheduler.ts +2 -7
  370. package/src/service/windows-taskxml.ts +2 -2
  371. package/src/service/windows-wscript.ts +14 -0
  372. package/src/service.ts +4 -2
  373. package/src/sidecar/auth.ts +2 -0
  374. package/src/types/config.ts +64 -3
  375. package/src/types/opencode-go.ts +61 -0
  376. package/src/types/opencode-zen.ts +35 -0
  377. package/src/types/provider.ts +32 -6
  378. package/src/types/request.ts +31 -2
  379. package/src/types/wire.ts +31 -37
  380. package/src/types.ts +2 -0
  381. package/src/update/npm-invocation.mjs +12 -2
  382. package/src/usage/cost.ts +48 -12
  383. package/src/usage/expected-prices.ts +3 -0
  384. package/src/usage/ledger-retention.ts +2 -1
  385. package/src/usage/ledger-scanner.ts +6 -5
  386. package/src/usage/log.ts +17 -8
  387. package/src/usage/summary.ts +30 -11
  388. package/src/usage/telemetry-contract.ts +1 -0
  389. package/src/usage/user-cost-overlays.ts +14 -19
  390. package/src/usage/user-cost-validation.ts +38 -0
  391. package/src/vision/eligibility.ts +13 -0
  392. package/src/web-search/anthropic-history.ts +59 -0
  393. package/src/web-search/loop.ts +236 -73
  394. package/src/web-search/progress-stream.ts +15 -2
  395. package/src/web-search/run-turn-loop.ts +9 -1
  396. package/gui/dist/assets/App-BjlttVLy.js +0 -58
  397. package/gui/dist/assets/App-CSJvmjNs.css +0 -1
  398. package/gui/dist/assets/index-BB6uK6tU.css +0 -1
  399. package/gui/dist/assets/index-BMssP4k3.js +0 -94
  400. package/gui/dist/assets/quota-summary-D8M1bc_R.js +0 -1
@@ -564,6 +564,7 @@ function providerCatalogFingerprint(name: string, prov: OcxProviderConfig): Reco
564
564
  };
565
565
  }
566
566
 
567
+ /** Coalesce only gathers with the same model inventory and effective sidecar visibility policy. */
567
568
  export function gatherFlightKey(config: OcxConfig): string {
568
569
  const providers = Object.entries(config.providers)
569
570
  .filter(([, prov]) => prov.disabled !== true)
@@ -571,6 +572,7 @@ export function gatherFlightKey(config: OcxConfig): string {
571
572
  .sort((a, b) => String(a.n).localeCompare(String(b.n)));
572
573
  const assembly = stableJson({
573
574
  providers,
575
+ visionSidecarEnabled: config.visionSidecar?.enabled !== false,
574
576
  disabledModels: [...(config.disabledModels ?? [])].sort(),
575
577
  combos: config.combos ?? {},
576
578
  customModels: (config.customModels ?? []).map((cm) => ({
@@ -276,6 +276,14 @@ function asLimits(input: NativeContextLimitsInput): NativeContextLimits {
276
276
  return typeof input === "number" ? { cap: input } : input;
277
277
  }
278
278
 
279
+ /** Configured hard ceiling only; an advertised default window is not a user limit. */
280
+ export function nativeOpenAiConfiguredContextLimit(slug: string, input?: NativeContextLimitsInput): number | undefined {
281
+ const limits = asLimits(input);
282
+ const overlay = positiveInt(limits.modelWindows?.[slug]) ?? positiveInt(limits.providerWindow);
283
+ const cap = positiveInt(limits.cap);
284
+ return overlay === undefined ? cap : cap === undefined ? overlay : Math.min(overlay, cap);
285
+ }
286
+
279
287
  /** Read both levers out of a config once, for call sites that hold one. */
280
288
  export function nativeContextLimits(
281
289
  config: Pick<OcxConfig, "providers" | "providerContextCaps">,
@@ -326,18 +334,12 @@ function longWindowOptInCeiling(slug: string): number | undefined {
326
334
 
327
335
  function narrowToLimits(raw: number | undefined, slug: string, input: NativeContextLimitsInput): number | undefined {
328
336
  if (raw === undefined) return undefined;
329
- const limits = asLimits(input);
330
- const overlay = positiveInt(limits.modelWindows?.[slug]) ?? positiveInt(limits.providerWindow);
331
- const cap = positiveInt(limits.cap);
337
+ const limit = nativeOpenAiConfiguredContextLimit(slug, input);
332
338
  const optInCeiling = longWindowOptInCeiling(slug);
333
339
  if (optInCeiling !== undefined) {
334
- const ceiling = optInCeiling;
335
- const chosen = overlay ?? cap ?? raw;
336
- const window = Math.min(chosen, ceiling);
337
- return overlay !== undefined && cap !== undefined ? Math.min(window, cap) : window;
340
+ return Math.min(limit ?? raw, optInCeiling);
338
341
  }
339
- const narrowed = overlay === undefined ? raw : Math.min(raw, overlay);
340
- return applyProviderContextCap(narrowed, cap) ?? narrowed;
342
+ return applyProviderContextCap(raw, limit);
341
343
  }
342
344
 
343
345
  export function nativeOpenAiContextWindow(slug: string, limits?: NativeContextLimitsInput): number | undefined {
@@ -252,6 +252,17 @@ export function configuredReasoningSummarySupport(prov: OcxProviderConfig | unde
252
252
  return modelRecordValue(prov.modelReasoningSummaryDelivery, id) !== undefined ? true : undefined;
253
253
  }
254
254
 
255
+ /** Add attachment metadata at publication time, independently of cached provider evidence. */
256
+ export function withVisionSidecarInput(
257
+ model: CatalogModel,
258
+ provider: OcxProviderConfig | undefined,
259
+ enabled = true,
260
+ ): CatalogModel {
261
+ if (!enabled || !provider || !isModelVisionSidecarConsumer(provider, model.id)) return model;
262
+ const modalities = model.inputModalities ?? ["text"];
263
+ return modalities.includes("image") ? model : { ...model, inputModalities: [...modalities, "image"] };
264
+ }
265
+
255
266
  /** Reapply configured limits and captured wire capabilities without trusting stale discovery hints. */
256
267
  export function applyProviderConfigHints(
257
268
  name: string,
@@ -261,6 +272,7 @@ export function applyProviderConfigHints(
261
272
  metadataModelIdCaseFold?: boolean,
262
273
  effectiveAlias?: string | null,
263
274
  metadataConfigDir?: string,
275
+ includeVisionSidecar = true,
264
276
  ): CatalogModel {
265
277
  const staticPolicy = resolveModelPolicy({
266
278
  providerName: name,
@@ -289,18 +301,7 @@ export function applyProviderConfigHints(
289
301
  // Removing an exact capability row therefore returns this projection to legacy-map inference.
290
302
  const resolvedModalities = staticPolicy.model.inputModalities ?? model.inputModalities
291
303
  ?? (azureMetadata?.input ? modelInputModalities({ id: model.id, input_modalities: azureMetadata.input }, undefined) : undefined);
292
- let inputModalities = resolvedModalities ? [...resolvedModalities] : undefined;
293
- // The shared vision-sidecar consumer predicate keeps catalog advertisement and request-time
294
- // planning aligned. The catalog must still advertise image input — the Codex app
295
- // gates attachments client-side on input_modalities, and a text-only entry would block images
296
- // before the sidecar ever runs ("This model does not support image inputs"). Discovery-derived
297
- // text-only rows stay untouched: the runtime predicate only reads these two config sources, so
298
- // it would not convert those.
299
- const sidecarCovered = isModelVisionSidecarConsumer(prov, model.id);
300
- if (sidecarCovered) {
301
- const base = inputModalities ?? model.inputModalities ?? ["text"];
302
- inputModalities = base.includes("image") ? [...base] : [...base, "image"];
303
- }
304
+ const inputModalities = resolvedModalities ? [...resolvedModalities] : undefined;
304
305
  const reasoningEfforts = configuredReasoningEfforts(prov, model.id);
305
306
  const suppressSyntheticMax = modelRecordValue(prov.modelSuppressSyntheticMax, model.id)
306
307
  ?? (model.antigravityEffortWireModelIds !== undefined);
@@ -337,7 +338,7 @@ export function applyProviderConfigHints(
337
338
  ?? azureWindow
338
339
  ?? inferredWindow?.contextWindow
339
340
  ?? (providerCap !== undefined ? resolveUnknownRoutedContextWindow(providerCap) : undefined);
340
- const hinted = {
341
+ const hinted = withVisionSidecarInput({
341
342
  ...modelWithoutServiceTier,
342
343
  ...(!model.contextWindowInference && previousContextCap !== undefined
343
344
  ? { contextCap: previousContextCap, contextCapped: previousContextCapped } : {}),
@@ -368,7 +369,7 @@ export function applyProviderConfigHints(
368
369
  ? { parallelToolCalls: true }
369
370
  : {}),
370
371
  ...(prov.codexToolMode !== undefined ? { codexToolMode: prov.codexToolMode } : {}),
371
- };
372
+ }, prov, includeVisionSidecar);
372
373
  const capped = applyProviderContextCap(hinted.contextWindow, providerCap);
373
374
  const withCap = providerCap !== undefined
374
375
  ? capped !== hinted.contextWindow
@@ -397,6 +398,7 @@ export function applyProviderConfigHints(
397
398
  };
398
399
  }
399
400
 
401
+ /** Project a configured row, optionally deferring sidecar attachment metadata until publication. */
400
402
  export function catalogHintsFromProviderConfig(
401
403
  name: string,
402
404
  prov: OcxProviderConfig,
@@ -405,12 +407,14 @@ export function catalogHintsFromProviderConfig(
405
407
  metadataModelIdCaseFold?: boolean,
406
408
  effectiveAlias?: string | null,
407
409
  metadataConfigDir?: string,
410
+ includeVisionSidecar = true,
408
411
  ): Partial<CatalogModel> {
409
- const hinted = applyProviderConfigHints(name, prov, { id, provider: name }, contextCap, metadataModelIdCaseFold, effectiveAlias, metadataConfigDir);
412
+ const hinted = applyProviderConfigHints(name, prov, { id, provider: name }, contextCap, metadataModelIdCaseFold, effectiveAlias, metadataConfigDir, includeVisionSidecar);
410
413
  const { provider: _provider, id: _id, ...hints } = hinted;
411
414
  return hints;
412
415
  }
413
416
 
417
+ /** Reapply current hints to cached rows without mutating their provider evidence. */
414
418
  export function applyConfigHintsToCachedModels(
415
419
  name: string,
416
420
  prov: OcxProviderConfig,
@@ -419,8 +423,9 @@ export function applyConfigHintsToCachedModels(
419
423
  metadataModelIdCaseFold?: boolean,
420
424
  effectiveAlias?: string | null,
421
425
  metadataConfigDir?: string,
426
+ includeVisionSidecar = true,
422
427
  ): CatalogModel[] {
423
- return models.map(model => applyProviderConfigHints(name, prov, model, contextCap, metadataModelIdCaseFold, effectiveAlias, metadataConfigDir));
428
+ return models.map(model => applyProviderConfigHints(name, prov, model, contextCap, metadataModelIdCaseFold, effectiveAlias, metadataConfigDir, includeVisionSidecar));
424
429
  }
425
430
 
426
431
  /** Catalog slugs whose configured model must not gain a missing synthetic max rung. */
@@ -231,6 +231,7 @@ export function mergeConfiguredModelsIntoLiveCatalog(opts: {
231
231
  retainComboTargets?: boolean;
232
232
  metadataModelIdCaseFold?: boolean;
233
233
  metadataConfigDir?: string;
234
+ includeVisionSidecar?: boolean;
234
235
  }): { models: CatalogModel[]; droppedConfiguredIds: string[] } {
235
236
  const {
236
237
  name,
@@ -242,6 +243,7 @@ export function mergeConfiguredModelsIntoLiveCatalog(opts: {
242
243
  retainComboTargets = true,
243
244
  metadataModelIdCaseFold,
244
245
  metadataConfigDir,
246
+ includeVisionSidecar,
245
247
  } = opts;
246
248
  const out = [...opts.models];
247
249
  const present = new Set(out.map(model => model.id));
@@ -250,7 +252,7 @@ export function mergeConfiguredModelsIntoLiveCatalog(opts: {
250
252
  if (present.has(candidate.id)) continue;
251
253
  const dated = out.find(live => isDatedVariantId(live.id, candidate.id));
252
254
  if (dated) {
253
- out.push(applyProviderConfigHints(name, prov, { ...dated, id: candidate.id }, contextCap, metadataModelIdCaseFold, undefined, metadataConfigDir));
255
+ out.push(applyProviderConfigHints(name, prov, { ...dated, id: candidate.id }, contextCap, metadataModelIdCaseFold, undefined, metadataConfigDir, includeVisionSidecar));
254
256
  present.add(candidate.id);
255
257
  continue;
256
258
  }
@@ -2,10 +2,16 @@ import type { VendorContextInference } from "./vendor-context";
2
2
  import { isCodexControlPlaneModel } from "../control-plane-models";
3
3
  import { execFileSync } from "node:child_process";
4
4
  import { createHash } from "node:crypto";
5
- import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
5
+ import { copyFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
6
6
  import { delimiter, dirname, join, resolve } from "node:path";
7
- import { atomicWriteFile, expandUserPath, getConfigDir, loadConfig, ultraFastTierEnabled, websocketsEnabled } from "../../config";
8
- import { CODEX_CONFIG_PATH, CODEX_MODELS_CACHE_PATH, DEFAULT_CATALOG_PATH, readRootTomlString, resolveCodexConfigPath } from "../paths";
7
+ import { atomicWriteFile, getConfigDir, loadConfig, ultraFastTierEnabled, websocketsEnabled } from "../../config";
8
+ import {
9
+ activeCodexConfigPath,
10
+ activeCodexModelsCachePath,
11
+ isDefaultCatalogPath,
12
+ readCodexCatalogPath,
13
+ readRootTomlString,
14
+ } from "../paths";
9
15
  import { clearModelCache, DEFAULT_MODEL_CACHE_TTL_MS, getFreshCached, getStaleCached, isModelsFetchCoolingDown, markModelsFetchFailure, setCached } from "../model-cache";
10
16
  import { buildModelsRequest, resolveModelsAuthToken } from "../../oauth";
11
17
  import type { OcxConfig, OcxProviderConfig } from "../../types";
@@ -33,7 +39,7 @@ import { redactSecretString } from "../../lib/redact";
33
39
  import upstreamModelsSnapshot from "../data/upstream-models.json";
34
40
 
35
41
 
36
- import { NATIVE_OPENAI_CONTEXT_OVERRIDES, SUPPORTED_NATIVE_OPENAI_SLUGS, UPSTREAM_NATIVE_ENTRIES, hasNativeOpenAiCapabilityMetadata, nativeMultiAgentVersion, nativeOpenAiAutoCompactTokenLimit, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, type NativeContextLimitsInput } from "./metadata";
42
+ import { NATIVE_OPENAI_CONTEXT_OVERRIDES, SUPPORTED_NATIVE_OPENAI_SLUGS, UPSTREAM_NATIVE_ENTRIES, hasNativeOpenAiCapabilityMetadata, nativeMultiAgentVersion, nativeOpenAiAutoCompactTokenLimit, nativeOpenAiConfiguredContextLimit, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, type NativeContextLimitsInput } from "./metadata";
37
43
  import { clampAutoCompactTokenLimit } from "../../providers/auto-compact-budget";
38
44
  import { trustedAccountBoundNativeCatalogSlug } from "./account-models";
39
45
  import { CODEX_NATIVE_ALIAS_CATALOG_KIND } from "./kinds";
@@ -50,46 +56,22 @@ export function catalogBackupPathFor(catalogPath: string): string {
50
56
  return join(getConfigDir(), `catalog-backup-${id}.json`);
51
57
  }
52
58
 
53
- export function samePath(a: string, b: string): boolean {
54
- const left = resolve(a);
55
- const right = resolve(b);
56
- return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
57
- }
58
-
59
- export function activeCodexHome(): string | null {
60
- const raw = process.env.CODEX_HOME?.trim();
61
- if (!raw) return null;
62
- const path = resolve(expandUserPath(raw));
63
- try {
64
- return realpathSync.native(path);
65
- } catch {
66
- return path;
67
- }
68
- }
69
-
70
- export function activeCodexConfigPath(): string {
71
- const home = activeCodexHome();
72
- return home ? join(home, "config.toml") : CODEX_CONFIG_PATH;
73
- }
74
-
75
- export function activeDefaultCatalogPath(): string {
76
- const home = activeCodexHome();
77
- return home ? join(home, "opencodex-catalog.json") : DEFAULT_CATALOG_PATH;
78
- }
79
-
80
- export function activeCodexModelsCachePath(): string {
81
- const home = activeCodexHome();
82
- return home ? join(home, "models_cache.json") : CODEX_MODELS_CACHE_PATH;
83
- }
84
-
85
- export function resolveActiveCodexConfigPath(path: string): string {
86
- const home = activeCodexHome();
87
- return home ? resolve(home, path) : resolveCodexConfigPath(path);
88
- }
89
-
90
- export function isDefaultCatalogPath(path: string): boolean {
91
- return samePath(path, activeDefaultCatalogPath());
92
- }
59
+ /**
60
+ * Active-home path resolution now lives in `../paths`, next to the constants it
61
+ * falls back to. It is re-exported here so existing importers keep working; new
62
+ * code that only needs a path should import from `../paths` directly.
63
+ */
64
+ export {
65
+ samePath,
66
+ activeCodexHome,
67
+ activeCodexConfigPath,
68
+ activeDefaultCatalogPath,
69
+ activeCodexModelsCachePath,
70
+ resolveActiveCodexConfigPath,
71
+ isDefaultCatalogPath,
72
+ readCodexCatalogPath,
73
+ readCodexCatalogPathForHome,
74
+ } from "../paths";
93
75
 
94
76
  /** Stable nonsemantic ownership marker for rows projected from config.customModels. */
95
77
  export const CODEX_CUSTOM_MODEL_CATALOG_KIND = "custom-model-v1";
@@ -254,40 +236,6 @@ export function shouldExposeRoutedModel(model: CatalogModel): boolean {
254
236
  return !isMediaGenerationModelId(model.id);
255
237
  }
256
238
 
257
- export function readCodexCatalogPath(): string {
258
- const home = activeCodexHome();
259
- if (home) return readCodexCatalogPathForHome(home);
260
- try {
261
- const configPath = activeCodexConfigPath();
262
- if (existsSync(configPath)) {
263
- const toml = readFileSync(configPath, "utf-8");
264
- const path = readRootTomlString(toml, "model_catalog_json");
265
- if (path) return resolveActiveCodexConfigPath(path);
266
- }
267
- } catch { /* ignore */ }
268
- return activeDefaultCatalogPath();
269
- }
270
-
271
- /**
272
- * Resolve the configured catalog without consulting ambient CODEX_HOME again.
273
- *
274
- * `configText` is for a caller that has already read that same `config.toml` under
275
- * its own constraints - the prompt-text probe reads it bounded, on the request
276
- * thread - so resolving the catalog does not cost a second, unbounded read of the
277
- * file the caller is holding. Omitting it keeps the original behaviour.
278
- */
279
- export function readCodexCatalogPathForHome(codexHome: string, configText?: string): string {
280
- try {
281
- const configPath = join(codexHome, "config.toml");
282
- if (configText !== undefined || existsSync(configPath)) {
283
- const toml = configText ?? readFileSync(configPath, "utf-8");
284
- const path = readRootTomlString(toml, "model_catalog_json");
285
- if (path) return resolve(codexHome, path);
286
- }
287
- } catch { /* ignore */ }
288
- return join(codexHome, "opencodex-catalog.json");
289
- }
290
-
291
239
  /**
292
240
  * Read the configured auto-review model from the root of Codex's config.toml (issue #1225).
293
241
  * Stamped onto catalog entries as `auto_review_model_override` during sync so the auto-review
@@ -506,7 +454,7 @@ export function isNativeOpenAiEntry(entry: RawEntry): boolean {
506
454
  * Narrow any already-resolved native window by the user levers.
507
455
  *
508
456
  * Used for the fields the accessors do not own (`max_context_window`, and preserved rows
509
- * that carry no static override) so every field on a row lands at the same width.
457
+ * that carry no static override). The advertised maximum may exceed the default window.
510
458
  */
511
459
  function narrowNativeMaxContextWindow(
512
460
  slug: string,
@@ -514,12 +462,7 @@ function narrowNativeMaxContextWindow(
514
462
  limits?: NativeContextLimitsInput,
515
463
  ): number | undefined {
516
464
  if (typeof value !== "number" || value <= 0) return value;
517
- const resolved = nativeOpenAiContextWindow(slug, limits);
518
- const authoritative = nativeOpenAiContextWindow(slug);
519
- // The accessor pair tells us how far the levers moved this slug; apply the same delta to a
520
- // field the accessor does not model, without ever raising it.
521
- if (resolved === undefined || authoritative === undefined) return value;
522
- return Math.min(value, Math.max(resolved, 1));
465
+ return applyProviderContextCap(value, nativeOpenAiConfiguredContextLimit(slug, limits));
523
466
  }
524
467
 
525
468
  export function applyNativeOpenAiContextOverride(entry: RawEntry, limits?: NativeContextLimitsInput): void {
@@ -636,7 +579,8 @@ export function ensureStrictCatalogFields(
636
579
  if (
637
580
  typeof entry.max_context_window !== "number"
638
581
  || entry.max_context_window <= 0
639
- || ((options.isRouted === true || !isNativeOpenAiEntry(entry)) && entry.max_context_window > contextWindow)
582
+ || ((options.isRouted === true || (!isNativeOpenAiEntry(entry)
583
+ && trustedAccountBoundNativeCatalogSlug(entry) === undefined)) && entry.max_context_window > contextWindow)
640
584
  ) {
641
585
  entry.max_context_window = contextWindow;
642
586
  }
@@ -117,7 +117,7 @@ import type {
117
117
  CatalogTrustedOpenAiApiPolicySnapshot,
118
118
  } from "../convergence-types";
119
119
  import type { CapturedProviderGather, CatalogGatherProviderAuthOutcome, CatalogGatherProviderModelOutcome, ModelsAuthResolution, ModelsAuthResolver } from "./gather-capture";
120
- import { QUIET_AUTHORITATIVE_CATALOG_PROVIDERS, applyConfigHintsToCachedModels, applyProviderConfigHints, boundedOwnedBy, catalogHintsFromModelsApiItem, catalogHintsFromProviderConfig } from "./model-hints";
120
+ import { QUIET_AUTHORITATIVE_CATALOG_PROVIDERS, applyConfigHintsToCachedModels, applyProviderConfigHints, boundedOwnedBy, catalogHintsFromModelsApiItem, catalogHintsFromProviderConfig, withVisionSidecarInput } from "./model-hints";
121
121
  import { mergeConfiguredModelsIntoLiveCatalog, shouldExposeProviderModel, warnDroppedConfiguredIdsOnce } from "./model-visibility";
122
122
  import { captureModelsRequest, captureProviderGather, materializeCapturedHeaders } from "./gather-capture";
123
123
 
@@ -168,7 +168,7 @@ export function observedModelsAuthResolver(
168
168
  },
169
169
  };
170
170
  }
171
- /** Project captured discovery through config hints and retention; Auto-only Copilot exposes only Auto. */
171
+ /** Project provider evidence without synthetic sidecar image input, which belongs to each gather. */
172
172
  export async function fetchProviderModelsWithAuth(
173
173
  captured: CapturedProviderGather,
174
174
  ttlMs: number,
@@ -211,7 +211,7 @@ export async function fetchProviderModelsWithAuth(
211
211
  const configured: CatalogModel[] = configuredIds.map(id => ({
212
212
  id,
213
213
  provider: name,
214
- ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
214
+ ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
215
215
  }));
216
216
  const withConfiguredRetention = (
217
217
  models: CatalogModel[],
@@ -228,6 +228,7 @@ export async function fetchProviderModelsWithAuth(
228
228
  retainComboTargets: options?.retainComboTargets,
229
229
  metadataModelIdCaseFold,
230
230
  metadataConfigDir,
231
+ includeVisionSidecar: false,
231
232
  });
232
233
  if (
233
234
  options?.warnDrops === true
@@ -260,7 +261,7 @@ export async function fetchProviderModelsWithAuth(
260
261
  }
261
262
  return observed(ids.map(id => {
262
263
  const hints = catalogHintsFromProviderConfig(name, prov, id, contextCap,
263
- metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir);
264
+ metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false);
264
265
  const observedWindow = kiroObservedContextWindow(id);
265
266
  return { id, provider: name, ...hints,
266
267
  ...(observedWindow !== undefined
@@ -296,7 +297,7 @@ export async function fetchProviderModelsWithAuth(
296
297
  model => applyProviderConfigHints(name, prov, {
297
298
  id: model.id, provider: name,
298
299
  ...catalogHintsFromModelsApiItem(name, model as ProviderModelsApiItem),
299
- }, contextCap, metadataModelIdCaseFold, captured.effectiveAlias));
300
+ }, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, undefined, false));
300
301
  if (!isCurrentCacheGeneration()) return observed(configured, "degraded");
301
302
  markProviderDiscoveryOk(name, picker.length);
302
303
  // Retain callable manual/combo selectors, but do not advertise named selection
@@ -326,7 +327,7 @@ export async function fetchProviderModelsWithAuth(
326
327
  : [{
327
328
  id: prov.defaultModel,
328
329
  provider: name,
329
- ...catalogHintsFromProviderConfig(name, prov, prov.defaultModel, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
330
+ ...catalogHintsFromProviderConfig(name, prov, prov.defaultModel, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
330
331
  }];
331
332
  const vertexDefaultSeed = seedVertexDefault ? configured[0] : undefined;
332
333
  const withVertexDefaultSeed = (models: CatalogModel[]): CatalogModel[] => (
@@ -348,13 +349,13 @@ export async function fetchProviderModelsWithAuth(
348
349
  const fresh = getFreshCached(name, ttlMs, Date.now(), authorityIdentity);
349
350
  if (fresh) {
350
351
  return observed(withConfiguredRetention(
351
- applyConfigHintsToCachedModels(name, prov, fresh, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
352
+ applyConfigHintsToCachedModels(name, prov, fresh, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
352
353
  ), "authoritative");
353
354
  }
354
355
  const scopedStale = getStaleCached(name, authorityIdentity);
355
356
  if (isModelsFetchCoolingDown(name, undefined, undefined, authorityIdentity) && scopedStale) {
356
357
  return observed(withConfiguredRetention(
357
- applyConfigHintsToCachedModels(name, prov, scopedStale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
358
+ applyConfigHintsToCachedModels(name, prov, scopedStale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
358
359
  ), "degraded");
359
360
  }
360
361
  const live = await fetchCodeBuddyModels(profile, apiKey);
@@ -362,7 +363,7 @@ export async function fetchProviderModelsWithAuth(
362
363
  const discovered = live.models.map(id => ({
363
364
  id,
364
365
  provider: name,
365
- ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
366
+ ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
366
367
  }));
367
368
  const forCache = withConfiguredRetention(discovered, { retainComboTargets: false });
368
369
  if (!setCached(name, forCache, Date.now(), cacheGeneration, authorityIdentity)) {
@@ -378,7 +379,7 @@ export async function fetchProviderModelsWithAuth(
378
379
  }
379
380
  const stale = getStaleCached(name, authorityIdentity);
380
381
  return observed(withConfiguredRetention(
381
- stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir) : configured,
382
+ stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false) : configured,
382
383
  ), "degraded");
383
384
  }
384
385
  if (name === "zed" && prov.adapter === "zed") {
@@ -391,14 +392,14 @@ export async function fetchProviderModelsWithAuth(
391
392
  const cached = getFreshCached(name, ttlMs, Date.now(), authorityIdentity);
392
393
  if (cached) {
393
394
  return observed(
394
- withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cached, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir)),
395
+ withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cached, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false)),
395
396
  "authoritative",
396
397
  );
397
398
  }
398
399
  const stale = getStaleCached(name, authorityIdentity);
399
400
  if (isModelsFetchCoolingDown(name, undefined, undefined, authorityIdentity) && stale) {
400
401
  return observed(
401
- withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir)),
402
+ withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false)),
402
403
  "degraded",
403
404
  );
404
405
  }
@@ -418,7 +419,7 @@ export async function fetchProviderModelsWithAuth(
418
419
  ...(model.maxOutputTokens ? { maxOutputTokens: model.maxOutputTokens } : {}),
419
420
  ...(model.supportsImages ? { inputModalities: ["text", "image"] } : {}),
420
421
  ...(reasoningEfforts?.length ? { reasoningEfforts } : {}),
421
- ...catalogHintsFromProviderConfig(name, prov, model.id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
422
+ ...catalogHintsFromProviderConfig(name, prov, model.id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
422
423
  } as CatalogModel;
423
424
  });
424
425
  const forCache = withConfiguredRetention(discovered, { retainComboTargets: false });
@@ -433,7 +434,7 @@ export async function fetchProviderModelsWithAuth(
433
434
  markProviderDiscoveryFailed(name, { reason: "provider" });
434
435
  }
435
436
  return observed(
436
- withConfiguredRetention(stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir) : configured),
437
+ withConfiguredRetention(stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false) : configured),
437
438
  "degraded",
438
439
  );
439
440
  }
@@ -449,13 +450,13 @@ export async function fetchProviderModelsWithAuth(
449
450
  const fresh = getFreshCached(name, ttlMs, Date.now(), authorityIdentity);
450
451
  if (fresh) {
451
452
  return observed(withConfiguredRetention(
452
- applyConfigHintsToCachedModels(name, prov, fresh, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
453
+ applyConfigHintsToCachedModels(name, prov, fresh, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
453
454
  ), "authoritative");
454
455
  }
455
456
  const scopedStale = getStaleCached(name, authorityIdentity);
456
457
  if (isModelsFetchCoolingDown(name) && scopedStale) {
457
458
  return observed(withConfiguredRetention(
458
- applyConfigHintsToCachedModels(name, prov, scopedStale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
459
+ applyConfigHintsToCachedModels(name, prov, scopedStale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
459
460
  ), "degraded");
460
461
  }
461
462
  const live = await fetchQoderModels(profile, apiKey);
@@ -463,7 +464,7 @@ export async function fetchProviderModelsWithAuth(
463
464
  const discovered = live.models.map(id => ({
464
465
  id,
465
466
  provider: name,
466
- ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
467
+ ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
467
468
  }));
468
469
  const forCache = withConfiguredRetention(discovered, { retainComboTargets: false });
469
470
  if (!setCached(name, forCache, Date.now(), cacheGeneration, authorityIdentity)) {
@@ -479,7 +480,7 @@ export async function fetchProviderModelsWithAuth(
479
480
  }
480
481
  const stale = getStaleCached(name, authorityIdentity);
481
482
  return observed(withConfiguredRetention(
482
- stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir) : configured,
483
+ stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false) : configured,
483
484
  ), "degraded");
484
485
  }
485
486
  if (prov.adapter === "devin") {
@@ -494,7 +495,7 @@ export async function fetchProviderModelsWithAuth(
494
495
  const cachedDevin = getFreshCached(name, ttlMs, Date.now(), authorityIdentity);
495
496
  if (cachedDevin) {
496
497
  return observed(
497
- withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cachedDevin, undefined, undefined, undefined, metadataConfigDir)),
498
+ withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cachedDevin, undefined, undefined, undefined, metadataConfigDir, false)),
498
499
  "authoritative",
499
500
  );
500
501
  }
@@ -502,7 +503,7 @@ export async function fetchProviderModelsWithAuth(
502
503
  const cooling = getStaleCached(name, authorityIdentity);
503
504
  return observed(
504
505
  withConfiguredRetention(
505
- cooling ? applyConfigHintsToCachedModels(name, prov, cooling, undefined, undefined, undefined, metadataConfigDir) : configured,
506
+ cooling ? applyConfigHintsToCachedModels(name, prov, cooling, undefined, undefined, undefined, metadataConfigDir, false) : configured,
506
507
  ),
507
508
  "degraded",
508
509
  );
@@ -540,11 +541,11 @@ export async function fetchProviderModelsWithAuth(
540
541
  ...(liveResult.defaultEfforts[id] ? { defaultReasoningEffort: liveResult.defaultEfforts[id] } : {}),
541
542
  // The account catalog's per-base supportsImages vote collapses to one
542
543
  // modalities value. It spreads before the hints so exact
543
- // modelCapabilities declarations, the legacy modelInputModalities
544
- // record and the vision-sidecar rewrite keep winning — the live
545
- // value survives only when none of them applies.
544
+ // modelCapabilities declarations and the legacy modelInputModalities
545
+ // record keep winning. Sidecar advertisement is added after discovery;
546
+ // the live value survives only when no explicit declaration applies.
546
547
  ...(liveResult.inputModalities[id]?.length ? { inputModalities: liveResult.inputModalities[id] } : {}),
547
- ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir),
548
+ ...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false),
548
549
  } as CatalogModel;
549
550
  });
550
551
  const forCache = withConfiguredRetention(result, { retainComboTargets: false });
@@ -560,7 +561,7 @@ export async function fetchProviderModelsWithAuth(
560
561
  }
561
562
  const stale = getStaleCached(name, authorityIdentity);
562
563
  return observed(
563
- withConfiguredRetention(stale ? applyConfigHintsToCachedModels(name, prov, stale, undefined, undefined, undefined, metadataConfigDir) : configured),
564
+ withConfiguredRetention(stale ? applyConfigHintsToCachedModels(name, prov, stale, undefined, undefined, undefined, metadataConfigDir, false) : configured),
564
565
  "degraded",
565
566
  );
566
567
  }
@@ -577,7 +578,7 @@ export async function fetchProviderModelsWithAuth(
577
578
  const cachedCursor = getFreshCached(name, ttlMs, Date.now(), authorityIdentity);
578
579
  if (cachedCursor) {
579
580
  return observed(
580
- withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cachedCursor, undefined, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir)),
581
+ withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cachedCursor, undefined, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false)),
581
582
  "authoritative",
582
583
  );
583
584
  }
@@ -585,7 +586,7 @@ export async function fetchProviderModelsWithAuth(
585
586
  const cooling = getStaleCached(name, authorityIdentity);
586
587
  return observed(
587
588
  withConfiguredRetention(
588
- cooling ? applyConfigHintsToCachedModels(name, prov, cooling, undefined, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir) : configured,
589
+ cooling ? applyConfigHintsToCachedModels(name, prov, cooling, undefined, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false) : configured,
589
590
  ),
590
591
  "degraded",
591
592
  );
@@ -631,7 +632,7 @@ export async function fetchProviderModelsWithAuth(
631
632
  const staleCursor = getStaleCached(name, authorityIdentity);
632
633
  return observed(
633
634
  withConfiguredRetention(
634
- staleCursor ? applyConfigHintsToCachedModels(name, prov, staleCursor, undefined, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir) : configured,
635
+ staleCursor ? applyConfigHintsToCachedModels(name, prov, staleCursor, undefined, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false) : configured,
635
636
  ),
636
637
  "degraded",
637
638
  );
@@ -649,7 +650,7 @@ export async function fetchProviderModelsWithAuth(
649
650
  if (fresh) {
650
651
  return observed(
651
652
  withConfiguredRetention(
652
- withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, fresh, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir)),
653
+ withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, fresh, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false)),
653
654
  ),
654
655
  "authoritative",
655
656
  ); // dedups Codex's frequent /v1/models polling within the TTL
@@ -661,7 +662,7 @@ export async function fetchProviderModelsWithAuth(
661
662
  return observed(
662
663
  withConfiguredRetention(
663
664
  stale
664
- ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir))
665
+ ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false))
665
666
  : failedDiscoveryConfigured,
666
667
  ),
667
668
  "degraded",
@@ -706,7 +707,7 @@ export async function fetchProviderModelsWithAuth(
706
707
  return {
707
708
  models: withConfiguredRetention(
708
709
  stale
709
- ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir))
710
+ ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false))
710
711
  : failedDiscoveryConfigured,
711
712
  ),
712
713
  fallback: stale ? "stale" : "configured",
@@ -797,7 +798,7 @@ export async function fetchProviderModelsWithAuth(
797
798
  ...(model.contextWindow ? { contextWindow: model.contextWindow } : {}),
798
799
  ...(model.inputModalities ? { inputModalities: model.inputModalities } : {}),
799
800
  }));
800
- const live = applyConfigHintsToCachedModels(name, prov, upstream, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir);
801
+ const live = applyConfigHintsToCachedModels(name, prov, upstream, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false);
801
802
  const forCache = azureMetadata ? upstream : withConfiguredRetention(live, { retainComboTargets: false });
802
803
  if (!isCurrentCacheGeneration()) {
803
804
  return observed(withConfiguredRetention(configured), "degraded");
@@ -878,7 +879,7 @@ export async function fetchProviderModelsWithAuth(
878
879
  };
879
880
  })
880
881
  .filter(m => shouldExposeProviderModel(name, m.id));
881
- const live = applyConfigHintsToCachedModels(name, prov, upstream, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir);
882
+ const live = applyConfigHintsToCachedModels(name, prov, upstream, contextCap, metadataModelIdCaseFold, captured.effectiveAlias, metadataConfigDir, false);
882
883
  // Capture the count BEFORE the alias/configured augmentation below pushes extra rows into
883
884
  // `live`; otherwise configured entries would be reported as discovered ones.
884
885
  const liveModelCount = live.length;
@@ -925,6 +926,7 @@ export async function fetchProviderModelsWithAuth(
925
926
  }
926
927
  }
927
928
 
929
+ /** Preserve the provider-only API's default-enabled projection without widening cached evidence. */
928
930
  export async function fetchProviderModels(
929
931
  name: string,
930
932
  prov: OcxProviderConfig,
@@ -937,5 +939,5 @@ export async function fetchProviderModels(
937
939
  ttlMs,
938
940
  contextCap,
939
941
  refreshingModelsAuthResolver,
940
- )).models;
942
+ )).models.map(model => withVisionSidecarInput(model, captured.provider));
941
943
  }