@bitkyc08/opencodex 2.81.0 → 2.82.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 (212) hide show
  1. package/bin/ocx.mjs +166 -73
  2. package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
  3. package/gui/dist/assets/{Tray-EwAOsP0S.js → Tray-BqHF5Trd.js} +1 -1
  4. package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
  5. package/gui/dist/assets/{index-RsoaAxXY.js → index-D3FBCNiP.js} +13 -13
  6. package/gui/dist/assets/{quota-summary-D2lN8tDm.js → quota-summary-DTBC8n7-.js} +1 -1
  7. package/gui/dist/index.html +2 -2
  8. package/package.json +1 -1
  9. package/src/adapters/anthropic.ts +1 -1
  10. package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
  11. package/src/adapters/openai-responses/passthrough.ts +9 -4
  12. package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
  13. package/src/claude/agents-inject.ts +14 -3
  14. package/src/claude/context-windows.ts +19 -17
  15. package/src/claude/desktop-3p.ts +88 -12
  16. package/src/claude/desktop-profile.ts +2 -1
  17. package/src/claude/gateway-cache.ts +18 -1
  18. package/src/claude/inbound.ts +77 -3
  19. package/src/claude/intercept/cli-catalog.ts +3 -0
  20. package/src/claude/intercept/picker-ca-persistence.ts +7 -6
  21. package/src/claude/intercept/picker-models.ts +14 -6
  22. package/src/claude/intercept/settings.ts +3 -0
  23. package/src/claude/long-context.ts +66 -0
  24. package/src/claude/model-info.ts +19 -16
  25. package/src/claude/outbound.ts +94 -9
  26. package/src/claude/subagent-model.ts +40 -11
  27. package/src/cli/agent.ts +9 -5
  28. package/src/cli/aside-profile-recovery.ts +33 -0
  29. package/src/cli/capabilities-base.ts +5 -5
  30. package/src/cli/capabilities-integrations.ts +2 -2
  31. package/src/cli/cli-path-diagnostics.ts +132 -0
  32. package/src/cli/desktop-runtime-guidance.ts +65 -0
  33. package/src/cli/dispatch.ts +5 -0
  34. package/src/cli/doctor.ts +16 -3
  35. package/src/cli/index.ts +14 -9
  36. package/src/cli/integration-aside-sync.ts +2 -1
  37. package/src/cli/integrations.ts +16 -3
  38. package/src/cli/resolve.ts +25 -2
  39. package/src/cli/root.ts +4 -2
  40. package/src/cli/status.ts +64 -12
  41. package/src/cli/update-restart-child.ts +4 -2
  42. package/src/cli/update-restart-home.ts +28 -10
  43. package/src/cli/update-restart-service-record.ts +116 -0
  44. package/src/cli/update-restart-supervision.ts +96 -0
  45. package/src/cli/update-restart.ts +59 -13
  46. package/src/cli/v2.ts +27 -20
  47. package/src/cli/version-skew-notice.ts +77 -0
  48. package/src/clients/lazycodex.ts +1 -1
  49. package/src/clients/omo-role-models.ts +32 -7
  50. package/src/codex/auth-api/account-selection.ts +107 -0
  51. package/src/codex/auth-api/routes.ts +10 -49
  52. package/src/codex/auth-context.ts +20 -1
  53. package/src/codex/autostart-health.ts +12 -3
  54. package/src/codex/catalog/build-entries.ts +18 -0
  55. package/src/codex/catalog/bundled.ts +155 -26
  56. package/src/codex/catalog/combo-member.ts +3 -2
  57. package/src/codex/catalog/effort.ts +26 -5
  58. package/src/codex/catalog/gather-capture.ts +5 -0
  59. package/src/codex/catalog/model-hints.ts +15 -8
  60. package/src/codex/catalog/model-visibility.ts +3 -1
  61. package/src/codex/catalog/operator-tiers.ts +38 -0
  62. package/src/codex/catalog/provider-models.ts +43 -35
  63. package/src/codex/catalog/retained-sync.ts +7 -5
  64. package/src/codex/catalog/routed-gather.ts +15 -1
  65. package/src/codex/catalog-auto-refresh-sources.ts +3 -4
  66. package/src/codex/catalog-auto-refresh.ts +19 -0
  67. package/src/codex/catalog.ts +1 -1
  68. package/src/codex/codex-home-owner.ts +3 -0
  69. package/src/codex/config-write-lock.ts +333 -0
  70. package/src/codex/convergence.ts +2 -1
  71. package/src/codex/features.ts +257 -200
  72. package/src/codex/inject/config-write-section.ts +34 -0
  73. package/src/codex/inject/multi-agent-v2.ts +14 -6
  74. package/src/codex/inject/remove.ts +36 -11
  75. package/src/codex/inject/restore.ts +85 -20
  76. package/src/codex/inject-coordination.ts +15 -6
  77. package/src/codex/inject.ts +62 -20
  78. package/src/codex/journal.ts +62 -17
  79. package/src/codex/main-account-cache.ts +43 -0
  80. package/src/codex/paths.ts +2 -0
  81. package/src/codex/prepared-home.ts +18 -0
  82. package/src/codex/prompt-journal.ts +25 -12
  83. package/src/codex/prompt-layers.ts +49 -26
  84. package/src/codex/prompt-lock-claim.ts +134 -0
  85. package/src/codex/prompt-lock-evidence.ts +26 -0
  86. package/src/codex/prompt-lock-io.ts +16 -0
  87. package/src/codex/prompt-lock-owner.ts +130 -0
  88. package/src/codex/prompt-lock.ts +84 -53
  89. package/src/codex/routing/failure-window.ts +146 -0
  90. package/src/codex/routing/selection.ts +4 -1
  91. package/src/codex/routing.ts +13 -17
  92. package/src/codex/runtime.ts +106 -18
  93. package/src/codex/shim.ts +45 -19
  94. package/src/combos/jev-service-exchange.ts +281 -0
  95. package/src/combos/jev.ts +34 -220
  96. package/src/config/atomic-write.ts +1 -1
  97. package/src/config/codex-ws-reuse-setting.ts +10 -0
  98. package/src/config/live-reconcile.ts +17 -0
  99. package/src/config/load-degrade.ts +8 -0
  100. package/src/config/rebase-provenance.ts +11 -0
  101. package/src/config/schema/config-schema.ts +4 -0
  102. package/src/generated/compatibility-version.json +303 -171
  103. package/src/generated/model-metadata.ts +2 -2
  104. package/src/grok/inject.ts +50 -4
  105. package/src/grok/sync.ts +2 -1
  106. package/src/images/loop.ts +29 -11
  107. package/src/integrations/aside-profiles.ts +10 -3
  108. package/src/integrations/catalog-refresh.ts +18 -2
  109. package/src/integrations/writer.ts +9 -3
  110. package/src/lib/bun-path-runtime.d.mts +32 -0
  111. package/src/lib/bun-path-runtime.mjs +95 -0
  112. package/src/lib/bun-runtime-preflight.ts +140 -0
  113. package/src/lib/desktop-cli-handoff.d.mts +20 -0
  114. package/src/lib/desktop-cli-handoff.mjs +92 -0
  115. package/src/lib/desktop-cli-record.d.mts +29 -0
  116. package/src/lib/desktop-cli-record.mjs +102 -0
  117. package/src/lib/request-execution-budget.ts +8 -0
  118. package/src/lib/synced-state-location.ts +46 -6
  119. package/src/lib/test-home-guard.ts +87 -1
  120. package/src/lib/translator-budget.ts +17 -4
  121. package/src/lib/windows-atomic-replace.ts +38 -16
  122. package/src/lib/windows-elevation.ts +6 -0
  123. package/src/lib/windows-secret-acl.ts +92 -25
  124. package/src/lib/winsw.ts +2 -3
  125. package/src/oauth/anthropic-account-refusal.ts +39 -1
  126. package/src/oauth/anthropic-routing.ts +1 -1
  127. package/src/oauth/anthropic-send-ownership.ts +3 -3
  128. package/src/oauth/chatgpt.ts +113 -41
  129. package/src/oauth/index.ts +6 -2
  130. package/src/oauth/store.ts +1 -1
  131. package/src/providers/azure-model-metadata.ts +115 -0
  132. package/src/providers/derive.ts +21 -0
  133. package/src/providers/quota/vendor-probes-key.ts +127 -17
  134. package/src/providers/quota.ts +1 -1
  135. package/src/responses/reasoning-envelope.ts +29 -1
  136. package/src/responses/reasoning-replay-cache.ts +17 -1
  137. package/src/responses/spill-store.ts +15 -2
  138. package/src/responses/state/metrics.ts +8 -0
  139. package/src/responses/state/spill-failure.ts +12 -0
  140. package/src/responses/state/spill-queue.ts +12 -5
  141. package/src/responses/state.ts +18 -10
  142. package/src/responses/task-input.ts +17 -0
  143. package/src/server/background-lifecycle.ts +27 -0
  144. package/src/server/chat-completions.ts +1 -0
  145. package/src/server/chat-native.ts +28 -12
  146. package/src/server/claude-messages.ts +43 -6
  147. package/src/server/inbound-body-admission.ts +1 -0
  148. package/src/server/index/claude-intercept-lifecycle.ts +3 -1
  149. package/src/server/index/serve-options.ts +10 -2
  150. package/src/server/index/spend-ledger-lifecycle.ts +2 -1
  151. package/src/server/index/startup-warnings.ts +19 -0
  152. package/src/server/index.ts +1 -0
  153. package/src/server/management/agent-settings-routes.ts +93 -32
  154. package/src/server/management/codex-agent-role-routes.ts +4 -2
  155. package/src/server/management/codex-prompt-routes.ts +1 -0
  156. package/src/server/management/codex-role-auto-assign.ts +13 -2
  157. package/src/server/management/config-routes.ts +59 -8
  158. package/src/server/management/context.ts +2 -2
  159. package/src/server/management/shared.ts +3 -3
  160. package/src/server/messages-native-oauth.ts +9 -8
  161. package/src/server/messages-native.ts +49 -13
  162. package/src/server/messages-response-headers.ts +14 -0
  163. package/src/server/request-log-conversation.ts +48 -5
  164. package/src/server/request-log.ts +31 -2
  165. package/src/server/responses/adapter-continuation.ts +2 -2
  166. package/src/server/responses/adapter-dispatch.ts +34 -13
  167. package/src/server/responses/codex-ws-exchange.ts +17 -2
  168. package/src/server/responses/codex-ws-pool.ts +100 -13
  169. package/src/server/responses/codex-ws-wire.ts +9 -0
  170. package/src/server/responses/combo-requested-effort.ts +3 -1
  171. package/src/server/responses/core-codex-account.ts +22 -1
  172. package/src/server/responses/core-combo-native.ts +20 -3
  173. package/src/server/responses/core-combo.ts +22 -14
  174. package/src/server/responses/core-lifetime.ts +3 -36
  175. package/src/server/responses/core-options.ts +5 -0
  176. package/src/server/responses/core-replay.ts +73 -0
  177. package/src/server/responses/core.ts +3 -3
  178. package/src/server/responses/fetch-helpers.ts +26 -3
  179. package/src/server/responses/passthrough-delivery.ts +24 -2
  180. package/src/server/responses/passthrough-dispatch.ts +19 -2
  181. package/src/server/responses/request-prepare.ts +4 -0
  182. package/src/server/responses/request-send-budget.ts +112 -49
  183. package/src/server/responses/response-effects.ts +1 -0
  184. package/src/server/responses/run-turn-execution.ts +2 -0
  185. package/src/server/responses/sidecar-execution.ts +25 -16
  186. package/src/server/responses/sidecar-send-budget.ts +58 -0
  187. package/src/server/responses/ws-upstream.ts +19 -6
  188. package/src/server/startup-health-cache.ts +2 -1
  189. package/src/server/workflow-refusal.ts +3 -0
  190. package/src/service/cli.ts +20 -4
  191. package/src/service/desktop-command-guard.ts +32 -0
  192. package/src/service/desktop-startup.ts +66 -40
  193. package/src/service/desktop-supervision.d.mts +26 -0
  194. package/src/service/desktop-supervision.mjs +140 -0
  195. package/src/service/managing-cli.ts +1 -0
  196. package/src/service/orchestration.ts +46 -20
  197. package/src/service/repair.ts +25 -9
  198. package/src/service/state.ts +4 -3
  199. package/src/service/systemd.ts +17 -8
  200. package/src/service/windows-ops.ts +61 -22
  201. package/src/storage/policy-job.ts +5 -1
  202. package/src/storage/policy-worker.ts +3 -1
  203. package/src/storage/policy.ts +9 -0
  204. package/src/types/config.ts +21 -0
  205. package/src/types/request.ts +5 -0
  206. package/src/types/wire.ts +1 -0
  207. package/src/update/index.ts +57 -9
  208. package/src/update/restart-ownership.ts +10 -3
  209. package/src/update/runtime-ownership.d.mts +6 -0
  210. package/src/update/runtime-ownership.mjs +23 -7
  211. package/src/web-search/loop.ts +5 -2
  212. package/gui/dist/assets/App-7yhoys8a.js +0 -54
