mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 17:34:45 +00:00
fix: normalize oauth auth-result config patches
This commit is contained in:
@@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- Gateway/OpenAI HTTP: honor `max_completion_tokens` and `max_tokens` on inbound `/v1/chat/completions` requests so client-provided token caps reach the upstream provider via `streamParams.maxTokens`, with `max_completion_tokens` taking precedence when both are sent. Thanks @Lellansin.
|
||||
- Models/OpenAI CLI auth: make `openclaw models auth login --provider openai` start the ChatGPT/Codex account login by default, while `--method api-key` remains the explicit OpenAI API-key setup path.
|
||||
- Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside explicit SDK OAuth auth-result config patches, so provider helpers emit `google/gemini-3.1-pro-preview` for Gemini 3.1 testing.
|
||||
- Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside SDK OAuth auth-result default config patches, so helper-built provider auth flows emit `google/gemini-3.1-pro-preview` for Gemini 3.1 testing.
|
||||
- Google/Gemini: normalize retired Gemini 3 Pro Preview ids returned by direct `openclaw models auth login --set-default` provider auth flows before writing config, so Gemini testing targets `google/gemini-3.1-pro-preview`.
|
||||
- Google/Gemini: normalize retired Gemini 3 Pro Preview ids in provider catalog rows when API-key onboarding only reapplies the agent default, so emitted config keeps testing `google/gemini-3.1-pro-preview`.
|
||||
|
||||
@@ -20,4 +20,76 @@ describe("buildOauthProviderAuthResult", () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes retired Gemini refs inside explicit config patches", () => {
|
||||
const result = buildOauthProviderAuthResult({
|
||||
providerId: "google",
|
||||
defaultModel: "google/gemini-3-pro-preview",
|
||||
access: "access-token",
|
||||
configPatch: {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "google/gemini-3-pro-preview",
|
||||
fallbacks: ["google/gemini-3-pro-preview", "openai/gpt-5.5"],
|
||||
},
|
||||
models: {
|
||||
"google/gemini-3-pro-preview": { alias: "gemini" },
|
||||
},
|
||||
},
|
||||
},
|
||||
models: {
|
||||
providers: {
|
||||
google: {
|
||||
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
||||
models: [
|
||||
{
|
||||
id: "google/gemini-3-pro-preview",
|
||||
name: "Gemini 3 Pro",
|
||||
contextWindow: 1_048_576,
|
||||
maxTokens: 65_536,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
reasoning: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.defaultModel).toBe("google/gemini-3.1-pro-preview");
|
||||
expect(result.configPatch).toEqual({
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "google/gemini-3.1-pro-preview",
|
||||
fallbacks: ["google/gemini-3.1-pro-preview", "openai/gpt-5.5"],
|
||||
},
|
||||
models: {
|
||||
"google/gemini-3.1-pro-preview": { alias: "gemini" },
|
||||
},
|
||||
},
|
||||
},
|
||||
models: {
|
||||
providers: {
|
||||
google: {
|
||||
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
||||
models: [
|
||||
{
|
||||
id: "google/gemini-3.1-pro-preview",
|
||||
name: "Gemini 3 Pro",
|
||||
contextWindow: 1_048_576,
|
||||
maxTokens: 65_536,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
reasoning: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,122 @@
|
||||
import { buildAuthProfileId } from "../agents/auth-profiles/identity.js";
|
||||
import type { AuthProfileCredential } from "../agents/auth-profiles/types.js";
|
||||
import { normalizeAgentModelRefForConfig } from "../config/model-input.js";
|
||||
import { normalizeConfiguredProviderCatalogModelId } from "../agents/model-ref-shared.js";
|
||||
import {
|
||||
normalizeAgentModelMapForConfig,
|
||||
normalizeAgentModelRefForConfig,
|
||||
} from "../config/model-input.js";
|
||||
import type { ModelProviderConfig } from "../config/types.models.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { ProviderAuthResult } from "../plugins/types.js";
|
||||
|
||||
function normalizeAgentModelConfigForAuthResult(value: unknown): unknown {
|
||||
if (typeof value === "string") {
|
||||
return normalizeAgentModelRefForConfig(value);
|
||||
}
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
let mutated = false;
|
||||
const next: Record<string, unknown> = { ...(value as Record<string, unknown>) };
|
||||
if (typeof next.primary === "string") {
|
||||
const primary = normalizeAgentModelRefForConfig(next.primary);
|
||||
if (primary !== next.primary) {
|
||||
next.primary = primary;
|
||||
mutated = true;
|
||||
}
|
||||
}
|
||||
if (Array.isArray(next.fallbacks)) {
|
||||
const originalFallbacks = next.fallbacks;
|
||||
const fallbacks = originalFallbacks.map((fallback) =>
|
||||
typeof fallback === "string" ? normalizeAgentModelRefForConfig(fallback) : fallback,
|
||||
);
|
||||
if (fallbacks.some((fallback, index) => fallback !== originalFallbacks[index])) {
|
||||
next.fallbacks = fallbacks;
|
||||
mutated = true;
|
||||
}
|
||||
}
|
||||
return mutated ? next : value;
|
||||
}
|
||||
|
||||
function normalizeProviderConfigModelIdsForAuthResult(
|
||||
provider: string,
|
||||
providerConfig: ModelProviderConfig,
|
||||
): ModelProviderConfig {
|
||||
const models = providerConfig.models;
|
||||
if (!Array.isArray(models) || models.length === 0) {
|
||||
return providerConfig;
|
||||
}
|
||||
|
||||
let mutated = false;
|
||||
const nextModels = models.map((model) => {
|
||||
const id = normalizeConfiguredProviderCatalogModelId(provider, model.id);
|
||||
if (id === model.id) {
|
||||
return model;
|
||||
}
|
||||
mutated = true;
|
||||
return Object.assign({}, model, { id });
|
||||
});
|
||||
return mutated ? { ...providerConfig, models: nextModels } : providerConfig;
|
||||
}
|
||||
|
||||
function normalizeProviderAuthConfigPatchModelRefs(
|
||||
patch: Partial<OpenClawConfig>,
|
||||
): Partial<OpenClawConfig> {
|
||||
let next = patch;
|
||||
const defaults = patch.agents?.defaults;
|
||||
if (defaults) {
|
||||
let nextDefaults = defaults;
|
||||
if (defaults.model !== undefined) {
|
||||
const model = normalizeAgentModelConfigForAuthResult(defaults.model);
|
||||
if (model !== defaults.model) {
|
||||
nextDefaults = { ...nextDefaults, model: model as typeof defaults.model };
|
||||
}
|
||||
}
|
||||
if (defaults.models) {
|
||||
const models = normalizeAgentModelMapForConfig(defaults.models);
|
||||
if (models !== defaults.models) {
|
||||
nextDefaults = { ...nextDefaults, models };
|
||||
}
|
||||
}
|
||||
if (nextDefaults !== defaults) {
|
||||
next = {
|
||||
...next,
|
||||
agents: {
|
||||
...next.agents,
|
||||
defaults: nextDefaults,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const providers = patch.models?.providers;
|
||||
if (!providers) {
|
||||
return next;
|
||||
}
|
||||
|
||||
let mutated = false;
|
||||
const nextProviders = { ...providers };
|
||||
for (const [provider, providerConfig] of Object.entries(providers)) {
|
||||
const normalized = normalizeProviderConfigModelIdsForAuthResult(provider, providerConfig);
|
||||
if (normalized === providerConfig) {
|
||||
continue;
|
||||
}
|
||||
nextProviders[provider] = normalized;
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
return mutated
|
||||
? {
|
||||
...next,
|
||||
models: {
|
||||
...next.models,
|
||||
providers: nextProviders,
|
||||
},
|
||||
}
|
||||
: next;
|
||||
}
|
||||
|
||||
/** Build the standard auth result payload for OAuth-style provider login flows. */
|
||||
export function buildOauthProviderAuthResult(params: {
|
||||
providerId: string;
|
||||
@@ -41,17 +154,18 @@ export function buildOauthProviderAuthResult(params: {
|
||||
|
||||
return {
|
||||
profiles: [{ profileId, credential }],
|
||||
configPatch:
|
||||
configPatch: normalizeProviderAuthConfigPatchModelRefs(
|
||||
params.configPatch ??
|
||||
({
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
[defaultModel]: {},
|
||||
({
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
[defaultModel]: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Partial<OpenClawConfig>),
|
||||
} as Partial<OpenClawConfig>),
|
||||
),
|
||||
defaultModel,
|
||||
notes: params.notes,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user