@bitkyc08/opencodex 2.57.0 → 2.59.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.
- package/README.md +28 -10
- package/gui/dist/assets/index-C5IebErG.js +136 -0
- package/gui/dist/assets/{index-C5-RdDmD.css → index-OESInAjC.css} +1 -1
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/crusoe.svg +1 -0
- package/gui/dist/provider-icons/opper.svg +3 -0
- package/package.json +2 -2
- package/src/adapters/base.ts +11 -1
- package/src/adapters/codebuddy/scaffold-guard.ts +5 -4
- package/src/adapters/command-code.ts +13 -4
- package/src/adapters/cursor/catalog.ts +11 -0
- package/src/adapters/cursor/cursor-errors.ts +15 -0
- package/src/adapters/cursor/discovery.ts +65 -1
- package/src/adapters/cursor/effort-map.ts +16 -2
- package/src/adapters/cursor/envelope-echo.ts +55 -2
- package/src/adapters/cursor/live-transport.ts +5 -1
- package/src/adapters/cursor/message-mapper.ts +3 -2
- package/src/adapters/cursor/protobuf-events.ts +110 -11
- package/src/adapters/cursor/protobuf-request.ts +27 -6
- package/src/adapters/cursor/request-builder.ts +14 -3
- package/src/adapters/cursor/text-toolcall.ts +230 -0
- package/src/adapters/cursor/thread-continuity.ts +141 -0
- package/src/adapters/cursor/tool-guidance.ts +5 -4
- package/src/adapters/cursor/types.ts +5 -0
- package/src/adapters/cursor.ts +97 -6
- package/src/adapters/devin/cloud-direct/chat.ts +11 -2
- package/src/adapters/devin/cloud-direct/index.ts +7 -0
- package/src/adapters/devin/cloud-direct/stated-reset-retry.ts +103 -0
- package/src/adapters/devin.ts +75 -13
- package/src/adapters/google-antigravity-wire.ts +29 -2
- package/src/adapters/google-http.ts +45 -13
- package/src/adapters/google.ts +23 -4
- package/src/adapters/mimo-free.ts +32 -17
- package/src/adapters/ollama-native.ts +42 -8
- package/src/adapters/openai-chat/response-events.ts +61 -0
- package/src/adapters/openai-chat.ts +5 -10
- package/src/adapters/openai-responses/passthrough.ts +40 -5
- package/src/adapters/openai-responses/request-strips.ts +43 -0
- package/src/adapters/openai-responses/tool-output-recovery.ts +75 -0
- package/src/adapters/openai-responses/tool-schema.ts +19 -7
- package/src/adapters/physical-send.ts +50 -0
- package/src/adapters/responses-tool-schema.ts +76 -46
- package/src/adapters/run-turn-queue.ts +17 -4
- package/src/bridge/response-json.ts +2 -2
- package/src/bridge/sse.ts +166 -25
- package/src/claude/context-windows.ts +22 -0
- package/src/claude/outbound.ts +46 -5
- package/src/cli/account-api.ts +4 -3
- package/src/cli/account-extended.ts +22 -2
- package/src/cli/account-orca-import.ts +63 -0
- package/src/cli/account.ts +32 -4
- package/src/cli/capabilities.ts +40 -0
- package/src/cli/claude.ts +29 -1
- package/src/cli/codex-cli-update.ts +97 -2
- package/src/cli/config-command.ts +35 -18
- package/src/cli/dispatch.ts +71 -4
- package/src/cli/doctor.ts +197 -2
- package/src/cli/help.ts +4 -1
- package/src/cli/index.ts +132 -22
- package/src/cli/models-runtime.ts +33 -4
- package/src/cli/registry.ts +11 -1
- package/src/cli/runtime-api.ts +44 -0
- package/src/cli/start-args.ts +94 -0
- package/src/cli/system-command.ts +72 -1
- package/src/cli/uninstall-client-state.ts +12 -0
- package/src/client/machine-api.ts +4 -3
- package/src/client/machine-listener.ts +14 -1
- package/src/clients/config-export/constants.ts +2 -3
- package/src/clients/config-export.ts +5 -5
- package/src/codex/account-store.ts +81 -5
- package/src/codex/auth-api/pool-quota-probe.ts +14 -3
- package/src/codex/auth-api/routes.ts +17 -2
- package/src/codex/auth-context.ts +58 -20
- package/src/codex/catalog/build-entries.ts +25 -4
- package/src/codex/catalog/derive-entry.ts +8 -1
- package/src/codex/catalog/effort.ts +10 -6
- package/src/codex/catalog/gather-capture.ts +1 -0
- package/src/codex/catalog/model-hints.ts +37 -5
- package/src/codex/catalog/parsing.ts +83 -5
- package/src/codex/catalog/reserve-warn.ts +96 -0
- package/src/codex/catalog/retained-sync.ts +19 -0
- package/src/codex/catalog/routed-gather.ts +42 -3
- package/src/codex/cli-installation-identity.ts +210 -0
- package/src/codex/cli-installation-targets.ts +158 -0
- package/src/codex/convergence.ts +5 -0
- package/src/codex/desktop-switches.ts +145 -0
- package/src/codex/history-job.ts +5 -1
- package/src/codex/history-provider.ts +37 -5
- package/src/codex/history-state-open.ts +105 -0
- package/src/codex/history-worker.ts +14 -1
- package/src/codex/inject/config-toml.ts +44 -2
- package/src/codex/inject/remove.ts +145 -7
- package/src/codex/inject/restore.ts +204 -32
- package/src/codex/inject.ts +6 -9
- package/src/codex/lineage.ts +83 -32
- package/src/codex/loopback-target.ts +40 -0
- package/src/codex/main-account-hard-lock.ts +2 -1
- package/src/codex/main-account.ts +10 -3
- package/src/codex/main-device-reauth.ts +17 -9
- package/src/codex/model-entitlements.ts +60 -1
- package/src/codex/native-profile-startup.ts +64 -20
- package/src/codex/observed-model-denials.ts +137 -0
- package/src/codex/orca-auth-source.ts +94 -0
- package/src/codex/orca-import.ts +219 -0
- package/src/codex/prompt-text-probe.ts +282 -12
- package/src/codex/quota-401-recovery.ts +12 -0
- package/src/codex/quota-types.ts +65 -0
- package/src/codex/quota.ts +24 -19
- package/src/codex/routing/cooldown-math.ts +8 -47
- package/src/codex/routing/pin-drain.ts +57 -0
- package/src/codex/routing.ts +13 -15
- package/src/codex/subagent-model-fallback.ts +94 -0
- package/src/codex/windows-installation-files.ts +224 -0
- package/src/combos/failover.ts +122 -5
- package/src/config/atomic-write.ts +83 -8
- package/src/config/diagnostics.ts +21 -0
- package/src/config/load-degrade.ts +15 -0
- package/src/config/pending-teardown.ts +8 -0
- package/src/config/process-state.ts +36 -3
- package/src/config/provider-relative-send-path.ts +16 -0
- package/src/config/proxy-env.ts +23 -5
- package/src/config/schema/config-schema.ts +23 -0
- package/src/config/schema/leaf-validators.ts +65 -17
- package/src/generated/compatibility-version.json +337 -201
- package/src/generated/model-metadata.ts +1 -1
- package/src/lib/bounded-body.ts +4 -2
- package/src/lib/bounded-subprocess.ts +62 -10
- package/src/lib/destination-policy.ts +48 -6
- package/src/lib/errors.ts +3 -15
- package/src/lib/local-destinations.ts +32 -5
- package/src/lib/provider-outbound.ts +3 -3
- package/src/lib/proxy-env.ts +70 -3
- package/src/lib/request-execution-budget.ts +11 -3
- package/src/lib/response-body-inactivity.ts +193 -0
- package/src/lib/retry-delay.ts +69 -0
- package/src/lib/socks5-fetch.ts +631 -0
- package/src/lib/spend-reservation-ledger.ts +115 -9
- package/src/lib/windows-secret-acl.ts +151 -15
- package/src/lib/windows-user-principal.ts +5 -1
- package/src/lib/workflow-budget.ts +145 -8
- package/src/oauth/account-quota-rank.ts +72 -15
- package/src/oauth/generic-account-failover.ts +40 -27
- package/src/oauth/orcarouter.ts +15 -2
- package/src/oauth/store.ts +8 -0
- package/src/providers/codex-capacity.ts +9 -0
- package/src/providers/derive.ts +6 -0
- package/src/providers/devin-provider-merge-migration.ts +33 -12
- package/src/providers/free-directory.ts +20 -2
- package/src/providers/key-failover.ts +261 -7
- package/src/providers/model-discovery.ts +19 -7
- package/src/providers/model-rename-migration.ts +1 -0
- package/src/providers/openai-sidecar.ts +4 -0
- package/src/providers/opencode-go-transport.ts +14 -5
- package/src/providers/quota/report-cache.ts +3 -0
- package/src/providers/registry/entries-core.ts +11 -0
- package/src/providers/registry/entries-extended.ts +146 -28
- package/src/providers/registry/model-seeds.ts +136 -29
- package/src/providers/registry/types.ts +9 -0
- package/src/responses/apply-patch-envelope.ts +44 -11
- package/src/responses/bridge-search-replay-cache.ts +152 -0
- package/src/responses/code-mode-helper-compat.ts +26 -16
- package/src/responses/custom-tool-compat.ts +1 -1
- package/src/responses/hosted-tool-policy.ts +85 -2
- package/src/responses/schema.ts +9 -2
- package/src/responses/spill-store.ts +17 -0
- package/src/responses/state/body-policy.ts +25 -0
- package/src/responses/state/spill-queue.ts +8 -6
- package/src/responses/state.ts +3 -22
- package/src/router.ts +4 -0
- package/src/server/auth-cors.ts +27 -0
- package/src/server/chat-completions.ts +9 -4
- package/src/server/chat-native-sse.ts +26 -9
- package/src/server/chat-native.ts +10 -4
- package/src/server/claude-messages.ts +24 -2
- package/src/server/gui-static.ts +36 -2
- package/src/server/inbound-body-admission.ts +187 -0
- package/src/server/index/websocket-handler.ts +48 -1
- package/src/server/index.ts +15 -19
- package/src/server/management/api-access.ts +3 -4
- package/src/server/management/config-routes.ts +57 -10
- package/src/server/management/provider-capability-config.ts +35 -7
- package/src/server/management/provider-routes.ts +70 -18
- package/src/server/models-capabilities.ts +24 -3
- package/src/server/proxy-liveness.ts +97 -2
- package/src/server/relay.ts +17 -24
- package/src/server/request-log.ts +25 -1
- package/src/server/responses/adapter-continuation.ts +71 -27
- package/src/server/responses/adapter-delivery.ts +39 -8
- package/src/server/responses/adapter-dispatch.ts +52 -24
- package/src/server/responses/codex-ws-exchange.ts +65 -4
- package/src/server/responses/combo-stream-preflight.ts +68 -5
- package/src/server/responses/compact.ts +60 -11
- package/src/server/responses/core-codex-account.ts +83 -22
- package/src/server/responses/core-combo.ts +26 -0
- package/src/server/responses/core-normalize.ts +12 -5
- package/src/server/responses/core-options.ts +3 -0
- package/src/server/responses/fetch-helpers.ts +72 -3
- package/src/server/responses/native-injection-protocol.ts +42 -0
- package/src/server/responses/native-injection-replay.ts +105 -0
- package/src/server/responses/native-injection.ts +242 -0
- package/src/server/responses/native-response-control.ts +56 -0
- package/src/server/responses/native-response-json.ts +14 -0
- package/src/server/responses/native-response-output.ts +37 -0
- package/src/server/responses/native-steering-log.ts +44 -0
- package/src/server/responses/native-steering-policy.ts +49 -0
- package/src/server/responses/native-steering-replay.ts +126 -0
- package/src/server/responses/native-steering-settings.ts +76 -0
- package/src/server/responses/native-steering.ts +400 -0
- package/src/server/responses/native-tool-results.ts +130 -0
- package/src/server/responses/passthrough-delivery.ts +21 -1
- package/src/server/responses/passthrough-dispatch.ts +146 -49
- package/src/server/responses/passthrough-execution.ts +11 -1
- package/src/server/responses/request-prepare.ts +70 -0
- package/src/server/responses/request-send-budget.ts +84 -7
- package/src/server/responses/request-sidecar-auth.ts +16 -8
- package/src/server/responses/request-spend.ts +38 -9
- package/src/server/responses/request-transport.ts +13 -10
- package/src/server/responses/run-turn-execution.ts +20 -5
- package/src/server/responses/sidecar-execution.ts +2 -0
- package/src/server/responses/ws-upstream.ts +23 -2
- package/src/server/responses-custom-tool-repair.ts +2 -2
- package/src/server/sse-frame-buffer.ts +12 -10
- package/src/server/sse-payload-rewrite.ts +36 -9
- package/src/server/stop-teardown.ts +8 -1
- package/src/server/system-env-shell.ts +5 -1
- package/src/server/system-env.ts +7 -1
- package/src/server/workflow-refusal.ts +56 -2
- package/src/server/ws-bridge.ts +16 -1
- package/src/service/cli.ts +29 -7
- package/src/service/guards.ts +10 -0
- package/src/service/health.ts +43 -0
- package/src/service/state.ts +7 -2
- package/src/types/accounts.ts +4 -0
- package/src/types/config.ts +104 -3
- package/src/types/provider.ts +32 -0
- package/src/types/request.ts +7 -1
- package/src/types/wire.ts +9 -1
- package/src/usage/expected-prices.ts +28 -0
- package/src/usage/log.ts +87 -4
- package/src/web-search/passthrough-bridge.ts +39 -5
- package/gui/dist/assets/index-Cz7CLdif.js +0 -128
|
@@ -49,7 +49,7 @@ const DATA: Record<string, readonly Row[]> = {
|
|
|
49
49
|
"moonshot": [["kimi-k2.5",262144,65536,"text,image",1,null,0,0,0,0]],
|
|
50
50
|
"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-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]],
|
|
51
51
|
"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]],
|
|
52
|
-
"opencode-go": [["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],["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],["hy3",256000,64000,"text",1,null,0.14,0.58,0.035,0],["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],["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],["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],["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]],
|
|
52
|
+
"opencode-go": [["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],["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],["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]],
|
|
53
53
|
"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-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-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],["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-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-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],["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]],
|
|
54
54
|
"xai": [["grok-2",131072,8192,"text",0,null,2,10,2,0],["grok-2-1212",131072,8192,"text",0,null,2,10,2,0],["grok-2-latest",131072,8192,"text",0,null,2,10,2,0],["grok-2-vision",8192,4096,"text,image",0,null,2,10,2,0],["grok-2-vision-1212",8192,4096,"text,image",0,null,2,10,2,0],["grok-2-vision-latest",8192,4096,"text,image",0,null,2,10,2,0],["grok-3",131072,8192,"text",0,null,3,15,0.75,0],["grok-3-fast",131072,8192,"text",0,null,5,25,1.25,0],["grok-3-fast-latest",131072,8192,"text",0,null,5,25,1.25,0],["grok-3-latest",131072,8192,"text",0,null,3,15,0.75,0],["grok-3-mini",131072,8192,"text",1,null,0.3,0.5,0.075,0],["grok-3-mini-fast",131072,8192,"text",1,null,0.6,4,0.15,0],["grok-3-mini-fast-latest",131072,8192,"text",1,null,0.6,4,0.15,0],["grok-3-mini-latest",131072,8192,"text",1,null,0.3,0.5,0.075,0],["grok-4",256000,64000,"text",1,null,3,15,0.75,0],["grok-4-1-fast",2000000,30000,"text,image",1,null,0.2,0.5,0.05,0],["grok-4-1-fast-non-reasoning",2000000,30000,"text,image",0,null,0.2,0.5,0.05,0],["grok-4-fast",2000000,30000,"text,image",1,null,0.2,0.5,0.05,0],["grok-4-fast-non-reasoning",2000000,30000,"text,image",0,null,0.2,0.5,0.05,0],["grok-4.20-0309-non-reasoning",1000000,30000,"text,image",0,null,1.25,2.5,0.2,0],["grok-4.20-0309-reasoning",1000000,30000,"text,image",1,null,1.25,2.5,0.2,0],["grok-4.20-beta-latest-non-reasoning",2000000,30000,"text,image",0,null,2,6,0.2,0],["grok-4.20-beta-latest-reasoning",2000000,30000,"text,image",1,null,2,6,0.2,0],["grok-4.20-multi-agent-0309",1000000,30000,"text,image",1,null,1.25,2.5,0.2,0],["grok-4.20-multi-agent-beta-latest",2000000,30000,"text,image",1,null,2,6,0.2,0],["grok-4.3",1000000,30000,"text,image",1,null,1.25,2.5,0.2,0],["grok-4.5",500000,500000,"text,image",1,null,2,6,0.3,0],["grok-4.6",500000,500000,"text,image",1,null,2,6,0.3,0],["grok-beta",131072,4096,"text",0,null,5,15,5,0],["grok-build-0.1",256000,256000,"text,image",1,null,1,2,0.2,0],["grok-code-fast-1",256000,10000,"text",1,null,0.2,1.5,0.02,0],["grok-composer-2.5-fast",200000,64000,"text",1,null,0,0,0,0],["grok-vision-beta",8192,4096,"text,image",0,null,5,15,5,0]],
|
|
55
55
|
"xiaomi": [["mimo-v2-flash",262144,65536,"text",1,null,0.14,0.28,0.0028,0],["mimo-v2-omni",262144,131072,"text,image",1,null,0.14,0.28,0.0028,0],["mimo-v2-pro",1048576,131072,"text",1,null,0.435,0.87,0.0036,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,0.435,0.87,0.0036,0],["mimo-v2.5-pro-ultraspeed",1048576,131072,"text",1,null,1.305,2.61,0.0108,0]],
|
package/src/lib/bounded-body.ts
CHANGED
|
@@ -129,9 +129,11 @@ export async function readBoundedResponseBytes(
|
|
|
129
129
|
options: BoundedBytesOptions,
|
|
130
130
|
): Promise<BoundedBytesResult> {
|
|
131
131
|
const signal = options.signal;
|
|
132
|
-
if (signal?.aborted) throw signal.reason;
|
|
133
|
-
|
|
134
132
|
const body = response.body;
|
|
133
|
+
if (signal?.aborted) {
|
|
134
|
+
if (body) cancelBodyWithoutWaiting(body, signal.reason);
|
|
135
|
+
throw signal.reason;
|
|
136
|
+
}
|
|
135
137
|
if (!body) return { bytes: new Uint8Array(0), oversized: false };
|
|
136
138
|
|
|
137
139
|
const reader = body.getReader();
|
|
@@ -9,28 +9,80 @@ export interface BoundedSubprocessExit {
|
|
|
9
9
|
timedOut: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
export type SubprocessDeadlineScheduler = (
|
|
13
|
+
callback: () => void,
|
|
14
|
+
milliseconds: number,
|
|
15
|
+
) => () => void;
|
|
16
|
+
|
|
17
|
+
const scheduleDeadline: SubprocessDeadlineScheduler = (callback, milliseconds) => {
|
|
18
|
+
const timer = setTimeout(callback, milliseconds);
|
|
19
|
+
return () => clearTimeout(timer);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Compatibility allowance used by the ACL runner's outer watchdog.
|
|
24
|
+
*
|
|
25
|
+
* `kill()` only REQUESTS termination. It returns before the kernel has torn the process down, and
|
|
26
|
+
* every handle that process holds stays held until it does. On Windows that is not a detail: file
|
|
27
|
+
* locking is mandatory, so a directory an abandoned `icacls.exe` still has open cannot be removed
|
|
28
|
+
* by anyone, and the removal fails with EPERM rather than waiting.
|
|
29
|
+
*/
|
|
30
|
+
export const SUBPROCESS_KILL_GRACE_MS = 2_000;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Wait for a child until the deadline. At the deadline, kill it AND wait for it to actually die.
|
|
34
|
+
*
|
|
35
|
+
* This used to kill, `unref`, and resolve in the same tick, which made every caller's "I waited
|
|
36
|
+
* for my child" guarantee false precisely when it mattered. The ACL runner now waits here until
|
|
37
|
+
* actual exit; if its separate caller-facing belt fires first, that layer registers the target so
|
|
38
|
+
* removal can wait for the reap without making ordinary startup or shutdown unbounded.
|
|
39
|
+
*
|
|
40
|
+
* That cost three failed fixes. #4789 blamed the removal retry budget and asked for more than
|
|
41
|
+
* 2.5s; #4796 gave it a 15s exponential schedule; a later change awaited the hardening flight from
|
|
42
|
+
* the test hook. Windows shard 1/6 failed identically through all three, because none of them
|
|
43
|
+
* addressed a live process holding the handle -- run 35108652486 burned the full 15s budget and
|
|
44
|
+
* still threw `EPERM ... rm ocx-management-auth-fDchUb`, with two
|
|
45
|
+
* `ACL hardening timed out (ETIMEDOUT) - transient icacls stall` lines logged beside it.
|
|
46
|
+
*
|
|
47
|
+
* The old grace still abandoned a live child after two seconds. That recreated the same false
|
|
48
|
+
* ownership contract on a slower clock: the ACL flight settled, cleanup removed the directory,
|
|
49
|
+
* and Windows returned EPERM because the child still held it. A handle-bearing caller therefore
|
|
50
|
+
* has no second deadline after kill. The child's actual exit is the only release signal.
|
|
51
|
+
*
|
|
52
|
+
* Pass `0` to opt out for a child that holds no path anyone will remove. The numeric form is kept
|
|
53
|
+
* for compatibility with the existing callers; any positive value means that reaping is required.
|
|
54
|
+
* The injected scheduler is a test seam so deadline and exit ordering can be proved without sleep.
|
|
55
|
+
*/
|
|
13
56
|
export function waitForSubprocessExit(
|
|
14
57
|
proc: KillableSubprocess,
|
|
15
58
|
timeoutMs: number,
|
|
59
|
+
reapAfterKill: number = SUBPROCESS_KILL_GRACE_MS,
|
|
60
|
+
schedule: SubprocessDeadlineScheduler = scheduleDeadline,
|
|
16
61
|
): Promise<BoundedSubprocessExit> {
|
|
17
62
|
return new Promise(resolve => {
|
|
18
63
|
let settled = false;
|
|
19
|
-
let
|
|
64
|
+
let deadlineFired = false;
|
|
65
|
+
let cancelDeadline: (() => void) | undefined;
|
|
20
66
|
const finish = (result: BoundedSubprocessExit): void => {
|
|
21
67
|
if (settled) return;
|
|
22
68
|
settled = true;
|
|
23
|
-
|
|
69
|
+
cancelDeadline?.();
|
|
24
70
|
resolve(result);
|
|
25
71
|
};
|
|
26
|
-
|
|
72
|
+
const reaped = proc.exited.then(
|
|
73
|
+
exitCode => finish(deadlineFired
|
|
74
|
+
? { exitCode: null, timedOut: true }
|
|
75
|
+
: { exitCode, timedOut: false }),
|
|
76
|
+
() => finish({ exitCode: null, timedOut: deadlineFired }),
|
|
77
|
+
);
|
|
78
|
+
cancelDeadline = schedule(() => {
|
|
79
|
+
deadlineFired = true;
|
|
27
80
|
try { proc.kill(); } catch { /* already exited */ }
|
|
28
|
-
|
|
29
|
-
|
|
81
|
+
if (reapAfterKill <= 0) {
|
|
82
|
+
try { proc.unref?.(); } catch { /* abandonment is still authoritative */ }
|
|
83
|
+
finish({ exitCode: null, timedOut: true });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
30
86
|
}, Math.max(1, timeoutMs));
|
|
31
|
-
void proc.exited.then(
|
|
32
|
-
exitCode => finish({ exitCode, timedOut: false }),
|
|
33
|
-
() => finish({ exitCode: null, timedOut: false }),
|
|
34
|
-
);
|
|
35
87
|
});
|
|
36
88
|
}
|
|
@@ -240,6 +240,43 @@ function registryAllowsPrivateNetwork(name: string): boolean {
|
|
|
240
240
|
return getProviderRegistryEntry(name)?.allowPrivateNetworkByDefault === true;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
function normalizedCanonicalEndpoint(value: string): string | null {
|
|
244
|
+
try {
|
|
245
|
+
const parsed = new URL(value.trim());
|
|
246
|
+
if (parsed.username || parsed.password || parsed.hash) return null;
|
|
247
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, "") || "/";
|
|
248
|
+
return parsed.toString().replace(/\/$/, "");
|
|
249
|
+
} catch {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Config-time Fake-IP allowance for the one overridable OAuth provider whose canonical
|
|
256
|
+
* Google endpoint is known to sit behind Clash/Mihomo transparent DNS in the field.
|
|
257
|
+
*
|
|
258
|
+
* Antigravity permits a custom base URL, so provider identity alone is not authority:
|
|
259
|
+
* adapter, auth mode, and the normalized final base URL must still match the registry seed.
|
|
260
|
+
* Custom destinations therefore keep the ordinary fail-closed SSRF policy.
|
|
261
|
+
*/
|
|
262
|
+
function registryAllowsBenchmarkDnsAtWriteTime(
|
|
263
|
+
name: string,
|
|
264
|
+
provider: Pick<OcxProviderConfig, "baseUrl"> & Partial<Pick<OcxProviderConfig, "adapter" | "authMode">>,
|
|
265
|
+
): boolean {
|
|
266
|
+
if (name !== "google-antigravity") return false;
|
|
267
|
+
const entry = getProviderRegistryEntry(name);
|
|
268
|
+
if (
|
|
269
|
+
!entry
|
|
270
|
+
|| entry.authKind !== "oauth"
|
|
271
|
+
|| entry.allowBaseUrlOverride !== true
|
|
272
|
+
|| provider.adapter !== entry.adapter
|
|
273
|
+
|| provider.authMode !== "oauth"
|
|
274
|
+
) return false;
|
|
275
|
+
const configured = normalizedCanonicalEndpoint(provider.baseUrl);
|
|
276
|
+
const canonical = normalizedCanonicalEndpoint(entry.baseUrl);
|
|
277
|
+
return configured !== null && configured === canonical;
|
|
278
|
+
}
|
|
279
|
+
|
|
243
280
|
/**
|
|
244
281
|
* OAuth registry entries that opt into `allowBaseUrlOverride` send bearer credentials to a
|
|
245
282
|
* user-configured endpoint (review findings, PR #2109 / PR #2110): a cleartext `http:`
|
|
@@ -328,13 +365,16 @@ export function assertProviderDestinationAllowed(name: string, provider: Pick<Oc
|
|
|
328
365
|
* advisory and must not hard-fail offline startups. DNS rebinding after validation is
|
|
329
366
|
* a recorded residual for this loopback proxy (devlog 260712_pr_batch_landing 000).
|
|
330
367
|
*
|
|
331
|
-
* `allowBenchmarkAddresses`
|
|
332
|
-
*
|
|
333
|
-
*
|
|
368
|
+
* `allowBenchmarkAddresses` remains the explicit caller opt-in used by canonical ChatGPT
|
|
369
|
+
* Codex. Canonical Google Antigravity receives the same 198.18.0.0/15 DNS-answer exception
|
|
370
|
+
* only when its adapter/auth/base URL still match the registry seed. Every other non-public
|
|
371
|
+
* answer — including custom Antigravity destinations and mixed benchmark + private/metadata
|
|
372
|
+
* sets — still fails.
|
|
334
373
|
*/
|
|
335
374
|
export async function providerDestinationResolvedError(
|
|
336
375
|
name: string,
|
|
337
|
-
provider: Pick<OcxProviderConfig, "baseUrl" | "allowPrivateNetwork"
|
|
376
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "allowPrivateNetwork">
|
|
377
|
+
& Partial<Pick<OcxProviderConfig, "adapter" | "authMode">>,
|
|
338
378
|
options?: { allowBenchmarkAddresses?: boolean },
|
|
339
379
|
): Promise<string | null> {
|
|
340
380
|
const syncError = providerDestinationConfigError(name, provider);
|
|
@@ -349,6 +389,8 @@ export async function providerDestinationResolvedError(
|
|
|
349
389
|
return null; // literals and localhost are fully handled by the sync path
|
|
350
390
|
}
|
|
351
391
|
if (providerAllowsPrivateNetwork(name, provider)) return null;
|
|
392
|
+
const allowBenchmarkAddresses = options?.allowBenchmarkAddresses === true
|
|
393
|
+
|| registryAllowsBenchmarkDnsAtWriteTime(name, provider);
|
|
352
394
|
let addresses: { address: string }[];
|
|
353
395
|
try {
|
|
354
396
|
addresses = await lookup(hostname, { all: true, verbatim: true });
|
|
@@ -360,7 +402,7 @@ export async function providerDestinationResolvedError(
|
|
|
360
402
|
const assessment = ipKind === 4 ? classifyIpv4(address) : ipKind === 6 ? classifyIpv6(normalizeHostname(address)) : null;
|
|
361
403
|
if (!assessment || assessment.kind === "public") continue;
|
|
362
404
|
// Clash fake-IP only: 198.18/19 benchmark detail. Mixed dangerous sets still reject.
|
|
363
|
-
if (
|
|
405
|
+
if (allowBenchmarkAddresses && isBenchmarkDnsAnswer(address, assessment)) {
|
|
364
406
|
continue;
|
|
365
407
|
}
|
|
366
408
|
if (assessment.kind === "metadata") return `baseUrl hostname ${hostname} resolves to a blocked metadata endpoint (${address})`;
|
|
@@ -492,4 +534,4 @@ export async function resolvePublicAddresses(
|
|
|
492
534
|
*/
|
|
493
535
|
export async function assertUrlResolvesPublic(url: string): Promise<void> {
|
|
494
536
|
await resolvePublicAddresses(url);
|
|
495
|
-
}
|
|
537
|
+
}
|
package/src/lib/errors.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { parseRetryAfterFromMessage } from "./retry-delay";
|
|
2
|
+
|
|
1
3
|
export interface OcxErrorPayload {
|
|
2
4
|
message: string;
|
|
3
5
|
type: string;
|
|
@@ -376,21 +378,7 @@ export function isRateLimitOrQuotaFailureMessage(message: string): boolean {
|
|
|
376
378
|
return normalized.toLowerCase().includes("usage limit");
|
|
377
379
|
}
|
|
378
380
|
|
|
379
|
-
|
|
380
|
-
export function parseRetryAfterFromMessage(message: string): number | undefined {
|
|
381
|
-
const patterns = [
|
|
382
|
-
/try again in (\d+(?:\.\d+)?)\s*s(?:ec(?:ond)?s?)?/i,
|
|
383
|
-
/retry after (\d+(?:\.\d+)?)\s*s(?:ec(?:ond)?s?)?/i,
|
|
384
|
-
/retry[- ]after[:\s]+(\d+)/i,
|
|
385
|
-
];
|
|
386
|
-
for (const pattern of patterns) {
|
|
387
|
-
const match = message.match(pattern);
|
|
388
|
-
if (!match?.[1]) continue;
|
|
389
|
-
const seconds = Number.parseFloat(match[1]);
|
|
390
|
-
if (Number.isFinite(seconds) && seconds > 0) return Math.ceil(seconds);
|
|
391
|
-
}
|
|
392
|
-
return undefined;
|
|
393
|
-
}
|
|
381
|
+
export { parseRetryAfterFromMessage };
|
|
394
382
|
|
|
395
383
|
/** Infer HTTP status from adapter terminal error text (provider-agnostic keyword matching). */
|
|
396
384
|
export function inferHttpStatusFromAdapterMessage(message: string): number {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* loopback listener enabled → `127.0.0.1:<effective listener port>`, no credential
|
|
22
22
|
* loopback/absent `hostname` → `127.0.0.1:<public port>`, no credential
|
|
23
23
|
* wildcard `hostname` → `127.0.0.1:<public port>`, ADMISSION CREDENTIAL REQUIRED
|
|
24
|
-
*
|
|
24
|
+
* literal non-loopback IP → `<probeHostname(hostname)>:<public port>`, credential REQUIRED
|
|
25
|
+
* DNS bind name → `127.0.0.1:<public port>`, credential REQUIRED (fail closed)
|
|
25
26
|
*
|
|
26
27
|
* A wildcard bind does answer on 127.0.0.1, which is why its origin stays loopback, but the
|
|
27
28
|
* public listener demands data-plane admission regardless of which address received the
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
* token: no exported client configuration may carry management authority (reviewer constraint
|
|
37
38
|
* on #4236).
|
|
38
39
|
*/
|
|
40
|
+
import { isIP } from "node:net";
|
|
39
41
|
import { effectiveLoopbackListenerPort, isLoopbackHostname, isWildcardHostname, shouldInjectApiAuthHeader } from "../codex/loopback-target";
|
|
40
42
|
import { probeHostname } from "../server/proxy-liveness";
|
|
41
43
|
import { loadServiceTokenFromFile, serviceApiTokenFilePath } from "./service-secrets";
|
|
@@ -59,6 +61,31 @@ export interface LocalInferenceDestination {
|
|
|
59
61
|
requiresAdmissionToken: boolean;
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Turn a bind setting into an address that is safe to combine with local credentials.
|
|
66
|
+
*
|
|
67
|
+
* Bun resolves a DNS bind name when the listener starts, but a later client lookup can receive
|
|
68
|
+
* a different answer. Local integrations therefore use only literal addresses; a DNS bind falls
|
|
69
|
+
* back to loopback and fails closed when the listener does not answer there. Operators who need
|
|
70
|
+
* local integrations on a DNS-bound listener can enable the dedicated loopback listener.
|
|
71
|
+
*
|
|
72
|
+
* `localhost` is deliberately NOT treated as a DNS bind here, even though it is a name. It is
|
|
73
|
+
* reserved to loopback by RFC 6761, so a second lookup cannot select a peer off this machine —
|
|
74
|
+
* the thing this function exists to prevent. Rewriting it to `127.0.0.1` would buy no safety and
|
|
75
|
+
* would change what every existing loopback install writes into its exported client
|
|
76
|
+
* configuration, which is a contract `tests/claude-integration/claude-cli.test.ts` pins.
|
|
77
|
+
* `isLoopbackHostname` is the existing encoding of "this name is loopback", so the two stay in
|
|
78
|
+
* agreement by construction rather than by a second list.
|
|
79
|
+
*/
|
|
80
|
+
export function localCredentialDestinationHostname(hostname: string | undefined): string {
|
|
81
|
+
const probed = probeHostname(hostname);
|
|
82
|
+
if (isLoopbackHostname(probed)) return probed;
|
|
83
|
+
const literal = probed.startsWith("[") && probed.endsWith("]")
|
|
84
|
+
? probed.slice(1, -1)
|
|
85
|
+
: probed;
|
|
86
|
+
return isIP(literal) !== 0 ? probed : "127.0.0.1";
|
|
87
|
+
}
|
|
88
|
+
|
|
62
89
|
/**
|
|
63
90
|
* The one answer for "where does a local client send inference, and does it need a key?".
|
|
64
91
|
*
|
|
@@ -85,7 +112,7 @@ export function localInferenceDestination(
|
|
|
85
112
|
// literal; `shouldInjectApiAuthHeader` is the existing encoding of "this bind demands a
|
|
86
113
|
// data-plane credential", so the two stay in agreement by construction.
|
|
87
114
|
return {
|
|
88
|
-
origin: `http://${
|
|
115
|
+
origin: `http://${localCredentialDestinationHostname(hostname)}:${publicPort}`,
|
|
89
116
|
port: publicPort,
|
|
90
117
|
requiresAdmissionToken: shouldInjectApiAuthHeader(config),
|
|
91
118
|
};
|
|
@@ -146,8 +173,8 @@ const ADMISSION_TOKEN_SHAPE = /^[A-Za-z0-9._~+/=-]{8,4096}$/;
|
|
|
146
173
|
*
|
|
147
174
|
* A hub's management ingress is loopback-only and exists precisely so the operator's own
|
|
148
175
|
* machine has a management address when the proxy listener is bound elsewhere. Everything else
|
|
149
|
-
* keeps dialing
|
|
150
|
-
*
|
|
176
|
+
* keeps dialing a literal public bind address it can actually reach. DNS bind names fail closed
|
|
177
|
+
* to loopback because resolving them again could select a different peer after startup.
|
|
151
178
|
*
|
|
152
179
|
* The caller still supplies the management credential. Never write that credential into an
|
|
153
180
|
* exported client configuration.
|
|
@@ -158,5 +185,5 @@ export function localManagementOrigin(
|
|
|
158
185
|
): string {
|
|
159
186
|
const ingress = config?.runtimeRole === "hub" ? config.hub?.managementIngress : undefined;
|
|
160
187
|
if (ingress?.enabled) return `http://127.0.0.1:${ingress.port}`;
|
|
161
|
-
return `http://${
|
|
188
|
+
return `http://${localCredentialDestinationHostname(config?.hostname)}:${publicPort}`;
|
|
162
189
|
}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
resolvePublicAddresses,
|
|
8
8
|
} from "./destination-policy";
|
|
9
9
|
import { pinnedHttpGet, pinnedHttpPost } from "./pinned-http";
|
|
10
|
-
import { effectiveProxyFor, noProxyMatches, normalizeProxyHostname, outboundProxyConfigured } from "./proxy-env";
|
|
10
|
+
import { configuredOutboundFetch, effectiveProxyFor, noProxyMatches, normalizeProxyHostname, outboundProxyConfigured } from "./proxy-env";
|
|
11
11
|
import { publicProviderBaseUrl } from "./provider-url";
|
|
12
12
|
|
|
13
13
|
type ProviderGetInit = Omit<RequestInit, "body" | "method" | "redirect">;
|
|
@@ -184,7 +184,7 @@ async function providerOutboundRequest(
|
|
|
184
184
|
if (!proxyConfigured) throw error;
|
|
185
185
|
warnProxyBoundaryOnce();
|
|
186
186
|
warnProxyDnsDegradationOnce();
|
|
187
|
-
return
|
|
187
|
+
return configuredOutboundFetch(url, { ...init, method, redirect: "manual" });
|
|
188
188
|
}
|
|
189
189
|
// A canonical TUN exception with no scheme-matched proxy must retain the
|
|
190
190
|
// validated address, even when an unrelated HTTP_PROXY/ALL_PROXY is present.
|
|
@@ -193,7 +193,7 @@ async function providerOutboundRequest(
|
|
|
193
193
|
// When the Mihomo exception could have admitted an answer, pin the transport to the
|
|
194
194
|
// proxy the admission assumed instead of letting fetch re-infer it from the environment.
|
|
195
195
|
const proxy = (allowMihomoIpv6FakeIp && effectiveProxy) ? effectiveProxy : undefined;
|
|
196
|
-
return
|
|
196
|
+
return configuredOutboundFetch(url, { ...init, method, redirect: "manual", ...(proxy ? { proxy } : {}) });
|
|
197
197
|
}
|
|
198
198
|
if (proxyConfigured && resolved.privateNetwork && !noProxyMatches(parsed)) {
|
|
199
199
|
const hostname = normalizeProxyHostname(parsed.hostname);
|
package/src/lib/proxy-env.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { socks5Fetch } from "./socks5-fetch";
|
|
2
|
+
|
|
1
3
|
export const OUTBOUND_PROXY_ENV_KEYS = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"] as const;
|
|
2
4
|
export const PROXY_ENV_KEYS = [...OUTBOUND_PROXY_ENV_KEYS, "NO_PROXY"] as const;
|
|
3
5
|
|
|
@@ -85,11 +87,11 @@ export function outboundProxyConfigured(
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
/**
|
|
88
|
-
* The proxy URL
|
|
90
|
+
* The proxy URL selected by configured outbound fetch for `url`, or null when none applies.
|
|
89
91
|
*
|
|
90
92
|
* Bun selects by scheme: `HTTPS_PROXY` for `https:` targets, `HTTP_PROXY` for `http:`.
|
|
91
|
-
* `ALL_PROXY` is
|
|
92
|
-
*
|
|
93
|
+
* A SOCKS5 `ALL_PROXY` is selected by the explicit wrapper first; other ALL_PROXY
|
|
94
|
+
* schemes remain excluded because the native HTTP fetch does not honor them.
|
|
93
95
|
* Presence of *some* proxy variable (`outboundProxyConfigured`) is not that guarantee.
|
|
94
96
|
*/
|
|
95
97
|
export function effectiveProxyFor(
|
|
@@ -102,6 +104,71 @@ export function effectiveProxyFor(
|
|
|
102
104
|
? "HTTP_PROXY"
|
|
103
105
|
: null;
|
|
104
106
|
if (!key) return null;
|
|
107
|
+
// The installed SOCKS wrapper takes this route before Bun sees scheme proxies.
|
|
108
|
+
const socksProxy = socks5ProxyFromEnv(env);
|
|
109
|
+
if (socksProxy) return socksProxy;
|
|
105
110
|
const value = env[key]?.trim() || env[key.toLowerCase()]?.trim();
|
|
106
111
|
return value ? value : null;
|
|
107
112
|
}
|
|
113
|
+
|
|
114
|
+
export function isSocks5ProxyUrl(proxy: string): boolean {
|
|
115
|
+
return /^socks5h?:\/\//i.test(proxy.trim());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function socks5ProxyFromEnv(env: ProxyEnvMap = process.env): string | undefined {
|
|
119
|
+
const candidates = [env.ALL_PROXY, env.all_proxy];
|
|
120
|
+
return candidates.find(value => typeof value === "string" && isSocks5ProxyUrl(value));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function configuredOutboundFetch(
|
|
124
|
+
input: RequestInfo | URL,
|
|
125
|
+
init?: RequestInit,
|
|
126
|
+
fallback?: typeof globalThis.fetch,
|
|
127
|
+
): Promise<Response> {
|
|
128
|
+
const base = fallback ?? (globalThis.fetch === installedFetch ? nativeFetch : globalThis.fetch);
|
|
129
|
+
const explicitProxy = (init as (RequestInit & { proxy?: string }) | undefined)?.proxy;
|
|
130
|
+
const proxy = typeof explicitProxy === "string"
|
|
131
|
+
? (isSocks5ProxyUrl(explicitProxy) ? explicitProxy : undefined)
|
|
132
|
+
: socks5ProxyFromEnv();
|
|
133
|
+
let url: URL;
|
|
134
|
+
try {
|
|
135
|
+
url = new URL(input instanceof Request ? input.url : String(input));
|
|
136
|
+
} catch {
|
|
137
|
+
return base!(input, init);
|
|
138
|
+
}
|
|
139
|
+
if (proxy && (url.protocol === "http:" || url.protocol === "https:") && (explicitProxy !== undefined || !noProxyMatches(url))) {
|
|
140
|
+
return socks5Fetch(input, init, proxy);
|
|
141
|
+
}
|
|
142
|
+
return base!(input, init);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
type FetchWithPreconnect = typeof globalThis.fetch & {
|
|
146
|
+
preconnect?: typeof globalThis.fetch.preconnect;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
let nativeFetch: FetchWithPreconnect | undefined;
|
|
150
|
+
let installedFetch: FetchWithPreconnect | undefined;
|
|
151
|
+
|
|
152
|
+
export function configureSocks5Fetch(): void {
|
|
153
|
+
if (globalThis.fetch !== installedFetch) {
|
|
154
|
+
nativeFetch = globalThis.fetch as FetchWithPreconnect;
|
|
155
|
+
installedFetch = undefined;
|
|
156
|
+
}
|
|
157
|
+
const proxy = socks5ProxyFromEnv();
|
|
158
|
+
if (!proxy) {
|
|
159
|
+
if (installedFetch && globalThis.fetch === installedFetch && nativeFetch) globalThis.fetch = nativeFetch;
|
|
160
|
+
installedFetch = undefined;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (installedFetch && globalThis.fetch === installedFetch) return;
|
|
164
|
+
const base = nativeFetch ?? globalThis.fetch as FetchWithPreconnect;
|
|
165
|
+
nativeFetch = base;
|
|
166
|
+
const wrapped = Object.assign(
|
|
167
|
+
(input: RequestInfo | URL, init?: RequestInit) => {
|
|
168
|
+
return configuredOutboundFetch(input, init, base);
|
|
169
|
+
},
|
|
170
|
+
{ preconnect: base.preconnect?.bind(base) },
|
|
171
|
+
) as FetchWithPreconnect;
|
|
172
|
+
installedFetch = wrapped;
|
|
173
|
+
globalThis.fetch = wrapped;
|
|
174
|
+
}
|
|
@@ -128,8 +128,16 @@ export type DispatchDecision =
|
|
|
128
128
|
* send rather than merely describe one.
|
|
129
129
|
*/
|
|
130
130
|
export interface RequestSendObserver {
|
|
131
|
-
/**
|
|
132
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Book one physical send. False refuses the dispatch before the budget charges it.
|
|
133
|
+
*
|
|
134
|
+
* `alreadySent` marks a send that has already left, which the reporting transports below
|
|
135
|
+
* do after the fact. Its answer is not a decision -- nothing can un-send it -- and the
|
|
136
|
+
* observer must RECORD it rather than drop it. Dropping it is a fixpoint: the send that
|
|
137
|
+
* would cross a ceiling never joins the total, the total stays just under, and the ceiling
|
|
138
|
+
* never fires for any later request either.
|
|
139
|
+
*/
|
|
140
|
+
charge(options?: { alreadySent?: boolean }): boolean;
|
|
133
141
|
/** Give back a booking whose send never happened. */
|
|
134
142
|
refund(): void;
|
|
135
143
|
}
|
|
@@ -218,7 +226,7 @@ function createRequestExecutionBudgetWithLedger(
|
|
|
218
226
|
// These sends have already left. The ledger records them even past a ceiling it would
|
|
219
227
|
// have refused, because refusing after the fact only hides spend that was really
|
|
220
228
|
// incurred -- the refusal has to happen at the reservation below, or not at all.
|
|
221
|
-
for (let index = 0; index < charged; index += 1) observer?.charge();
|
|
229
|
+
for (let index = 0; index < charged; index += 1) observer?.charge({ alreadySent: true });
|
|
222
230
|
},
|
|
223
231
|
logicalRequestId: logicalRequestId ?? `lr-${Date.now().toString(36)}-${(logicalRequestSeq += 1).toString(36)}`,
|
|
224
232
|
policyVersion: REQUEST_BUDGET_POLICY_VERSION,
|