fix(config): inherit provider token defaults (#105807)

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: moguangyu5-design <moguangyu5-design@users.noreply.github.com>
This commit is contained in:
moguangyu5-design
2026-07-21 23:09:16 +08:00
committed by GitHub
parent 86075ed738
commit b1deaf8dd9
2 changed files with 82 additions and 2 deletions
+22 -2
View File
@@ -186,6 +186,15 @@ export function applyModelDefaults(
continue;
}
const providerApi = normalizedProvider.api;
const providerContextWindow = isPositiveNumber(normalizedProvider.contextWindow)
? normalizedProvider.contextWindow
: undefined;
const providerContextTokens = isPositiveNumber(normalizedProvider.contextTokens)
? normalizedProvider.contextTokens
: undefined;
const providerMaxTokens = isPositiveNumber(normalizedProvider.maxTokens)
? normalizedProvider.maxTokens
: undefined;
const nextProvider = normalizedProvider;
if (nextProvider !== provider) {
mutated = true;
@@ -226,12 +235,22 @@ export function applyModelDefaults(
const contextWindow = isPositiveNumber(raw.contextWindow)
? raw.contextWindow
: DEFAULT_CONTEXT_TOKENS;
: (providerContextWindow ?? DEFAULT_CONTEXT_TOKENS);
if (raw.contextWindow !== contextWindow) {
modelMutated = true;
}
const defaultMaxTokens = Math.min(DEFAULT_MODEL_MAX_TOKENS, contextWindow);
const contextTokens = isPositiveNumber(raw.contextTokens)
? raw.contextTokens
: providerContextTokens;
if (raw.contextTokens !== contextTokens) {
modelMutated = true;
}
const defaultMaxTokens = Math.min(
providerMaxTokens ?? DEFAULT_MODEL_MAX_TOKENS,
contextWindow,
);
const rawMaxTokens = isPositiveNumber(raw.maxTokens) ? raw.maxTokens : defaultMaxTokens;
const maxTokens = resolveNormalizedProviderModelMaxTokens({
providerId,
@@ -257,6 +276,7 @@ export function applyModelDefaults(
input,
cost,
contextWindow,
contextTokens,
maxTokens,
api,
}) as ModelDefinitionConfig;
+60
View File
@@ -95,6 +95,34 @@ describe("applyModelDefaults", () => {
} satisfies OpenClawConfig;
}
function buildProviderTokenDefaultsConfig(params: {
provider: { contextWindow?: number; contextTokens?: number; maxTokens?: number };
model?: { contextWindow?: number; contextTokens?: number; maxTokens?: number };
}) {
return {
models: {
providers: {
myproxy: {
baseUrl: "https://proxy.example/v1",
apiKey: "sk-test",
api: "openai-completions",
...params.provider,
models: [
{
id: "gpt-5.4",
name: "GPT-5.4",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
...params.model,
},
],
},
},
},
} as never;
}
function buildCustomProviderManifestRegistry() {
return {
plugins: [
@@ -439,6 +467,38 @@ describe("applyModelDefaults", () => {
expect(model?.maxTokens).toBe(32768);
});
it.each([
{
name: "inherits provider defaults",
provider: { contextWindow: 50_000, contextTokens: 32_000, maxTokens: 4_096 },
model: undefined,
expected: { contextWindow: 50_000, contextTokens: 32_000, maxTokens: 4_096 },
},
{
name: "keeps model overrides",
provider: { contextWindow: 50_000, contextTokens: 32_000, maxTokens: 4_096 },
model: { contextWindow: 10_000, contextTokens: 8_000, maxTokens: 2_048 },
expected: { contextWindow: 10_000, contextTokens: 8_000, maxTokens: 2_048 },
},
{
name: "clamps inherited maxTokens to the inherited contextWindow",
provider: { contextWindow: 4_096, maxTokens: 8_192 },
model: undefined,
expected: { contextWindow: 4_096, contextTokens: undefined, maxTokens: 4_096 },
},
])("$name", ({ provider, model, expected }) => {
const cfg = buildProviderTokenDefaultsConfig({ provider, model });
const next = applyModelDefaults(cfg);
const resolved = next.models?.providers?.myproxy?.models?.[0];
expect({
contextWindow: resolved?.contextWindow,
contextTokens: resolved?.contextTokens,
maxTokens: resolved?.maxTokens,
}).toEqual(expected);
});
it("normalizes stale mistral maxTokens that matched the full context window", () => {
const cfg = buildMistralProviderConfig();