GigaChat: distinguish Basic and OAuth credentials
This commit is contained in:
parent
4ffdb2bb19
commit
2d2cdf24c2
@ -1,40 +1,26 @@
|
||||
import { mkdtempSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { withEnvAsync } from "../test-utils/env.js";
|
||||
import { resolveImplicitProvidersForTest } from "./models-config.e2e-harness.js";
|
||||
import { GIGACHAT_BASE_URL, GIGACHAT_BASIC_BASE_URL } from "../commands/onboard-auth.models.js";
|
||||
import { resolveImplicitGigachatBaseUrl } from "./models-config.providers.js";
|
||||
|
||||
describe("GigaChat implicit provider", () => {
|
||||
it("injects the default provider when GIGACHAT_CREDENTIALS is configured", async () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
it("uses the Basic default host for implicit Basic credentials", async () => {
|
||||
expect(resolveImplicitGigachatBaseUrl({ apiKey: "user:password" })).toBe(
|
||||
GIGACHAT_BASIC_BASE_URL,
|
||||
);
|
||||
});
|
||||
|
||||
await withEnvAsync({ GIGACHAT_CREDENTIALS: "user:password" }, async () => {
|
||||
const providers = await resolveImplicitProvidersForTest({ agentDir });
|
||||
|
||||
expect(providers?.gigachat).toMatchObject({
|
||||
baseUrl: "https://gigachat.devices.sberbank.ru/api/v1",
|
||||
api: "openai-completions",
|
||||
apiKey: "GIGACHAT_CREDENTIALS",
|
||||
});
|
||||
expect(providers?.gigachat?.models?.map((model) => model.id)).toEqual(["GigaChat-2-Max"]);
|
||||
});
|
||||
it("keeps the OAuth default host for implicit OAuth credentials keys", async () => {
|
||||
expect(resolveImplicitGigachatBaseUrl({ apiKey: "oauth-credentials-key" })).toBe(
|
||||
GIGACHAT_BASE_URL,
|
||||
);
|
||||
});
|
||||
|
||||
it("honors GIGACHAT_BASE_URL for implicit providers", async () => {
|
||||
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
||||
|
||||
await withEnvAsync(
|
||||
{
|
||||
GIGACHAT_CREDENTIALS: "user:password",
|
||||
GIGACHAT_BASE_URL: "https://preview.gigachat.example/api/v1",
|
||||
},
|
||||
async () => {
|
||||
const providers = await resolveImplicitProvidersForTest({ agentDir });
|
||||
|
||||
expect(providers?.gigachat?.baseUrl).toBe("https://preview.gigachat.example/api/v1");
|
||||
expect(providers?.gigachat?.apiKey).toBe("GIGACHAT_CREDENTIALS");
|
||||
},
|
||||
);
|
||||
expect(
|
||||
resolveImplicitGigachatBaseUrl({
|
||||
apiKey: "user:password",
|
||||
envBaseUrl: "https://preview.gigachat.example/api/v1",
|
||||
}),
|
||||
).toBe("https://preview.gigachat.example/api/v1");
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
} from "../../extensions/qianfan/provider-catalog.js";
|
||||
import { XIAOMI_DEFAULT_MODEL_ID } from "../../extensions/xiaomi/provider-catalog.js";
|
||||
import {
|
||||
GIGACHAT_BASIC_BASE_URL,
|
||||
buildGigachatModelDefinition,
|
||||
GIGACHAT_BASE_URL,
|
||||
} from "../commands/onboard-auth.models.js";
|
||||
@ -13,6 +14,11 @@ import { isRecord } from "../utils.js";
|
||||
import { normalizeOptionalSecretInput } from "../utils/normalize-secret-input.js";
|
||||
import { ensureAuthProfileStore, listProfilesForProvider } from "./auth-profiles.js";
|
||||
import { discoverBedrockModels } from "./bedrock-discovery.js";
|
||||
import {
|
||||
type GigachatAuthMetadata,
|
||||
resolveGigachatAuthMode,
|
||||
resolveGigachatAuthProfileMetadata,
|
||||
} from "./gigachat-auth.js";
|
||||
import { normalizeGoogleModelId } from "./model-id-normalization.js";
|
||||
import { resolveOllamaApiBase } from "./models-config.providers.discovery.js";
|
||||
export { buildKimiCodingProvider } from "../../extensions/kimi-coding/provider-catalog.js";
|
||||
@ -97,6 +103,25 @@ function buildGigachatProvider(params: { apiKey?: string; baseUrl?: string }): P
|
||||
} satisfies ProviderConfig;
|
||||
}
|
||||
|
||||
export function resolveImplicitGigachatBaseUrl(params: {
|
||||
envBaseUrl?: string;
|
||||
metadata?: GigachatAuthMetadata;
|
||||
apiKey?: string;
|
||||
authProfileId?: string;
|
||||
}): string {
|
||||
const envBaseUrl = params.envBaseUrl?.trim();
|
||||
if (envBaseUrl) {
|
||||
return envBaseUrl;
|
||||
}
|
||||
return resolveGigachatAuthMode({
|
||||
metadata: params.metadata,
|
||||
apiKey: params.apiKey,
|
||||
authProfileId: params.authProfileId,
|
||||
}) === "basic"
|
||||
? GIGACHAT_BASIC_BASE_URL
|
||||
: GIGACHAT_BASE_URL;
|
||||
}
|
||||
|
||||
function withStreamingUsageCompat(provider: ProviderConfig): ProviderConfig {
|
||||
if (!Array.isArray(provider.models) || provider.models.length === 0) {
|
||||
return provider;
|
||||
@ -712,10 +737,16 @@ function resolveImplicitGigachatProvider(ctx: ImplicitProviderContext): Provider
|
||||
if (!auth.apiKey) {
|
||||
return null;
|
||||
}
|
||||
const metadata = resolveGigachatAuthProfileMetadata(ctx.authStore, auth.profileId);
|
||||
|
||||
return buildGigachatProvider({
|
||||
apiKey: auth.apiKey,
|
||||
baseUrl: ctx.env.GIGACHAT_BASE_URL,
|
||||
baseUrl: resolveImplicitGigachatBaseUrl({
|
||||
envBaseUrl: ctx.env.GIGACHAT_BASE_URL,
|
||||
metadata,
|
||||
apiKey: auth.discoveryApiKey ?? auth.apiKey,
|
||||
authProfileId: auth.profileId,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -218,6 +218,7 @@ export function buildXaiModelDefinition(): ModelDefinitionConfig {
|
||||
}
|
||||
|
||||
export const GIGACHAT_BASE_URL = "https://gigachat.devices.sberbank.ru/api/v1";
|
||||
export const GIGACHAT_BASIC_BASE_URL = "https://gigachat.ift.sberdevices.ru/v1";
|
||||
export const GIGACHAT_DEFAULT_MODEL_ID = "GigaChat-2-Max";
|
||||
export const GIGACHAT_DEFAULT_MODEL_REF = `gigachat/${GIGACHAT_DEFAULT_MODEL_ID}`;
|
||||
export const GIGACHAT_DEFAULT_CONTEXT_WINDOW = 128000;
|
||||
|
||||
@ -117,4 +117,37 @@ describe("applySimpleNonInteractiveApiKeyChoice", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects Basic-shaped GIGACHAT_CREDENTIALS in the OAuth onboarding path", async () => {
|
||||
const nextConfig = { agents: { defaults: {} } } as OpenClawConfig;
|
||||
const runtime = {
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
log: vi.fn(),
|
||||
} as never;
|
||||
const resolveApiKey = vi.fn(async () => ({
|
||||
key: "basic-user:basic-pass",
|
||||
source: "env" as const,
|
||||
}));
|
||||
const maybeSetResolvedApiKey = vi.fn();
|
||||
|
||||
const result = await applySimpleNonInteractiveApiKeyChoice({
|
||||
authChoice: "gigachat-api-key",
|
||||
nextConfig,
|
||||
baseConfig: nextConfig,
|
||||
opts: {} as never,
|
||||
runtime,
|
||||
apiKeyStorageOptions: undefined,
|
||||
resolveApiKey,
|
||||
maybeSetResolvedApiKey,
|
||||
});
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(maybeSetResolvedApiKey).not.toHaveBeenCalled();
|
||||
expect(setGigachatApiKey).not.toHaveBeenCalled();
|
||||
expect(runtime.error).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Basic user:password credentials"),
|
||||
);
|
||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { resolveGigachatAuthMode } from "../../../agents/gigachat-auth.js";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import type { SecretInput } from "../../../config/types.secrets.js";
|
||||
import { applyAuthProfileConfig } from "../../../plugins/provider-auth-helpers.js";
|
||||
@ -50,6 +51,17 @@ async function applyGigachatNonInteractiveApiKeyChoice(params: {
|
||||
if (!resolved) {
|
||||
return null;
|
||||
}
|
||||
if (resolveGigachatAuthMode({ apiKey: resolved.key }) === "basic") {
|
||||
params.runtime.error(
|
||||
[
|
||||
"GIGACHAT_CREDENTIALS looks like Basic user:password credentials.",
|
||||
'Non-interactive "--gigachat-api-key" only supports personal OAuth credentials keys.',
|
||||
"Set GIGACHAT_CREDENTIALS to a real OAuth credentials key and retry.",
|
||||
].join("\n"),
|
||||
);
|
||||
params.runtime.exit(1);
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
!(await params.maybeSetResolvedApiKey(resolved, (value) =>
|
||||
setGigachatApiKey(value, undefined, params.apiKeyStorageOptions, {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user