GigaChat: avoid stale auth metadata fallback
This commit is contained in:
parent
47355b93de
commit
fb08d4e434
@ -5,10 +5,14 @@ export type GigachatAuthMetadata = Record<string, string> | undefined;
|
||||
export function resolveGigachatAuthProfileMetadata(
|
||||
store: Pick<AuthProfileStore, "profiles">,
|
||||
authProfileId?: string,
|
||||
options?: {
|
||||
allowDefaultProfileFallback?: boolean;
|
||||
},
|
||||
): GigachatAuthMetadata {
|
||||
const profileIds = [authProfileId?.trim(), "gigachat:default"].filter(
|
||||
(profileId): profileId is string => Boolean(profileId),
|
||||
);
|
||||
const profileIds = [
|
||||
authProfileId?.trim(),
|
||||
options?.allowDefaultProfileFallback === false ? undefined : "gigachat:default",
|
||||
].filter((profileId): profileId is string => Boolean(profileId));
|
||||
for (const profileId of profileIds) {
|
||||
const credential = store.profiles[profileId];
|
||||
if (credential?.type === "api_key" && credential.provider === "gigachat") {
|
||||
@ -39,7 +43,7 @@ export function resolveGigachatAuthMode(params: {
|
||||
return metadataAuthMode;
|
||||
}
|
||||
|
||||
if (!params.authProfileId?.trim() && looksLikeGigachatBasicCredentials(params.apiKey)) {
|
||||
if (looksLikeGigachatBasicCredentials(params.apiKey)) {
|
||||
return "basic";
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { GIGACHAT_BASE_URL, GIGACHAT_BASIC_BASE_URL } from "../commands/onboard-auth.models.js";
|
||||
import { resolveGigachatAuthProfileMetadata } from "./gigachat-auth.js";
|
||||
import { resolveImplicitGigachatBaseUrl } from "./models-config.providers.js";
|
||||
|
||||
describe("GigaChat implicit provider", () => {
|
||||
@ -29,4 +30,30 @@ describe("GigaChat implicit provider", () => {
|
||||
}),
|
||||
).toBe("https://preview.gigachat.example/api/v1");
|
||||
});
|
||||
|
||||
it("does not inherit stale default-profile metadata for auth-profile-less credentials", async () => {
|
||||
const metadata = resolveGigachatAuthProfileMetadata(
|
||||
{
|
||||
profiles: {
|
||||
"gigachat:default": {
|
||||
type: "api_key",
|
||||
provider: "gigachat",
|
||||
metadata: {
|
||||
authMode: "basic",
|
||||
scope: "GIGACHAT_API_B2B",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
{ allowDefaultProfileFallback: false },
|
||||
);
|
||||
|
||||
expect(
|
||||
resolveImplicitGigachatBaseUrl({
|
||||
metadata,
|
||||
apiKey: "oauth:credential:with:colon",
|
||||
}),
|
||||
).toBe(GIGACHAT_BASE_URL);
|
||||
});
|
||||
});
|
||||
|
||||
@ -737,7 +737,11 @@ function resolveImplicitGigachatProvider(ctx: ImplicitProviderContext): Provider
|
||||
if (!auth.apiKey) {
|
||||
return null;
|
||||
}
|
||||
const metadata = resolveGigachatAuthProfileMetadata(ctx.authStore, auth.profileId);
|
||||
const metadata = resolveGigachatAuthProfileMetadata(ctx.authStore, auth.profileId, {
|
||||
// Env-backed GIGACHAT_CREDENTIALS has no profile id, so do not inherit
|
||||
// stale auth-mode metadata from a stored default profile.
|
||||
allowDefaultProfileFallback: Boolean(auth.profileId?.trim()),
|
||||
});
|
||||
|
||||
return buildGigachatProvider({
|
||||
apiKey: auth.apiKey,
|
||||
|
||||
@ -1064,6 +1064,66 @@ describe("compactEmbeddedPiSessionDirect hooks", () => {
|
||||
|
||||
expect(result.ok, result.reason).toBe(true);
|
||||
});
|
||||
|
||||
it("does not inherit stale GigaChat metadata for env-backed OAuth credentials", async () => {
|
||||
resolveModelMock.mockReturnValue({
|
||||
model: {
|
||||
provider: "gigachat",
|
||||
api: "openai-completions",
|
||||
id: "GigaChat-2-Max",
|
||||
input: ["text"],
|
||||
baseUrl: "https://gigachat.devices.sberbank.ru/api/v1",
|
||||
},
|
||||
error: null,
|
||||
authStorage: { setRuntimeApiKey: vi.fn() },
|
||||
modelRegistry: {},
|
||||
} as never);
|
||||
vi.mocked(getApiKeyForModel).mockResolvedValueOnce({
|
||||
apiKey: "oauth:credential:with:colon",
|
||||
mode: "api-key",
|
||||
source: "env: GIGACHAT_CREDENTIALS",
|
||||
});
|
||||
ensureAuthProfileStoreMock.mockReturnValue({
|
||||
profiles: {
|
||||
"gigachat:default": {
|
||||
type: "api_key",
|
||||
provider: "gigachat",
|
||||
metadata: {
|
||||
authMode: "basic",
|
||||
insecureTls: "true",
|
||||
scope: "GIGACHAT_API_B2B",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
sessionCompactImpl.mockImplementation(async () => {
|
||||
expect(createGigachatStreamFnMock).toHaveBeenCalledWith({
|
||||
baseUrl: "https://gigachat.devices.sberbank.ru/api/v1",
|
||||
authMode: "oauth",
|
||||
insecureTls: false,
|
||||
scope: undefined,
|
||||
});
|
||||
return {
|
||||
summary: "summary",
|
||||
firstKeptEntryId: "entry-1",
|
||||
tokensBefore: 120,
|
||||
details: { ok: true },
|
||||
};
|
||||
});
|
||||
|
||||
const result = await compactEmbeddedPiSessionDirect({
|
||||
sessionId: "session-1",
|
||||
sessionKey: "agent:main:session-1",
|
||||
sessionFile: "/tmp/session.jsonl",
|
||||
workspaceDir: "/tmp",
|
||||
config: gigachatTestConfig(),
|
||||
provider: "gigachat",
|
||||
model: "GigaChat-2-Max",
|
||||
customInstructions: "focus on decisions",
|
||||
});
|
||||
|
||||
expect(result.ok, result.reason).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("compactEmbeddedPiSession hooks (ownsCompaction engine)", () => {
|
||||
|
||||
@ -856,6 +856,9 @@ export async function compactEmbeddedPiSessionDirect(
|
||||
const gigachatMeta = resolveGigachatAuthProfileMetadata(
|
||||
gigachatStore,
|
||||
resolvedGigachatProfileId,
|
||||
{
|
||||
allowDefaultProfileFallback: Boolean(resolvedGigachatProfileId),
|
||||
},
|
||||
);
|
||||
|
||||
session.agent.streamFn = createGigachatStreamFn({
|
||||
|
||||
@ -204,6 +204,24 @@ describe("resolveGigachatAuthProfileMetadata", () => {
|
||||
),
|
||||
).toEqual({ scope: "GIGACHAT_API_PERS" });
|
||||
});
|
||||
|
||||
it("does not inherit the default GigaChat profile when fallback is disabled", () => {
|
||||
expect(
|
||||
resolveGigachatAuthProfileMetadata(
|
||||
{
|
||||
profiles: {
|
||||
"gigachat:default": {
|
||||
type: "api_key",
|
||||
provider: "gigachat",
|
||||
metadata: { scope: "GIGACHAT_API_B2B", insecureTls: "true" },
|
||||
},
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
{ allowDefaultProfileFallback: false },
|
||||
),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveGigachatAuthMode", () => {
|
||||
@ -223,6 +241,15 @@ describe("resolveGigachatAuthMode", () => {
|
||||
}),
|
||||
).toBe("oauth");
|
||||
});
|
||||
|
||||
it("infers basic auth for single-separator stored profile credentials without metadata", () => {
|
||||
expect(
|
||||
resolveGigachatAuthMode({
|
||||
apiKey: "user:password",
|
||||
authProfileId: "gigachat:default",
|
||||
}),
|
||||
).toBe("basic");
|
||||
});
|
||||
});
|
||||
|
||||
describe("composeSystemPromptWithHookContext", () => {
|
||||
|
||||
@ -1982,6 +1982,9 @@ export async function runEmbeddedAttempt(
|
||||
const gigachatMeta = resolveGigachatAuthProfileMetadata(
|
||||
gigachatStore,
|
||||
params.authProfileId,
|
||||
{
|
||||
allowDefaultProfileFallback: Boolean(params.authProfileId?.trim()),
|
||||
},
|
||||
);
|
||||
const gigachatApiKey = await params.authStorage.getApiKey(params.provider);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user