mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-28 06:03:33 +00:00
fix: accept Google API keys for Gemini CLI
This commit is contained in:
@@ -14,6 +14,7 @@ const GEMINI_MODEL_ALIASES: Record<string, string> = {
|
||||
};
|
||||
const GEMINI_CLI_DEFAULT_MODEL_REF = "google-gemini-cli/gemini-3-flash-preview";
|
||||
const GEMINI_CLI_PROVIDER_ID = "google-gemini-cli";
|
||||
const GOOGLE_PROVIDER_ID = "google";
|
||||
const VERCEL_AI_GATEWAY_PROVIDER_ID = "vercel-ai-gateway";
|
||||
const GEMINI_CLI_CREDENTIALS_FILENAME = "gemini-credentials.json";
|
||||
const GEMINI_CLI_GCA_AUTH_ENV = [
|
||||
@@ -68,7 +69,7 @@ type GeminiOAuthCredential = GeminiAuthProfileCredential & {
|
||||
|
||||
type GeminiApiKeyCredential = GeminiAuthProfileCredential & {
|
||||
type: "api_key";
|
||||
provider: typeof GEMINI_CLI_PROVIDER_ID;
|
||||
provider: typeof GEMINI_CLI_PROVIDER_ID | typeof GOOGLE_PROVIDER_ID;
|
||||
key: string;
|
||||
};
|
||||
|
||||
@@ -154,7 +155,10 @@ function requireGeminiApiKeyCredential(
|
||||
if (credential.type !== "api_key") {
|
||||
return null;
|
||||
}
|
||||
if (credential.provider !== GEMINI_CLI_PROVIDER_ID) {
|
||||
if (
|
||||
credential.provider !== GEMINI_CLI_PROVIDER_ID &&
|
||||
credential.provider !== GOOGLE_PROVIDER_ID
|
||||
) {
|
||||
throwUnsupportedGeminiCredential(credential);
|
||||
}
|
||||
|
||||
@@ -166,7 +170,7 @@ function requireGeminiApiKeyCredential(
|
||||
return {
|
||||
...credential,
|
||||
type: "api_key",
|
||||
provider: GEMINI_CLI_PROVIDER_ID,
|
||||
provider: credential.provider,
|
||||
key,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -52,11 +52,11 @@ function buildGeminiApiKeyPrepareContext(workspaceDir: string): GeminiPrepareCon
|
||||
agentDir,
|
||||
provider: "google-gemini-cli",
|
||||
modelId: "gemini-3.1-flash-lite",
|
||||
authProfileId: "google-gemini-cli:api-key",
|
||||
authProfileId: "google:api-key",
|
||||
// Private bundled-runtime bridge, not public Plugin SDK surface.
|
||||
authCredential: {
|
||||
type: "api_key",
|
||||
provider: "google-gemini-cli",
|
||||
provider: "google",
|
||||
key: "gemini-api-key",
|
||||
email: "user@example.test",
|
||||
},
|
||||
@@ -141,7 +141,7 @@ describe("google gemini cli backend auth bridge", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("prepares selected Gemini API-key credentials and removes stale OAuth state for that profile home", async () => {
|
||||
it("prepares selected canonical Google API-key credentials and removes stale OAuth state for that profile home", async () => {
|
||||
const backend = buildGoogleGeminiCliBackend();
|
||||
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-test-workspace-"));
|
||||
let home: string | undefined;
|
||||
|
||||
@@ -806,6 +806,77 @@ describe("CLI attempt execution", () => {
|
||||
expect(firstRunCliAgentArg().authProfileId).toBe("google-gemini-cli:user@example.test");
|
||||
});
|
||||
|
||||
it("forwards pinned canonical Google API-key profiles to Google models routed through Gemini CLI", async () => {
|
||||
const sessionKey = "agent:main:direct:gemini-cli-google-api-key";
|
||||
const sessionEntry: SessionEntry = {
|
||||
sessionId: "openclaw-session-gemini-api-key",
|
||||
updatedAt: Date.now(),
|
||||
authProfileOverride: "google:api-key",
|
||||
authProfileOverrideSource: "user",
|
||||
};
|
||||
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
|
||||
await fs.writeFile(storePath, JSON.stringify(sessionStore, null, 2), "utf-8");
|
||||
saveAuthProfileStore(
|
||||
{
|
||||
version: 1,
|
||||
profiles: {
|
||||
"google:api-key": {
|
||||
type: "api_key",
|
||||
provider: "google",
|
||||
key: "gemini-api-key",
|
||||
},
|
||||
},
|
||||
},
|
||||
tmpDir,
|
||||
{ filterExternalAuthProfiles: false, syncExternalCli: false },
|
||||
);
|
||||
runCliAgentMock.mockResolvedValueOnce(makeCliResult("gemini cli api-key response"));
|
||||
|
||||
await runAgentAttempt({
|
||||
providerOverride: "google",
|
||||
originalProvider: "google",
|
||||
modelOverride: "gemini-3.1-pro-preview",
|
||||
cfg: {
|
||||
agents: {
|
||||
defaults: {
|
||||
models: {
|
||||
"google/gemini-3.1-pro-preview": {
|
||||
agentRuntime: { id: "google-gemini-cli" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
sessionEntry,
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
workspaceDir: tmpDir,
|
||||
body: "continue",
|
||||
isFallbackRetry: false,
|
||||
resolvedThinkLevel: "medium",
|
||||
timeoutMs: 1_000,
|
||||
runId: "run-gemini-cli-google-api-key",
|
||||
opts: {} as Parameters<typeof runAgentAttempt>[0]["opts"],
|
||||
runContext: {} as Parameters<typeof runAgentAttempt>[0]["runContext"],
|
||||
spawnedBy: undefined,
|
||||
messageChannel: undefined,
|
||||
skillsSnapshot: undefined,
|
||||
resolvedVerboseLevel: undefined,
|
||||
agentDir: tmpDir,
|
||||
onAgentEvent: vi.fn(),
|
||||
authProfileProvider: "google",
|
||||
sessionStore,
|
||||
storePath,
|
||||
sessionHasHistory: false,
|
||||
});
|
||||
|
||||
expect(runCliAgentMock).toHaveBeenCalledTimes(1);
|
||||
expect(firstRunCliAgentArg().provider).toBe("google-gemini-cli");
|
||||
expect(firstRunCliAgentArg().authProfileId).toBe("google:api-key");
|
||||
});
|
||||
|
||||
it("persists CLI replies into the session transcript", async () => {
|
||||
const sessionKey = "agent:main:subagent:cli-transcript";
|
||||
const sessionFile = path.join(tmpDir, "session-cli-transcript.jsonl");
|
||||
|
||||
Reference in New Issue
Block a user