@@ -51,7 +51,7 @@ const DATA: Record<string, readonly Row[]> = {
51
51
  "minimax": [["MiniMax-M2",196608,128000,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.1",204800,131072,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.5",204800,131072,"text",1,null,0.3,1.2,0.03,0.375],["MiniMax-M2.5-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["MiniMax-M2.5-lightning",204800,32000,"text",1,null,0.3,2.4,0,0],["MiniMax-M2.7",204800,131072,"text",1,null,0.3,1.2,0.06,0.375],["MiniMax-M2.7-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["minimax-m3",512000,128000,"text,image",1,null,0.6,2.4,0.12,0],["MiniMax-M3",1000000,128000,"text,image,video",1,null,0.3,1.2,0.06,0],["MiniMax-M3.1-Flash-Preview",1000000,null,"text,image,video",1]],
52
52
  "mistral": [["codestral-latest",256000,4096,"text",0,null,0.3,0.9,0,0],["devstral-2512",262144,262144,"text",0,null,0.4,2,0,0],["devstral-latest",262144,262144,"text",0,null,0.4,2,0,0],["devstral-medium-2507",128000,128000,"text",0,null,0.4,2,0,0],["devstral-medium-latest",262144,262144,"text",0,null,0.4,2,0,0],["devstral-small-2505",128000,128000,"text",0,null,0.1,0.3,0,0],["devstral-small-2507",128000,128000,"text",0,null,0.1,0.3,0,0],["labs-devstral-small-2512",256000,256000,"text,image",0,null,0,0,0,0],["magistral-medium-latest",128000,16384,"text",1,null,2,5,0,0],["magistral-small",128000,128000,"text",1,null,0.5,1.5,0,0],["ministral-3b-latest",128000,128000,"text",0,null,0.04,0.04,0,0],["ministral-8b-latest",128000,128000,"text",0,null,0.1,0.1,0,0],["mistral-large-2411",131072,16384,"text",0,null,2,6,0,0],["mistral-large-2512",262144,262144,"text,image",0,null,0.5,1.5,0,0],["mistral-large-latest",262144,262144,"text,image",0,null,0.5,1.5,0,0],["mistral-medium-2505",131072,131072,"text,image",0,null,0.4,2,0,0],["mistral-medium-2508",262144,262144,"text,image",0,null,0.4,2,0,0],["mistral-medium-2604",262144,262144,"text,image",1,null,1.5,7.5,0,0],["mistral-medium-latest",262144,262144,"text,image",1,null,1.5,7.5,0,0],["mistral-nemo",128000,128000,"text",0,null,0.15,0.15,0,0],["mistral-small-2506",128000,16384,"text,image",0,null,0.1,0.3,0,0],["mistral-small-2603",256000,256000,"text,image",1,null,0.15,0.6,0,0],["mistral-small-latest",256000,256000,"text,image",1,null,0.15,0.6,0,0],["open-mistral-7b",8000,8000,"text",0,null,0.25,0.25,0,0],["open-mistral-nemo",128000,128000,"text",0,null,0.15,0.15,0,0],["open-mixtral-8x22b",64000,64000,"text",0,null,2,6,0,0],["open-mixtral-8x7b",32000,32000,"text",0,null,0.7,0.7,0,0],["pixtral-12b",128000,128000,"text,image",0,null,0.15,0.15,0,0],["pixtral-large-latest",128000,128000,"text,image",0,null,2,6,0,0]],
53
53
  "moonshot": [["kimi-k2.5",262144,65536,"text,image",1,null,0,0,0,0]],
54
- "openai": [["codex-mini-latest",200000,100000,"text",1,null,1.5,6,0.375,0],["gpt-4",8192,8192,"text",0,null,30,60,0,0],["gpt-4-turbo",128000,4096,"text,image",0,null,10,30,0,0],["gpt-4.1",1047576,32768,"text,image",0,null,2,8,0.5,0],["gpt-4.1-mini",1047576,32768,"text,image",0,null,0.4,1.6,0.1,0],["gpt-4.1-nano",1047576,32768,"text,image",0,null,0.1,0.4,0.025,0],["gpt-4o",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-2024-05-13",128000,4096,"text,image",0,null,5,15,0,0],["gpt-4o-2024-08-06",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-2024-11-20",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-mini",128000,16384,"text,image",0,null,0.15,0.6,0.075,0],["gpt-5",400000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-chat-latest",128000,16384,"text,image",0,null,1.25,10,0.125,0],["gpt-5-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-mini",400000,128000,"text,image",1,null,0.25,2,0.025,0],["gpt-5-nano",400000,128000,"text,image",1,null,0.05,0.4,0.005,0],["gpt-5-pro",400000,272000,"text,image",1,null,15,120,0,0],["gpt-5.1",400000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-chat-latest",128000,16384,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-max",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-mini",272000,128000,"text,image",1,null,0.25,2,0.025,0],["gpt-5.2",400000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-chat-latest",128000,16384,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-pro",400000,128000,"text,image",1,null,21,168,0,0],["gpt-5.3-chat-latest",128000,16384,"text,image",0,null,1.75,14,0.175,0],["gpt-5.3-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.3-codex-spark",128000,32000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.4",1050000,128000,"text,image",1,null,2.5,15,0.25,0],["gpt-5.4-mini",400000,128000,"text,image",1,null,0.75,4.5,0.075,0],["gpt-5.4-nano",400000,128000,"text,image",1,null,0.2,1.25,0.02,0],["gpt-5.4-pro",1050000,128000,"text,image",1,null,30,180,0,0],["gpt-5.5",1050000,128000,"text,image",1,null,5,30,0.5,0],["gpt-5.5-pro",1050000,128000,"text,image",1,null,30,180,0,0],["gpt-5.6",373000,128000,"text,image",1,null,5,30,0.5,6.25],["gpt-5.6-luna",373000,128000,"text,image",1,null,0.2,1.2,0.02,0.25],["gpt-5.6-sol",373000,128000,"text,image",1,null,5,30,0.5,6.25],["gpt-5.6-terra",373000,128000,"text,image",1,null,2,12,0.2,2.5],["gpt-6-luna",373000,128000,"text,image",1,null,0.1,0.5,0.01,0.125],["gpt-6-sol",373000,128000,"text,image",1,null,2,10,0.2,2.5],["gpt-6.1-sol",373000,128000,"text,image",1,null,2,10,0.1,2.5],["gpt-realtime-2.1",128000,32000,"text,image",1,null,4,24,0.4,0],["o1",200000,100000,"text,image",1,null,15,60,7.5,0],["o1-pro",200000,100000,"text,image",1,null,150,600,0,0],["o3",200000,100000,"text,image",1,null,2,8,0.5,0],["o3-deep-research",200000,100000,"text,image",1,null,10,40,2.5,0],["o3-mini",200000,100000,"text",1,null,1.1,4.4,0.55,0],["o3-pro",200000,100000,"text,image",1,null,20,80,0,0],["o4-mini",200000,100000,"text,image",1,null,1.1,4.4,0.275,0],["o4-mini-deep-research",200000,100000,"text,image",1,null,2,8,0.5,0]],
54
+ "openai": [["codex-mini-latest",200000,100000,"text",1,null,1.5,6,0.375,0],["gpt-4",8192,8192,"text",0,null,30,60,0,0],["gpt-4-turbo",128000,4096,"text,image",0,null,10,30,0,0],["gpt-4.1",1047576,32768,"text,image",0,null,2,8,0.5,0],["gpt-4.1-mini",1047576,32768,"text,image",0,null,0.4,1.6,0.1,0],["gpt-4.1-nano",1047576,32768,"text,image",0,null,0.1,0.4,0.025,0],["gpt-4o",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-2024-05-13",128000,4096,"text,image",0,null,5,15,0,0],["gpt-4o-2024-08-06",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-2024-11-20",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-mini",128000,16384,"text,image",0,null,0.15,0.6,0.075,0],["gpt-5",400000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-chat-latest",128000,16384,"text,image",0,null,1.25,10,0.125,0],["gpt-5-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-mini",400000,128000,"text,image",1,null,0.25,2,0.025,0],["gpt-5-nano",400000,128000,"text,image",1,null,0.05,0.4,0.005,0],["gpt-5-pro",400000,272000,"text,image",1,null,15,120,0,0],["gpt-5.1",400000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-chat-latest",128000,16384,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-max",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-mini",272000,128000,"text,image",1,null,0.25,2,0.025,0],["gpt-5.2",400000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-chat-latest",128000,16384,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-pro",400000,128000,"text,image",1,null,21,168,0,0],["gpt-5.3-chat-latest",128000,16384,"text,image",0,null,1.75,14,0.175,0],["gpt-5.3-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.3-codex-spark",128000,32000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.4",1050000,128000,"text,image",1,null,2.5,15,0.25,0],["gpt-5.4-mini",400000,128000,"text,image",1,null,0.75,4.5,0.075,0],["gpt-5.4-nano",400000,128000,"text,image",1,null,0.2,1.25,0.02,0],["gpt-5.4-pro",1050000,128000,"text,image",1,null,30,180,0,0],["gpt-5.5",1050000,128000,"text,image",1,null,5,30,0.5,0],["gpt-5.5-pro",1050000,128000,"text,image",1,null,30,180,0,0],["gpt-5.6",1050000,128000,"text,image",1,null,5,30,0.5,6.25],["gpt-5.6-luna",1050000,128000,"text,image",1,null,0.2,1.2,0.02,0.25],["gpt-5.6-sol",1050000,128000,"text,image",1,null,5,30,0.5,6.25],["gpt-5.6-terra",1050000,128000,"text,image",1,null,2,12,0.2,2.5],["gpt-6-astra",1050000,128000,"text,image",1,null,10,50,1,12.5],["gpt-6-luna",1050000,128000,"text,image",1,null,0.1,0.5,0.01,0.125],["gpt-6-sol",1050000,128000,"text,image",1,null,2,10,0.2,2.5],["gpt-6.1-sol",1050000,128000,"text,image",1,null,2,10,0.1,2.5],["gpt-realtime-2.1",128000,32000,"text,image",1,null,4,24,0.4,0],["o1",200000,100000,"text,image",1,null,15,60,7.5,0],["o1-pro",200000,100000,"text,image",1,null,150,600,0,0],["o3",200000,100000,"text,image",1,null,2,8,0.5,0],["o3-deep-research",200000,100000,"text,image",1,null,10,40,2.5,0],["o3-mini",200000,100000,"text",1,null,1.1,4.4,0.55,0],["o3-pro",200000,100000,"text,image",1,null,20,80,0,0],["o4-mini",200000,100000,"text,image",1,null,1.1,4.4,0.275,0],["o4-mini-deep-research",200000,100000,"text,image",1,null,2,8,0.5,0]],
55
55
  "openai-codex": [["codex-auto-review",1000000,128000,"text,image",1,null,0,0,0,0],["gpt-5",400000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5-codex-mini",272000,128000,"text,image",1,null,0,0,0,0],["gpt-5.1",400000,128000,"text,image",1,null,1.25,10,0.13,0],["gpt-5.1-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-max",272000,128000,"text,image",1,null,1.25,10,0.125,0],["gpt-5.1-codex-mini",272000,128000,"text,image",1,null,0.25,2,0.025,0],["gpt-5.2",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.2-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.3-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["gpt-5.3-codex-spark",128000,128000,"text",1,null,1.75,14,0.175,0],["gpt-5.4",1000000,128000,"text,image",1,null,2.5,15,0.25,0],["gpt-5.4-mini",272000,128000,"text,image",1,null,0.75,4.5,0.075,0],["gpt-5.4-nano",272000,128000,"text,image",1,null,0.2,1.25,0.02,0],["gpt-5.5",272000,128000,"text,image",1,null,5,30,0.5,0],["gpt-5.6-luna",373000,128000,"text,image",1,null,0.2,1.2,0.02,0.25],["gpt-5.6-sol",373000,128000,"text,image",1,null,5,30,0.5,6.25],["gpt-5.6-terra",373000,128000,"text,image",1,null,2,12,0.2,2.5],["gpt-6-luna",373000,128000,"text,image",1,null,0.1,0.5,0.01,0.125],["gpt-6-sol",373000,128000,"text,image",1,null,2,10,0.2,2.5],["gpt-6.1-sol",373000,128000,"text,image",1,null,2,10,0.1,2.5]],
56
56
  "opencode-go": [["claude-haiku-5-5",1000000,128000,"text,image",1,null,0.1,0.5,0.01,0.125],["deepseek-v4-flash",1000000,384000,"text",1,null,0.14,0.28,0.0028,0],["deepseek-v4-pro",1000000,384000,"text",1,null,1.74,3.48,0.0145,0],["glm-5",204800,131072,"text",1,null,1,3.2,0.2,0],["glm-5.1",200000,131072,"text",1,null,1.4,4.4,0.26,0],["glm-5.2",1000000,131072,"text",1,null,1.4,4.4,0.26,0],["glm-5.3",1000000,131072,"text",1,null,1.4,4.4,0.26,0],["glm-5.3-flash",1000000,131072,"text,image",1],["gpt-5.6-luna",1050000,128000,"text,image",1],["grok-4.5",500000,500000,"text,image",1,null,2,6,0.5,0],["grok-4.6",500000,500000,"text,image",1,null,2,6,0.5,0],["grok-4.7",500000,500000,"text,image",1,null,2,6,0.5,0],["hy3",256000,64000,"text",1,null,0.14,0.58,0.035,0],["hy4-preview",1024000,64000,"text",1],["kimi-k2.5",262144,262144,"text,image",1,null,0.3,1.9,0,0],["kimi-k2.6",262144,262144,"text,image",1,null,0.95,4,0.2,0],["kimi-k2.7-code",262144,262144,"text,image",1,null,0.95,4,0.19,0],["kimi-k3",1048576,131072,"text,image",1,null,3,15,0.3,0],["longcat-2.0",1000000,131072,"text",1],["mimo-v2-omni",262144,131072,"text,image",1,null,0.4,2,0.08,0],["mimo-v2-pro",1048576,131072,"text",1,null,1,3,0.2,0],["mimo-v2.5",1048576,131072,"text,image",1,null,0.14,0.28,0.0028,0],["mimo-v2.5-pro",1048576,131072,"text",1,null,1.74,3.48,0.0145,0],["mimo-v2.6-flash",1048576,131072,"text",1,null,0.14,0.28,0.0028,0],["mimo-v2.6-pro",1048576,131072,"text",1,null,0.435,0.87,0.003625,0],["minimax-m2.5",204800,131072,"text",1,null,0.3,1.2,0.06,0.375],["minimax-m2.7",204800,131072,"text",1,null,0.3,1.2,0.06,0.375],["minimax-m3",512000,128000,"text,image",1,null,0.3,1.2,0.06,0],["muse-spark-1.2-contributor",1048576,131072,"text,image",1],["muse-spark-1.3-contributor",1048576,131072,"text,image",1],["omen-alpha",500000,128000,"text,image",1],["ox-alpha-free",1000000,131072,"text,image",1],["qwen3.5-plus",1000000,65536,"text,image",1,null,0.4,2.4,0,0],["qwen3.6-plus",1000000,65536,"text,image",1,null,2,6,0.2,2.5],["qwen3.7-max",1000000,65536,"text",1,null,2.5,7.5,0.5,3.125],["qwen3.7-plus",1000000,64000,"text,image",1,null,1.2,4.8,0.12,1.5],["qwen3.8-flash",1000000,131072,"text,image",1],["qwen3.8-max",1000000,131072,"text,image",1],["union-alpha",262144,131072,"text,image",1]],
57
57
  "openrouter": [["~anthropic/claude-fable-latest",1000000,128000,"text,image",1,null,10,50,1,12.5],["~anthropic/claude-haiku-latest",200000,64000,"text,image",1,null,1,5,0.09999999999999999,1.25],["~anthropic/claude-opus-latest",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["~anthropic/claude-sonnet-latest",1000000,128000,"text,image",1,null,2,10,0.19999999999999998,2.5],["~google/gemini-flash-latest",1048576,65536,"text,image",1,null,1.5,7.5,0.15,0.08333333333333334],["~google/gemini-pro-latest",1048576,65536,"text,image",1,null,2,12,0.19999999999999998,0.375],["~moonshotai/kimi-latest",1048576,8888,"text,image",1,null,3,15,0.3,0],["~openai/gpt-latest",1050000,128000,"text,image",1,null,5,30,0.5,6.25],["~openai/gpt-mini-latest",400000,128000,"text,image",1,null,0.75,4.5,0.075,0],["~x-ai/grok-latest",500000,8888,"text,image",1,null,2,6,0.3,0],["ai21/jamba-large-1.7",256000,4096,"text",0,null,2,8,0,0],["aion-labs/aion-2.0",131072,32768,"text",1,null,0.7999999999999999,1.5999999999999999,0.19999999999999998,0],["aion-labs/aion-3.0",131072,32768,"text",1,null,3,6,0.75,0],["aion-labs/aion-3.0-mini",131072,32768,"text",1,null,0.7,1.4,0.18,0],["alibaba/tongyi-deepresearch-30b-a3b",131072,131072,"text",1,null,0.09,0.44999999999999996,0.09,0],["allenai/olmo-3.1-32b-instruct",65536,16384,"text",0,null,0.19999999999999998,0.6,0,0],["amazon/nova-2-lite-v1",1000000,65535,"text,image",1,null,0.3,2.5,0,0],["amazon/nova-lite-v1",300000,5120,"text,image",0,null,0.06,0.24,0,0],["amazon/nova-micro-v1",128000,5120,"text",0,null,0.035,0.14,0,0],["amazon/nova-premier-v1",1000000,32000,"text,image",0,null,2.5,12.5,0.625,0],["amazon/nova-pro-v1",300000,5120,"text,image",0,null,0.7999999999999999,3.1999999999999997,0,0],["anthropic/claude-3-haiku",200000,4096,"text,image",0,null,0.25,1.25,0.03,0.3],["anthropic/claude-3.5-haiku",200000,8192,"text,image",0,null,0.7999999999999999,4,0.08,1],["anthropic/claude-3.5-sonnet",200000,8192,"text,image",0,null,6,30,0.6,7.5],["anthropic/claude-3.7-sonnet",200000,128000,"text,image",1,null,3,15,0.3,3.75],["anthropic/claude-3.7-sonnet:thinking",200000,64000,"text,image",1,null,3,15,0.3,3.75],["anthropic/claude-fable-5",1000000,128000,"text,image",1,null,10,50,1,12.5],["anthropic/claude-haiku-4.5",200000,64000,"text,image",0,null,1,5,0.09999999999999999,1.25],["anthropic/claude-haiku-5.5",1000000,128000,"text,image",1,null,0.1,0.5,0.01,0.125],["anthropic/claude-opus-4",200000,32000,"text,image",1,null,15,75,1.5,18.75],["anthropic/claude-opus-4.1",200000,32000,"text,image",1,null,15,75,1.5,18.75],["anthropic/claude-opus-4.5",200000,64000,"text,image",1,null,5,25,0.5,6.25],["anthropic/claude-opus-4.6",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic/claude-opus-4.6-fast",1000000,128000,"text,image",1,null,30,150,3,37.5],["anthropic/claude-opus-4.7",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic/claude-opus-4.7-fast",1000000,128000,"text,image",1,null,30,150,3,37.5],["anthropic/claude-opus-4.8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic/claude-opus-4.8-fast",1000000,128000,"text,image",1,null,10,50,1,12.5],["anthropic/claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic/claude-opus-5-fast",1000000,128000,"text,image",1,null,10,50,1,12.5],["anthropic/claude-opus-5.5",1000000,128000,"text,image",1,null,4,20,0.2,5],["anthropic/claude-opus-5.5-fast",1000000,128000,"text,image",1,null,8,40,0.4,10],["anthropic/claude-sonnet-4",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["anthropic/claude-sonnet-4.5",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["anthropic/claude-sonnet-4.6",1000000,128000,"text,image",1,null,3,15,0.3,3.75],["anthropic/claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.19999999999999998,2.5],["anthropic/claude-sonnet-5.5",1000000,128000,"text,image",1,null,2,10,0.1,2.5],["arcee-ai/trinity-large-preview",131000,8888,"text",0,null,0.15,0.44999999999999996,0,0],["arcee-ai/trinity-large-preview:free",131000,8888,"text",0,null,0,0,0,0],["arcee-ai/trinity-large-thinking",262144,262144,"text",1,null,0.22,0.85,0.06,0],["arcee-ai/trinity-large-thinking:free",262144,80000,"text",1,null,0,0,0,0],["arcee-ai/trinity-mini",131072,131072,"text",1,null,0.045,0.15,0,0],["arcee-ai/trinity-mini:free",131072,8888,"text",1,null,0,0,0,0],["arcee-ai/virtuoso-large",131072,64000,"text",0,null,0.75,1.2,0,0],["auto",2000000,30000,"text,image",1,null,0,0,0,0],["baidu/cobuddy:free",131072,65536,"text",1,null,0,0,0,0],["baidu/ernie-4.5-21b-a3b",131072,8000,"text",0,null,0.07,0.28,0,0],["baidu/ernie-4.5-vl-28b-a3b",131072,8000,"text,image",1,null,0.14,0.56,0,0],["bytedance-seed/seed-1.6",262144,32768,"text,image",1,null,0.25,2,0,0],["bytedance-seed/seed-1.6-flash",262144,32768,"text,image",1,null,0.075,0.3,0,0],["bytedance-seed/seed-2.0-lite",262144,131072,"text,image",1,null,0.25,2,0,0],["bytedance-seed/seed-2.0-mini",262144,131072,"text,image",1,null,0.09999999999999999,0.39999999999999997,0,0],["cohere/command-r-08-2024",128000,4000,"text",0,null,0.15,0.6,0,0],["cohere/command-r-plus-08-2024",128000,4000,"text",0,null,2.5,10,0,0],["cohere/north-mini-code:free",256000,64000,"text",1,null,0,0,0,0],["deepseek/deepseek-chat",163840,16000,"text",0,null,0.20020000000000002,0.8000999999999999,0.15,0],["deepseek/deepseek-chat-v3-0324",163840,65536,"text",1,null,0.27,1.12,0.135,0],["deepseek/deepseek-chat-v3.1",163840,32768,"text",1,null,0.25,0.95,0.13,0],["deepseek/deepseek-r1",163840,16000,"text",1,null,0.7,2.5,0,0],["deepseek/deepseek-r1-0528",163840,32768,"text",1,null,0.5,2.1500000000000004,0.35,0],["deepseek/deepseek-v3.1-terminus",163840,32768,"text",1,null,0.27,1,0.135,0],["deepseek/deepseek-v3.1-terminus:exacto",163840,8888,"text",1,null,0.21,0.7899999999999999,0.16799999999999998,0],["deepseek/deepseek-v3.2",163840,65536,"text",1,null,0.26899999999999996,0.39999999999999997,0.13449999999999998,0],["deepseek/deepseek-v3.2-exp",163840,65536,"text",1,null,0.27,0.41,0,0],["deepseek/deepseek-v4-flash",1048576,384000,"text",1,null,0.09380000000000001,0.18760000000000002,0.01876,0],["deepseek/deepseek-v4-flash:free",1048576,384000,"text",1,null,0,0,0,0],["deepseek/deepseek-v4-pro",1048576,384000,"text",1,null,0.435,0.87,0.003625,0],["essentialai/rnj-1-instruct",32768,8888,"text",0,null,0.15,0.15,0,0],["google/gemini-2.0-flash-001",1048576,8192,"text,image",0,null,0.09999999999999999,0.39999999999999997,0.024999999999999998,0.08333333333333334],["google/gemini-2.0-flash-lite-001",1048576,8192,"text,image",0,null,0.075,0.3,0,0],["google/gemini-2.5-flash",1048576,65535,"text,image",1,null,0.3,2.5,0.03,0.08333333333333334],["google/gemini-2.5-flash-lite",1048576,65535,"text,image",0,null,0.09999999999999999,0.39999999999999997,0.01,0.08333333333333334],["google/gemini-2.5-flash-lite-preview-09-2025",1048576,65535,"text,image",1,null,0.09999999999999999,0.39999999999999997,0.01,0.08333333333333334],["google/gemini-2.5-flash-preview-09-2025",1048576,65536,"text,image",1,null,0.3,2.5,0.03,0.08333333333333334],["google/gemini-2.5-pro",1048576,65536,"text,image",1,null,1.25,10,0.125,0.375],["google/gemini-2.5-pro-preview",1048576,65536,"text,image",1,null,1.25,10,0.125,0.375],["google/gemini-2.5-pro-preview-05-06",1048576,65535,"text,image",1,null,1.25,10,0.125,0.375],["google/gemini-3-flash-preview",1048576,65535,"text,image",1,null,0.5,3,0.049999999999999996,0.08333333333333334],["google/gemini-3-pro-image",131072,32768,"text,image",1,null,2,12,0.19999999999999998,0.375],["google/gemini-3-pro-preview",1048000,64000,"text,image",1,null,2,12,0.19999999999999998,0.375],["google/gemini-3.1-flash-lite",1048576,65536,"text,image",1,null,0.25,1.5,0.024999999999999998,0.08333333333333334],["google/gemini-3.1-flash-lite-preview",1048576,65536,"text,image",0,null,0.25,1.5,0.024999999999999998,0.08333333333333334],["google/gemini-3.1-pro-preview",1048576,65536,"text,image",1,null,2,12,0.19999999999999998,0.375],["google/gemini-3.1-pro-preview-customtools",1048576,65536,"text,image",1,null,2,12,0.19999999999999998,0.375],["google/gemini-3.5-flash",1048576,65536,"text,image",1,null,1.5,9,0.15,0.08333333333333334],["google/gemini-3.5-flash-lite",1048576,65536,"text,image",1,null,0.3,2.5,0.03,0.08333333333333334],["google/gemini-3.6-flash",1048576,65536,"text,image",1,null,1.5,7.5,0.15,0.08333333333333334],["google/gemma-3-12b-it",131072,16384,"text,image",0,null,0.049999999999999996,0.15,0,0],["google/gemma-3-27b-it",262144,131072,"text,image",1,null,0.08,0.44999999999999996,0.04,0],["google/gemma-3-27b-it:free",131072,8192,"text,image",0,null,0,0,0,0],["google/gemma-4-26b-a4b-it",262144,262144,"text,image",1,null,0.12,0.35,0.049999999999999996,0],["google/gemma-4-26b-a4b-it:free",262144,32768,"text,image",1,null,0,0,0,0],["google/gemma-4-31b-it",262144,262144,"text,image",1,null,0.14,0.39999999999999997,0.09,0],["google/gemma-4-31b-it:free",262144,32768,"text,image",1,null,0,0,0,0],["ibm-granite/granite-4.1-8b",131072,131072,"text",0,null,0.049999999999999996,0.09999999999999999,0.049999999999999996,0],["inception/mercury",128000,32000,"text",0,null,0.25,0.75,0.024999999999999998,0],["inception/mercury-2",128000,50000,"text",1,null,0.25,0.75,0.024999999999999998,0],["inception/mercury-coder",128000,32000,"text",0,null,0.25,0.75,0.024999999999999998,0],["inclusionai/ling-2.6-1t",262144,32768,"text",0,null,0.075,0.625,0.015,0],["inclusionai/ling-2.6-1t:free",262144,32768,"text",0,null,0,0,0,0],["inclusionai/ling-2.6-flash",262144,32768,"text",0,null,0.01,0.03,0.002,0],["inclusionai/ling-2.6-flash:free",262144,32768,"text",0,null,0,0,0,0],["inclusionai/ling-3.0-flash:free",262144,32768,"text",1,null,0,0,0,0],["inclusionai/ring-2.6-1t",262144,65536,"text",1,null,0.075,0.625,0.015,0],["inclusionai/ring-2.6-1t:free",262144,65536,"text",1,null,0,0,0,0],["kwaipilot/kat-coder-air-v2.5",256000,80000,"text",0,null,0.15,0.6,0.03,0],["kwaipilot/kat-coder-pro",256000,128000,"text",0,null,0.207,0.828,0.0414,0],["kwaipilot/kat-coder-pro-v2",262144,80000,"text",0,null,0.3,1.2,0.06,0],["kwaipilot/kat-coder-pro-v2.5",256000,80000,"text",0,null,0.74,2.96,0.15,0],["liquid/lfm-2.5-1.2b-thinking:free",32768,8888,"text",1,null,0,0,0,0],["meituan/longcat-2.0",1048756,262144,"text",1,null,0.3,1.2,0.006,0],["meituan/longcat-flash-chat",131072,131072,"text",0,null,0.19999999999999998,0.7999999999999999,0.19999999999999998,0],["meta-llama/llama-3-8b-instruct",8192,16384,"text",0,null,0.03,0.04,0,0],["meta-llama/llama-3.1-405b-instruct",131000,8888,"text",0,null,4,4,0,0],["meta-llama/llama-3.1-70b-instruct",131072,16384,"text",0,null,0.39999999999999997,0.39999999999999997,0,0],["meta-llama/llama-3.1-8b-instruct",131072,131072,"text",0,null,0.049999999999999996,0.08,0.024999999999999998,0],["meta-llama/llama-3.3-70b-instruct",131072,128000,"text",0,null,0.13,0.39999999999999997,0,0],["meta-llama/llama-3.3-70b-instruct:free",131072,8888,"text",0,null,0,0,0,0],["meta-llama/llama-4-maverick",1048576,16384,"text,image",0,null,0.19999999999999998,0.7999999999999999,0,0],["meta-llama/llama-4-scout",1310720,16384,"text,image",0,null,0.09999999999999999,0.3,0,0],["meta/muse-spark-1.1",1048576,8888,"text,image",1,null,1.25,4.25,0.15,0],["minimax/minimax-m1",1000000,40000,"text",1,null,0.55,2.2,0,0],["minimax/minimax-m2",204800,131072,"text",1,null,0.255,1.02,0.03,0],["minimax/minimax-m2.1",204800,131072,"text",1,null,0.3,1.2,0.03,0],["minimax/minimax-m2.5",204800,196608,"text",1,null,0.15,0.8999999999999999,0.049999999999999996,0],["minimax/minimax-m2.5:free",262144,8192,"text",1,null,0,0,0,0],["minimax/minimax-m2.7",204800,131072,"text",1,null,0.25,1,0.049999999999999996,0],["minimax/minimax-m3",1048576,512000,"text,image",1,null,0.3,1.2,0.06,0],["mistralai/codestral-2508",256000,8888,"text",0,null,0.3,0.8999999999999999,0.03,0],["mistralai/devstral-2512",262144,8888,"text",0,null,0.39999999999999997,2,0.04,0],["mistralai/devstral-medium",131072,8888,"text",0,null,0.39999999999999997,2,0.04,0],["mistralai/devstral-small",131072,8888,"text",0,null,0.09999999999999999,0.3,0.01,0],["mistralai/ministral-14b-2512",262144,8888,"text,image",0,null,0.19999999999999998,0.19999999999999998,0.02,0],["mistralai/ministral-3b-2512",131072,8888,"text,image",0,null,0.09999999999999999,0.09999999999999999,0.01,0],["mistralai/ministral-8b-2512",262144,8888,"text,image",0,null,0.15,0.15,0.015,0],["mistralai/mistral-large",128000,8888,"text",0,null,2,6,0.19999999999999998,0],["mistralai/mistral-large-2407",131072,8888,"text",0,null,2,6,0.19999999999999998,0],["mistralai/mistral-large-2411",131072,8888,"text",0,null,2,6,0.19999999999999998,0],["mistralai/mistral-large-2512",262144,8888,"text,image",0,null,0.5,1.5,0.049999999999999996,0],["mistralai/mistral-medium-3",131072,8888,"text,image",0,null,0.39999999999999997,2,0.04,0],["mistralai/mistral-medium-3-5",262144,8888,"text,image",1,null,1.5,7.5,0,0],["mistralai/mistral-medium-3.1",131072,8888,"text,image",0,null,0.39999999999999997,2,0.04,0],["mistralai/mistral-nemo",131072,16384,"text",0,null,0.019000000000000003,0.03,0,0],["mistralai/mistral-saba",32768,8888,"text",0,null,0.19999999999999998,0.6,0.02,0],["mistralai/mistral-small-24b-instruct-2501",32768,16384,"text",0,null,0.049999999999999996,0.08,0,0],["mistralai/mistral-small-2603",262144,8888,"text,image",1,null,0.15,0.6,0.015,0],["mistralai/mistral-small-3.1-24b-instruct",131072,131072,"text,image",0,null,0.03,0.11,0.015,0],["mistralai/mistral-small-3.1-24b-instruct:free",128000,8888,"text,image",0,null,0,0,0,0],["mistralai/mistral-small-3.2-24b-instruct",256000,8888,"text,image",0,null,0.09999999999999999,0.3,0.01,0],["mistralai/mistral-small-creative",32768,8888,"text",0,null,0.09999999999999999,0.3,0.01,0],["mistralai/mixtral-8x22b-instruct",65536,13108,"text",0,null,2,6,0.19999999999999998,0],["mistralai/mixtral-8x7b-instruct",32768,16384,"text",0,null,0.54,0.54,0,0],["mistralai/pixtral-large-2411",131072,8888,"text,image",0,null,2,6,0.19999999999999998,0],["mistralai/voxtral-small-24b-2507",32000,8888,"text",0,null,0.09999999999999999,0.3,0.01,0],["moonshotai/kimi-k2",131072,100352,"text",0,null,0.5700000000000001,2.3,0,0],["moonshotai/kimi-k2-0905",262144,100352,"text",0,null,0.6,2.5,0.15,0],["moonshotai/kimi-k2-0905:exacto",262144,8888,"text",0,null,0.6,2.5,0,0],["moonshotai/kimi-k2-thinking",262144,100352,"text",1,null,0.6,2.5,0.15,0],["moonshotai/kimi-k2.5",262144,262144,"text,image",1,null,0.5700000000000001,2.8499999999999996,0.095,0],["moonshotai/kimi-k2.6",262144,262144,"text,image",1,null,0.646,2.7199999999999998,0.1088,0],["moonshotai/kimi-k2.6:free",262144,8888,"text,image",1,null,0,0,0,0],["moonshotai/kimi-k2.7-code",262144,262144,"text,image",1,null,0.78,3.5,0.15,0],["moonshotai/kimi-k3",1048576,131072,"text,image",1,null,3,15,0.3,0],["nex-agi/deepseek-v3.1-nex-n1",131072,163840,"text",0,null,0.135,0.5,0,0],["nex-agi/nex-n2-mini",262144,262144,"text,image",1,null,0.024999999999999998,0.09999999999999999,0.0025,0],["nex-agi/nex-n2-pro",262144,262144,"text,image",1,null,0.25,1,0.024999999999999998,0],["nex-agi/nex-n2-pro:free",262144,262144,"text,image",1,null,0,0,0,0],["nousresearch/deephermes-3-mistral-24b-preview",32768,32768,"text",1,null,0.02,0.09999999999999999,0.01,0],["nousresearch/hermes-4-70b",131072,131072,"text",1,null,0.11,0.38,0.055,0],["nvidia/llama-3.1-nemotron-70b-instruct",131072,16384,"text",0,null,1.2,1.2,0,0],["nvidia/llama-3.3-nemotron-super-49b-v1.5",131072,16384,"text",1,null,0.39999999999999997,0.39999999999999997,0,0],["nvidia/nemotron-3-nano-30b-a3b",262144,228000,"text",1,null,0.049999999999999996,0.19999999999999998,0,0],["nvidia/nemotron-3-nano-30b-a3b:free",256000,8888,"text",1,null,0,0,0,0],["nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",256000,65536,"text,image",1,null,0,0,0,0],["nvidia/nemotron-3-super-120b-a12b",1000000,16384,"text",1,null,0.08499999999999999,0.39999999999999997,0.09999999999999999,0],["nvidia/nemotron-3-super-120b-a12b:free",262144,262144,"text",1,null,0,0,0,0],["nvidia/nemotron-3-ultra-550b-a55b",512288,65536,"text",1,null,0.6,3.5999999999999996,0.19999999999999998,0],["nvidia/nemotron-3-ultra-550b-a55b:free",1000000,65536,"text",1,null,0,0,0,0],["nvidia/nemotron-nano-12b-v2-vl:free",128000,128000,"text,image",1,null,0,0,0,0],["nvidia/nemotron-nano-9b-v2",131072,16384,"text",1,null,0.04,0.16,0,0],["nvidia/nemotron-nano-9b-v2:free",128000,8888,"text",1,null,0,0,0,0],["openai/gpt-3.5-turbo",16385,4096,"text",0,null,0.5,1.5,0,0],["openai/gpt-3.5-turbo-0613",4095,4096,"text",0,null,1,2,0,0],["openai/gpt-3.5-turbo-16k",16385,4096,"text",0,null,3,4,0,0],["openai/gpt-4",8191,8192,"text",0,null,30,60,0,0],["openai/gpt-4-0314",8191,4096,"text",0,null,30,60,0,0],["openai/gpt-4-1106-preview",128000,4096,"text",0,null,10,30,0,0],["openai/gpt-4-turbo",128000,4096,"text,image",0,null,10,30,0,0],["openai/gpt-4-turbo-preview",128000,4096,"text",0,null,10,30,0,0],["openai/gpt-4.1",1047576,32768,"text,image",0,null,2,8,0.5,0],["openai/gpt-4.1-mini",1047576,32768,"text,image",0,null,0.39999999999999997,1.5999999999999999,0.09999999999999999,0],["openai/gpt-4.1-nano",1047576,32768,"text,image",0,null,0.09999999999999999,0.39999999999999997,0.024999999999999998,0],["openai/gpt-4o",128000,16384,"text,image",0,null,2.5,10,1.25,0],["openai/gpt-4o-2024-05-13",128000,4096,"text,image",0,null,5,15,0,0],["openai/gpt-4o-2024-08-06",128000,16384,"text,image",0,null,2.5,10,1.25,0],["openai/gpt-4o-2024-11-20",128000,16384,"text,image",0,null,2.5,10,1.25,0],["openai/gpt-4o-audio-preview",128000,16384,"text",0,null,2.5,10,0,0],["openai/gpt-4o-mini",128000,16384,"text,image",0,null,0.15,0.6,0.075,0],["openai/gpt-4o-mini-2024-07-18",128000,16384,"text,image",0,null,0.15,0.6,0.075,0],["openai/gpt-4o:extended",128000,64000,"text,image",0,null,6,18,0,0],["openai/gpt-5",400000,128000,"text,image",1,null,1.25,10,0.125,0],["openai/gpt-5-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["openai/gpt-5-image",400000,128000,"text,image",1,null,10,10,1.25,0],["openai/gpt-5-image-mini",400000,128000,"text,image",1,null,2.5,2,0.25,0],["openai/gpt-5-mini",400000,128000,"text,image",1,null,0.25,2,0.024999999999999998,0],["openai/gpt-5-nano",400000,128000,"text,image",1,null,0.049999999999999996,0.39999999999999997,0.005,0],["openai/gpt-5-pro",400000,128000,"text,image",1,null,15,120,0,0],["openai/gpt-5.1",400000,128000,"text,image",1,null,1.25,10,0.125,0],["openai/gpt-5.1-chat",128000,16384,"text,image",0,null,1.25,10,0.125,0],["openai/gpt-5.1-codex",272000,128000,"text,image",1,null,1.25,10,0.125,0],["openai/gpt-5.1-codex-max",272000,128000,"text,image",1,null,1.25,10,0.125,0],["openai/gpt-5.1-codex-mini",272000,100000,"text,image",1,null,0.25,2,0.024999999999999998,0],["openai/gpt-5.2",400000,128000,"text,image",1,null,1.75,14,0.175,0],["openai/gpt-5.2-chat",128000,16384,"text,image",0,null,1.75,14,0.175,0],["openai/gpt-5.2-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["openai/gpt-5.2-pro",400000,128000,"text,image",1,null,21,168,0,0],["openai/gpt-5.3-chat",128000,16384,"text",0,null,1.75,14,0.175,0],["openai/gpt-5.3-codex",272000,128000,"text,image",1,null,1.75,14,0.175,0],["openai/gpt-5.4",1050000,128000,"text,image",1,null,2.5,15,0.25,0],["openai/gpt-5.4-mini",400000,128000,"text",0,null,0.75,4.5,0.075,0],["openai/gpt-5.4-nano",400000,128000,"text",0,null,0.19999999999999998,1.25,0.02,0],["openai/gpt-5.4-pro",1050000,128000,"text,image",1,null,30,180,0,0],["openai/gpt-5.5",1050000,128000,"text,image",1,null,5,30,0.5,0],["openai/gpt-5.5-pro",1050000,128000,"text,image",1,null,30,180,0,0],["openai/gpt-5.6-luna",373000,128000,"text,image",1,null,1,6,0.09999999999999999,1.25],["openai/gpt-5.6-luna-pro",373000,128000,"text,image",1,null,1,6,0.09999999999999999,1.25],["openai/gpt-5.6-sol",373000,128000,"text,image",1,null,5,30,0.5,6.25],["openai/gpt-5.6-sol-pro",373000,128000,"text,image",1,null,5,30,0.5,6.25],["openai/gpt-5.6-terra",373000,128000,"text,image",1,null,2.5,15,0.25,3.125],["openai/gpt-5.6-terra-pro",373000,128000,"text,image",1,null,2.5,15,0.25,3.125],["openai/gpt-6-luna",373000,128000,"text,image",1,null,0.1,0.5,0.01,0.125],["openai/gpt-6-sol",373000,128000,"text,image",1,null,2,10,0.2,2.5],["openai/gpt-6.1-sol",373000,128000,"text,image",1,null,2,10,0.1,2.5],["openai/gpt-audio",128000,16384,"text",0,null,2.5,10,0,0],["openai/gpt-audio-mini",128000,16384,"text",0,null,0.6,2.4,0,0],["openai/gpt-chat-latest",400000,128000,"text,image",0,null,5,30,0.5,0],["openai/gpt-oss-120b",131072,131072,"text",1,null,0.037,0.16999999999999998,0,0],["openai/gpt-oss-120b:exacto",131072,8888,"text",1,null,0.039,0.19,0,0],["openai/gpt-oss-120b:free",131072,131072,"text",1,null,0,0,0,0],["openai/gpt-oss-20b",131072,131072,"text",1,null,0.03,0.13,0.03,0],["openai/gpt-oss-20b:free",131072,32768,"text",1,null,0,0,0,0],["openai/gpt-oss-safeguard-20b",131072,65536,"text",1,null,0.075,0.3,0.0375,0],["openai/o1",200000,100000,"text,image",1,null,15,60,7.5,0],["openai/o3",200000,100000,"text,image",1,null,2,8,0.5,0],["openai/o3-deep-research",200000,100000,"text,image",1,null,10,40,2.5,0],["openai/o3-mini",200000,100000,"text",1,null,1.1,4.4,0.55,0],["openai/o3-mini-high",200000,100000,"text",1,null,1.1,4.4,0.55,0],["openai/o3-pro",200000,100000,"text,image",1,null,20,80,0,0],["openai/o4-mini",200000,100000,"text,image",1,null,1.1,4.4,0.275,0],["openai/o4-mini-deep-research",200000,100000,"text,image",1,null,2,8,0.5,0],["openai/o4-mini-high",200000,100000,"text,image",1,null,1.1,4.4,0.275,0],["openrouter/aurora-alpha",128000,50000,"text",1,null,0,0,0,0],["openrouter/auto",2000000,8888,"text,image",1,null,-1000000,-1000000,0,0],["openrouter/auto-beta",2000000,8888,"text,image",1,null,-1000000,-1000000,0,0],["openrouter/elephant-alpha",262144,32768,"text",0,null,0,0,0,0],["openrouter/free",200000,8888,"text,image",1,null,0,0,0,0],["openrouter/healer-alpha",262144,32000,"text,image",1,null,0,0,0,0],["openrouter/hunter-alpha",1048576,32000,"text",1,null,0,0,0,0],["openrouter/owl-alpha",1048756,262144,"text",0,null,0,0,0,0],["poolside/laguna-m.1",262144,32768,"text",1,null,0.19999999999999998,0.39999999999999997,0.09999999999999999,0],["poolside/laguna-m.1:free",262144,32768,"text",1,null,0,0,0,0],["poolside/laguna-s-2.1",1048576,131072,"text",1,null,0.09999999999999999,0.19999999999999998,0.01,0],["poolside/laguna-s-2.1:free",262144,32768,"text",1,null,0,0,0,0],["poolside/laguna-xs-2.1",262144,32768,"text",1,null,0.06,0.12,0.03,0],["poolside/laguna-xs-2.1:free",262144,32768,"text",1,null,0,0,0,0],["poolside/laguna-xs.2",262144,32768,"text",1,null,0.09999999999999999,0.19999999999999998,0.049999999999999996,0],["poolside/laguna-xs.2:free",262144,32768,"text",1,null,0,0,0,0],["prime-intellect/intellect-3",131072,131072,"text",1,null,0.19999999999999998,1.1,0,0],["qwen/qwen-2.5-72b-instruct",32768,16384,"text",0,null,0.36,0.39999999999999997,0,0],["qwen/qwen-2.5-7b-instruct",32768,32768,"text",0,null,0.04,0.09999999999999999,0,0],["qwen/qwen-max",32768,8192,"text",0,null,1.04,4.16,0.20800000000000002,0],["qwen/qwen-plus",1000000,32768,"text",0,null,0.26,0.78,0.052000000000000005,0.325],["qwen/qwen-plus-2025-07-28",1000000,32768,"text",0,null,0.26,0.78,0,0.325],["qwen/qwen-plus-2025-07-28:thinking",1000000,32768,"text",1,null,0.26,0.78,0,0.325],["qwen/qwen-turbo",131072,8192,"text",0,null,0.0325,0.13,0.006500000000000001,0],["qwen/qwen-vl-max",131072,32768,"text,image",0,null,0.52,2.08,0,0],["qwen/qwen3-14b",131072,8192,"text",1,null,0.22749999999999998,0.9099999999999999,0,0],["qwen/qwen3-235b-a22b",131072,8192,"text",1,null,0.45499999999999996,1.8199999999999998,0,0],["qwen/qwen3-235b-a22b-2507",262144,16384,"text",1,null,0.09,0.55,0,0],["qwen/qwen3-235b-a22b-thinking-2507",262144,32768,"text",1,null,0.3,3,0.09999999999999999,0],["qwen/qwen3-30b-a3b",131072,8192,"text",1,null,0.13,0.52,0,0],["qwen/qwen3-30b-a3b-instruct-2507",262144,32000,"text",0,null,0.04815,0.19305,0,0],["qwen/qwen3-30b-a3b-thinking-2507",81920,32768,"text",1,null,0.13,1.56,0.08,0],["qwen/qwen3-32b",131072,16384,"text",1,null,0.08,0.28,0.04,0],["qwen/qwen3-4b",131072,8192,"text",1,null,0.0715,0.273,0,0],["qwen/qwen3-4b:free",40960,8888,"text",1,null,0,0,0,0],["qwen/qwen3-8b",131072,8192,"text",1,null,0.117,0.45499999999999996,0.049999999999999996,0],["qwen/qwen3-coder",262144,65536,"text",0,null,0.3,1,0.09999999999999999,0],["qwen/qwen3-coder-30b-a3b-instruct",262144,32768,"text",0,null,0.07,0.27,0,0],["qwen/qwen3-coder-flash",1000000,65536,"text",0,null,0.195,0.975,0.039,0.24375],["qwen/qwen3-coder-next",262144,262144,"text",0,null,0.11,0.7999999999999999,0.07,0],["qwen/qwen3-coder-plus",1000000,65536,"text",0,null,0.65,3.25,0.13,0.8125],["qwen/qwen3-coder:exacto",262144,65536,"text",0,null,0.22,1.7999999999999998,0.022,0],["qwen/qwen3-coder:free",1048576,262000,"text",0,null,0,0,0,0],["qwen/qwen3-max",262144,32768,"text",1,null,0.78,3.9,0.156,0.975],["qwen/qwen3-max-thinking",262144,32768,"text",1,null,0.78,3.9,0,0],["qwen/qwen3-next-80b-a3b-instruct",262144,262144,"text",0,null,0.09999999999999999,1.1,0.07,0],["qwen/qwen3-next-80b-a3b-instruct:free",262144,8888,"text",0,null,0,0,0,0],["qwen/qwen3-next-80b-a3b-thinking",262144,32768,"text",1,null,0.0975,0.78,0,0],["qwen/qwen3-vl-235b-a22b-instruct",262144,32768,"text,image",0,null,0.21,1.9,0.09999999999999999,0],["qwen/qwen3-vl-235b-a22b-thinking",131072,32768,"text,image",1,null,0.26,2.6,0,0],["qwen/qwen3-vl-30b-a3b-instruct",262144,16384,"text,image",0,null,0.15,0.6,0,0],["qwen/qwen3-vl-30b-a3b-thinking",262144,32768,"text,image",1,null,0.13,1.56,0,0],["qwen/qwen3-vl-32b-instruct",131072,32768,"text,image",0,null,0.10400000000000001,0.41600000000000004,0,0],["qwen/qwen3-vl-8b-instruct",262144,32768,"text,image",0,null,0.117,0.45499999999999996,0,0],["qwen/qwen3-vl-8b-thinking",131072,32768,"text,image",1,null,0.117,1.365,0,0],["qwen/qwen3.5-122b-a10b",262144,65536,"text,image",1,null,0.26,2.08,0,0],["qwen/qwen3.5-27b",262144,65536,"text,image",1,null,0.195,1.56,0,0],["qwen/qwen3.5-35b-a3b",262144,262144,"text,image",1,null,0.14,1,0.049999999999999996,0],["qwen/qwen3.5-397b-a17b",262144,65536,"text,image",1,null,0.39,2.34,0.111,0],["qwen/qwen3.5-9b",262144,262144,"text,image",1,null,0.09999999999999999,0.15,0,0],["qwen/qwen3.5-flash-02-23",1000000,65536,"text,image",1,null,0.065,0.26,0,0.08125],["qwen/qwen3.5-plus-02-15",1000000,65536,"text,image",1,null,0.26,1.56,0,0.325],["qwen/qwen3.5-plus-20260420",1000000,65536,"text,image",1,null,0.3,1.7999999999999998,0,0.375],["qwen/qwen3.6-27b",262144,131072,"text,image",1,null,0.28900000000000003,2.4,0.15,0],["qwen/qwen3.6-35b-a3b",262144,262144,"text,image",1,null,0.14,1,0.049999999999999996,0],["qwen/qwen3.6-flash",1000000,65536,"text,image",1,null,0.1875,1.125,0,0.234375],["qwen/qwen3.6-max-preview",262144,65536,"text",1,null,1.04,6.24,0,1.3],["qwen/qwen3.6-plus",1000000,65536,"text",1,null,0.325,1.95,0,0.40625],["qwen/qwen3.6-plus-preview:free",1000000,32000,"text",1,null,0,0,0,0],["qwen/qwen3.6-plus:free",1000000,65536,"text,image",1,null,0,0,0,0],["qwen/qwen3.7-max",1000000,65536,"text",1,null,1.475,4.425,0.295,1.84375],["qwen/qwen3.7-plus",1000000,65536,"text,image",1,null,0.32,1.28,0.064,0.39999999999999997],["qwen/qwq-32b",131072,131072,"text",1,null,0.15,0.58,0,0],["reka/reka-edge",16384,16384,"text,image",0,null,0.09999999999999999,0.09999999999999999,0,0],["rekaai/reka-edge",16384,16384,"text,image",0,null,0.09999999999999999,0.09999999999999999,0,0],["relace/relace-search",256000,128000,"text",0,null,1,3,0,0],["sakana/fugu-ultra",1000000,128000,"text,image",1,null,5,30,0.5,0],["sao10k/l3-euryale-70b",8192,8192,"text",0,null,1.48,1.48,0,0],["sao10k/l3.1-euryale-70b",131072,16384,"text",0,null,0.85,0.85,0,0],["stepfun/step-3.5-flash",262144,65536,"text",0,null,0.09999999999999999,0.3,0.02,0],["stepfun/step-3.5-flash:free",256000,256000,"text",1,null,0,0,0,0],["stepfun/step-3.7-flash",262144,256000,"text,image",1,null,0.19999999999999998,1.15,0.04,0],["tencent/hy3",262144,128000,"text",1,null,0.13199999999999998,0.5279999999999999,0.032999999999999995,0],["tencent/hy3-preview",262144,64000,"text",1,null,0.063,0.21,0.020999999999999998,0],["tencent/hy3-preview:free",262144,262144,"text",1,null,0,0,0,0],["tencent/hy3:free",262144,262144,"text",1,null,0,0,0,0],["thedrummer/rocinante-12b",32768,32768,"text",0,null,0.16999999999999998,0.43,0,0],["thedrummer/unslopnemo-12b",32768,32768,"text",0,null,0.39999999999999997,0.39999999999999997,0,0],["thinkingmachines/inkling",1048576,8888,"text,image",1,null,1,4.05,0.16999999999999998,0],["tngtech/deepseek-r1t2-chimera",163840,163840,"text",1,null,0.3,1.1,0.15,0],["tngtech/tng-r1t-chimera",163840,65536,"text",1,null,0.25,0.85,0.125,0],["upstage/solar-pro-3",128000,8888,"text",1,null,0.15,0.6,0.015,0],["upstage/solar-pro-3:free",128000,8888,"text",1,null,0,0,0,0],["x-ai/grok-3",131072,8888,"text",0,null,3,15,0.75,0],["x-ai/grok-3-beta",131072,8888,"text",0,null,3,15,0.75,0],["x-ai/grok-3-mini",131072,8888,"text",1,null,0.3,0.5,0.075,0],["x-ai/grok-3-mini-beta",131072,8888,"text",1,null,0.3,0.5,0.075,0],["x-ai/grok-4",256000,64000,"text,image",1,null,3,15,0.75,0],["x-ai/grok-4-fast",2000000,30000,"text,image",1,null,0.19999999999999998,0.5,0.049999999999999996,0],["x-ai/grok-4.1-fast",2000000,30000,"text,image",1,null,0.19999999999999998,0.5,0.049999999999999996,0],["x-ai/grok-4.20",2000000,8888,"text,image",1,null,1.25,2.5,0.19999999999999998,0],["x-ai/grok-4.20-beta",2000000,8888,"text,image",1,null,2,6,0.19999999999999998,0],["x-ai/grok-4.3",1000000,1000000,"text,image",1,null,1.25,2.5,0.19999999999999998,0],["x-ai/grok-4.5",500000,500000,"text,image",1,null,2,6,0.3,0],["x-ai/grok-4.6",500000,500000,"text,image",1,null,2,6,0.3,0],["x-ai/grok-4.7",500000,450000,"text,image",1,null,1.6,4.8,0.4,0],["x-ai/grok-build-0.1",256000,256000,"text,image",1,null,1,2,0.19999999999999998,0],["x-ai/grok-code-fast-1",256000,10000,"text",1,null,0.19999999999999998,1.5,0.02,0],["xiaomi/mimo-v2-flash",262144,65536,"text",1,null,0.09999999999999999,0.3,0.01,0],["xiaomi/mimo-v2-omni",262144,65536,"text,image",1,null,0.39999999999999997,2,0.08,0],["xiaomi/mimo-v2-pro",1048576,131072,"text",1,null,1,3,0.19999999999999998,0],["xiaomi/mimo-v2.5",1050000,131072,"text,image",1,null,0.14,0.28,0.0028,0],["xiaomi/mimo-v2.5-pro",1050000,131072,"text",1,null,0.435,0.87,0.0036,0],["xiaomi/mimo-v2.6-flash",1048576,131072,"text,image",1,null,0.14,0.28,0.0028,0],["xiaomi/mimo-v2.6-pro",1048576,131072,"text,image",1,null,0.435,0.87,0.0036,0],["xiaomi/mimo-v2.6-pro-ultraspeed",1048576,131072,"text,image",1,null,4.35,8.7,0.036,0],["z-ai/glm-4-32b",128000,8888,"text",0,null,0.09999999999999999,0.09999999999999999,0,0],["z-ai/glm-4.5",131072,98304,"text",1,null,0.6,2.2,0.11,0],["z-ai/glm-4.5-air",131072,98304,"text",1,null,0.13,0.85,0.024999999999999998,0],["z-ai/glm-4.5-air:free",131072,96000,"text",1,null,0,0,0,0],["z-ai/glm-4.5v",65536,16384,"text,image",1,null,0.6,1.7999999999999998,0.11,0],["z-ai/glm-4.6",204800,131072,"text",1,null,0.5,2,0.09999999999999999,0],["z-ai/glm-4.6:exacto",204800,131072,"text",1,null,0.44,1.76,0.11,0],["z-ai/glm-4.6v",131072,32768,"text,image",1,null,0.3,0.8999999999999999,0.055,0],["z-ai/glm-4.7",204800,131072,"text",1,null,0.39999999999999997,1.75,0.08,0],["z-ai/glm-4.7-flash",202752,16384,"text",1,null,0.06,0.39999999999999997,0.01,0],["z-ai/glm-5",204800,131072,"text",1,null,0.95,2.5500000000000003,0.19999999999999998,0],["z-ai/glm-5-turbo",202752,131072,"text",1,null,1.2,4,0.24,0],["z-ai/glm-5.1",204800,128000,"text",1,null,0.966,3.036,0.1794,0],["z-ai/glm-5.2",1048576,131072,"text",1,null,0.707,2.222,0.1313,0],["z-ai/glm-5.3",1048576,131072,"text",1,null,0.707,2.222,0.1313,0],["z-ai/glm-5v-turbo",202752,131072,"text,image",1,null,1.2,4,0.24,0]],
@@ -84,7 +84,7 @@ export function listModelMetadata(provider: string): ModelMetadata[] {
84
84
  // Cross-provider model-level price fallback (260720 WP5): a model follows its
85
85
  // official vendor price regardless of the serving provider. Exact modelId match in
86
86
  // priority-ordered vendor bundles; first nonzero cost wins.
87
- const COST_VENDOR_PRIORITY = ["anthropic","openai","google","moonshot","minimax","deepseek","xai","zai","mistral","cerebras","azure-openai","amazon-bedrock","xiaomi"];
87
+ export const COST_VENDOR_PRIORITY = ["anthropic","openai","google","moonshot","minimax","deepseek","xai","zai","mistral","cerebras","azure-openai","amazon-bedrock","xiaomi"];
88
88
  export function findVendorCostByModelId(modelId: string): { provider: string; cost: { input: number; output: number; cacheRead: number; cacheWrite: number } } | undefined {
89
89
  for (const provider of COST_VENDOR_PRIORITY) {
90
90
  const row = DATA[provider]?.find(r => r[0] === modelId);
@@ -1,7 +1,8 @@
1
- import { constants, copyFileSync, existsSync, readFileSync, statSync } from "node:fs";
1
+ import { constants, copyFileSync, existsSync, readFileSync, lstatSync, statSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { atomicWriteFile } from "../config";
5
+ import { atomicWriteFileNoFollow } from "../config/atomic-write";
5
6
  import { applyEol, dominantEol, isLoopbackHostname, providerBaseHost } from "../codex/inject";
6
7
  import {
7
8
  grokDefaultReasoningEffort,
@@ -22,7 +23,7 @@ export interface GrokInjectResult {
22
23
  ok: boolean;
23
24
  changed: boolean;
24
25
  message: string;
25
- skippedReason?: "no-grok-home" | "orphaned-marker" | "non-loopback";
26
+ skippedReason?: "no-grok-home" | "orphaned-marker" | "non-loopback" | "refresh-only";
26
27
  }
27
28
 
28
29
  const BEGIN_MARKER = "# >>> opencodex managed block — do not edit (removed by `ocx stop`) >>>";
@@ -78,6 +79,18 @@ export function findManagedRegion(content: string): ManagedRegion | null {
78
79
  return { start: begin.index, end: endMatch.index + endMatch[0].length, orphaned: false };
79
80
  }
80
81
 
82
+ /** A complete managed fence is the existing opt-in required by refresh-only callers. */
83
+ export function grokManagedBlockPresent(grokHome?: string): boolean {
84
+ try {
85
+ const path = join(resolveGrokHome(grokHome), "config.toml");
86
+ if (!lstatSync(path).isFile()) return false;
87
+ const region = findManagedRegion(applyEol(readFileSync(path, "utf8"), "\n"));
88
+ return region != null && !region.orphaned;
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
81
94
  /**
82
95
  * A TOML key segment as it may be spelled in a table header: bare, basic string, or literal
83
96
  * string. All three spellings of the same key address the SAME table, so both segments of a
@@ -1074,12 +1087,27 @@ export function buildGrokManagedBlock(
1074
1087
  return lines.join("\n");
1075
1088
  }
1076
1089
 
1090
+ class GrokRefreshOnlyRefusal extends Error {}
1091
+
1092
+ function refreshOnlySkipped(): GrokInjectResult {
1093
+ return { ok: true, changed: false, message: "Grok refresh skipped", skippedReason: "refresh-only" };
1094
+ }
1095
+
1096
+ function isSymlink(path: string): boolean {
1097
+ try { return lstatSync(path).isSymbolicLink(); }
1098
+ catch (error) {
1099
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
1100
+ throw error;
1101
+ }
1102
+ }
1103
+
1077
1104
  export function injectGrokConfig(
1078
1105
  port: number,
1079
1106
  models: GrokInjectModel[],
1080
1107
  opts: {
1081
1108
  grokHome?: string;
1082
1109
  hostname?: string;
1110
+ refreshOnly?: { admit: () => boolean };
1083
1111
  excluded?: ReadonlySet<string>;
1084
1112
  /** Unfiltered known ids used only to distinguish hidden current models from retired ones. */
1085
1113
  catalogModelIds?: ReadonlySet<string>;
@@ -1108,6 +1136,7 @@ export function injectGrokConfig(
1108
1136
  // at all here; the user configures models manually, outside our fence, where nothing we do
1109
1137
  // can clobber their credential.
1110
1138
  if (!isLoopbackHostname(opts.hostname)) {
1139
+ if (opts.refreshOnly) return refreshOnlySkipped();
1111
1140
  const removed = stripGrokConfig({ ...(opts.grokHome !== undefined ? { grokHome: opts.grokHome } : {}) });
1112
1141
  const cleanup = removed.changed
1113
1142
  ? " Removed the previously generated block, which pointed at a loopback address."
@@ -1131,6 +1160,10 @@ export function injectGrokConfig(
1131
1160
  const eol = dominantEol(rawContent);
1132
1161
  const originalContent = applyEol(rawContent, "\n");
1133
1162
  const originalRegion = findManagedRegion(originalContent);
1163
+ if (opts.refreshOnly && (!configExisted || !originalRegion || originalRegion.orphaned
1164
+ || !opts.refreshOnly.admit() || isSymlink(configPath) || isSymlink(backupPath))) {
1165
+ return refreshOnlySkipped();
1166
+ }
1134
1167
  // Ambiguous fence: refuse before the sweep, or "outside the region" could mean the
1135
1168
  // entire file.
1136
1169
  if (originalRegion?.orphaned) return orphanedMarkerResult("injection");
@@ -1240,8 +1273,20 @@ export function injectGrokConfig(
1240
1273
  // deletes a table the user has in their file. Previously the adjacent-orphan layout got a
1241
1274
  // backup only as a side effect of the fence being destroyed (which made `region` falsy);
1242
1275
  // preserving the fence must not silently drop that safety net.
1243
- if (configExisted && (!region || orphans.length > 0)) copyBackupOnce(configPath, backupPath);
1244
- atomicWriteFile(configPath, output);
1276
+ if (opts.refreshOnly) {
1277
+ const refreshOnly = opts.refreshOnly;
1278
+ atomicWriteFileNoFollow(configPath, output, undefined, {
1279
+ validateBeforeRename: () => {
1280
+ try {
1281
+ if (!refreshOnly.admit() || !lstatSync(configPath).isFile()
1282
+ || readFileSync(configPath, "utf8") !== rawContent) throw new Error();
1283
+ } catch { throw new GrokRefreshOnlyRefusal(); }
1284
+ },
1285
+ });
1286
+ } else {
1287
+ if (configExisted && (!region || orphans.length > 0)) copyBackupOnce(configPath, backupPath);
1288
+ atomicWriteFile(configPath, output);
1289
+ }
1245
1290
  return {
1246
1291
  ok: true,
1247
1292
  changed: true,
@@ -1250,6 +1295,7 @@ export function injectGrokConfig(
1250
1295
  : "Added the opencodex managed block to Grok config.",
1251
1296
  };
1252
1297
  } catch (error) {
1298
+ if (error instanceof GrokRefreshOnlyRefusal) return refreshOnlySkipped();
1253
1299
  return errorResult("inject", error);
1254
1300
  }
1255
1301
  }
package/src/grok/sync.ts CHANGED
@@ -31,7 +31,7 @@ async function defaultFetchAllModels(config: OcxConfig): Promise<CatalogModel[]>
31
31
  export async function syncGrokConfig(
32
32
  port: number,
33
33
  config: OcxConfig,
34
- opts: { hostname?: string; grokHome?: string } = {},
34
+ opts: { hostname?: string; grokHome?: string; refreshOnly?: { admit: () => boolean } } = {},
35
35
  deps: GrokSyncDeps = { fetchAllModels: defaultFetchAllModels, injectGrokConfig },
36
36
  ): Promise<GrokInjectResult> {
37
37
  let projection: ReturnType<typeof projectGrokCatalog>;
@@ -58,6 +58,7 @@ export async function syncGrokConfig(
58
58
  ? (opts.hostname ?? config.hostname)
59
59
  : targetUrl.hostname,
60
60
  ...(opts.grokHome !== undefined ? { grokHome: opts.grokHome } : {}),
61
+ ...opts.refreshOnly ? { refreshOnly: opts.refreshOnly } : {},
61
62
  excluded: new Set(config.grokExcludedModels ?? []),
62
63
  catalogModelIds: projection.catalogModelIds,
63
64
  disabledProviderNamespaces: projection.disabledProviderNamespaces,
@@ -300,6 +300,11 @@ export interface ImageBridgeDeps {
300
300
  onRequestBuilt?: (request: AdapterRequest) => void;
301
301
  abortSignal?: AbortSignal;
302
302
  onFirstOutput?: () => void;
303
+ /** Transfer prepaid cleanup before asynchronous inference can outlive Response construction. */
304
+ onProducerStart?: () => void;
305
+ onProducerEnd?: () => void;
306
+ /** Release a prepaid recovery that did not dispatch during this fetch iteration. */
307
+ onIterationEnd?: () => void;
303
308
  /** Max image-generation rounds before forcing a final answer. Defaults to 3; clamped to [0, 10]. */
304
309
  maxRounds?: number;
305
310
  /** Connect / response-header budget for non-runTurn iterations. */
@@ -309,7 +314,7 @@ export interface ImageBridgeDeps {
309
314
  /** Provider-specific fetch (e.g. xAI transport wrapper). Falls back to global fetch. */
310
315
  fetchImpl?: typeof globalThis.fetch;
311
316
  /** Bind physical dispatch to this iteration's built request; pacing remains owned by the loop. */
312
- fetchForRequest?: (request: AdapterRequest, parsed: OcxParsedRequest) => typeof globalThis.fetch;
317
+ fetchForRequest?: (request: AdapterRequest, parsed: OcxParsedRequest, adapter: ProviderAdapter) => typeof globalThis.fetch;
313
318
  /** Reserve the routed provider's next request-start slot before each adapter dispatch. */
314
319
  waitForRequestSlot?: (signal?: AbortSignal) => Promise<ProviderRequestSlot | void>;
315
320
  /** Raw adapter usage at the terminal event, pre wire-normalization (see bridgeToResponsesSSE onUsage). */
@@ -372,6 +377,7 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
372
377
  let paidImageCalls = 0;
373
378
  let paidVideoCalls = 0;
374
379
  let hiddenUsage: OcxUsage | undefined;
380
+ let activeProducers = 0;
375
381
 
376
382
  const addUsage = (a: OcxUsage | undefined, b: OcxUsage | undefined): OcxUsage | undefined => {
377
383
  if (!a) return b;
@@ -514,19 +520,25 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
514
520
  try {
515
521
  // Attempt telemetry must fire at dispatch time, not after collection.
516
522
  deps.onAttemptSend?.();
517
- void adapter.runTurn(iterParsed, {
518
- headers: deps.forwardHeaders ? new Headers(deps.forwardHeaders) : new Headers(),
519
- ...(deps.incomingMeta.providerName ? { providerName: deps.incomingMeta.providerName } : {}),
520
- abortSignal: signal,
521
- translatorBudget,
522
- pacingSlot,
523
- }, emit).then(closeOnAbort).catch(err => {
523
+ activeProducers++;
524
+ let producer: Promise<void>;
525
+ try {
526
+ producer = adapter.runTurn(iterParsed, {
527
+ ...deps.incomingMeta,
528
+ headers: deps.forwardHeaders ? new Headers(deps.forwardHeaders) : new Headers(),
529
+ ...(deps.incomingMeta.providerName ? { providerName: deps.incomingMeta.providerName } : {}),
530
+ abortSignal: signal,
531
+ translatorBudget,
532
+ pacingSlot,
533
+ }, emit);
534
+ } catch (err) { producer = Promise.reject(err); }
535
+ void producer.then(closeOnAbort).catch(err => {
524
536
  if (accepting) {
525
537
  collectionError = err;
526
538
  if (isTranslatorBudgetExceededError(err)) internalAbort.abort(err);
527
539
  }
528
540
  closeOnAbort();
529
- });
541
+ }).finally(() => { activeProducers--; deps.onProducerEnd?.(); });
530
542
  idle.reset();
531
543
  for await (const event of queue.stream()) {
532
544
  if (timedOut) break;
@@ -602,7 +614,7 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
602
614
  cachedRequest = request;
603
615
  cachedAdapter = requestAdapter;
604
616
  }
605
- const requestFetch = deps.fetchForRequest?.(request, iterParsed) ?? fetchImpl;
617
+ const requestFetch = deps.fetchForRequest?.(request, iterParsed, requestAdapter) ?? fetchImpl;
606
618
  let response: Response;
607
619
  try {
608
620
  if (requestAdapter.fetchResponse) {
@@ -615,6 +627,9 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
615
627
  returnRawErrors: true,
616
628
  stream: true,
617
629
  executor: requestFetch,
630
+ sendBudget: deps.incomingMeta.sendBudget,
631
+ onPhysicalSend: deps.incomingMeta.onPhysicalSend,
632
+ onRecoveryWithheld: deps.incomingMeta.onRecoveryWithheld,
618
633
  }));
619
634
  } finally {
620
635
  releaseProviderRequestSlot(slot);
@@ -689,7 +704,7 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
689
704
  }
690
705
  // 429 key-failover parity with web-search / normal routed path.
691
706
  while ((prepared.response.status === 429
692
- || (prepared.response.status === 403 && isAnthropicInstanceId(deps.incomingMeta?.providerName))
707
+ || ((prepared.response.status === 403 || prepared.response.status === 401) && isAnthropicInstanceId(deps.incomingMeta?.providerName))
693
708
  || (iterParsed._kiroAuthContext && (prepared.response.status === 400 || prepared.response.status === 403))) && deps.on429) {
694
709
  const rotated = await deps.on429(prepared.response.headers.get("retry-after"), prepared.response.headers,
695
710
  iterParsed, prepared.response);
@@ -734,6 +749,7 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
734
749
  throw new LoopError(502, `Provider unreachable: ${error instanceof Error ? error.message : String(error)}`);
735
750
  } finally {
736
751
  headerDeadline.clear();
752
+ deps.onIterationEnd?.();
737
753
  }
738
754
  };
739
755
 
@@ -796,6 +812,7 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
796
812
  // non-2xx JSON. Skip for runTurn adapters: their "headers" are synthetic, and awaiting
797
813
  // queue.collect() before returning SSE starves clients of headers/heartbeats on slow first turns.
798
814
  const skipEagerDrain = !!adapter.runTurn;
815
+ if (skipEagerDrain) deps.onProducerStart?.();
799
816
  let firstPrepared: IterationResponse | undefined;
800
817
  if (!skipEagerDrain) {
801
818
  try {
@@ -1056,6 +1073,7 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise<Respons
1056
1073
  }
1057
1074
  }
1058
1075
  } finally {
1076
+ if (skipEagerDrain && activeProducers === 0) deps.onProducerEnd?.();
1059
1077
  if (abortSignal) abortSignal.removeEventListener("abort", linkAbort);
1060
1078
  }
1061
1079
  }
@@ -8,7 +8,7 @@ import { readIntegrationState, type IntegrationState, type IntegrationStatus } f
8
8
  import {
9
9
  applyIntegrationCoordinated, disableIntegrationCoordinated,
10
10
  overwriteIntegrationCoordinated, refreshIntegrationCoordinated,
11
- type IntegrationWriteInput,
11
+ type CoordinatedIntegrationOptions, type IntegrationWriteInput,
12
12
  } from "./writer";
13
13
  import {
14
14
  asideProfileEnabled, asideProfileFailure, asideProfileScope, asideWriteInput,
@@ -260,7 +260,10 @@ export function mutateAsideProfiles(
260
260
  });
261
261
  }
262
262
 
263
- export function refreshAsideProfiles(input: AsideProfilesInput): Promise<Array<OwnedIntegrationRefreshOutcome & { profileId: number }>> {
263
+ export function refreshAsideProfiles(
264
+ input: AsideProfilesInput,
265
+ options?: { refreshOnly?: boolean; guard?: CoordinatedIntegrationOptions["guard"] },
266
+ ): Promise<Array<OwnedIntegrationRefreshOutcome & { profileId: number }>> {
264
267
  const policy = input.config.asideProfileSync;
265
268
  const selected = Object.values(policy?.profiles ?? {}).some(enabled => enabled === true);
266
269
  if (!selected && (policy?.allProfiles === false
@@ -272,11 +275,15 @@ export function refreshAsideProfiles(input: AsideProfilesInput): Promise<Array<O
272
275
  try {
273
276
  const scope = asideProfileScope(ctx, profile);
274
277
  const owned = scope.store.readRecords().aside !== undefined;
278
+ if (options?.refreshOnly && !owned) continue;
275
279
  const bound = await asideWriteInput(ctx, scope);
276
280
  // A surviving ownership record means a removed block stays removed.
277
281
  // A newly discovered, enabled profile may receive its first safe apply.
278
282
  const operation = owned ? refreshIntegrationCoordinated : applyIntegrationCoordinated;
279
- const result = await operation(bound, { lockSeams: input.lockSeams });
283
+ const result = await operation(bound, {
284
+ lockSeams: input.lockSeams,
285
+ ...(options?.guard ? { guard: options.guard } : {}),
286
+ });
280
287
  outcomes.push({
281
288
  client: "aside", profileId: profile.id, ok: result.ok,
282
289
  ...(result.ok ? { changed: result.changed } : {}),
@@ -2,6 +2,7 @@ import { siblingOfLivePort } from "../codex/sibling-start";
2
2
  import { redactSecretString } from "../lib/redact";
3
3
  import type { ExportModel } from "../clients/config-export";
4
4
  import type { IntegrationClientId } from "./registry";
5
+ import type { CoordinatedIntegrationOptions, WriteOutcome } from "./writer";
5
6
  import {
6
7
  refreshOwnedIntegration,
7
8
  type OwnedIntegrationRefreshInput,
@@ -12,6 +13,7 @@ import {
12
13
  export async function refreshOwnedCatalogIntegrations(
13
14
  input: Omit<OwnedIntegrationRefreshInput, "clientId">,
14
15
  clientIds: readonly IntegrationClientId[] = ["pi", "aside", "raycast", "omo", "commandcode", "droid", "opencode", "kilo"],
16
+ options: { refreshOnly?: boolean; admit?: () => boolean } = {},
15
17
  ): Promise<OwnedIntegrationRefreshOutcome[]> {
16
18
  // Client files are shared with the live proxy a sibling instance runs beside; their entries
17
19
  // point at the owner's port, and refreshing them here would re-point them at this one.
@@ -20,14 +22,28 @@ export async function refreshOwnedCatalogIntegrations(
20
22
  const loadModels = () => models ??= Promise.resolve().then(() =>
21
23
  typeof input.models === "function" ? input.models() : input.models);
22
24
  const outcomes: OwnedIntegrationRefreshOutcome[] = [];
25
+ const admit = options.admit;
26
+ const writeOptions: CoordinatedIntegrationOptions | undefined = admit ? {
27
+ guard: (frozen): WriteOutcome | null => admit() ? null : {
28
+ ok: false, reason: "superseded_store", state: "current", clientId: frozen.clientId,
29
+ message: "Background refresh superseded",
30
+ },
31
+ } : undefined;
23
32
  for (const clientId of clientIds) {
33
+ if (admit?.() === false) break;
24
34
  try {
25
35
  if (clientId === "aside") {
26
36
  const { refreshAsideProfiles } = await import("./aside-profiles");
27
- outcomes.push(...await refreshAsideProfiles({ ...input, models: loadModels }));
37
+ const asideOptions = options.refreshOnly === undefined ? writeOptions
38
+ : { ...writeOptions, refreshOnly: options.refreshOnly };
39
+ const bound = { ...input, models: loadModels };
40
+ outcomes.push(...await (asideOptions === undefined
41
+ ? refreshAsideProfiles(bound) : refreshAsideProfiles(bound, asideOptions)));
28
42
  continue;
29
43
  }
30
- const result = await refreshOwnedIntegration({ ...input, clientId, models: loadModels });
44
+ const bound = { ...input, clientId, models: loadModels };
45
+ const result = await (writeOptions === undefined
46
+ ? refreshOwnedIntegration(bound) : refreshOwnedIntegration(bound, writeOptions));
31
47
  if (result) outcomes.push(result);
32
48
  } catch (error) {
33
49
  const busy = error !== null && typeof error === "object"
@@ -801,6 +801,11 @@ export interface CoordinatedIntegrationOptions {
801
801
  * non-null result refuses without writing anything.
802
802
  */
803
803
  revalidate?: (frozen: IntegrationWriteInput) => Promise<WriteOutcome | null>;
804
+ /**
805
+ * Synchronous last word, evaluated with no await between it and the transaction (after
806
+ * `revalidate` and any lock acquisition). A non-null result refuses without writing.
807
+ */
808
+ guard?: (frozen: IntegrationWriteInput) => WriteOutcome | null;
804
809
  }
805
810
 
806
811
  /** Freeze all mutable resolution seams before the first lock await. */
@@ -942,21 +947,22 @@ async function coordinatedWrite(
942
947
  if (!prepared.ok) return prepared.refusal;
943
948
  const frozen = prepared.value;
944
949
  const spec = INTEGRATION_CLIENTS[frozen.clientId];
950
+ const guarded = (bound: IntegrationWriteInput) => options?.guard?.(bound) ?? operation(bound);
945
951
  if (!spec.writerLock) {
946
952
  const refused = await options?.revalidate?.(frozen);
947
- return refused ?? operation(frozen);
953
+ return refused ?? guarded(frozen);
948
954
  }
949
955
 
950
956
  // An absent client home is not created merely to acquire a sibling lock.
951
957
  if (frozen.io.statKind(frozen.resolvedPaths.detectDir) !== "dir") {
952
958
  const refused = await options?.revalidate?.(frozen);
953
959
  if (refused) return refused;
954
- if (frozen.io.statKind(frozen.resolvedPaths.detectDir) !== "dir") return operation(frozen);
960
+ if (frozen.io.statKind(frozen.resolvedPaths.detectDir) !== "dir") return guarded(frozen);
955
961
  }
956
962
  return withClientLocks(
957
963
  frozen,
958
964
  spec.writerLock.suffix,
959
- () => operation(frozen),
965
+ () => guarded(frozen),
960
966
  options,
961
967
  );
962
968
  }
@@ -0,0 +1,32 @@
1
+ export interface DesktopCliIo {
2
+ stat?: (path: string) => { isFile(): boolean };
3
+ access?: (path: string, mode: number) => void;
4
+ }
5
+ export interface PathBunIo extends DesktopCliIo {
6
+ now?: () => number;
7
+ realpath?: (path: string) => string;
8
+ stat?: (path: string) => { isFile(): boolean; mode: number };
9
+ isRealBunBinary?: (path: string) => boolean;
10
+ spawnSync?: (path: string, args: string[], options: {
11
+ env: NodeJS.ProcessEnv;
12
+ encoding: "utf8";
13
+ timeout: number;
14
+ maxBuffer: number;
15
+ killSignal: "SIGKILL";
16
+ shell: false;
17
+ windowsHide: true;
18
+ stdio: ["ignore", "pipe", "pipe"];
19
+ }) => { status: number | null; stdout?: string; signal?: string | null; error?: unknown };
20
+ }
21
+ export declare function findPathBun(options: {
22
+ env?: NodeJS.ProcessEnv;
23
+ platform?: NodeJS.Platform;
24
+ pinnedVersion: string;
25
+ deadlineMs?: number;
26
+ io?: PathBunIo;
27
+ }): { path: string; version: string } | null;
28
+ export declare function findDesktopCli(options?: {
29
+ platform?: NodeJS.Platform;
30
+ home?: string;
31
+ io?: DesktopCliIo;
32
+ }): string | null;
@@ -0,0 +1,95 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { accessSync, constants, realpathSync, statSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { posix, win32 } from "node:path";
5
+ import { performance } from "node:perf_hooks";
6
+ import { isRealBunBinary } from "./bun-binary-validator.mjs";
7
+
8
+ const STABLE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
9
+ const MAX_VERSION_BYTES = 4096;
10
+ const IDENTITY_PROBE = "process.stdout.write(String(typeof Bun==='object'&&Bun.version))";
11
+
12
+ function stableVersion(value) {
13
+ if (typeof value !== "string" || value.length > 64) return null;
14
+ const match = STABLE.exec(value);
15
+ if (!match) return null;
16
+ const numbers = match.slice(1, 4).map(Number);
17
+ return numbers.every(Number.isSafeInteger) ? numbers : null;
18
+ }
19
+
20
+ /** Discover the first absolute PATH Bun passing version-policy and identity checks. */
21
+ export function findPathBun({
22
+ env = process.env, platform = process.platform, pinnedVersion,
23
+ deadlineMs = 750, io = {},
24
+ }) {
25
+ const pin = stableVersion(pinnedVersion);
26
+ if (!pin || !Number.isFinite(deadlineMs) || deadlineMs <= 0) return null;
27
+ const paths = platform === "win32" ? win32 : posix;
28
+ const absolute = value => paths.isAbsolute(value)
29
+ && (platform !== "win32" || /^(?:[A-Za-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+)/.test(value));
30
+ const now = io.now ?? (() => performance.now());
31
+ const end = now() + deadlineMs;
32
+ const realpath = io.realpath ?? realpathSync.native;
33
+ const stat = io.stat ?? statSync;
34
+ const access = io.access ?? accessSync;
35
+ const validate = io.isRealBunBinary ?? isRealBunBinary;
36
+ const spawn = io.spawnSync ?? spawnSync;
37
+ const key = platform === "win32"
38
+ ? Object.keys(env).find(name => name.toLowerCase() === "path") : "PATH";
39
+ const directories = (env[key ?? "PATH"] ?? "").split(platform === "win32" ? ";" : ":");
40
+ const seen = new Set();
41
+ const probe = (path, args) => {
42
+ const remaining = Math.floor(end - now());
43
+ if (remaining <= 0) return null;
44
+ const result = spawn(path, args, {
45
+ env, encoding: "utf8", timeout: remaining, maxBuffer: MAX_VERSION_BYTES,
46
+ killSignal: "SIGKILL", shell: false, windowsHide: true,
47
+ stdio: ["ignore", "pipe", "pipe"],
48
+ });
49
+ if (now() >= end || result.error || result.signal || result.status !== 0
50
+ || typeof result.stdout !== "string" || result.stdout.length > MAX_VERSION_BYTES) return null;
51
+ return result.stdout.trim();
52
+ };
53
+ for (const directory of directories) {
54
+ if (now() >= end) break;
55
+ if (!directory || !absolute(directory)) continue;
56
+ try {
57
+ const path = realpath(paths.join(directory, platform === "win32" ? "bun.exe" : "bun"));
58
+ if (!absolute(path)) continue;
59
+ const identity = platform === "win32" ? path.toLowerCase() : path;
60
+ if (seen.has(identity)) continue;
61
+ seen.add(identity);
62
+ const file = stat(path);
63
+ if (!file.isFile()) continue;
64
+ if (platform !== "win32" && ((file.mode & 0o022) || (stat(paths.dirname(path)).mode & 0o022))) continue;
65
+ access(path, constants.X_OK);
66
+ if (!validate(path)) continue;
67
+ const version = probe(path, ["--version"]);
68
+ const candidate = stableVersion(version);
69
+ if (!candidate || candidate[0] !== pin[0] || candidate[1] < pin[1]) continue;
70
+ if (probe(path, ["-e", IDENTITY_PROBE]) !== version) continue;
71
+ return { path, version };
72
+ } catch {
73
+ // Unreadable, unexecutable, vanished or invalid: try the next absolute candidate.
74
+ }
75
+ }
76
+ return null;
77
+ }
78
+
79
+ /** Failure-text pointer only. Never execute or delegate to this binary. */
80
+ export function findDesktopCli({ platform = process.platform, home = homedir(), io = {} } = {}) {
81
+ if (platform !== "darwin") return null;
82
+ const stat = io.stat ?? statSync;
83
+ const access = io.access ?? accessSync;
84
+ for (const path of [
85
+ "/Applications/OpenCodex.app/Contents/MacOS/ocx",
86
+ posix.join(home, "Applications/OpenCodex.app/Contents/MacOS/ocx"),
87
+ ]) {
88
+ try {
89
+ if (!stat(path).isFile()) continue;
90
+ access(path, constants.X_OK);
91
+ return path;
92
+ } catch { /* Missing or not executable: no pointer for this candidate. */ }
93
+ }
94
+ return null;
95
+ }