@bitkyc08/opencodex 2.91.0 → 2.92.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/bin/ocx.mjs +37 -3
- package/gui/dist/assets/{App-nZ34cR5G.js → App-sUf_8afJ.js} +18 -18
- package/gui/dist/assets/{Tray-BuLy7hL1.js → Tray-BSsxznDm.js} +1 -1
- package/gui/dist/assets/index-BlFE_VB_.js +94 -0
- package/gui/dist/assets/quota-summary-BRlbXgw0.js +1 -0
- package/gui/dist/index.html +1 -1
- package/gui/dist/provider-icons/workbuddy-color.svg +29 -0
- package/package.json +4 -3
- package/src/adapters/google-vertex-endpoint.ts +9 -1
- package/src/adapters/google-vertex-key-project.ts +223 -0
- package/src/adapters/google.ts +13 -3
- package/src/adapters/openai-chat/tool-name-registry.ts +3 -1
- package/src/adapters/openai-chat.ts +2 -2
- package/src/adapters/openai-responses/request-strips.ts +60 -0
- package/src/adapters/registry.ts +5 -0
- package/src/adapters/workbuddy-schema.ts +61 -0
- package/src/adapters/workbuddy.ts +68 -0
- package/src/bridge/response-json.ts +1 -1
- package/src/bridge/sse.ts +1 -1
- package/src/chat/outbound.ts +11 -4
- package/src/cli/capabilities-agents-routing.ts +3 -3
- package/src/cli/codex-cli-update.ts +8 -0
- package/src/cli/combo-result.ts +6 -0
- package/src/cli/combo-stats.ts +3 -0
- package/src/cli/combo.ts +66 -42
- package/src/cli/launcher-context.ts +49 -2
- package/src/cli/link.ts +45 -32
- package/src/cli/provider.ts +2 -1
- package/src/cli/usage-compare.ts +68 -12
- package/src/client/link-ingress.ts +1 -1
- package/src/client/link-readiness.ts +97 -0
- package/src/client/link-relay-transport.ts +79 -11
- package/src/client/link-relay.ts +74 -15
- package/src/client/link-tunnel.ts +45 -18
- package/src/client/machine-listener.ts +20 -2
- package/src/client/runtime.ts +20 -2
- package/src/codex/account-store.ts +17 -3
- package/src/codex/app-server-restart-service.ts +6 -5
- package/src/codex/catalog/effort.ts +9 -2
- package/src/codex/catalog/gather-capture.ts +4 -2
- package/src/codex/catalog/provider-models.ts +14 -8
- package/src/codex/chatgpt-refresh-failure.ts +6 -2
- package/src/codex/cli-install-provenance.ts +418 -0
- package/src/codex/cli-installation-targets.ts +5 -1
- package/src/codex/cli-update-plan.ts +43 -16
- package/src/codex/desktop-app/picker-freshness.ts +10 -8
- package/src/codex/desktop-compatibility/usage-activation.ts +2 -1
- package/src/codex/desktop-compatibility/usage-controller.ts +7 -1
- package/src/codex/pool-refresh-backoff.ts +3 -1
- package/src/codex/user-identity.ts +35 -6
- package/src/codex/windows-current-sid.ts +162 -0
- package/src/combos/jev-quota-activation.ts +5 -1
- package/src/combos/jev-quota-route.ts +1 -1
- package/src/combos/jev-quota.ts +9 -1
- package/src/combos/jev-session-pin-config.ts +51 -0
- package/src/combos/jev.ts +6 -0
- package/src/combos/types.ts +19 -0
- package/src/config/provider-validation.ts +7 -0
- package/src/config/schema/leaf-validators.ts +1 -0
- package/src/generated/compatibility-version.json +194 -122
- package/src/lib/decision-quota-sink.ts +10 -0
- package/src/lib/translator-budget.ts +4 -4
- package/src/lib/upstream-retry.ts +4 -1
- package/src/link/diagnostics.ts +193 -0
- package/src/link/relay-auth.ts +6 -0
- package/src/link/status-projection.ts +39 -0
- package/src/link/supervisor.ts +45 -12
- package/src/link/tunnel-history.ts +109 -0
- package/src/link/tunnel-state.ts +80 -17
- package/src/messaging/remote-files.ts +24 -1
- package/src/oauth/generic-account-failover.ts +91 -7
- package/src/oauth/index.ts +15 -0
- package/src/oauth/model-discovery-auth.ts +5 -0
- package/src/oauth/store.ts +4 -1
- package/src/oauth/token-guardian.ts +7 -0
- package/src/oauth/types.ts +9 -0
- package/src/oauth/workbuddy.ts +139 -0
- package/src/providers/antigravity-quota-identity.ts +37 -0
- package/src/providers/base-url-choices.ts +8 -5
- package/src/providers/derive.ts +23 -3
- package/src/providers/model-discovery.ts +2 -0
- package/src/providers/model-rename-fields.ts +1 -0
- package/src/providers/quota/account-cache.ts +3 -2
- package/src/providers/quota/antigravity.ts +25 -14
- package/src/providers/quota/report-cache.ts +13 -4
- package/src/providers/quota/vendor-probes-key.ts +60 -0
- package/src/providers/quota/workbuddy.ts +83 -0
- package/src/providers/quota-decision-antigravity.ts +64 -0
- package/src/providers/quota-decision-publication.ts +11 -0
- package/src/providers/quota-decision-snapshot.ts +21 -4
- package/src/providers/quota-types.ts +2 -0
- package/src/providers/quota.ts +3 -1
- package/src/providers/registry/entries-core.ts +9 -0
- package/src/providers/registry/entries-extended.ts +20 -7
- package/src/providers/registry/model-ids.ts +3 -0
- package/src/providers/registry/model-seeds.ts +27 -28
- package/src/providers/registry/types.ts +19 -1
- package/src/providers/resolved-model-policy.ts +4 -4
- package/src/providers/routed-config.ts +15 -0
- package/src/providers/stale-model-roster-migration.ts +83 -15
- package/src/providers/workbuddy-credit-balance.ts +81 -0
- package/src/providers/workbuddy-models.ts +37 -0
- package/src/providers/workbuddy.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +18 -14
- package/src/router.ts +2 -0
- package/src/routing/analytics.ts +2 -3
- package/src/routing/fallback-policy.ts +3 -3
- package/src/server/auth-cors.ts +1 -0
- package/src/server/chat-completions.ts +14 -1
- package/src/server/chat-native-reasoning.ts +10 -3
- package/src/server/chat-native.ts +13 -2
- package/src/server/claude-messages.ts +3 -0
- package/src/server/index/link-relay-sessions.ts +9 -5
- package/src/server/index/optional-listeners.ts +4 -0
- package/src/server/local-management-read-client.ts +3 -1
- package/src/server/management/combo-routes.ts +10 -4
- package/src/server/management/link-routes.ts +5 -2
- package/src/server/management/provider-routes.ts +1 -1
- package/src/server/port-reclaim.ts +51 -9
- package/src/server/request-log-conversation.ts +49 -0
- package/src/server/request-log.ts +2 -0
- package/src/server/responses/anthropic-thinking-recovery.ts +1 -0
- package/src/server/responses/compact.ts +10 -2
- package/src/server/responses/core-combo.ts +53 -31
- package/src/server/responses/core-lifetime.ts +2 -2
- package/src/server/responses/core-normalize.ts +6 -3
- package/src/server/responses/core-opaque-recovery.ts +1 -0
- package/src/server/responses/core-options.ts +5 -0
- package/src/server/responses/core-replay.ts +2 -1
- package/src/server/responses/jev-combo-choice.ts +39 -0
- package/src/server/responses/jev-session-pin.ts +203 -0
- package/src/server/responses/passthrough-delivery.ts +4 -0
- package/src/server/responses/request-prepare.ts +10 -5
- package/src/server/responses/request-transport.ts +25 -6
- package/src/server/responses/run-turn-execution.ts +2 -4
- package/src/server/responses/sidecar-execution.ts +2 -4
- package/src/server/responses-phase-inference.ts +267 -0
- package/src/server/sse-payload-rewrite.ts +14 -1
- package/src/service/definition.ts +20 -8
- package/src/types/config.ts +6 -0
- package/src/types/provider.ts +9 -1
- package/src/types/request.ts +1 -0
- package/src/types/wire.ts +1 -0
- package/src/update/codex-cli-update-launch-policy.d.mts +9 -0
- package/src/update/codex-cli-update-launch-policy.mjs +30 -0
- package/src/usage/jev-stats.ts +54 -14
- package/gui/dist/assets/index-DGXS51sp.js +0 -94
- package/gui/dist/assets/quota-summary-DO1Sx5TM.js +0 -1
|
@@ -3,12 +3,23 @@ import { createHash } from "node:crypto";
|
|
|
3
3
|
import { getConfigDir } from "../config/paths";
|
|
4
4
|
import { captureConfigGeneration } from "../lib/state-store-sweeper";
|
|
5
5
|
import type { OcxProviderConfig } from "../types";
|
|
6
|
+
import { invalidateAntigravityQuota, readAntigravityQuota } from "./quota-decision-antigravity";
|
|
7
|
+
import type { DecisionKeyObservation } from "../lib/decision-quota-sink";
|
|
6
8
|
|
|
7
9
|
export interface DecisionQuotaWindow {
|
|
8
10
|
window: "5h" | "weekly" | "monthly" | "fable" | "opus" | "sonnet";
|
|
9
11
|
percent: number;
|
|
10
12
|
observedAt: number;
|
|
11
13
|
resetAt?: number;
|
|
14
|
+
/** Model family this window meters (Antigravity Gemini vs Claude/3P buckets); absent means every model of the provider. */
|
|
15
|
+
family?: DecisionQuotaFamily;
|
|
16
|
+
}
|
|
17
|
+
export type DecisionQuotaFamily = "gem" | "cla";
|
|
18
|
+
/** True when the provider row can carry sole-credential decision evidence under `name`. */
|
|
19
|
+
function keyEvidenceEligible(name: string, provider: OcxProviderConfig): boolean {
|
|
20
|
+
if (provider.disabled || (provider.apiKeyPool?.length ?? 0) > 1) return false;
|
|
21
|
+
const mode = provider.authMode ?? "key";
|
|
22
|
+
return mode === "key";
|
|
12
23
|
}
|
|
13
24
|
export interface DecisionQuotaAccount {
|
|
14
25
|
id: string;
|
|
@@ -54,18 +65,24 @@ function keyPolicy(provider: OcxProviderConfig): string {
|
|
|
54
65
|
])).digest("hex");
|
|
55
66
|
}
|
|
56
67
|
/** Drop all key-based decision evidence and advance the epoch so earlier publications cannot be read. */
|
|
57
|
-
export function invalidateDecisionKeyQuotas(): void { keyEpoch++; keys.clear(); }
|
|
68
|
+
export function invalidateDecisionKeyQuotas(): void { keyEpoch++; keys.clear(); invalidateAntigravityQuota(); }
|
|
69
|
+
/** Collector replacement does not retire live OAuth producer receipts or their original clocks. */
|
|
70
|
+
export function replaceDecisionKeyQuotas(rows: readonly DecisionKeyObservation[]): void {
|
|
71
|
+
keyEpoch++; keys.clear();
|
|
72
|
+
for (const row of rows) publishDecisionKeyQuota(row.name, row.provider, row.windows);
|
|
73
|
+
}
|
|
58
74
|
/** Publish decision windows for a single-key provider; pooled, disabled or non-key providers are never published, and the table is bounded. */
|
|
59
75
|
export function publishDecisionKeyQuota(name: string, provider: OcxProviderConfig, windows: readonly DecisionQuotaWindow[]): void {
|
|
60
76
|
writesForTests++;
|
|
61
|
-
if (name.length > 1024 ||
|
|
77
|
+
if (name.length > 1024 || !keyEvidenceEligible(name, provider)) return;
|
|
62
78
|
if (keys.size >= 256 && !keys.has(name)) keys.delete(keys.keys().next().value!);
|
|
63
79
|
keys.set(name, { root: getConfigDir(), epoch: keyEpoch, configGeneration: captureConfigGeneration(), policy: keyPolicy(provider), windows: copyWindows(windows) });
|
|
64
80
|
}
|
|
65
81
|
/** Read key-based evidence only when the config root, epoch, generation and provider policy still match what was published. */
|
|
66
82
|
export function readLoadedDecisionKeyQuota(name: string, provider: OcxProviderConfig): readonly DecisionQuotaWindow[] | undefined {
|
|
83
|
+
if (provider.authMode === "oauth") return readAntigravityQuota(name, provider);
|
|
67
84
|
const row = keys.get(name);
|
|
68
|
-
if (!row ||
|
|
85
|
+
if (!row || !keyEvidenceEligible(name, provider)
|
|
69
86
|
|| row.root !== getConfigDir() || row.epoch !== keyEpoch || row.configGeneration !== captureConfigGeneration()
|
|
70
87
|
|| row.policy !== keyPolicy(provider)) return undefined;
|
|
71
88
|
return row.windows.map(row => ({ ...row }));
|
|
@@ -141,5 +158,5 @@ export function clearDecisionAccountQuotas(provider?: string, id?: string): void
|
|
|
141
158
|
/** Copy only known window kinds into the bounded evidence table, so callers cannot retain a mutable reference. */
|
|
142
159
|
function copyWindows(windows: readonly DecisionQuotaWindow[]): DecisionQuotaWindow[] {
|
|
143
160
|
if (windows.length > MAX_WINDOWS) return [];
|
|
144
|
-
return windows.filter(row => ["5h", "weekly", "monthly", "fable", "opus", "sonnet"].includes(row.window)).map(row => ({ window: row.window, percent: row.percent, observedAt: row.observedAt, ...(row.resetAt !== undefined ? { resetAt: row.resetAt } : {}) }));
|
|
161
|
+
return windows.filter(row => ["5h", "weekly", "monthly", "fable", "opus", "sonnet"].includes(row.window)).map(row => ({ window: row.window, percent: row.percent, observedAt: row.observedAt, ...(row.resetAt !== undefined ? { resetAt: row.resetAt } : {}), ...(row.family === "gem" || row.family === "cla" ? { family: row.family } : {}) }));
|
|
145
162
|
}
|
|
@@ -53,6 +53,8 @@ export interface ProviderQuotaCreditsUsd {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export interface ProviderQuota {
|
|
56
|
+
/** Display-only subscription credits; not a routing or exhaustion window. */
|
|
57
|
+
workbuddyCredits?: import("./workbuddy-credit-balance").WorkBuddyCreditBalance;
|
|
56
58
|
fiveHourPercent?: number;
|
|
57
59
|
fiveHourResetAt?: number;
|
|
58
60
|
weeklyPercent?: number;
|
package/src/providers/quota.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { listCodexAuthAccountsSnapshot } from "../codex/auth-api";
|
|
2
2
|
import { isAnthropicInstanceId, configuredAnthropicInstance } from "./anthropic-instance";
|
|
3
|
+
import { ANTIGRAVITY_OAUTH_STORE_KEY } from "./antigravity-quota-identity";
|
|
3
4
|
import { fetchAnthropicAccountQuota } from "./quota/anthropic-account-quota";
|
|
4
5
|
import { thrownQuotaFailure } from "./quota/failure-codes";
|
|
5
6
|
import { resolveEnvValue } from "../config";
|
|
@@ -124,7 +125,7 @@ async function maybeFetchProviderQuota(
|
|
|
124
125
|
}
|
|
125
126
|
if (provider.authMode === "oauth" && explicitAccountReader(name)) return await fetchExplicitCurrentQuota(name, provider, config);
|
|
126
127
|
if (provider.authMode === "oauth" && configuredAnthropicInstance(config, name)) return fetchAnthropicQuota(name, config);
|
|
127
|
-
if (provider.authMode === "oauth" && name ===
|
|
128
|
+
if (provider.authMode === "oauth" && name === ANTIGRAVITY_OAUTH_STORE_KEY) return await fetchAntigravityQuota(name, { ...provider });
|
|
128
129
|
if (provider.authMode === "oauth" && name === "kiro") return fetchKiroQuota(name);
|
|
129
130
|
// meta-muse: a device-logged-in account can be probed at the key endpoint; an
|
|
130
131
|
// imported or pasted one cannot, and falls back to its last in-band observation.
|
|
@@ -368,6 +369,7 @@ async function readExplicitAccountQuota(provider: string, accountId: string, con
|
|
|
368
369
|
case "kimi": result = await fetchKimiQuota(provider, config, accessToken); break;
|
|
369
370
|
case "command-code": result = await fetchCommandCodeQuota(provider, config, accessToken); break;
|
|
370
371
|
case "devin": result = await (await import("./quota/devin")).fetchDevinQuota(provider, accessToken, credential.apiBaseUrl, config.baseUrl); break;
|
|
372
|
+
case "workbuddy-ai": result = await (await import("./quota/workbuddy")).fetchWorkBuddyQuota(provider, credential); break;
|
|
371
373
|
case "dsh-account": result = await (await import("./quota/dsh-account")).fetchDshAccountQuota(provider, accessToken, { accountId, credential }); break;
|
|
372
374
|
default: return null;
|
|
373
375
|
}
|
|
@@ -516,6 +516,15 @@ export const PROVIDER_REGISTRY_CORE: readonly ProviderRegistryEntry[] = [
|
|
|
516
516
|
// The proprietary generate wire has no verified per-request serialization flag.
|
|
517
517
|
parallelToolCalls: false,
|
|
518
518
|
},
|
|
519
|
+
{
|
|
520
|
+
id: "workbuddy-ai", label: "WorkBuddy AI", adapter: "workbuddy-ai",
|
|
521
|
+
baseUrl: "https://www.workbuddy.ai/v2", authKind: "oauth", oauthId: "workbuddy-ai",
|
|
522
|
+
featured: false, dashboardPreset: true, liveModels: true,
|
|
523
|
+
defaultModel: "default-model", models: ["default-model"],
|
|
524
|
+
modelDiscovery: { path: "/v3/config", format: "workbuddy" },
|
|
525
|
+
dashboardUrl: "https://www.workbuddy.ai",
|
|
526
|
+
note: "Use your WorkBuddy AI international subscription. Sign in in your browser; models follow your account catalog.",
|
|
527
|
+
},
|
|
519
528
|
{
|
|
520
529
|
id: "dsh-account",
|
|
521
530
|
label: "DeepSeek Account (DSH)",
|
|
@@ -483,6 +483,10 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [
|
|
|
483
483
|
noPenaltyModels: KIMI_API_MODELS,
|
|
484
484
|
autoToolChoiceOnlyModels: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed"],
|
|
485
485
|
preserveReasoningContentModels: KIMI_API_MODELS,
|
|
486
|
+
// api.moonshot.ai answers `400 Invalid request: role 'developer' is not allowed`. The
|
|
487
|
+
// translated route already folds when nothing is recorded, but the native
|
|
488
|
+
// /v1/chat/completions passthrough only folds on an explicit record, so record it here.
|
|
489
|
+
foldDeveloperRoleToSystem: true,
|
|
486
490
|
note: "International default (api.moonshot.ai). China accounts: choose China (.cn) or Custom for api.moonshot.cn.",
|
|
487
491
|
},
|
|
488
492
|
{ id: "huggingface", label: "Hugging Face", baseUrl: "https://router.huggingface.co/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://huggingface.co/settings/tokens" },
|
|
@@ -837,6 +841,8 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [
|
|
|
837
841
|
{
|
|
838
842
|
id: "alibaba-token-plan",
|
|
839
843
|
label: "Alibaba Token Plan (Beijing)",
|
|
844
|
+
// Official Personal quick start (2026-10-23) still documents this host:
|
|
845
|
+
// https://help.aliyun.com/en/model-studio/token-plan-personal-quick-start
|
|
840
846
|
baseUrl: "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
|
|
841
847
|
adapter: "openai-chat",
|
|
842
848
|
authKind: "key",
|
|
@@ -887,19 +893,23 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [
|
|
|
887
893
|
"deepseek-v4-pro-0813": deepseekThinkingEffortsFor("deepseek-v4-pro-0813"),
|
|
888
894
|
"deepseek-v4-flash-0731": deepseekThinkingEffortsFor("deepseek-v4-flash-0731"),
|
|
889
895
|
"deepseek-v4.1-flash": deepseekThinkingEffortsFor("deepseek-v4.1-flash"),
|
|
896
|
+
"deepseek-v4.1-flash-1017": deepseekThinkingEffortsFor("deepseek-v4.1-flash-1017"),
|
|
890
897
|
},
|
|
891
898
|
modelReasoningEffortMap: {
|
|
892
899
|
"deepseek-v4-pro": deepseekReasoningMapFor("deepseek-v4-pro"),
|
|
893
900
|
"deepseek-v4-pro-0813": deepseekReasoningMapFor("deepseek-v4-pro-0813"),
|
|
894
901
|
"deepseek-v4-flash-0731": deepseekReasoningMapFor("deepseek-v4-flash-0731"),
|
|
895
902
|
"deepseek-v4.1-flash": deepseekReasoningMapFor("deepseek-v4.1-flash"),
|
|
903
|
+
"deepseek-v4.1-flash-1017": deepseekReasoningMapFor("deepseek-v4.1-flash-1017"),
|
|
896
904
|
},
|
|
897
905
|
// Probed 260915 on the plan gateway: json_object returns valid JSON, strict
|
|
898
906
|
// json_schema is rejected 400 ("This response_format type is unavailable now")
|
|
899
907
|
// in both thinking modes, so requests downgrade to json_object rather than
|
|
900
908
|
// sending a schema the gateway refuses.
|
|
901
909
|
noJsonSchemaModels: ["deepseek-v4.1-flash"],
|
|
902
|
-
|
|
910
|
+
// 261020 strict schema rejected; json_object unverified. Omit rather than invent a fallback.
|
|
911
|
+
noStructuredOutputModels: ["deepseek-v4.1-flash-1017"],
|
|
912
|
+
modelDefaultReasoningEfforts: { ...Object.fromEntries(QWEN38_FAMILY.map(id => [id, "xhigh"])), "deepseek-v4.1-flash-1017": "high" },
|
|
903
913
|
directReasoningEffortModels: QWEN38_FAMILY,
|
|
904
914
|
thinkingBudgetModels: ALIBABA_TOKEN_PLAN_QWEN_MODELS.filter(id => !QWEN38_FAMILY.includes(id)),
|
|
905
915
|
preserveReasoningContentModels: ALIBABA_TOKEN_PLAN_PRESERVE_REASONING,
|
|
@@ -935,25 +945,27 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [
|
|
|
935
945
|
"glm-5.3": ZAI_GLM_53_REASONING_EFFORTS,
|
|
936
946
|
"deepseek-v4-pro": deepseekThinkingEffortsFor("deepseek-v4-pro"),
|
|
937
947
|
"deepseek-v4-pro-0813": deepseekThinkingEffortsFor("deepseek-v4-pro-0813"),
|
|
938
|
-
"deepseek-v4-flash": deepseekThinkingEffortsFor("deepseek-v4-flash"),
|
|
939
948
|
"deepseek-v4-flash-0731": deepseekThinkingEffortsFor("deepseek-v4-flash-0731"),
|
|
940
949
|
"deepseek-v4.1-flash": deepseekThinkingEffortsFor("deepseek-v4.1-flash"),
|
|
950
|
+
"deepseek-v4.1-flash-1017": deepseekThinkingEffortsFor("deepseek-v4.1-flash-1017"),
|
|
941
951
|
},
|
|
942
952
|
modelReasoningEffortMap: {
|
|
943
953
|
"deepseek-v4-pro": deepseekReasoningMapFor("deepseek-v4-pro"),
|
|
944
954
|
"deepseek-v4-pro-0813": deepseekReasoningMapFor("deepseek-v4-pro-0813"),
|
|
945
|
-
"deepseek-v4-flash": deepseekReasoningMapFor("deepseek-v4-flash"),
|
|
946
955
|
"deepseek-v4-flash-0731": deepseekReasoningMapFor("deepseek-v4-flash-0731"),
|
|
947
956
|
"deepseek-v4.1-flash": deepseekReasoningMapFor("deepseek-v4.1-flash"),
|
|
957
|
+
"deepseek-v4.1-flash-1017": deepseekReasoningMapFor("deepseek-v4.1-flash-1017"),
|
|
948
958
|
},
|
|
949
959
|
// Same 260915 json_schema rejection probe as the Beijing entry.
|
|
950
960
|
noJsonSchemaModels: ["deepseek-v4.1-flash"],
|
|
961
|
+
// 261020 strict schema rejected; json_object unverified. Omit rather than invent a fallback.
|
|
962
|
+
noStructuredOutputModels: ["deepseek-v4.1-flash-1017"],
|
|
951
963
|
directReasoningEffortModels: QWEN38_FAMILY,
|
|
952
964
|
thinkingBudgetModels: ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS.filter(id => !QWEN38_FAMILY.includes(id)),
|
|
953
965
|
preserveReasoningContentModels: ALIBABA_TOKEN_PLAN_PRESERVE_REASONING,
|
|
954
966
|
noVisionModels: ALIBABA_TOKEN_PLAN_NO_VISION,
|
|
955
|
-
noReasoningModels: ["kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", "
|
|
956
|
-
modelDefaultReasoningEfforts: Object.fromEntries(QWEN38_FAMILY.map(id => [id, "xhigh"])),
|
|
967
|
+
noReasoningModels: ["kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", "glm-5.1", "glm-5", "MiniMax-M2.5"],
|
|
968
|
+
modelDefaultReasoningEfforts: { ...Object.fromEntries(QWEN38_FAMILY.map(id => [id, "xhigh"])), "deepseek-v4.1-flash-1017": "high" },
|
|
957
969
|
promptCacheKey: true,
|
|
958
970
|
},
|
|
959
971
|
// NEEDS_HUMAN 2026-07-10: kept for config compatibility, but this is a dashboard URL,
|
|
@@ -1303,14 +1315,15 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [
|
|
|
1303
1315
|
baseUrl: "https://api.xiaomimimo.com/api/free-ai/openai/chat",
|
|
1304
1316
|
authKind: "key",
|
|
1305
1317
|
keyOptional: true,
|
|
1306
|
-
featured:
|
|
1318
|
+
featured: false,
|
|
1319
|
+
deprecated: "Deprecated: requests through this entry fail. Bootstrap may still return a JWT, but /api/free-ai/openai/chat rejects the configured model \"mimo-auto\" with 400 \"Unsupported model\". Kept only so existing saved providers keep resolving; new setups should use the keyed xiaomi provider.",
|
|
1307
1320
|
liveModels: true,
|
|
1308
1321
|
dashboardUrl: "https://xiaomimimo.com",
|
|
1309
1322
|
defaultModel: "mimo-auto",
|
|
1310
1323
|
models: ["mimo-auto"],
|
|
1311
1324
|
reasoningEfforts: ["low", "medium", "high"],
|
|
1312
1325
|
reasoningEffortMap: { xhigh: "high", max: "high", ultra: "high" },
|
|
1313
|
-
note: "
|
|
1326
|
+
note: "Deprecated: the anonymous MiMo free lane stopped completing requests for this entry in 2026. Bootstrap may still issue a JWT, but /api/free-ai/openai/chat rejects the configured model \"mimo-auto\" with 400 \"Unsupported model\", so turns cannot finish. This entry remains only so existing saved providers keep resolving; add the keyed Xiaomi provider at https://platform.xiaomimimo.com instead. Xiaomi may resume or change the service at any time.",
|
|
1314
1327
|
},
|
|
1315
1328
|
// Xiaomi MiMo paid token plan. Separate host and wire from both `xiaomi` (Anthropic) and
|
|
1316
1329
|
// `mimo-free` (free tier, bespoke adapter), so it needs its own entry rather than a variant.
|
|
@@ -61,6 +61,7 @@ export const REGISTRY_FIELD_MODEL_ID_ROLES = {
|
|
|
61
61
|
featured: NONE,
|
|
62
62
|
sponsor: NONE,
|
|
63
63
|
dashboardPreset: NONE,
|
|
64
|
+
deprecated: NONE,
|
|
64
65
|
note: NONE,
|
|
65
66
|
dashboardUrl: NONE,
|
|
66
67
|
defaultModel: NONE,
|
|
@@ -114,10 +115,12 @@ export const REGISTRY_FIELD_MODEL_ID_ROLES = {
|
|
|
114
115
|
noStopModels: NONE,
|
|
115
116
|
noPenaltyModels: NONE,
|
|
116
117
|
noJsonSchemaModels: NONE,
|
|
118
|
+
noStructuredOutputModels: NONE,
|
|
117
119
|
parallelToolCalls: NONE,
|
|
118
120
|
promptCacheKey: NONE,
|
|
119
121
|
chatServiceTier: NONE,
|
|
120
122
|
openaiChatEofTolerance: NONE,
|
|
123
|
+
foldDeveloperRoleToSystem: NONE,
|
|
121
124
|
autoToolChoiceOnlyModels: NONE,
|
|
122
125
|
preserveReasoningContentModels: NONE,
|
|
123
126
|
requiresReasoningPlaceholderModels: NONE,
|
|
@@ -573,22 +573,22 @@ export const deepseekReasoningMapFor = (modelId: string): Record<string, string>
|
|
|
573
573
|
// text-only input, strict json_schema accepted. glm-5.3-flash REMAINS OUT:
|
|
574
574
|
// still never served by the Token Plan gateway (docs.z.ai VLM id, not plan
|
|
575
575
|
// entitlement).
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
//
|
|
580
|
-
//
|
|
581
|
-
//
|
|
582
|
-
//
|
|
583
|
-
//
|
|
584
|
-
//
|
|
585
|
-
//
|
|
586
|
-
//
|
|
587
|
-
//
|
|
588
|
-
//
|
|
576
|
+
// Both regions support Personal and Team subscriptions. Keep the existing Beijing
|
|
577
|
+
// Personal and International Team model rosters. Discovery stays disabled because
|
|
578
|
+
// the upstream list includes non-chat models.
|
|
579
|
+
// 261020: 0813 is now listed on Global Personal/Team and CN Team, and the CN Personal
|
|
580
|
+
// overview documents entitlement. Add it to the existing Personal curation without
|
|
581
|
+
// claiming new Personal inference. Retired 261011: deepseek-v3.2 and bare v4-flash.
|
|
582
|
+
// 1017 evidence: https://www.qianwenai.com/models/deepseek-v4.1-flash-1017 and
|
|
583
|
+
// https://docs.qwencloud.com/api-reference/chat/openai-chat (checked 2026-10-20).
|
|
584
|
+
// Global Personal probes: completion, thinking-off, low effort, tools, user/tool images
|
|
585
|
+
// and Responses succeed; strict json_schema rejects 400. json_object and replay are
|
|
586
|
+
// untested on this exact id. Published 1M context and 393K output use 393216 here,
|
|
587
|
+
// consistent with the existing plan budget convention, not a measured boundary;
|
|
588
|
+
// the lab's 384000 precision differs. Do not inherit the bare model's JSON fallback.
|
|
589
589
|
export const ALIBABA_TOKEN_PLAN_MODELS = [
|
|
590
590
|
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
|
|
591
|
-
"deepseek-v4-pro", "deepseek-v4-flash-0731", "deepseek-v4.1-flash", "glm-5.2", "glm-5.3",
|
|
591
|
+
"deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash-0731", "deepseek-v4.1-flash", "deepseek-v4.1-flash-1017", "glm-5.2", "glm-5.3",
|
|
592
592
|
];
|
|
593
593
|
export const ALIBABA_TOKEN_PLAN_QWEN_MODELS = [
|
|
594
594
|
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
|
|
@@ -604,12 +604,13 @@ export const ALIBABA_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
|
604
604
|
"deepseek-v4-flash-0731": ["text"],
|
|
605
605
|
// Vision probed on the plan gateway 260915 (user message and tool result, both 200).
|
|
606
606
|
"deepseek-v4.1-flash": ["text", "image"],
|
|
607
|
+
"deepseek-v4.1-flash-1017": ["text", "image"],
|
|
607
608
|
"glm-5.2": ["text"],
|
|
608
609
|
"glm-5.3": ["text"],
|
|
609
610
|
};
|
|
610
611
|
|
|
611
612
|
// 260721 Alibaba Token Plan International (ap-southeast-1 / Singapore, hardened 260721).
|
|
612
|
-
//
|
|
613
|
+
// International Team model roster; tier and region are independent.
|
|
613
614
|
// Evidence: https://www.alibabacloud.com/help/en/model-studio/token-plan-overview
|
|
614
615
|
// https://qwencloud.com/pricing/token-plan (qwen3.8 metadata)
|
|
615
616
|
// The Team Edition roster (Singapore), verified identical to the CN Team set on 260909.
|
|
@@ -617,7 +618,7 @@ export const ALIBABA_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
|
617
618
|
// listed on /models on both regions) after being dropped as "retired" upstream.
|
|
618
619
|
export const ALIBABA_INTL_TOKEN_PLAN_MODELS = [
|
|
619
620
|
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
|
|
620
|
-
"deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash", "deepseek-v4-flash
|
|
621
|
+
"deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash-0731", "deepseek-v4.1-flash", "deepseek-v4.1-flash-1017",
|
|
621
622
|
"kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5",
|
|
622
623
|
"glm-5.2", "glm-5.3", "glm-5.1", "glm-5",
|
|
623
624
|
"MiniMax-M2.5",
|
|
@@ -702,8 +703,6 @@ export const VOLCENGINE_PLAN_TEXT_ONLY_MODELS = [
|
|
|
702
703
|
export const ALIBABA_INTL_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
703
704
|
...ALIBABA_TOKEN_PLAN_INPUT_MODALITIES,
|
|
704
705
|
"qwen3.6-plus": ["text", "image"],
|
|
705
|
-
"deepseek-v4-flash": ["text"],
|
|
706
|
-
"deepseek-v3.2": ["text"],
|
|
707
706
|
"kimi-k2.7-code": ["text", "image"],
|
|
708
707
|
"kimi-k2.6": ["text", "image"],
|
|
709
708
|
"kimi-k2.5": ["text", "image"],
|
|
@@ -712,14 +711,14 @@ export const ALIBABA_INTL_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]>
|
|
|
712
711
|
"MiniMax-M2.5": ["text"],
|
|
713
712
|
};
|
|
714
713
|
|
|
715
|
-
// Shared Token Plan metadata
|
|
716
|
-
//
|
|
714
|
+
// Shared Token Plan metadata: legacy rows use 260909 max_tokens boundary probes.
|
|
715
|
+
// The 1017 row uses published card normalization, not a boundary probe (see above).
|
|
717
716
|
export const QWEN38_FAMILY = ["qwen3.8-max", "qwen3.8-flash"];
|
|
718
717
|
export const ALIBABA_TOKEN_PLAN_CONTEXT_WINDOWS: Record<string, number> = {
|
|
719
718
|
"qwen3.8-max": 1_000_000, "qwen3.8-flash": 1_000_000, "qwen3.7-max": 1_000_000, "qwen3.7-plus": 1_000_000,
|
|
720
719
|
"qwen3.6-plus": 1_000_000, "qwen3.6-flash": 1_000_000,
|
|
721
|
-
"deepseek-v4-pro": 1_000_000, "deepseek-v4-pro-0813": 1_000_000,
|
|
722
|
-
"deepseek-v4-flash-0731": 1_000_000, "deepseek-v4.1-flash": 1_000_000, "deepseek-
|
|
720
|
+
"deepseek-v4-pro": 1_000_000, "deepseek-v4-pro-0813": 1_000_000,
|
|
721
|
+
"deepseek-v4-flash-0731": 1_000_000, "deepseek-v4.1-flash": 1_000_000, "deepseek-v4.1-flash-1017": 1_000_000,
|
|
723
722
|
"kimi-k2.7-code": 262_144, "kimi-k2.6": 262_144, "kimi-k2.5": 262_144,
|
|
724
723
|
"glm-5.2": 1_000_000, "glm-5.3": 1_000_000, "glm-5.1": 202_752, "glm-5": 202_752,
|
|
725
724
|
"MiniMax-M2.5": 196_608,
|
|
@@ -727,20 +726,20 @@ export const ALIBABA_TOKEN_PLAN_CONTEXT_WINDOWS: Record<string, number> = {
|
|
|
727
726
|
export const ALIBABA_TOKEN_PLAN_MAX_OUTPUT_TOKENS: Record<string, number> = {
|
|
728
727
|
"qwen3.8-max": 131_072, "qwen3.8-flash": 131_072, "qwen3.7-max": 131_072, "qwen3.7-plus": 131_072,
|
|
729
728
|
"qwen3.6-plus": 65_536, "qwen3.6-flash": 65_536,
|
|
730
|
-
"deepseek-v4-pro": 393_216, "deepseek-v4-pro-0813": 393_216,
|
|
731
|
-
"deepseek-v4-flash-0731": 393_216, "deepseek-v4.1-flash": 393_216, "deepseek-
|
|
729
|
+
"deepseek-v4-pro": 393_216, "deepseek-v4-pro-0813": 393_216,
|
|
730
|
+
"deepseek-v4-flash-0731": 393_216, "deepseek-v4.1-flash": 393_216, "deepseek-v4.1-flash-1017": 393_216,
|
|
732
731
|
"kimi-k2.7-code": 262_144, "kimi-k2.6": 262_144, "kimi-k2.5": 98_304,
|
|
733
732
|
"glm-5.2": 131_072, "glm-5.3": 131_072, "glm-5.1": 128_000, "glm-5": 16_384,
|
|
734
733
|
"MiniMax-M2.5": 32_768,
|
|
735
734
|
};
|
|
736
735
|
export const ALIBABA_TOKEN_PLAN_NO_VISION = [
|
|
737
|
-
"qwen3.7-max", "deepseek-v4-pro", "deepseek-v4-pro-0813",
|
|
738
|
-
"deepseek-v4-flash-0731", "
|
|
736
|
+
"qwen3.7-max", "deepseek-v4-pro", "deepseek-v4-pro-0813",
|
|
737
|
+
"deepseek-v4-flash-0731", "glm-5.2", "glm-5.3", "glm-5.1", "glm-5", "MiniMax-M2.5",
|
|
739
738
|
];
|
|
740
739
|
export const ALIBABA_TOKEN_PLAN_PRESERVE_REASONING = [
|
|
741
740
|
"qwen3.8-max", "qwen3.8-flash", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
|
|
742
|
-
"deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash
|
|
743
|
-
"deepseek-v4.1-flash", "glm-5.2", "glm-5.3",
|
|
741
|
+
"deepseek-v4-pro", "deepseek-v4-pro-0813", "deepseek-v4-flash-0731",
|
|
742
|
+
"deepseek-v4.1-flash", "deepseek-v4.1-flash-1017", "glm-5.2", "glm-5.3",
|
|
744
743
|
];
|
|
745
744
|
|
|
746
745
|
// 260717 Kimi K3: the subscription endpoint uses one upstream id (`k3`) for both
|
|
@@ -63,6 +63,8 @@ export interface ProviderModelDiscoveryFilter {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
interface ProviderModelDiscoverySharedSpec {
|
|
66
|
+
/** Product-config envelope used by WorkBuddy AI instead of an OpenAI model list. */
|
|
67
|
+
format?: "workbuddy";
|
|
66
68
|
/** Query parameters applied to the resolved discovery URL. */
|
|
67
69
|
query?: Readonly<Record<string, string>>;
|
|
68
70
|
/** Top-level response key containing model rows; defaults to `data`. */
|
|
@@ -160,6 +162,14 @@ export interface ProviderRegistryEntry {
|
|
|
160
162
|
*/
|
|
161
163
|
sponsor?: { tier: "main" | "standard"; url: string };
|
|
162
164
|
dashboardPreset?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* The upstream route or service this entry depends on is gone. Deprecated entries stay in the
|
|
167
|
+
* registry so saved providers keep resolving and a pinned adapter keeps loading, but they are
|
|
168
|
+
* excluded from the add-provider picker, the init menu, the featured list, and new key logins.
|
|
169
|
+
* The value is the operator-facing reason; it is registry-only and never seeded into saved
|
|
170
|
+
* config.
|
|
171
|
+
*/
|
|
172
|
+
deprecated?: string;
|
|
163
173
|
note?: string;
|
|
164
174
|
dashboardUrl?: string;
|
|
165
175
|
defaultModel?: string;
|
|
@@ -334,6 +344,8 @@ export interface ProviderRegistryEntry {
|
|
|
334
344
|
* `directReasoningEffortModels` above is registry-owned.
|
|
335
345
|
*/
|
|
336
346
|
noJsonSchemaModels?: string[];
|
|
347
|
+
/** Exact models with no established structured-output wire format. Registry-owned at routing. */
|
|
348
|
+
noStructuredOutputModels?: string[];
|
|
337
349
|
/** Opt this provider into parallel tool calls (see OcxProviderConfig.parallelToolCalls). */
|
|
338
350
|
parallelToolCalls?: boolean;
|
|
339
351
|
/** Opt this provider into forwarding prompt_cache_key (OpenAI-specific; strict backends reject it). */
|
|
@@ -346,6 +358,12 @@ export interface ProviderRegistryEntry {
|
|
|
346
358
|
chatServiceTier?: boolean;
|
|
347
359
|
/** OpenAI Chat EOF policy for gateways that omit terminal frames after complete tool calls. */
|
|
348
360
|
openaiChatEofTolerance?: boolean;
|
|
361
|
+
/**
|
|
362
|
+
* Record that this destination rejects the Chat `developer` role (`400 role 'developer' is not
|
|
363
|
+
* allowed`), so both the translated route and the native `/v1/chat/completions` passthrough send
|
|
364
|
+
* `system` instead. Seeds `foldDeveloperRoleToSystem` on the provider config; a user value wins.
|
|
365
|
+
*/
|
|
366
|
+
foldDeveloperRoleToSystem?: boolean;
|
|
349
367
|
autoToolChoiceOnlyModels?: string[];
|
|
350
368
|
preserveReasoningContentModels?: string[];
|
|
351
369
|
requiresReasoningPlaceholderModels?: string[];
|
|
@@ -382,6 +400,6 @@ export type ProviderConfigSeed = Pick<
|
|
|
382
400
|
| "modelMaxInputTokens" | "defaultMaxOutputTokens" | "modelMaxOutputTokens"
|
|
383
401
|
| "reasoningEfforts" | "modelReasoningEfforts" | "modelDefaultReasoningEfforts" | "reasoningEffortMap" | "modelReasoningEffortMap" | "reasoningWireFormat"
|
|
384
402
|
| "noVisionModels" | "noReasoningModels" | "noTemperatureModels" | "noTopPModels" | "noStopModels" | "noPenaltyModels"
|
|
385
|
-
| "autoToolChoiceOnlyModels" | "preserveReasoningContentModels" | "requiresReasoningPlaceholderModels" | "reasoningSplitModels" | "inlineThinkTagModels" | "reasoningDetailsModels" | "thinkingToggleModels" | "thinkingBudgetModels" | "escapeBuiltinToolNames" | "openaiChatEofTolerance" | "showThinkingSummary"
|
|
403
|
+
| "autoToolChoiceOnlyModels" | "preserveReasoningContentModels" | "requiresReasoningPlaceholderModels" | "reasoningSplitModels" | "inlineThinkTagModels" | "reasoningDetailsModels" | "thinkingToggleModels" | "thinkingBudgetModels" | "escapeBuiltinToolNames" | "openaiChatEofTolerance" | "foldDeveloperRoleToSystem" | "showThinkingSummary"
|
|
386
404
|
| "googleMode" | "project" | "location" | "headers"
|
|
387
405
|
>;
|
|
@@ -31,8 +31,8 @@ export type StaticProviderPolicyField =
|
|
|
31
31
|
| "modelMaxOutputTokens" | "reasoningEfforts" | "modelReasoningEfforts" | "modelReasoningEffortsAuthoritative"
|
|
32
32
|
| "modelDefaultReasoningEfforts" | "reasoningEffortMap" | "modelReasoningEffortMap"
|
|
33
33
|
| "reasoningWireFormat" | "noVisionModels" | "noReasoningModels" | "noTemperatureModels"
|
|
34
|
-
| "noTopPModels" | "noStopModels" | "noPenaltyModels" | "noJsonSchemaModels" | "parallelToolCalls"
|
|
35
|
-
| "promptCacheKey" | "chatServiceTier" | "openaiChatEofTolerance" | "statelessResponses"
|
|
34
|
+
| "noTopPModels" | "noStopModels" | "noPenaltyModels" | "noJsonSchemaModels" | "noStructuredOutputModels" | "parallelToolCalls"
|
|
35
|
+
| "promptCacheKey" | "chatServiceTier" | "openaiChatEofTolerance" | "foldDeveloperRoleToSystem" | "statelessResponses"
|
|
36
36
|
| "requiresAdjacentResponsesToolResults" | "requiresPairedResponsesToolResults" | "annotateEmptyToolOutputs"
|
|
37
37
|
| "fastWire" | "supportsServiceTier" | "modelSupportsServiceTier" | "supportsOpenAiWebSearchToolFields"
|
|
38
38
|
| "supportsResponsesCustomTools" | "preserveResponsesReasoningContent" | "dropResponsesReasoningItems"
|
|
@@ -173,7 +173,7 @@ export function resolveModelPolicy(input: ResolveModelPolicyInput): ResolvedMode
|
|
|
173
173
|
"responsesPath", "chatCompletionsPath", "keyOptional", "freeTier", "modelSuffixBracketStrip",
|
|
174
174
|
"defaultModel", "models", "liveModels", "contextWindow", "defaultMaxOutputTokens",
|
|
175
175
|
"reasoningWireFormat", "parallelToolCalls", "promptCacheKey",
|
|
176
|
-
"openaiChatEofTolerance", "statelessResponses",
|
|
176
|
+
"openaiChatEofTolerance", "foldDeveloperRoleToSystem", "statelessResponses",
|
|
177
177
|
"requiresAdjacentResponsesToolResults", "requiresPairedResponsesToolResults",
|
|
178
178
|
"annotateEmptyToolOutputs", "fastWire", "supportsServiceTier",
|
|
179
179
|
"supportsOpenAiWebSearchToolFields", "supportsResponsesCustomTools",
|
|
@@ -231,7 +231,7 @@ export function resolveModelPolicy(input: ResolveModelPolicyInput): ResolvedMode
|
|
|
231
231
|
for (const key of [
|
|
232
232
|
"noVisionModels", "noReasoningModels", "noTemperatureModels", "noTopPModels",
|
|
233
233
|
"noStopModels",
|
|
234
|
-
"noPenaltyModels", "noJsonSchemaModels", "autoToolChoiceOnlyModels",
|
|
234
|
+
"noPenaltyModels", "noJsonSchemaModels", "noStructuredOutputModels", "autoToolChoiceOnlyModels",
|
|
235
235
|
"preserveReasoningContentModels", "requiresReasoningPlaceholderModels",
|
|
236
236
|
"reasoningSplitModels", "reasoningDetailsModels", "thinkingToggleModels", "thinkingBudgetModels",
|
|
237
237
|
] as const) putUnion(key, entry?.[key]);
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
providerSupportsLiveModelDiscovery,
|
|
22
22
|
} from "./static-model-discovery";
|
|
23
23
|
import { resolveModelPolicy } from "./resolved-model-policy";
|
|
24
|
+
import { mapFill, nestedMapFill, stableUnion } from "./resolved-model-policy-merge";
|
|
24
25
|
|
|
25
26
|
/** Same endpoint modulo surrounding space and trailing slashes — matches `matchBaseUrlChoice`. */
|
|
26
27
|
function isSameEndpoint(a: string, b: string): boolean {
|
|
@@ -124,6 +125,15 @@ export function routedProviderConfig(providerName: string, provider: OcxProvider
|
|
|
124
125
|
return {
|
|
125
126
|
...provider,
|
|
126
127
|
apiKey: usableResolvedApiKey(provider.apiKey),
|
|
128
|
+
...(destination?.modelDefaultReasoningEfforts ? {
|
|
129
|
+
modelDefaultReasoningEfforts: mapFill(destination.modelDefaultReasoningEfforts, provider.modelDefaultReasoningEfforts)[0],
|
|
130
|
+
} : {}),
|
|
131
|
+
...(destination?.modelReasoningEffortMap ? {
|
|
132
|
+
modelReasoningEffortMap: nestedMapFill(destination.modelReasoningEffortMap, provider.modelReasoningEffortMap)[0],
|
|
133
|
+
} : {}),
|
|
134
|
+
...(destination?.noStructuredOutputModels?.length ? {
|
|
135
|
+
noStructuredOutputModels: stableUnion(destination.noStructuredOutputModels, provider.noStructuredOutputModels)[0],
|
|
136
|
+
} : {}),
|
|
127
137
|
...(provider.dropResponsesReasoningItems === undefined && destination?.dropResponsesReasoningItems !== undefined
|
|
128
138
|
? { dropResponsesReasoningItems: destination.dropResponsesReasoningItems }
|
|
129
139
|
: {}),
|
|
@@ -172,6 +182,7 @@ export function routedProviderConfig(providerName: string, provider: OcxProvider
|
|
|
172
182
|
const noStopModels = staticPolicy.noStopModels;
|
|
173
183
|
const noPenaltyModels = staticPolicy.noPenaltyModels;
|
|
174
184
|
const noJsonSchemaModels = staticPolicy.noJsonSchemaModels;
|
|
185
|
+
const noStructuredOutputModels = staticPolicy.noStructuredOutputModels;
|
|
175
186
|
const autoToolChoiceOnlyModels = staticPolicy.autoToolChoiceOnlyModels;
|
|
176
187
|
const preserveReasoningContentModels = staticPolicy.preserveReasoningContentModels;
|
|
177
188
|
const requiresReasoningPlaceholderModels = staticPolicy.requiresReasoningPlaceholderModels;
|
|
@@ -302,6 +313,9 @@ export function routedProviderConfig(providerName: string, provider: OcxProvider
|
|
|
302
313
|
...(provider.openaiChatEofTolerance === undefined && registryEntry.openaiChatEofTolerance !== undefined
|
|
303
314
|
? { openaiChatEofTolerance: registryEntry.openaiChatEofTolerance }
|
|
304
315
|
: {}),
|
|
316
|
+
...(provider.foldDeveloperRoleToSystem === undefined && registryEntry.foldDeveloperRoleToSystem !== undefined
|
|
317
|
+
? { foldDeveloperRoleToSystem: registryEntry.foldDeveloperRoleToSystem }
|
|
318
|
+
: {}),
|
|
305
319
|
...(provider.reasoningWireFormat === undefined && registryEntry.reasoningWireFormat !== undefined
|
|
306
320
|
? { reasoningWireFormat: registryEntry.reasoningWireFormat }
|
|
307
321
|
: {}),
|
|
@@ -325,6 +339,7 @@ export function routedProviderConfig(providerName: string, provider: OcxProvider
|
|
|
325
339
|
...(noStopModels ? { noStopModels } : {}),
|
|
326
340
|
...(noPenaltyModels ? { noPenaltyModels } : {}),
|
|
327
341
|
...(noJsonSchemaModels ? { noJsonSchemaModels } : {}),
|
|
342
|
+
...(noStructuredOutputModels ? { noStructuredOutputModels } : {}),
|
|
328
343
|
...(autoToolChoiceOnlyModels ? { autoToolChoiceOnlyModels } : {}),
|
|
329
344
|
...(preserveReasoningContentModels ? { preserveReasoningContentModels } : {}),
|
|
330
345
|
...(requiresReasoningPlaceholderModels ? { requiresReasoningPlaceholderModels } : {}),
|