@bitkyc08/opencodex 2.63.0 → 2.64.0-preview.20260923
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/AGENTS_INSTALL.md +4 -3
- package/README.md +46 -33
- package/assets/download-linux.svg +10 -0
- package/assets/download-macos.svg +10 -0
- package/assets/download-windows.svg +10 -0
- package/bin/ocx.mjs +12 -4
- package/gui/dist/assets/App-D5eN1TID.js +50 -0
- package/gui/dist/assets/App-I5AnaSLh.css +1 -0
- package/gui/dist/assets/{Tray-CncKDBTp.js → Tray-Bh_ErQDh.js} +1 -1
- package/gui/dist/assets/index-BEq4OCOz.js +86 -0
- package/gui/dist/assets/index-DiBRuK-d.css +1 -0
- package/gui/dist/assets/usage-companion-chart-DBG_37kQ.js +1 -0
- package/gui/dist/index.html +2 -2
- package/native/remote-workspace-helper/src/protocol.rs +5 -0
- package/package.json +4 -1
- package/src/adapters/anthropic.ts +66 -7
- package/src/adapters/codebuddy/adapter.ts +112 -16
- package/src/adapters/codebuddy/mcp-server.ts +180 -0
- package/src/adapters/codebuddy/scaffold-guard.ts +25 -8
- package/src/adapters/codebuddy/tool-bridge.ts +597 -0
- package/src/adapters/coding-agent/protocol.ts +123 -10
- package/src/adapters/coding-agent/turn.ts +324 -2
- package/src/adapters/command-code-restored-schema.ts +112 -0
- package/src/adapters/command-code-tool-text.ts +589 -0
- package/src/adapters/command-code.ts +80 -6
- package/src/adapters/cursor/catalog.ts +12 -0
- package/src/adapters/cursor/current-request.ts +46 -0
- package/src/adapters/cursor/discovery.ts +1 -1
- package/src/adapters/cursor/effort-map.ts +4 -0
- package/src/adapters/cursor/native-exec.ts +15 -0
- package/src/adapters/cursor/protobuf-events.ts +40 -12
- package/src/adapters/cursor/protobuf-request.ts +83 -18
- package/src/adapters/cursor/request-builder.ts +5 -4
- package/src/adapters/cursor/tool-guidance.ts +1 -1
- package/src/adapters/devin/live-models.ts +7 -0
- package/src/adapters/inline-think-tags.ts +251 -0
- package/src/adapters/kiro/adapter.ts +1 -0
- package/src/adapters/kiro/stream.ts +5 -3
- package/src/adapters/kiro/usage.ts +4 -3
- package/src/adapters/mimo-free.ts +37 -18
- package/src/adapters/openai-chat/messages.ts +5 -5
- package/src/adapters/openai-chat/tool-schema.ts +124 -2
- package/src/adapters/openai-chat.ts +13 -3
- package/src/adapters/openai-responses/passthrough.ts +15 -2
- package/src/adapters/openai-responses/reasoning.ts +14 -1
- package/src/adapters/openai-responses/request-strips.ts +29 -3
- package/src/adapters/openai-responses/tool-output-recovery.ts +9 -3
- package/src/adapters/qoder/adapter.ts +15 -12
- package/src/adapters/qoder/scaffold-guard.ts +45 -13
- package/src/bridge/internal.ts +20 -0
- package/src/bridge/sse.ts +14 -5
- package/src/claude/agents-inject.ts +2 -1
- package/src/claude/desktop-applied-marker.ts +44 -0
- package/src/claude/desktop-profile.ts +22 -12
- package/src/claude/inbound.ts +8 -3
- package/src/cli/access.ts +22 -5
- package/src/cli/account-api.ts +6 -0
- package/src/cli/account-auth.ts +5 -2
- package/src/cli/account.ts +5 -6
- package/src/cli/aside-profiles.ts +61 -1
- package/src/cli/claude-desktop.ts +3 -2
- package/src/cli/claude.ts +3 -1
- package/src/cli/codex-cli-update.ts +2 -2
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/dispatch.ts +12 -4
- package/src/cli/index.ts +98 -10
- package/src/cli/registry.ts +1 -1
- package/src/cli/resolve.ts +113 -1
- package/src/cli/root.ts +5 -0
- package/src/cli/stop-approval.ts +186 -0
- package/src/cli/stop-report.ts +1 -1
- package/src/cli/system-restart-client.ts +19 -4
- package/src/client/hub-client.ts +25 -18
- package/src/clients/config-export.ts +12 -4
- package/src/codex/account-auto-switch.ts +59 -0
- package/src/codex/account-lifecycle.ts +7 -0
- package/src/codex/account-priority.ts +10 -0
- package/src/codex/account-usability.ts +9 -0
- package/src/codex/auth-api/account-list.ts +5 -0
- package/src/codex/auth-api/login-flow.ts +15 -5
- package/src/codex/auth-api/login-state.ts +5 -16
- package/src/codex/auth-api/pool-mode-gate.ts +30 -7
- package/src/codex/auth-api/routes.ts +39 -3
- package/src/codex/auth-context.ts +145 -17
- package/src/codex/catalog/build-entries.ts +2 -1
- package/src/codex/catalog/effort.ts +8 -2
- package/src/codex/catalog/metadata.ts +33 -7
- package/src/codex/catalog/native-models.ts +102 -5
- package/src/codex/catalog/parsing.ts +2 -0
- package/src/codex/catalog/provider-models.ts +19 -6
- package/src/codex/cli-installation-targets.ts +44 -40
- package/src/codex/codex-write-lock.ts +32 -2
- package/src/codex/inject/multi-agent-v2.ts +90 -0
- package/src/codex/inject/plan.ts +365 -0
- package/src/codex/inject.ts +237 -362
- package/src/codex/log-guard/maintenance.ts +30 -13
- package/src/codex/project-config-warnings.ts +47 -7
- package/src/codex/prompt-layers/encoding.ts +41 -0
- package/src/codex/prompt-layers/toml-read.ts +1 -1
- package/src/codex/prompt-layers.ts +17 -13
- package/src/codex/prompt-text-probe.ts +20 -10
- package/src/codex/quota-observation-freshness.ts +34 -0
- package/src/codex/quota-rejection.ts +8 -4
- package/src/codex/quota.ts +4 -2
- package/src/codex/routing/selection.ts +32 -9
- package/src/codex/routing.ts +53 -11
- package/src/codex/subagent-model-fallback.ts +4 -3
- package/src/codex/sync.ts +11 -0
- package/src/codex/windows-installation-files.ts +33 -11
- package/src/codex/write-coordination.ts +4 -0
- package/src/combos/request.ts +6 -2
- package/src/companion/settings.ts +6 -1
- package/src/config/atomic-write.ts +12 -1
- package/src/config/derived-registries.ts +29 -0
- package/src/config/diagnostics.ts +17 -0
- package/src/config/live-reconcile.ts +11 -2
- package/src/config/load-degrade.ts +9 -2
- package/src/config/persist-unlocked.ts +4 -3
- package/src/config/persisted-mutation.ts +94 -0
- package/src/config/provider-validation.ts +1 -1
- package/src/config/proxy-env.ts +62 -12
- package/src/config/rebase-provenance.ts +80 -1
- package/src/config/schema/config-schema.ts +5 -0
- package/src/config/schema/leaf-validators.ts +50 -1
- package/src/config/subagent-models.ts +41 -15
- package/src/config.ts +18 -95
- package/src/generated/compatibility-version.json +330 -218
- package/src/generated/model-metadata.ts +8 -5
- package/src/github/star-state.ts +46 -6
- package/src/grok/inject.ts +74 -40
- package/src/grok/status.ts +11 -4
- package/src/integrations/cursor-effort-table.ts +50 -13
- package/src/integrations/raycast-detect.ts +19 -4
- package/src/integrations/serialize.ts +11 -1
- package/src/lib/bounded-body.ts +30 -0
- package/src/lib/crash-guard.ts +52 -4
- package/src/lib/local-aside-sync-contract.ts +41 -0
- package/src/lib/package-tree-integrity.ts +181 -9
- package/src/lib/proxy-env.ts +18 -1
- package/src/lib/request-failure-attribution.ts +1 -0
- package/src/lib/request-failure-model.ts +3 -0
- package/src/lib/service-secrets.ts +99 -2
- package/src/lib/socks5-fetch.ts +43 -14
- package/src/lib/token-estimate.ts +17 -2
- package/src/oauth/command-code.ts +3 -2
- package/src/oauth/generic-account-failover.ts +29 -1
- package/src/oauth/index.ts +24 -16
- package/src/oauth/login-flow-state.ts +5 -5
- package/src/oauth/meta-muse-device.ts +49 -7
- package/src/oauth/store.ts +74 -9
- package/src/providers/alibaba-region-backup.ts +16 -1
- package/src/providers/anthropic-fast.ts +89 -0
- package/src/providers/anthropic-reset-grant-ledger.ts +288 -0
- package/src/providers/anthropic-reset-grants.ts +329 -0
- package/src/providers/claude-cli-identity.ts +12 -0
- package/src/providers/command-code-efforts.ts +184 -102
- package/src/providers/derive.ts +11 -3
- package/src/providers/fastwire.ts +16 -3
- package/src/providers/label.ts +8 -3
- package/src/providers/model-rename-fields.ts +1 -0
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/quota/vendor-probes-oauth.ts +2 -1
- package/src/providers/reasoning-metadata.ts +38 -15
- package/src/providers/registry/entries-core.ts +95 -7
- package/src/providers/registry/entries-extended.ts +21 -10
- package/src/providers/registry/model-ids.ts +1 -0
- package/src/providers/registry/model-seeds.ts +31 -3
- package/src/providers/registry/types.ts +3 -1
- package/src/providers/resolved-model-policy-merge.ts +38 -8
- package/src/providers/resolved-model-policy.ts +4 -2
- package/src/providers/service-tier.ts +3 -1
- package/src/reasoning-effort.ts +6 -5
- package/src/responses/code-mode-helper-compat.ts +14 -4
- package/src/responses/code-mode-shell-input.ts +54 -0
- package/src/responses/custom-tool-compat.ts +173 -5
- package/src/responses/parser.ts +38 -2
- package/src/responses/reasoning-replay-cache.ts +26 -0
- package/src/router.ts +11 -1
- package/src/routing/history/indexer.ts +7 -2
- package/src/routing/history/schema.ts +3 -1
- package/src/server/adapter-resolve.ts +2 -2
- package/src/server/auth-cors.ts +3 -0
- package/src/server/chat-completions.ts +14 -1
- package/src/server/chat-native.ts +17 -0
- package/src/server/claude-messages.ts +4 -3
- package/src/server/direct-local-http.ts +45 -19
- package/src/server/gui-session.ts +6 -15
- package/src/server/index/package-tree-guard.ts +53 -0
- package/src/server/index/serve-options.ts +17 -3
- package/src/server/index/startup-warnings.ts +17 -0
- package/src/server/index.ts +15 -17
- package/src/server/lifecycle.ts +8 -0
- package/src/server/live.ts +54 -4
- package/src/server/management/agent-settings-routes.ts +44 -8
- package/src/server/management/anthropic-reset-grant-routes.ts +252 -0
- package/src/server/management/codex-prompt-routes.ts +5 -1
- package/src/server/management/config-routes.ts +14 -4
- package/src/server/management/oauth-account-routes.ts +17 -1
- package/src/server/management/provider-overwrite-carry.ts +164 -0
- package/src/server/management/provider-routes.ts +36 -6
- package/src/server/management/remote-workspace-routes.ts +2 -2
- package/src/server/management/route-registry.ts +2 -0
- package/src/server/management/shadow-call-validation.ts +39 -0
- package/src/server/management/system-restart.ts +72 -6
- package/src/server/management-api.ts +16 -2
- package/src/server/management-auth.ts +52 -8
- package/src/server/proxy-liveness.ts +110 -4
- package/src/server/request-log.ts +26 -9
- package/src/server/request-metrics.ts +5 -0
- package/src/server/responses/adapter-continuation.ts +6 -3
- package/src/server/responses/adapter-dispatch.ts +65 -1
- package/src/server/responses/compact.ts +31 -1
- package/src/server/responses/compaction-routing.ts +28 -3
- package/src/server/responses/core-codex-account.ts +85 -26
- package/src/server/responses/core-combo-failure.ts +16 -15
- package/src/server/responses/core-normalize.ts +5 -1
- package/src/server/responses/core-opaque-recovery.ts +50 -2
- package/src/server/responses/core-options.ts +2 -0
- package/src/server/responses/core-replay.ts +7 -0
- package/src/server/responses/core.ts +1 -1
- package/src/server/responses/encrypted-payload.ts +23 -9
- package/src/server/responses/passthrough-delivery.ts +55 -35
- package/src/server/responses/passthrough-dispatch.ts +12 -13
- package/src/server/responses/policy-fallback.ts +12 -1
- package/src/server/responses/request-prepare.ts +46 -7
- package/src/server/responses/request-spend.ts +31 -15
- package/src/server/responses/run-turn-execution.ts +6 -5
- package/src/server/responses/shadow-target-availability.ts +61 -0
- package/src/server/responses-custom-tool-repair.ts +2 -0
- package/src/service/claim.ts +185 -0
- package/src/service/cli.ts +10 -1
- package/src/service/guarded-manager-target.ts +151 -0
- package/src/service/guards.ts +47 -48
- package/src/service/managing-cli.ts +170 -0
- package/src/service/orchestration.ts +3 -1
- package/src/service/state.ts +4 -0
- package/src/service/systemd.ts +16 -1
- package/src/service.ts +1 -1
- package/src/types/config.ts +8 -0
- package/src/types/provider.ts +16 -0
- package/src/types/request.ts +10 -0
- package/src/types/tools.ts +9 -1
- package/src/types/wire.ts +68 -4
- package/src/types.ts +1 -0
- package/src/update/job.ts +10 -16
- package/src/update/npm-invocation.mjs +17 -16
- package/src/update/transactional-install.d.mts +22 -1
- package/src/update/transactional-install.mjs +176 -19
- package/src/update/update-failure-guidance.d.mts +8 -0
- package/src/update/update-failure-guidance.mjs +47 -0
- package/src/usage/expected-prices.ts +54 -12
- package/src/usage/log.ts +117 -3
- package/src/usage/telemetry-contract.ts +1 -0
- package/src/usage/timeline.ts +34 -6
- package/src/usage/user-cost-overlay-reconciler.ts +3 -3
- package/src/vision/reasoning.ts +2 -4
- package/src/web-search/xai-executor.ts +14 -4
- package/gui/dist/assets/App-BqrsSrIR.js +0 -50
- package/gui/dist/assets/index-C6SJrh0N.js +0 -86
- package/gui/dist/assets/index-DdDunwDb.css +0 -1
- package/gui/dist/assets/usage-companion-chart-CzAAAB1o.js +0 -1
- package/src/adapters/kiro-thinking.ts +0 -112
|
@@ -1,41 +1,58 @@
|
|
|
1
1
|
import { readBoundedResponseBody } from "../lib/bounded-body";
|
|
2
2
|
|
|
3
|
+
/*
|
|
4
|
+
* Keys must match the EXACT upstream /provider/v1/models ids (GLM ships as `zai-org/GLM-5.3`, not
|
|
5
|
+
* `zai-org/glm-5.3`). The table doubles as the router's known-ids decode source (via
|
|
6
|
+
* `knownModelIdsForProvider`), so a case mismatch makes a Codex-facing slug such as
|
|
7
|
+
* `commandcode/zai-org-GLM-5.3` pass through undecoded and upstream rejects it with
|
|
8
|
+
* `unsupported_model`.
|
|
9
|
+
*
|
|
10
|
+
* PROVENANCE. commandcode.ai renders each /models/<slug> profile client-side, but the delivered HTML
|
|
11
|
+
* carries the loader data as a React Router payload: one `streamController.enqueue("<json>")` call
|
|
12
|
+
* whose JSON is an indexed value table. A model record's `reasoningEfforts` field points at an array
|
|
13
|
+
* of indices that resolve to effort names (for example the 2026-08-29 glm-5-3-flash page resolved
|
|
14
|
+
* 224=low, 225=medium, 226=high, 227=xhigh, 569=max, cross-checked six for six against committed
|
|
15
|
+
* rows). Rows marked "captured 2026-09-23" were read from that payload. On the same date a live
|
|
16
|
+
* `refreshCommandCodeReasoningEfforts` pass reproduced every other row except GLM-5, GLM-5.1 and
|
|
17
|
+
* GLM-5.2-Fast (their payload ladders are empty, so the static rows stay) and the Muse 1.x rows.
|
|
18
|
+
*
|
|
19
|
+
* The profile is Command Code's per-model statement, but /alpha/generate validates effort against
|
|
20
|
+
* one global enum (low..max) and accepts rungs a profile omits: `max` on muse-spark-1.2 and
|
|
21
|
+
* 1.3-contributor, and `high` and `max` on Qwen3.8-Flash, all returned 200 on 2026-09-23 while
|
|
22
|
+
* `ultra` returned 400. A correction therefore adds the rungs a profile newly lists and keeps the
|
|
23
|
+
* rungs the upstream measurably accepts; dropping them would strip an effort that works today,
|
|
24
|
+
* including Codex's default `high`. The refresh path decodes the same payload, so it narrows a row
|
|
25
|
+
* only after the upstream actually rejects a rung.
|
|
26
|
+
*/
|
|
3
27
|
const COMMAND_CODE_MODEL_EFFORTS = {
|
|
28
|
+
// Captured profile payload 2026-09-23: claude-fable-5-1.html.
|
|
29
|
+
"claude-fable-5-1": {
|
|
30
|
+
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
31
|
+
profileUrl: "https://commandcode.ai/models/claude-fable-5-1",
|
|
32
|
+
},
|
|
33
|
+
// Captured profile payload 2026-09-23: claude-opus-5-5.html.
|
|
34
|
+
"claude-opus-5-5": {
|
|
35
|
+
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
36
|
+
profileUrl: "https://commandcode.ai/models/claude-opus-5-5",
|
|
37
|
+
},
|
|
4
38
|
"deepseek/deepseek-v4-flash": {
|
|
5
39
|
efforts: ["high", "max"],
|
|
6
40
|
profileUrl: "https://commandcode.ai/models/deepseek-v4-flash",
|
|
7
41
|
},
|
|
8
|
-
/*
|
|
9
|
-
* Three live routes that reached the catalog without an effort ladder (#2647).
|
|
10
|
-
* Without a row here the model advertises no efforts at all, so a client that
|
|
11
|
-
* sends one gets it stripped or rejected rather than honored.
|
|
12
|
-
*
|
|
13
|
-
* PROVENANCE, stated plainly: these three ladders are the reporter's
|
|
14
|
-
* (darwintree, #2647), recorded as reported and NOT independently verified.
|
|
15
|
-
* All three profileUrls return HTTP 200, but commandcode.ai renders these
|
|
16
|
-
* pages client-side and ships the ladder inside a serialized React payload
|
|
17
|
-
* whose `reasoningEfforts` array is EMPTY in the delivered HTML. There is no
|
|
18
|
-
* fetchable statement of these ladders to check them against.
|
|
19
|
-
*
|
|
20
|
-
* Do not assume the refresh path launders this. It does not:
|
|
21
|
-
* `parsedProfileEfforts` below matches prose of the form
|
|
22
|
-
* "Reasoning efforts ... are supported;", and `grep -c -i 'reasoning efforts'`
|
|
23
|
-
* against the live pages returns 0 — for these three AND for the older rows
|
|
24
|
-
* (deepseek-v4-pro, GLM-5.3, muse-spark-1.2 all measured 0 on 2026-08-27).
|
|
25
|
-
* So `refreshCommandCodeReasoningEfforts` returns undefined and the caller
|
|
26
|
-
* keeps whatever is written here, indefinitely. The self-correction mechanism
|
|
27
|
-
* is currently dead for EVERY row in this table, which is a pre-existing
|
|
28
|
-
* defect worth its own fix (teach the parser to read the embedded payload),
|
|
29
|
-
* not something these three rows introduced.
|
|
30
|
-
*
|
|
31
|
-
* The practical consequence: a wrong ladder here stays wrong until a human
|
|
32
|
-
* changes it. It degrades safely — an effort the upstream rejects surfaces as
|
|
33
|
-
* an error rather than silent corruption — but it does not self-heal.
|
|
34
|
-
*/
|
|
35
42
|
"deepseek/deepseek-v4-flash-vision-exp": {
|
|
36
43
|
efforts: ["high", "max"],
|
|
37
44
|
profileUrl: "https://commandcode.ai/models/deepseek-v4-flash-vision-exp",
|
|
38
45
|
},
|
|
46
|
+
// Captured profile payload 2026-09-23: deepseek-v4-flash-fast.html.
|
|
47
|
+
"deepseek/deepseek-v4-flash-fast": {
|
|
48
|
+
efforts: ["low", "high", "max"],
|
|
49
|
+
profileUrl: "https://commandcode.ai/models/deepseek-v4-flash-fast",
|
|
50
|
+
},
|
|
51
|
+
// Captured profile payload 2026-09-23: deepseek-v4-1-flash.html.
|
|
52
|
+
"deepseek/deepseek-v4.1-flash": {
|
|
53
|
+
efforts: ["low", "high", "max"],
|
|
54
|
+
profileUrl: "https://commandcode.ai/models/deepseek-v4-1-flash",
|
|
55
|
+
},
|
|
39
56
|
"gpt-5.6-luna": {
|
|
40
57
|
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
41
58
|
profileUrl: "https://commandcode.ai/models/gpt-5-6-luna",
|
|
@@ -44,11 +61,11 @@ const COMMAND_CODE_MODEL_EFFORTS = {
|
|
|
44
61
|
efforts: ["low", "medium", "high"],
|
|
45
62
|
profileUrl: "https://commandcode.ai/models/gemini-3-7-flash",
|
|
46
63
|
},
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
// Captured profile payload 2026-09-23: gemini-3-8-flash.html.
|
|
65
|
+
"google/gemini-3.8-flash": {
|
|
66
|
+
efforts: ["low", "medium", "high"],
|
|
67
|
+
profileUrl: "https://commandcode.ai/models/gemini-3-8-flash",
|
|
68
|
+
},
|
|
52
69
|
"zai-org/GLM-5": {
|
|
53
70
|
efforts: ["high", "max"],
|
|
54
71
|
profileUrl: "https://commandcode.ai/models/glm-5",
|
|
@@ -69,86 +86,71 @@ const COMMAND_CODE_MODEL_EFFORTS = {
|
|
|
69
86
|
efforts: ["low", "high", "max"],
|
|
70
87
|
profileUrl: "https://commandcode.ai/models/glm-5-3",
|
|
71
88
|
},
|
|
72
|
-
/*
|
|
73
|
-
* GLM-5.3-Flash (#2883). Reported as advertising NO efforts at all: the live
|
|
74
|
-
* route is `z-ai/glm-5.3-flash`, which shares neither vendor prefix nor model
|
|
75
|
-
* id with `zai-org/GLM-5.3` above, so `modelRecordValue` cannot bridge them
|
|
76
|
-
* (exact / colon-family / case-folded only — by design; a substring match here
|
|
77
|
-
* would merge two genuinely different models across two vendor namespaces).
|
|
78
|
-
*
|
|
79
|
-
* PROVENANCE: unlike the #2647 rows above, this ladder is MEASURED, not
|
|
80
|
-
* reported. commandcode.ai renders the profile client-side, but the delivered
|
|
81
|
-
* HTML ships a serialized React payload whose string table can be read
|
|
82
|
-
* directly: in the 2026-08-29 fetch of /models/glm-5-3-flash (HTTP 200,
|
|
83
|
-
* 228749 bytes) the indices resolve as 224=low, 225=medium, 226=high,
|
|
84
|
-
* 227=xhigh, 569=max, and this model's array is [224,226,569].
|
|
85
|
-
*
|
|
86
|
-
* The index map was cross-validated against every row in this table that the
|
|
87
|
-
* same page carries: deepseek-v4-pro and -flash [226,569], gpt-5.6-luna
|
|
88
|
-
* [224,225,226,227,569], gemini-3.7-flash [224,225,226], GLM-5.2 [226,569],
|
|
89
|
-
* GLM-5.3 [224,226,569] — six for six against the values already committed
|
|
90
|
-
* here. No authenticated upstream generate probe was performed.
|
|
91
|
-
*/
|
|
92
89
|
"z-ai/glm-5.3-flash": {
|
|
93
90
|
efforts: ["low", "high", "max"],
|
|
94
91
|
profileUrl: "https://commandcode.ai/models/glm-5-3-flash",
|
|
95
92
|
},
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
// the 1.2 pair, and Zen serves muse-spark-1.3-contributor over the same
|
|
106
|
-
// /responses wire). It carries the 1.2 ladder because it IS the 1.2 spec: the
|
|
107
|
-
// upstream ladder statement is per-family, and a narrower guess here would
|
|
108
|
-
// strip an effort the gateway accepts. Additive — 1.2 and 1.1 stay live.
|
|
93
|
+
// Captured profile payload 2026-09-23: glm-5-3-flashx.html.
|
|
94
|
+
"z-ai/glm-5.3-flashx": {
|
|
95
|
+
efforts: ["low", "high", "max"],
|
|
96
|
+
profileUrl: "https://commandcode.ai/models/glm-5-3-flashx",
|
|
97
|
+
},
|
|
98
|
+
// Captured profile payload 2026-09-23: muse-spark-1-3.html.
|
|
99
|
+
// Muse Spark: the Command Code CLI prints "has no adjustable reasoning effort", but /alpha/generate
|
|
100
|
+
// accepts reasoning_effort for these routes (verified 2026-08-13 on 1.2-contributor: low..max 200,
|
|
101
|
+
// ultra 400), so the table, not the CLI, is the ladder authority.
|
|
109
102
|
"meta/muse-spark-1.3": {
|
|
110
103
|
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
111
|
-
profileUrl: "https://commandcode.ai/models/
|
|
104
|
+
profileUrl: "https://commandcode.ai/models/muse-spark-1-3",
|
|
112
105
|
},
|
|
106
|
+
// Captured profile payload 2026-09-23 lists low..xhigh; max stays because /alpha/generate accepts it.
|
|
113
107
|
"meta/muse-spark-1.3-contributor": {
|
|
114
108
|
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
115
|
-
profileUrl: "https://commandcode.ai/models/
|
|
109
|
+
profileUrl: "https://commandcode.ai/models/muse-spark-1-3-contributor",
|
|
116
110
|
},
|
|
117
111
|
"meta/muse-spark-1.2": {
|
|
118
112
|
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
119
|
-
profileUrl: "https://commandcode.ai/models/
|
|
113
|
+
profileUrl: "https://commandcode.ai/models/muse-spark-1-2",
|
|
120
114
|
},
|
|
121
115
|
"meta/muse-spark-1.2-contributor": {
|
|
122
116
|
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
123
|
-
profileUrl: "https://commandcode.ai/models/
|
|
117
|
+
profileUrl: "https://commandcode.ai/models/muse-spark-1-2-contributor",
|
|
124
118
|
},
|
|
125
119
|
"meta/muse-spark-1.1": {
|
|
126
120
|
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
127
|
-
profileUrl: "https://commandcode.ai/models/
|
|
128
|
-
},
|
|
129
|
-
/*
|
|
130
|
-
* Two live routes that never gained a row here, so the adapter dropped every
|
|
131
|
-
* requested effort (a client's `max` left the wire as no reasoning parameter
|
|
132
|
-
* at all) and the preset advertised no effort control for them.
|
|
133
|
-
*
|
|
134
|
-
* PROVENANCE, stated plainly: both ladders are inferred from the same-family
|
|
135
|
-
* rows above — deepseek v4: high..max; the Qwen 3.8 family: low..max — NOT
|
|
136
|
-
* read from the profile pages. commandcode.ai renders those client-side and
|
|
137
|
-
* ships an empty reasoning payload, so the self-refresh below is as dead for
|
|
138
|
-
* these rows as the #2647 block above already documents. Measured live
|
|
139
|
-
* 2026-09-11: /alpha/generate accepts `reasoning_effort: "max"` on both
|
|
140
|
-
* routes (HTTP 200). `ultra` is deliberately not offered: the adapter would
|
|
141
|
-
* strip it, and no profile evidence backs an ultra→max alias the way it does
|
|
142
|
-
* for v4-pro/v4-flash above.
|
|
143
|
-
*/
|
|
144
|
-
"deepseek/deepseek-v4.1-flash": {
|
|
145
|
-
efforts: ["high", "max"],
|
|
146
|
-
profileUrl: "https://commandcode.ai/models/deepseek-v4-1-flash",
|
|
121
|
+
profileUrl: "https://commandcode.ai/models/muse-spark-1-1",
|
|
147
122
|
},
|
|
123
|
+
// Captured profile payload 2026-09-23 lists low, medium, xhigh; high and max stay because
|
|
124
|
+
// /alpha/generate accepts both (measured 2026-09-11 and 2026-09-23).
|
|
148
125
|
"Qwen/Qwen3.8-Flash": {
|
|
149
|
-
efforts: ["low", "medium", "high", "max"],
|
|
126
|
+
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
150
127
|
profileUrl: "https://commandcode.ai/models/qwen3-8-flash",
|
|
151
128
|
},
|
|
129
|
+
// Captured profile payload 2026-09-23: qwen3-8-omni-flash.html.
|
|
130
|
+
"Qwen/Qwen3.8-Omni-Flash": {
|
|
131
|
+
efforts: ["low", "medium", "xhigh"],
|
|
132
|
+
profileUrl: "https://commandcode.ai/models/qwen3-8-omni-flash",
|
|
133
|
+
},
|
|
134
|
+
// Captured profile payload 2026-09-23: qwen3-8-max-0902.html.
|
|
135
|
+
"Qwen/Qwen3.8-Max-0902": {
|
|
136
|
+
efforts: ["low", "medium", "xhigh"],
|
|
137
|
+
profileUrl: "https://commandcode.ai/models/qwen3-8-max-0902",
|
|
138
|
+
},
|
|
139
|
+
// Captured profile payload 2026-09-23: step-5-preview.html.
|
|
140
|
+
"stepfun/Step-5-Preview": {
|
|
141
|
+
efforts: ["low", "medium", "high"],
|
|
142
|
+
profileUrl: "https://commandcode.ai/models/step-5-preview",
|
|
143
|
+
},
|
|
144
|
+
// Captured profile payload 2026-09-23: hy4-preview.html.
|
|
145
|
+
"tencent/hy4-preview": {
|
|
146
|
+
efforts: ["low", "medium", "high"],
|
|
147
|
+
profileUrl: "https://commandcode.ai/models/hy4-preview",
|
|
148
|
+
},
|
|
149
|
+
// Captured profile payload 2026-09-23: grok-4-7.html.
|
|
150
|
+
"xai/grok-4.7": {
|
|
151
|
+
efforts: ["low", "medium", "high", "xhigh"],
|
|
152
|
+
profileUrl: "https://commandcode.ai/models/grok-4-7",
|
|
153
|
+
},
|
|
152
154
|
} as const;
|
|
153
155
|
|
|
154
156
|
/**
|
|
@@ -160,24 +162,91 @@ export const COMMAND_CODE_MODEL_REASONING_EFFORTS: Record<string, string[]> = Ob
|
|
|
160
162
|
);
|
|
161
163
|
|
|
162
164
|
const refreshedEfforts = new Map<string, string[]>();
|
|
165
|
+
const rejectedEfforts = new Map<string, Set<string>>();
|
|
166
|
+
const DEFAULT_EFFORT_DESTINATION = "https://api.commandcode.ai";
|
|
163
167
|
|
|
164
168
|
function keyFor(modelId: string): string {
|
|
165
169
|
return modelId.trim().toLowerCase();
|
|
166
170
|
}
|
|
167
171
|
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
function cacheKey(modelId: string, destination: string): string {
|
|
173
|
+
let normalized = destination.trim().replace(/\/+$/, "");
|
|
174
|
+
try {
|
|
175
|
+
const url = new URL(destination);
|
|
176
|
+
normalized = `${url.origin}${url.pathname.replace(/\/+$/, "")}`;
|
|
177
|
+
} catch { /* Config validation owns malformed destinations. */ }
|
|
178
|
+
return JSON.stringify([normalized, keyFor(modelId)]);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function commandCodeReasoningEfforts(
|
|
182
|
+
modelId: string,
|
|
183
|
+
destination = DEFAULT_EFFORT_DESTINATION,
|
|
184
|
+
): readonly string[] | undefined {
|
|
185
|
+
const key = cacheKey(modelId, destination);
|
|
186
|
+
const rejected = rejectedEfforts.get(key);
|
|
170
187
|
const refreshed = refreshedEfforts.get(key);
|
|
171
|
-
if (refreshed !== undefined) return refreshed;
|
|
188
|
+
if (refreshed !== undefined) return rejected ? refreshed.filter(effort => !rejected.has(effort)) : refreshed;
|
|
172
189
|
// Case-insensitive: the table keys match the EXACT upstream ids (e.g. `zai-org/GLM-5.3`),
|
|
173
190
|
// but callers may pass either case.
|
|
174
191
|
for (const [id, efforts] of Object.entries(COMMAND_CODE_MODEL_REASONING_EFFORTS)) {
|
|
175
|
-
if (keyFor(id) ===
|
|
192
|
+
if (keyFor(id) === keyFor(modelId)) return rejected ? efforts.filter(effort => !rejected.has(effort)) : efforts;
|
|
176
193
|
}
|
|
177
194
|
return undefined;
|
|
178
195
|
}
|
|
179
196
|
|
|
180
|
-
|
|
197
|
+
/** Upper bound for one fetched profile page. */
|
|
198
|
+
export const PROFILE_PAGE_MAX_BYTES = 512 * 1024;
|
|
199
|
+
|
|
200
|
+
const PROFILE_EFFORTS = new Set(["low", "medium", "high", "xhigh", "max"]);
|
|
201
|
+
|
|
202
|
+
function parsedRouterEfforts(page: string, modelId: string): string[] | undefined {
|
|
203
|
+
// React Router serializes the loader as a JSON string of an indexed value table.
|
|
204
|
+
// Object keys such as _125 and array elements are references into that table.
|
|
205
|
+
const flights = [...page.matchAll(/window\.__reactRouterContext\.streamController\.enqueue\(("(?:\\.|[^"\\])*")\);/g)];
|
|
206
|
+
if (flights.length !== 1) return undefined;
|
|
207
|
+
let values: unknown;
|
|
208
|
+
try {
|
|
209
|
+
values = JSON.parse(JSON.parse(flights[0]![1]!));
|
|
210
|
+
} catch {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
if (!Array.isArray(values)) return undefined;
|
|
214
|
+
const table: unknown[] = values;
|
|
215
|
+
const dereference = (ref: unknown): unknown =>
|
|
216
|
+
Number.isInteger(ref) && (ref as number) >= 0 && (ref as number) < table.length
|
|
217
|
+
? table[ref as number] : undefined;
|
|
218
|
+
let matched: string[] | undefined;
|
|
219
|
+
for (const value of table) {
|
|
220
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
221
|
+
const fields = new Map<string, unknown>();
|
|
222
|
+
let conflicting = false;
|
|
223
|
+
for (const [key, ref] of Object.entries(value)) {
|
|
224
|
+
if (!/^_\d+$/.test(key)) continue;
|
|
225
|
+
const name = dereference(Number(key.slice(1)));
|
|
226
|
+
if (typeof name !== "string") continue;
|
|
227
|
+
// Two keys decoding to one field name is not a record this parser understands.
|
|
228
|
+
if (fields.has(name)) conflicting = true;
|
|
229
|
+
fields.set(name, ref);
|
|
230
|
+
}
|
|
231
|
+
if (conflicting && (fields.has("id") || fields.has("reasoningEfforts"))) return undefined;
|
|
232
|
+
const id = dereference(fields.get("id"));
|
|
233
|
+
if (typeof id !== "string" || keyFor(id) !== keyFor(modelId)) continue;
|
|
234
|
+
const refs = dereference(fields.get("reasoningEfforts"));
|
|
235
|
+
if (!Array.isArray(refs) || refs.length === 0) return undefined;
|
|
236
|
+
const efforts = refs.map(dereference);
|
|
237
|
+
if (efforts.some(effort => typeof effort !== "string" || !PROFILE_EFFORTS.has(effort)) ||
|
|
238
|
+
new Set(efforts).size !== efforts.length) return undefined;
|
|
239
|
+
const complete = efforts as string[];
|
|
240
|
+
if (matched && JSON.stringify(matched) !== JSON.stringify(complete)) return undefined;
|
|
241
|
+
matched = complete;
|
|
242
|
+
}
|
|
243
|
+
return matched;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function parsedProfileEfforts(page: string, modelId: string): string[] | undefined {
|
|
247
|
+
if (page.includes("window.__reactRouterContext.streamController.enqueue(")) {
|
|
248
|
+
return parsedRouterEfforts(page, modelId);
|
|
249
|
+
}
|
|
181
250
|
const match = page.match(/Reasoning efforts\s+([^.;]+?)\s+are supported;\s*([^.]*)/i);
|
|
182
251
|
if (!match) return undefined;
|
|
183
252
|
const listed = match[1]!.toLowerCase().match(/\b(?:low|medium|high|xhigh|max)\b/g) ?? [];
|
|
@@ -200,16 +269,23 @@ function parsedProfileEfforts(page: string): string[] | undefined {
|
|
|
200
269
|
export async function refreshCommandCodeReasoningEfforts(
|
|
201
270
|
modelId: string,
|
|
202
271
|
fetchFn: typeof globalThis.fetch = globalThis.fetch,
|
|
272
|
+
rejectedEffort?: string,
|
|
273
|
+
destination = DEFAULT_EFFORT_DESTINATION,
|
|
203
274
|
): Promise<readonly string[] | undefined> {
|
|
204
|
-
const key =
|
|
275
|
+
const key = cacheKey(modelId, destination);
|
|
205
276
|
let profile: { efforts: readonly string[]; profileUrl: string } | undefined;
|
|
206
277
|
for (const [id, row] of Object.entries(COMMAND_CODE_MODEL_EFFORTS)) {
|
|
207
|
-
if (keyFor(id) ===
|
|
278
|
+
if (keyFor(id) === keyFor(modelId)) {
|
|
208
279
|
profile = row;
|
|
209
280
|
break;
|
|
210
281
|
}
|
|
211
282
|
}
|
|
212
283
|
if (!profile) return undefined;
|
|
284
|
+
if (rejectedEffort) {
|
|
285
|
+
const rejected = rejectedEfforts.get(key) ?? new Set<string>();
|
|
286
|
+
rejected.add(rejectedEffort);
|
|
287
|
+
rejectedEfforts.set(key, rejected);
|
|
288
|
+
}
|
|
213
289
|
try {
|
|
214
290
|
const response = await fetchFn(profile.profileUrl, {
|
|
215
291
|
headers: { Accept: "text/html" },
|
|
@@ -217,13 +293,18 @@ export async function refreshCommandCodeReasoningEfforts(
|
|
|
217
293
|
});
|
|
218
294
|
if (!response.ok) return undefined;
|
|
219
295
|
// Bound the profile page before parsing: a large or malformed page must not
|
|
220
|
-
// allocate unbounded memory on the request path.
|
|
221
|
-
|
|
296
|
+
// allocate unbounded memory on the request path. Live profiles measured 240-259 KB on
|
|
297
|
+
// 2026-09-23, so the cap leaves room for growth; a truncated page fails to parse and keeps
|
|
298
|
+
// the static row.
|
|
299
|
+
const observed = await readBoundedResponseBody(response, { maxBytes: PROFILE_PAGE_MAX_BYTES });
|
|
222
300
|
if (!observed.displaySafe) return undefined;
|
|
223
|
-
const efforts = parsedProfileEfforts(observed.text);
|
|
301
|
+
const efforts = parsedProfileEfforts(observed.text, modelId);
|
|
224
302
|
if (efforts === undefined) return undefined;
|
|
225
|
-
|
|
226
|
-
|
|
303
|
+
const accepted = commandCodeReasoningEfforts(modelId, destination) ?? [];
|
|
304
|
+
const merged = [...new Set([...accepted, ...efforts])]
|
|
305
|
+
.filter(effort => !rejectedEfforts.get(key)?.has(effort));
|
|
306
|
+
refreshedEfforts.set(key, merged);
|
|
307
|
+
return merged;
|
|
227
308
|
} catch {
|
|
228
309
|
return undefined;
|
|
229
310
|
}
|
|
@@ -231,4 +312,5 @@ export async function refreshCommandCodeReasoningEfforts(
|
|
|
231
312
|
|
|
232
313
|
export function resetCommandCodeReasoningEffortsForTest(): void {
|
|
233
314
|
refreshedEfforts.clear();
|
|
315
|
+
rejectedEfforts.clear();
|
|
234
316
|
}
|
package/src/providers/derive.ts
CHANGED
|
@@ -47,6 +47,7 @@ export interface DerivedKeyLoginProvider {
|
|
|
47
47
|
requiresReasoningPlaceholderModels?: string[];
|
|
48
48
|
showThinkingSummary?: boolean;
|
|
49
49
|
reasoningSplitModels?: string[];
|
|
50
|
+
inlineThinkTagModels?: string[];
|
|
50
51
|
reasoningDetailsModels?: string[];
|
|
51
52
|
thinkingToggleModels?: string[];
|
|
52
53
|
thinkingBudgetModels?: string[];
|
|
@@ -113,13 +114,17 @@ function cloneRecordOfArrays(input: Record<string, string[]>): Record<string, st
|
|
|
113
114
|
* is how a partially customized `modelInputModalities` could leave a
|
|
114
115
|
* vision-capable model advertising no image support, which in turn collapses any
|
|
115
116
|
* combo containing it to text-only. Routing already merges these maps per key
|
|
116
|
-
* (`
|
|
117
|
+
* (`mapFill` in src/providers/resolved-model-policy-merge.ts); catalog enrichment now matches.
|
|
117
118
|
*/
|
|
118
119
|
function fillRecordOfArrays(
|
|
119
120
|
seed: Record<string, string[]>,
|
|
120
121
|
user: Record<string, string[]> | undefined,
|
|
121
122
|
): Record<string, string[]> {
|
|
122
|
-
|
|
123
|
+
const userKeys = new Set(Object.keys(user ?? {}).map(key => key.toLowerCase()));
|
|
124
|
+
const defaults = Object.fromEntries(
|
|
125
|
+
Object.entries(seed).filter(([key]) => !userKeys.has(key.toLowerCase())),
|
|
126
|
+
);
|
|
127
|
+
return { ...cloneRecordOfArrays(defaults), ...(user ? cloneRecordOfArrays(user) : {}) };
|
|
123
128
|
}
|
|
124
129
|
|
|
125
130
|
function cloneNestedRecord(input: Record<string, Record<string, string>>): Record<string, Record<string, string>> {
|
|
@@ -286,6 +291,7 @@ export function providerConfigSeed(entry: ProviderRegistryEntry): OcxProviderCon
|
|
|
286
291
|
...(entry.requiresReasoningPlaceholderModels ? { requiresReasoningPlaceholderModels: [...entry.requiresReasoningPlaceholderModels] } : {}),
|
|
287
292
|
...(entry.showThinkingSummary !== undefined ? { showThinkingSummary: entry.showThinkingSummary } : {}),
|
|
288
293
|
...(entry.reasoningSplitModels ? { reasoningSplitModels: [...entry.reasoningSplitModels] } : {}),
|
|
294
|
+
...(entry.inlineThinkTagModels ? { inlineThinkTagModels: [...entry.inlineThinkTagModels] } : {}),
|
|
289
295
|
...(entry.reasoningDetailsModels ? { reasoningDetailsModels: [...entry.reasoningDetailsModels] } : {}),
|
|
290
296
|
...(entry.thinkingToggleModels ? { thinkingToggleModels: [...entry.thinkingToggleModels] } : {}),
|
|
291
297
|
...(entry.thinkingBudgetModels ? { thinkingBudgetModels: [...entry.thinkingBudgetModels] } : {}),
|
|
@@ -336,6 +342,7 @@ export function deriveKeyLoginMap(): Record<string, DerivedKeyLoginProvider> {
|
|
|
336
342
|
...(entry.requiresReasoningPlaceholderModels ? { requiresReasoningPlaceholderModels: [...entry.requiresReasoningPlaceholderModels] } : {}),
|
|
337
343
|
...(entry.showThinkingSummary !== undefined ? { showThinkingSummary: entry.showThinkingSummary } : {}),
|
|
338
344
|
...(entry.reasoningSplitModels ? { reasoningSplitModels: [...entry.reasoningSplitModels] } : {}),
|
|
345
|
+
...(entry.inlineThinkTagModels ? { inlineThinkTagModels: [...entry.inlineThinkTagModels] } : {}),
|
|
339
346
|
...(entry.reasoningDetailsModels ? { reasoningDetailsModels: [...entry.reasoningDetailsModels] } : {}),
|
|
340
347
|
...(entry.thinkingToggleModels ? { thinkingToggleModels: [...entry.thinkingToggleModels] } : {}),
|
|
341
348
|
...(entry.thinkingBudgetModels ? { thinkingBudgetModels: [...entry.thinkingBudgetModels] } : {}),
|
|
@@ -534,7 +541,7 @@ export function enrichProviderFromRegistry(name: string, prov: OcxProviderConfig
|
|
|
534
541
|
// Per-model fill for the same reason as modelInputModalities above: an all-or-nothing
|
|
535
542
|
// copy let ONE customized model hide the registry's ladder for every other model on the
|
|
536
543
|
// provider. That split the two planes apart — routing merges these maps per key
|
|
537
|
-
// (
|
|
544
|
+
// (mapFill in src/providers/resolved-model-policy-merge.ts), so the wire honored the effort while /v1/models and
|
|
538
545
|
// every client export showed no effort control at all.
|
|
539
546
|
if (resolvedStatic.modelReasoningEfforts) prov.modelReasoningEfforts = cloneRecordOfArrays(resolvedStatic.modelReasoningEfforts);
|
|
540
547
|
if (!prov.modelDefaultReasoningEfforts && seed.modelDefaultReasoningEfforts) prov.modelDefaultReasoningEfforts = { ...seed.modelDefaultReasoningEfforts };
|
|
@@ -602,6 +609,7 @@ export function enrichProviderFromRegistry(name: string, prov: OcxProviderConfig
|
|
|
602
609
|
if (!prov.preserveReasoningContentModels && seed.preserveReasoningContentModels) prov.preserveReasoningContentModels = [...seed.preserveReasoningContentModels];
|
|
603
610
|
if (!prov.requiresReasoningPlaceholderModels && seed.requiresReasoningPlaceholderModels) prov.requiresReasoningPlaceholderModels = [...seed.requiresReasoningPlaceholderModels];
|
|
604
611
|
if (!prov.reasoningSplitModels && seed.reasoningSplitModels) prov.reasoningSplitModels = [...seed.reasoningSplitModels];
|
|
612
|
+
if (!prov.inlineThinkTagModels && seed.inlineThinkTagModels) prov.inlineThinkTagModels = [...seed.inlineThinkTagModels];
|
|
605
613
|
if (!prov.reasoningDetailsModels && seed.reasoningDetailsModels) prov.reasoningDetailsModels = [...seed.reasoningDetailsModels];
|
|
606
614
|
if (!prov.thinkingToggleModels && seed.thinkingToggleModels) prov.thinkingToggleModels = [...seed.thinkingToggleModels];
|
|
607
615
|
if (!prov.thinkingBudgetModels && seed.thinkingBudgetModels) prov.thinkingBudgetModels = [...seed.thinkingBudgetModels];
|
|
@@ -12,8 +12,9 @@ import type { InboundWire, ModelWireDefault, ProviderAuthKind } from "./registry
|
|
|
12
12
|
const SERVICE_TIER_ADAPTERS = new Set(["openai-chat", "openai-responses"]);
|
|
13
13
|
const FAST_WIRE_ADAPTERS: Readonly<Record<FastWire["kind"], ReadonlySet<string>>> = {
|
|
14
14
|
"service-tier": SERVICE_TIER_ADAPTERS,
|
|
15
|
-
//
|
|
16
|
-
|
|
15
|
+
// Anthropic fast mode: top-level `speed: "fast"` plus the declared beta, serialized and
|
|
16
|
+
// observed (`usage.speed`) by the Anthropic adapter itself.
|
|
17
|
+
"anthropic-speed": new Set(["anthropic"]),
|
|
17
18
|
// Cursor expresses Fast as a variant dimension of the picked model, resolved in the
|
|
18
19
|
// request builder, so the adapter set is exactly the cursor adapter.
|
|
19
20
|
"cursor-variant": new Set(["cursor"]),
|
|
@@ -46,6 +47,7 @@ export interface FastPolicyAuthority {
|
|
|
46
47
|
};
|
|
47
48
|
readonly modelAdapters: Readonly<Record<string, string>>;
|
|
48
49
|
readonly hardPins: Readonly<Record<string, string>>;
|
|
50
|
+
readonly hardPinPrefixes?: Readonly<Record<string, string>>;
|
|
49
51
|
readonly registryWireDefaults: Readonly<Record<string, ModelWireDefault>>;
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -153,6 +155,12 @@ function resolvePolicyAdapter(
|
|
|
153
155
|
? authority.hardPins[modelId]
|
|
154
156
|
: undefined;
|
|
155
157
|
if (typeof hardPin === "string") return { adapter: hardPin, hardPinned: true };
|
|
158
|
+
const foldedModelId = modelId.toLowerCase();
|
|
159
|
+
for (const [prefix, adapter] of Object.entries(authority.hardPinPrefixes ?? {})) {
|
|
160
|
+
if (foldedModelId.startsWith(prefix.toLowerCase())) {
|
|
161
|
+
return { adapter, hardPinned: true };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
156
164
|
if (authority.modelWireOverrideAllowed) {
|
|
157
165
|
const registryDefault = MODEL_ADAPTER_OVERRIDE_ALLOWED.has(authority.providerAdapter)
|
|
158
166
|
? registryDefaultForModel(
|
|
@@ -368,7 +376,12 @@ export function createAdapterTierMetadata(
|
|
|
368
376
|
outcome.fastOutcome = "not-requested";
|
|
369
377
|
} else if (!effectiveFastRequested || context.eligibility !== "eligible" || wireValue === null) {
|
|
370
378
|
outcome.fastOutcome = "downgraded";
|
|
371
|
-
|
|
379
|
+
// An upstream that refused the fast wire earlier in this request is a decline, not a
|
|
380
|
+
// missing wire: the route is eligible and was asked, and the standard resend that follows
|
|
381
|
+
// must not read as if the proxy never tried.
|
|
382
|
+
outcome.fastDowngradeReason = context.upstreamDeclinedFast === true
|
|
383
|
+
? "response-declined"
|
|
384
|
+
: downgradeReasonForUnavailable(context);
|
|
372
385
|
outcome.confirmation = "downgraded";
|
|
373
386
|
} else if (canonicalFromWire(context.fastWire, wireValue) === "priority") {
|
|
374
387
|
outcome.canonical = "priority";
|
package/src/providers/label.ts
CHANGED
|
@@ -5,6 +5,8 @@ export function canonicalUsageProviderLabel(provider: string): string {
|
|
|
5
5
|
return provider === "chatgpt" || provider === "openai-multi" ? "openai" : provider;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
const LEGACY_MAIN_ACCOUNT_PROVIDER_LABELS = new Set(["openai-main", "chatgpt-main", "openai-multi-main"]);
|
|
9
|
+
|
|
8
10
|
export function usesApiKeyAccount(provider: Pick<OcxProviderConfig, "authMode" | "_apiKeyAttempt">): boolean {
|
|
9
11
|
return provider.authMode === "key"
|
|
10
12
|
|| (provider.authMode === undefined && !!provider._apiKeyAttempt?.reference);
|
|
@@ -29,11 +31,14 @@ export function baseProviderLabel(provider: string): string {
|
|
|
29
31
|
const cut = provider.lastIndexOf("-");
|
|
30
32
|
if (cut <= 0) return canonicalUsageProviderLabel(provider);
|
|
31
33
|
const suffix = provider.slice(cut + 1);
|
|
32
|
-
// `-main`
|
|
33
|
-
//
|
|
34
|
+
// `-main` was the legacy log label for the main Codex account (MAIN_CODEX_ACCOUNT_ID). Restrict
|
|
35
|
+
// that compatibility mapping to the known Codex provider labels so configured providers whose
|
|
36
|
+
// names naturally end in `-main` remain distinct.
|
|
34
37
|
// ChatGPT auth-pool and OpenAI passthrough are the same Codex/OpenAI usage surface, so display
|
|
35
38
|
// summaries normalize them to one `openai` row after recognized main/pool suffixes are removed.
|
|
36
|
-
if (
|
|
39
|
+
if (LEGACY_MAIN_ACCOUNT_PROVIDER_LABELS.has(provider)) {
|
|
40
|
+
return canonicalUsageProviderLabel(provider.slice(0, cut));
|
|
41
|
+
}
|
|
37
42
|
return CODEX_ACCOUNT_LOG_LABEL_RE.test(suffix) ? canonicalUsageProviderLabel(provider.slice(0, cut)) : provider;
|
|
38
43
|
}
|
|
39
44
|
|
|
@@ -121,6 +121,7 @@ export const PROVIDER_MODEL_RENAME_ROLES = {
|
|
|
121
121
|
transientRetryOn5xx: "none",
|
|
122
122
|
retryOnReset: "none",
|
|
123
123
|
reasoningSplitModels: "list",
|
|
124
|
+
inlineThinkTagModels: "list",
|
|
124
125
|
reasoningDetailsModels: "list",
|
|
125
126
|
thinkingToggleModels: "list",
|
|
126
127
|
thinkingBudgetModels: "list",
|
|
@@ -99,6 +99,7 @@ export function applyOpenAiVirtualModel(
|
|
|
99
99
|
|
|
100
100
|
logCtx.model = resolution.selectedModelId;
|
|
101
101
|
logCtx.resolvedModel = resolution.wireModelId;
|
|
102
|
+
logCtx.wireModel = resolution.wireModelId;
|
|
102
103
|
route.modelId = resolution.wireModelId;
|
|
103
104
|
captureOpenAiVirtualWirePolicy(route, resolution, inboundWire);
|
|
104
105
|
parsed.modelId = resolution.wireModelId;
|
|
@@ -3,6 +3,7 @@ import { MAIN_CODEX_ACCOUNT_ID } from "../../codex/main-account";
|
|
|
3
3
|
import { getValidAccessToken } from "../../oauth";
|
|
4
4
|
import { getAccountCredential, getAccountSet } from "../../oauth/store";
|
|
5
5
|
import { fetchMuseKeyQuotaSnapshot } from "../muse-key-quota";
|
|
6
|
+
import { CLAUDE_CLI_USER_AGENT } from "../claude-cli-identity";
|
|
6
7
|
import { XAI_GROK_CLIENT_VERSION, XAI_GROK_COMPATIBILITY } from "../xai-transport";
|
|
7
8
|
import {
|
|
8
9
|
commitKiroAccountUsageState,
|
|
@@ -276,7 +277,7 @@ export async function fetchAnthropicUsageQuota(accessToken: string): Promise<Pro
|
|
|
276
277
|
headers: {
|
|
277
278
|
Accept: "application/json, text/plain, */*",
|
|
278
279
|
"Content-Type": "application/json",
|
|
279
|
-
"User-Agent":
|
|
280
|
+
"User-Agent": CLAUDE_CLI_USER_AGENT,
|
|
280
281
|
"anthropic-beta": "claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05",
|
|
281
282
|
Authorization: `Bearer ${accessToken}`,
|
|
282
283
|
},
|