GigaChat: reset Basic base URLs on OAuth reauth
This commit is contained in:
parent
be72c4f011
commit
c46ec2ebf4
@ -1,3 +1,4 @@
|
||||
import { loadAuthProfileStoreForSecretsRuntime } from "../agents/auth-profiles.js";
|
||||
import { resolveGigachatAuthMode } from "../agents/gigachat-auth.js";
|
||||
import { resolveManifestProviderApiKeyChoice } from "../plugins/provider-auth-choices.js";
|
||||
import { ensureApiKeyFromOptionEnvOrPrompt } from "./auth-choice.apply-helpers.js";
|
||||
@ -15,6 +16,7 @@ import {
|
||||
GIGACHAT_DEFAULT_MODEL_REF,
|
||||
setGigachatApiKey,
|
||||
} from "./onboard-auth.js";
|
||||
import { GIGACHAT_BASE_URL } from "./onboard-auth.models.js";
|
||||
import type { AuthChoice } from "./onboard-types.js";
|
||||
|
||||
const CORE_API_KEY_TOKEN_PROVIDER_AUTH_CHOICES: Partial<Record<string, AuthChoice>> = {
|
||||
@ -22,6 +24,15 @@ const CORE_API_KEY_TOKEN_PROVIDER_AUTH_CHOICES: Partial<Record<string, AuthChoic
|
||||
litellm: "litellm-api-key",
|
||||
};
|
||||
|
||||
function hadStoredGigachatBasicProfile(agentDir?: string): boolean {
|
||||
const profile = loadAuthProfileStoreForSecretsRuntime(agentDir).profiles["gigachat:default"];
|
||||
return (
|
||||
profile?.type === "api_key" &&
|
||||
profile.provider === "gigachat" &&
|
||||
profile.metadata?.authMode === "basic"
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeApiKeyTokenProviderAuthChoice(params: {
|
||||
authChoice: AuthChoice;
|
||||
tokenProvider?: string;
|
||||
@ -123,6 +134,7 @@ export async function applyAuthChoiceApiProviders(
|
||||
authChoice = "gigachat-basic";
|
||||
gigachatBasicScope = gigachatScope;
|
||||
} else {
|
||||
const resetGigachatBaseUrl = hadStoredGigachatBasicProfile(params.agentDir);
|
||||
await ensureApiKeyFromOptionEnvOrPrompt({
|
||||
token: params.opts?.gigachatApiKey ?? params.opts?.token,
|
||||
provider: "gigachat",
|
||||
@ -173,8 +185,16 @@ export async function applyAuthChoiceApiProviders(
|
||||
});
|
||||
await applyProviderDefaultModel({
|
||||
defaultModel: GIGACHAT_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyGigachatConfig,
|
||||
applyProviderConfig: applyGigachatProviderConfig,
|
||||
applyDefaultConfig: (config) =>
|
||||
applyGigachatConfig(
|
||||
config,
|
||||
resetGigachatBaseUrl ? { baseUrl: GIGACHAT_BASE_URL } : undefined,
|
||||
),
|
||||
applyProviderConfig: (config) =>
|
||||
applyGigachatProviderConfig(
|
||||
config,
|
||||
resetGigachatBaseUrl ? { baseUrl: GIGACHAT_BASE_URL } : undefined,
|
||||
),
|
||||
noteDefault: GIGACHAT_DEFAULT_MODEL_REF,
|
||||
});
|
||||
return { config: nextConfig, agentModelOverride };
|
||||
|
||||
@ -37,6 +37,7 @@ import { registerProviderPlugins } from "../test-utils/plugin-registration.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
||||
import { GOOGLE_GEMINI_DEFAULT_MODEL } from "./google-gemini-model-default.js";
|
||||
import { GIGACHAT_BASE_URL } from "./onboard-auth.models.js";
|
||||
import type { AuthChoice } from "./onboard-types.js";
|
||||
import {
|
||||
authProfilePathForAgent,
|
||||
@ -382,6 +383,56 @@ describe("applyAuthChoice", () => {
|
||||
await expect(readAuthProfile("gigachat:default")).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("resets a custom Basic GigaChat base URL when switching to OAuth", async () => {
|
||||
await setupTempState();
|
||||
|
||||
delete process.env.GIGACHAT_CREDENTIALS;
|
||||
delete process.env.GIGACHAT_USER;
|
||||
delete process.env.GIGACHAT_PASSWORD;
|
||||
delete process.env.GIGACHAT_BASE_URL;
|
||||
|
||||
const basicText = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce("https://preview-basic.gigachat.example/api/v1")
|
||||
.mockResolvedValueOnce("basic-user")
|
||||
.mockResolvedValueOnce("basic-pass");
|
||||
const basicHarness = createApiKeyPromptHarness({ text: basicText });
|
||||
|
||||
const basicResult = await applyAuthChoice({
|
||||
authChoice: "gigachat-basic",
|
||||
config: {},
|
||||
prompter: basicHarness.prompter,
|
||||
runtime: basicHarness.runtime,
|
||||
setDefaultModel: true,
|
||||
});
|
||||
|
||||
expect(basicResult.config.models?.providers?.gigachat?.baseUrl).toBe(
|
||||
"https://preview-basic.gigachat.example/api/v1",
|
||||
);
|
||||
|
||||
process.env.GIGACHAT_CREDENTIALS = "gigachat-oauth-credentials=="; // pragma: allowlist secret
|
||||
const oauthHarness = createApiKeyPromptHarness();
|
||||
|
||||
const oauthResult = await applyAuthChoice({
|
||||
authChoice: "gigachat-personal",
|
||||
config: basicResult.config,
|
||||
prompter: oauthHarness.prompter,
|
||||
runtime: oauthHarness.runtime,
|
||||
setDefaultModel: true,
|
||||
});
|
||||
|
||||
expect(oauthResult.config.models?.providers?.gigachat?.baseUrl).toBe(GIGACHAT_BASE_URL);
|
||||
expect(await readAuthProfile("gigachat:default")).toMatchObject({
|
||||
type: "api_key",
|
||||
provider: "gigachat",
|
||||
metadata: {
|
||||
authMode: "oauth",
|
||||
scope: "GIGACHAT_API_PERS",
|
||||
insecureTls: "false",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("prompts and writes provider API key for common providers", async () => {
|
||||
const scenarios: Array<{
|
||||
authChoice:
|
||||
|
||||
@ -1,8 +1,17 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ApiKeyCredential, AuthProfileStore } from "../../../agents/auth-profiles.js";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import type { RuntimeEnv } from "../../../runtime.js";
|
||||
import { GIGACHAT_BASE_URL } from "../../onboard-auth.models.js";
|
||||
import { applySimpleNonInteractiveApiKeyChoice } from "./auth-choice.api-key-providers.js";
|
||||
|
||||
const loadAuthProfileStoreForSecretsRuntime = vi.hoisted(() =>
|
||||
vi.fn<() => AuthProfileStore>(() => ({ version: 1, profiles: {} })),
|
||||
);
|
||||
vi.mock("../../../agents/auth-profiles.js", () => ({
|
||||
loadAuthProfileStoreForSecretsRuntime,
|
||||
}));
|
||||
|
||||
const applyAuthProfileConfig = vi.hoisted(() => vi.fn((cfg: OpenClawConfig) => cfg));
|
||||
vi.mock("../../../plugins/provider-auth-helpers.js", () => ({
|
||||
applyAuthProfileConfig,
|
||||
@ -28,6 +37,7 @@ vi.mock("../../onboard-auth.config-litellm.js", () => ({
|
||||
describe("applySimpleNonInteractiveApiKeyChoice", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
loadAuthProfileStoreForSecretsRuntime.mockReturnValue({ version: 1, profiles: {} });
|
||||
applyAuthProfileConfig.mockImplementation((cfg: OpenClawConfig) => cfg);
|
||||
applyGigachatConfig.mockImplementation((cfg: OpenClawConfig) => cfg);
|
||||
applyLitellmConfig.mockImplementation((cfg: OpenClawConfig) => cfg);
|
||||
@ -151,4 +161,55 @@ describe("applySimpleNonInteractiveApiKeyChoice", () => {
|
||||
);
|
||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it("resets the GigaChat provider base URL when replacing a Basic profile with OAuth", async () => {
|
||||
const nextConfig = { agents: { defaults: {} } } as OpenClawConfig;
|
||||
const basicProfile: ApiKeyCredential = {
|
||||
type: "api_key",
|
||||
provider: "gigachat",
|
||||
key: "basic-user:basic-pass",
|
||||
metadata: {
|
||||
authMode: "basic",
|
||||
},
|
||||
};
|
||||
loadAuthProfileStoreForSecretsRuntime.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {
|
||||
"gigachat:default": basicProfile,
|
||||
},
|
||||
});
|
||||
const resolveApiKey = vi.fn(async () => ({
|
||||
key: "gigachat-oauth-credentials",
|
||||
source: "flag" as const,
|
||||
}));
|
||||
const maybeSetResolvedApiKey = vi.fn(async (resolved, setter) => {
|
||||
await setter(resolved.key);
|
||||
return true;
|
||||
});
|
||||
|
||||
await applySimpleNonInteractiveApiKeyChoice({
|
||||
authChoice: "gigachat-oauth",
|
||||
nextConfig,
|
||||
baseConfig: {
|
||||
models: {
|
||||
providers: {
|
||||
gigachat: {
|
||||
baseUrl: "https://preview-basic.gigachat.example/api/v1",
|
||||
api: "openai-completions",
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
opts: { token: "gigachat-oauth-credentials" } as never,
|
||||
runtime: { error: vi.fn(), exit: vi.fn(), log: vi.fn() } as never,
|
||||
apiKeyStorageOptions: undefined,
|
||||
resolveApiKey,
|
||||
maybeSetResolvedApiKey,
|
||||
});
|
||||
|
||||
expect(applyGigachatConfig).toHaveBeenCalledWith(expect.any(Object), {
|
||||
baseUrl: GIGACHAT_BASE_URL,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { loadAuthProfileStoreForSecretsRuntime } from "../../../agents/auth-profiles.js";
|
||||
import { resolveGigachatAuthMode } from "../../../agents/gigachat-auth.js";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import type { SecretInput } from "../../../config/types.secrets.js";
|
||||
@ -6,6 +7,7 @@ import { setGigachatApiKey, setLitellmApiKey } from "../../../plugins/provider-a
|
||||
import type { RuntimeEnv } from "../../../runtime.js";
|
||||
import { applyGigachatConfig } from "../../onboard-auth.config-core.js";
|
||||
import { applyLitellmConfig } from "../../onboard-auth.config-litellm.js";
|
||||
import { GIGACHAT_BASE_URL } from "../../onboard-auth.models.js";
|
||||
import type { AuthChoice, OnboardOptions } from "../../onboard-types.js";
|
||||
|
||||
type ApiKeyStorageOptions = {
|
||||
@ -17,6 +19,15 @@ type ResolvedNonInteractiveApiKey = {
|
||||
source: "profile" | "env" | "flag";
|
||||
};
|
||||
|
||||
function hadStoredGigachatBasicProfile(): boolean {
|
||||
const profile = loadAuthProfileStoreForSecretsRuntime().profiles["gigachat:default"];
|
||||
return (
|
||||
profile?.type === "api_key" &&
|
||||
profile.provider === "gigachat" &&
|
||||
profile.metadata?.authMode === "basic"
|
||||
);
|
||||
}
|
||||
|
||||
async function applyGigachatNonInteractiveApiKeyChoice(params: {
|
||||
nextConfig: OpenClawConfig;
|
||||
baseConfig: OpenClawConfig;
|
||||
@ -37,6 +48,7 @@ async function applyGigachatNonInteractiveApiKeyChoice(params: {
|
||||
setter: (value: SecretInput) => Promise<void> | void,
|
||||
) => Promise<boolean>;
|
||||
}): Promise<OpenClawConfig | null> {
|
||||
const resetGigachatBaseUrl = hadStoredGigachatBasicProfile();
|
||||
const resolved = await params.resolveApiKey({
|
||||
provider: "gigachat",
|
||||
cfg: params.baseConfig,
|
||||
@ -79,6 +91,7 @@ async function applyGigachatNonInteractiveApiKeyChoice(params: {
|
||||
provider: "gigachat",
|
||||
mode: "api_key",
|
||||
}),
|
||||
resetGigachatBaseUrl ? { baseUrl: GIGACHAT_BASE_URL } : undefined,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user