@iislee/opencodex 2.11.0 → 2.35.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 (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -9,7 +9,7 @@
9
9
  * Modelled after src/codex/routing.ts cooldown logic but scoped to plain API-key pools.
10
10
  */
11
11
  import { saveConfigPreservingClaudeCode } from "../config";
12
- import type { OcxConfig, OcxProviderConfig } from "../types";
12
+ import type { OcxConfig, OcxProviderConfig, RateLimitRetryPolicy } from "../types";
13
13
  import { resolveProviderTransport, type OcxProviderTransport } from "./xai-transport";
14
14
  import { sweepExpiredOnWrite } from "../lib/state-store-sweeper";
15
15
 
@@ -22,6 +22,18 @@ interface KeyCooldown {
22
22
  const DEFAULT_COOLDOWN_MS = 60_000;
23
23
  const MAX_COOLDOWN_MS = 10 * 60_000; // cap at 10 min for api-key rotation
24
24
 
25
+ /**
26
+ * Default same-target 429 retry policy used when a provider opts in via a bare
27
+ * `retryOn429: {}` (presence = opt-in with these defaults).
28
+ */
29
+ const DEFAULT_RATE_LIMIT_RETRY = {
30
+ enabled: true,
31
+ attempts: 3,
32
+ intervalMs: 5_000,
33
+ maxIntervalMs: 60_000,
34
+ respectRetryAfter: true,
35
+ } as const satisfies Required<RateLimitRetryPolicy>;
36
+
25
37
  /** Map<`${providerName}\0${keyId}`, KeyCooldown> */
26
38
  const keyCooldowns = new Map<string, KeyCooldown>();
27
39
 
@@ -29,21 +41,32 @@ function cooldownKey(providerName: string, keyId: string): string {
29
41
  return `${providerName}\0${keyId}`;
30
42
  }
31
43
 
44
+ /**
45
+ * Parse an upstream `Retry-After` header: numeric seconds (including `0`) or an HTTP-date.
46
+ * Returns a bounded delay in ms (1..MAX_COOLDOWN_MS), or undefined when the value is
47
+ * malformed. An HTTP-date already in the past yields an immediate (1 ms) retry.
48
+ */
32
49
  function parseRetryAfterMs(value: string | null | undefined, now = Date.now()): number | undefined {
33
50
  const text = value?.trim();
34
51
  if (!text) return undefined;
35
52
  if (/^\d+(?:\.\d+)?$/.test(text)) {
36
53
  const seconds = Number(text);
37
- if (Number.isFinite(seconds) && seconds > 0) {
54
+ if (Number.isFinite(seconds) && seconds >= 0) {
38
55
  return Math.min(Math.max(Math.ceil(seconds * 1000), 1), MAX_COOLDOWN_MS);
39
56
  }
40
57
  }
41
58
  const timestamp = Date.parse(text);
42
59
  if (!Number.isFinite(timestamp)) return undefined;
43
60
  const delay = timestamp - now;
44
- return delay > 0 ? Math.min(delay, MAX_COOLDOWN_MS) : undefined;
61
+ // A valid HTTP-date whose retry time has already passed is an immediate retry, exactly like
62
+ // numeric `Retry-After: 0` — never a malformed-header fallback to the fixed interval.
63
+ return Math.min(Math.max(delay, 1), MAX_COOLDOWN_MS);
45
64
  }
46
65
 
66
+ /**
67
+ * True while the given key is inside its 429 cooldown window (lazily evicting the entry once the
68
+ * window expires). Used to skip keys that the upstream just rate-limited during failover.
69
+ */
47
70
  function isKeyInCooldown(providerName: string, keyId: string, now = Date.now()): boolean {
48
71
  const entry = keyCooldowns.get(cooldownKey(providerName, keyId));
49
72
  if (!entry) return false;
@@ -65,6 +88,51 @@ export function hasKeyPoolFailover(provider: OcxProviderConfig): boolean {
65
88
  return (provider.apiKeyPool?.length ?? 0) >= 2;
66
89
  }
67
90
 
91
+ /**
92
+ * Normalize a provider's `retryOn429` policy, or return null when the knob is absent,
93
+ * explicitly disabled, or the provider is not key-auth (OAuth/forward credentials must not be
94
+ * replayed on the same token, forward passthrough never reaches the recovery loop anyway, and
95
+ * local runtimes have no remote key to preserve). The returned policy is fully defaulted so
96
+ * callers never re-check fields.
97
+ */
98
+ export function rateLimitRetryPolicyFor(
99
+ provider: Pick<OcxProviderConfig, "retryOn429" | "authMode">,
100
+ ): Required<RateLimitRetryPolicy> | null {
101
+ const policy = provider.retryOn429;
102
+ if (!policy || policy.enabled === false) return null;
103
+ // Fail closed: only explicit key auth or the documented omitted-default (undefined == key for
104
+ // custom API-key providers) may use same-key replays. OAuth/forward are never replayed on the
105
+ // same token, local runtimes have no remote key to preserve, and unknown/custom values are
106
+ // rejected rather than guessed at.
107
+ if (provider.authMode !== undefined && provider.authMode !== "key") return null;
108
+ return {
109
+ enabled: policy.enabled ?? DEFAULT_RATE_LIMIT_RETRY.enabled,
110
+ attempts: policy.attempts ?? DEFAULT_RATE_LIMIT_RETRY.attempts,
111
+ intervalMs: policy.intervalMs ?? DEFAULT_RATE_LIMIT_RETRY.intervalMs,
112
+ maxIntervalMs: policy.maxIntervalMs ?? DEFAULT_RATE_LIMIT_RETRY.maxIntervalMs,
113
+ respectRetryAfter: policy.respectRetryAfter ?? DEFAULT_RATE_LIMIT_RETRY.respectRetryAfter,
114
+ };
115
+ }
116
+
117
+ /**
118
+ * Wait before the next same-target replay: upstream Retry-After (seconds or HTTP-date) when
119
+ * `respectRetryAfter` is on and the header parses, capped at `maxIntervalMs`; otherwise the
120
+ * fixed `intervalMs`, also capped at `maxIntervalMs` (a single wait never exceeds the cap).
121
+ * Malformed headers fall back to the fixed interval.
122
+ */
123
+ export function rateLimitRetryDelayMs(
124
+ policy: Required<RateLimitRetryPolicy>,
125
+ retryAfterHeader: string | null | undefined,
126
+ now = Date.now(),
127
+ ): number {
128
+ const raw = retryAfterHeader?.trim();
129
+ if (policy.respectRetryAfter && raw) {
130
+ const parsed = parseRetryAfterMs(raw, now);
131
+ if (parsed !== undefined) return Math.min(parsed, policy.maxIntervalMs);
132
+ }
133
+ return Math.min(policy.intervalMs, policy.maxIntervalMs);
134
+ }
135
+
68
136
  /**
69
137
  * Record a 429 for the current key and attempt to switch to the next available one.
70
138
  *
@@ -1,6 +1,7 @@
1
- import { CODEX_ACCOUNT_LOG_LABEL_RE } from "../codex/account-label";
1
+ import { CODEX_ACCOUNT_LOG_LABEL_RE, oauthAccountLogLabel } from "../codex/account-label";
2
+ import type { OcxProviderConfig } from "../types";
2
3
 
3
- function canonicalUsageProviderLabel(provider: string): string {
4
+ export function canonicalUsageProviderLabel(provider: string): string {
4
5
  return provider === "chatgpt" || provider === "openai-multi" ? "openai" : provider;
5
6
  }
6
7
 
@@ -17,3 +18,35 @@ export function baseProviderLabel(provider: string): string {
17
18
  if (suffix === "main") return canonicalUsageProviderLabel(provider.slice(0, cut));
18
19
  return CODEX_ACCOUNT_LOG_LABEL_RE.test(suffix) ? canonicalUsageProviderLabel(provider.slice(0, cut)) : provider;
19
20
  }
21
+
22
+ /**
23
+ * Stamp the per-account usage label for a non-Codex OAuth provider (#2699).
24
+ *
25
+ * Call this where the resolved credential is known and NOT inside a failover gate. The obvious
26
+ * place -- next to the `genericFailoverAccountId` assignment in `core.ts` -- sits inside
27
+ * `isGenericFailoverProvider`, and the rotation paths additionally require two or more stored
28
+ * accounts. Stamping there would leave the ordinary case (one xai account, failover off) with no
29
+ * label at all while every test still passed, which is the bug this fixes rather than a variant
30
+ * of it.
31
+ *
32
+ * Two providers are skipped because they already have attribution:
33
+ * - `openai` produces its own `p`-labels through `codexAuthContextLogLabel`.
34
+ * - `anthropic` folds the account into the provider label (`formatAnthropicProviderForLog`).
35
+ *
36
+ * It lives here rather than in `account-label.ts` because it needs `baseProviderLabel`, and this
37
+ * module already imports from that one -- the reverse direction would be an import cycle. This
38
+ * file stays Lab-clean, which matters because `core.ts` is one of the three files
39
+ * `tests/core-lab-boundary.test.ts` guards.
40
+ */
41
+ export function stampOAuthAccountLabel(
42
+ logCtx: { accountLogLabel?: string },
43
+ providerName: string,
44
+ provider: Pick<OcxProviderConfig, "authMode">,
45
+ accountId: string | undefined,
46
+ ): void {
47
+ if (!accountId) return;
48
+ if (provider.authMode !== "oauth") return;
49
+ const base = baseProviderLabel(providerName);
50
+ if (base === "openai" || base === "anthropic") return;
51
+ logCtx.accountLogLabel = oauthAccountLogLabel(accountId, base);
52
+ }
@@ -0,0 +1,16 @@
1
+ /** Hard process-wide limits shared by all live model-discovery parsers. */
2
+ export const MODEL_DISCOVERY_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
3
+ export const MODEL_DISCOVERY_MAX_MODELS = 2_000;
4
+ export const MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH = 1_024;
5
+
6
+ const MODEL_DISCOVERY_MODEL_ID_CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
7
+
8
+ /** Reject model IDs that cannot safely be published as callable catalog selectors. */
9
+ export function isValidModelDiscoveryModelId(value: unknown): value is string {
10
+ if (typeof value !== "string") return false;
11
+ const normalized = value.trim();
12
+ return Boolean(normalized)
13
+ && normalized === value
14
+ && normalized.length <= MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH
15
+ && !MODEL_DISCOVERY_MODEL_ID_CONTROL_CHARS.test(normalized);
16
+ }
@@ -1,20 +1,28 @@
1
1
  import type { OcxProviderConfig } from "../types";
2
+ import {
3
+ isValidModelDiscoveryModelId,
4
+ MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH,
5
+ MODEL_DISCOVERY_MAX_MODELS,
6
+ MODEL_DISCOVERY_MAX_RESPONSE_BYTES,
7
+ } from "./model-discovery-limits";
8
+ export {
9
+ isValidModelDiscoveryModelId,
10
+ MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH,
11
+ MODEL_DISCOVERY_MAX_MODELS,
12
+ MODEL_DISCOVERY_MAX_RESPONSE_BYTES,
13
+ } from "./model-discovery-limits";
2
14
  import {
3
15
  getProviderRegistryEntry,
4
16
  providerMatchesRegistryTransport,
17
+ registryEntryForProviderDestination,
5
18
  type ProviderModelDiscoveryFilter,
6
19
  type ProviderModelDiscoveryPredicate,
7
20
  type ProviderModelDiscoveryScalar,
8
21
  type ProviderModelDiscoverySpec,
9
22
  } from "./registry";
10
23
 
11
- /** Hard process-wide limits. Registry entries may lower, but never raise, these ceilings. */
12
- export const MODEL_DISCOVERY_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
13
- export const MODEL_DISCOVERY_MAX_MODELS = 2_000;
14
- export const MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH = 1_024;
15
24
  const MODEL_DISCOVERY_MAX_FILTER_VALUES = 256;
16
25
  const MODEL_DISCOVERY_MAX_FILTER_STRING_LENGTH = 1_024;
17
- const MODEL_DISCOVERY_MODEL_ID_CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
18
26
 
19
27
  export interface ResolvedProviderModelDiscovery {
20
28
  spec?: ProviderModelDiscoverySpec;
@@ -91,7 +99,12 @@ export function providerModelDiscoverySpecError(spec: ProviderModelDiscoverySpec
91
99
  return "discovery path must be a query-free relative/origin path";
92
100
  }
93
101
  if (path.includes("\\")) return "discovery path must use forward slashes";
94
- if (path.split("/").some(segment => segment.replace(/%2e/gi, ".") === "..")) {
102
+ const segments = path.split("/");
103
+ if (segments.some((segment, index) => {
104
+ const decoded = segment.replace(/%2e/gi, ".");
105
+ if (decoded !== "..") return false;
106
+ return index !== 0 || segments.filter(s => s.replace(/%2e/gi, ".") === "..").length !== 1;
107
+ })) {
95
108
  return "discovery path must not contain parent-directory segments";
96
109
  }
97
110
  }
@@ -124,9 +137,14 @@ export function resolveProviderModelDiscovery(
124
137
  providerName: string,
125
138
  provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
126
139
  ): ResolvedProviderModelDiscovery {
127
- const entry = providerMatchesRegistryTransport(providerName, provider)
128
- ? getProviderRegistryEntry(providerName)
129
- : undefined;
140
+ // The dashboard permits a canonical preset to be saved under a different name. Recover its
141
+ // registry-owned discovery policy by transport in that case. The destination helper is limited
142
+ // to exact fixed-key baseUrl + adapter matches, so custom endpoints, OAuth rows, templates, and
143
+ // overridable destinations cannot acquire another provider's discovery URL or filter.
144
+ const namedEntry = getProviderRegistryEntry(providerName);
145
+ const entry = namedEntry
146
+ ? (providerMatchesRegistryTransport(providerName, provider) ? namedEntry : undefined)
147
+ : registryEntryForProviderDestination(provider);
130
148
  const spec = entry?.modelDiscovery;
131
149
  return {
132
150
  ...(spec ? { spec } : {}),
@@ -313,12 +331,83 @@ export function extractModelEnvelopeRows(
313
331
  }
314
332
 
315
333
  /** Validate, bound, deduplicate, and declaratively filter OpenAI `{data:[...]}` or top-level arrays (Together `#617`). */
334
+ /**
335
+ * Metadata a sibling `models[]` array may contribute to an ALREADY-ADMITTED
336
+ * `data[]` row (#1797).
337
+ *
338
+ * llama.cpp serves a dual-envelope body: an Ollama-style `models[]` array
339
+ * carrying `capabilities` alongside the OpenAI-style `data[]` array carrying
340
+ * `meta`, so the two halves of one model's metadata never meet and a server
341
+ * that truthfully advertises "multimodal" produced an image-blind row.
342
+ *
343
+ * Two boundaries make this safe, and both were added after review found the
344
+ * first attempt unsound:
345
+ *
346
+ * 1. It runs AFTER admission filtering. Enriching first let a sibling supply
347
+ * the exact field a provider filter requires — reproduced against the real
348
+ * Chutes policy, where a row lacking `supported_features: ["tools"]` was
349
+ * admitted once a same-id sibling provided it. Enrichment may change what is
350
+ * KNOWN about a model, never WHICH models are published.
351
+ * 2. Only the capability keys #1797 needs are copied. A blanket "fill every
352
+ * absent key" made the untrusted `models[]` array a way into any field the
353
+ * pipeline consumes.
354
+ *
355
+ * The list deliberately EXCLUDES `supported_features` and `features`, even
356
+ * though both are capability-shaped: they are the two keys real provider
357
+ * filters test (`registry.ts:1591` requires `supported_features` to contain
358
+ * "tools"; `registry.ts:1883` tests `features.tool_use`). Ordering already
359
+ * prevents a sibling from flipping an admission verdict, but a key that is
360
+ * both enrichable and filter-relevant is one refactor away from becoming a
361
+ * bypass again. #1797 does not need them.
362
+ */
363
+ const SIBLING_ENRICHABLE_KEYS = new Set(["capabilities", "modalities", "input_modalities"]);
364
+
365
+ type SiblingIndex = Map<string, Record<string, unknown> | null>;
366
+
367
+ function buildSiblingIndex(value: unknown, limit: number): SiblingIndex | null {
368
+ const record = plainObject(value);
369
+ const sibling = record?.models;
370
+ if (!Array.isArray(sibling) || sibling.length === 0 || sibling.length > limit) return null;
371
+
372
+ const byId: SiblingIndex = new Map();
373
+ for (const raw of sibling) {
374
+ const entry = plainObject(raw);
375
+ if (!entry) continue;
376
+ for (const key of ["id", "model", "name"]) {
377
+ const id = entry[key];
378
+ if (typeof id !== "string" || id.length === 0) continue;
379
+ // `null` marks an ambiguous id: two sibling entries claim it, so neither
380
+ // can be attributed with confidence and both are ignored.
381
+ byId.set(id, byId.has(id) && byId.get(id) !== entry ? null : entry);
382
+ }
383
+ }
384
+ return byId.size > 0 ? byId : null;
385
+ }
386
+
387
+ function enrichAdmittedModel(item: ProviderModelsApiItem, siblings: SiblingIndex): ProviderModelsApiItem {
388
+ const extra = siblings.get(item.id);
389
+ if (!extra) return item;
390
+ let merged: Record<string, unknown> | null = null;
391
+ for (const key of SIBLING_ENRICHABLE_KEYS) {
392
+ if (!(key in extra) || key in item) continue;
393
+ merged ??= { ...(item as Record<string, unknown>) };
394
+ merged[key] = extra[key];
395
+ }
396
+ return (merged ?? item) as ProviderModelsApiItem;
397
+ }
398
+
399
+ function plainObject(value: unknown): Record<string, unknown> | null {
400
+ return typeof value === "object" && value !== null && !Array.isArray(value)
401
+ ? value as Record<string, unknown>
402
+ : null;
403
+ }
316
404
  export function extractProviderModelItems(
317
405
  value: unknown,
318
406
  discovery: ResolvedProviderModelDiscovery,
319
407
  ): ProviderModelItemsResult {
320
408
  const limit = positiveIntegerAtMost(discovery.maxModels, MODEL_DISCOVERY_MAX_MODELS);
321
409
  let data: unknown[];
410
+ let siblings: SiblingIndex | null = null;
322
411
  if (Array.isArray(value)) {
323
412
  // Together-style top-level /models arrays. Catalog discovery must not treat a stray
324
413
  // `models` key on openai-chat responses as valid — only `data` envelopes or top-level arrays.
@@ -328,6 +417,7 @@ export function extractProviderModelItems(
328
417
  const envelope = extractModelEnvelopeRows(value, discovery.maxModels, ["data"]);
329
418
  if (!envelope.ok) return envelope;
330
419
  data = envelope.rows;
420
+ siblings = buildSiblingIndex(value, limit);
331
421
  }
332
422
 
333
423
  const items: ProviderModelsApiItem[] = [];
@@ -337,20 +427,23 @@ export function extractProviderModelItems(
337
427
  return { ok: false, reason: "invalid_shape" };
338
428
  }
339
429
  const id = (raw as { id?: unknown }).id;
340
- if (typeof id !== "string") return { ok: false, reason: "invalid_shape" };
341
- const normalizedId = id.trim();
342
- if (
343
- !normalizedId
344
- || normalizedId !== id
345
- || normalizedId.length > MODEL_DISCOVERY_MAX_MODEL_ID_LENGTH
346
- || MODEL_DISCOVERY_MODEL_ID_CONTROL_CHARS.test(normalizedId)
347
- ) {
348
- return { ok: false, reason: "invalid_shape" };
430
+ if (!isValidModelDiscoveryModelId(id)) return { ok: false, reason: "invalid_shape" };
431
+ const prefix = discovery.spec?.stripIdPrefix;
432
+ let finalId = id;
433
+ if (prefix && finalId.startsWith(prefix)) {
434
+ finalId = finalId.slice(prefix.length);
435
+ if (!isValidModelDiscoveryModelId(finalId)) continue;
349
436
  }
350
- const item = raw as ProviderModelsApiItem;
351
- if (!providerModelMatchesDiscoveryFilter(item, discovery.spec?.filter) || seen.has(normalizedId)) continue;
352
- seen.add(normalizedId);
353
- items.push(item);
437
+ const item = finalId === id ? raw as ProviderModelsApiItem : { ...(raw as ProviderModelsApiItem), id: finalId };
438
+ // Admission is decided on the ORIGINAL `data[]` row, before any sibling
439
+ // enrichment. Merging first let a `models[]` entry supply the very field a
440
+ // provider filter requires — reproduced against the real Chutes policy,
441
+ // where a row lacking `supported_features: ["tools"]` was admitted once a
442
+ // same-id sibling provided it. Enrichment must never change WHICH models
443
+ // are published, only what is known about an already-admitted one.
444
+ if (!providerModelMatchesDiscoveryFilter(item, discovery.spec?.filter) || seen.has(finalId)) continue;
445
+ seen.add(finalId);
446
+ items.push(siblings ? enrichAdmittedModel(item, siblings) : item);
354
447
  }
355
448
  return { ok: true, items, rawCount: data.length };
356
449
  }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Shipped per-provider "latest/core" model presets (#2465).
3
+ *
4
+ * Adding a high-volume provider exposes its entire catalog to the Codex picker on day one:
5
+ * openrouter ships 400+ rows, an Anthropic provider ships every historical snapshot. The useful
6
+ * set is a handful of current flagships, so a newly added provider seeds from a curated preset
7
+ * and "everything" stays one click away.
8
+ *
9
+ * Rules are ID PATTERNS rather than literal id lists so a vendor snapshot suffix does not stale
10
+ * the preset between releases: `claude-opus-5-20260814` and `claude-opus-5` both match one rule.
11
+ *
12
+ * The preset is a SEED, not a lock. Materialization evaluates these rules against the provider's
13
+ * current catalog and stores CONCRETE ids in `selectedModels`, so the visibility hot path
14
+ * (`filterCatalogVisibleModels`) never learns about patterns and an older binary still sees a
15
+ * plain allowlist. Design: devlog/_plan/260824_model_ux_aliases_and_defaults/030_default_preset.md
16
+ */
17
+
18
+ import type { OcxProviderConfig } from "../types";
19
+
20
+ export interface ModelPresetRule {
21
+ readonly pattern: RegExp;
22
+ }
23
+
24
+ export interface ModelPreset {
25
+ /** Bumped whenever this provider's rules change; drives upgrade reconciliation. */
26
+ readonly version: number;
27
+ readonly rules: readonly ModelPresetRule[];
28
+ }
29
+
30
+ /**
31
+ * Curated on the same release train as the provider registry. A provider WITHOUT an entry has no
32
+ * preset and behaves exactly as today (mode "all").
33
+ *
34
+ * Deliberately limited to high-volume catalogs. A provider that already ships a short curated
35
+ * list gains nothing from a preset and would only add a marker to reconcile.
36
+ */
37
+ export const MODEL_PRESETS: Readonly<Record<string, ModelPreset>> = Object.freeze({
38
+ openrouter: {
39
+ version: 1,
40
+ rules: [
41
+ { pattern: /^anthropic\/claude-(opus|sonnet|haiku)-[45]/ },
42
+ { pattern: /^google\/gemini-3(\.\d+)?-(pro|flash)/ },
43
+ { pattern: /^openai\/gpt-5(\.\d+)?/ },
44
+ { pattern: /^deepseek\/deepseek-(v4|r2)/ },
45
+ { pattern: /^x-ai\/grok-4(\.\d+)?/ },
46
+ { pattern: /^moonshotai\/kimi-k[23]/ },
47
+ { pattern: /^z-ai\/glm-[45]/ },
48
+ ],
49
+ },
50
+ anthropic: {
51
+ version: 1,
52
+ rules: [
53
+ { pattern: /^claude-opus-[45]/ },
54
+ { pattern: /^claude-sonnet-[45]/ },
55
+ { pattern: /^claude-haiku-[45]/ },
56
+ { pattern: /^claude-fable-5/ },
57
+ ],
58
+ },
59
+ "anthropic-apikey": {
60
+ version: 1,
61
+ rules: [
62
+ { pattern: /^claude-opus-[45]/ },
63
+ { pattern: /^claude-sonnet-[45]/ },
64
+ { pattern: /^claude-haiku-[45]/ },
65
+ { pattern: /^claude-fable-5/ },
66
+ ],
67
+ },
68
+ });
69
+
70
+ /** The preset for a provider, or undefined when none is shipped. */
71
+ export function modelPresetFor(providerName: string): ModelPreset | undefined {
72
+ return MODEL_PRESETS[providerName];
73
+ }
74
+
75
+ /** True when a provider has a shipped preset at all. */
76
+ export function hasModelPreset(providerName: string): boolean {
77
+ return modelPresetFor(providerName) !== undefined;
78
+ }
79
+
80
+ /**
81
+ * Evaluate a provider's rules against concrete catalog ids.
82
+ *
83
+ * Input order is preserved so a caller can show the preset in the same order the picker does.
84
+ * Duplicates are collapsed; a model matching several rules is selected once.
85
+ */
86
+ export function materializeModelPreset(
87
+ providerName: string,
88
+ catalogModelIds: Iterable<string>,
89
+ ): string[] {
90
+ const preset = modelPresetFor(providerName);
91
+ if (!preset) return [];
92
+ const seen = new Set<string>();
93
+ const out: string[] = [];
94
+ for (const id of catalogModelIds) {
95
+ if (seen.has(id)) continue;
96
+ // `RegExp.test` on a shared literal is safe here because no rule uses the `g` flag; a
97
+ // sticky/global pattern would carry lastIndex between calls and skip rows.
98
+ if (preset.rules.some(rule => rule.pattern.test(id))) {
99
+ seen.add(id);
100
+ out.push(id);
101
+ }
102
+ }
103
+ return out;
104
+ }
105
+
106
+
107
+ /**
108
+ * Flip a provider out of preset mode when the user edits its selection (#2465).
109
+ *
110
+ * No-op unless the provider is currently in preset mode: "all" has no marker to keep, and
111
+ * "custom" is already terminal. The applied version is retained so the GUI can still offer
112
+ * "a newer preset is available" without losing what the user chose.
113
+ */
114
+ export function markModelPresetDiverged(provider: OcxProviderConfig): void {
115
+ const marker = provider.modelPreset;
116
+ if (marker?.mode !== "preset") return;
117
+ provider.modelPreset = { ...marker, mode: "custom" };
118
+ }
119
+