feat: add Google Antigravity authentication support
- Add 'antigravity' as new auth choice in onboard and configure wizards - Implement Google Antigravity OAuth flow using loginAntigravity from pi-ai - Update writeOAuthCredentials to accept any OAuthProvider (not just 'anthropic') - Add schema sanitization for Google Cloud Code Assist API to fix tool call errors - Default model set to google-antigravity/claude-opus-4-5 after successful auth The schema sanitization removes unsupported JSON Schema keywords (patternProperties, const, anyOf, etc.) that Google's Cloud Code Assist API doesn't understand.
This commit is contained in:
committed by
Peter Steinberger
parent
5eff541da8
commit
05bd345828
@@ -10,7 +10,11 @@ import {
|
||||
spinner,
|
||||
text,
|
||||
} from "@clack/prompts";
|
||||
import { loginAnthropic, type OAuthCredentials } from "@mariozechner/pi-ai";
|
||||
import {
|
||||
loginAnthropic,
|
||||
loginAntigravity,
|
||||
type OAuthCredentials,
|
||||
} from "@mariozechner/pi-ai";
|
||||
|
||||
import type { ClawdisConfig } from "../config/config.js";
|
||||
import {
|
||||
@@ -223,13 +227,17 @@ async function promptAuthConfig(
|
||||
message: "Model/auth choice",
|
||||
options: [
|
||||
{ value: "oauth", label: "Anthropic OAuth (Claude Pro/Max)" },
|
||||
{
|
||||
value: "antigravity",
|
||||
label: "Google Antigravity (Claude Opus 4.5, Gemini 3, etc.)",
|
||||
},
|
||||
{ value: "apiKey", label: "Anthropic API key" },
|
||||
{ value: "minimax", label: "Minimax M2.1 (LM Studio)" },
|
||||
{ value: "skip", label: "Skip for now" },
|
||||
],
|
||||
}),
|
||||
runtime,
|
||||
) as "oauth" | "apiKey" | "minimax" | "skip";
|
||||
) as "oauth" | "antigravity" | "apiKey" | "minimax" | "skip";
|
||||
|
||||
let next = cfg;
|
||||
|
||||
@@ -266,6 +274,47 @@ async function promptAuthConfig(
|
||||
spin.stop("OAuth failed");
|
||||
runtime.error(String(err));
|
||||
}
|
||||
} else if (authChoice === "antigravity") {
|
||||
note(
|
||||
[
|
||||
"Browser will open for Google authentication.",
|
||||
"Sign in with your Google account that has Antigravity access.",
|
||||
"The callback will be captured automatically on localhost:51121.",
|
||||
].join("\n"),
|
||||
"Google Antigravity OAuth",
|
||||
);
|
||||
const spin = spinner();
|
||||
spin.start("Starting OAuth flow…");
|
||||
let oauthCreds: OAuthCredentials | null = null;
|
||||
try {
|
||||
oauthCreds = await loginAntigravity(
|
||||
async ({ url, instructions }) => {
|
||||
spin.message(instructions ?? "Complete sign-in in browser…");
|
||||
await openUrl(url);
|
||||
runtime.log(`Open: ${url}`);
|
||||
},
|
||||
(msg) => spin.message(msg),
|
||||
);
|
||||
spin.stop("Antigravity OAuth complete");
|
||||
if (oauthCreds) {
|
||||
await writeOAuthCredentials("google-antigravity", oauthCreds);
|
||||
// Set default model to Claude Opus 4.5 via Antigravity
|
||||
next = {
|
||||
...next,
|
||||
agent: {
|
||||
...next.agent,
|
||||
model: "google-antigravity/claude-opus-4-5",
|
||||
},
|
||||
};
|
||||
note(
|
||||
"Default model set to google-antigravity/claude-opus-4-5",
|
||||
"Model configured",
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
spin.stop("Antigravity OAuth failed");
|
||||
runtime.error(String(err));
|
||||
}
|
||||
} else if (authChoice === "apiKey") {
|
||||
const key = guardCancel(
|
||||
await text({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
import type { OAuthCredentials } from "@mariozechner/pi-ai";
|
||||
import type { OAuthCredentials, OAuthProvider } from "@mariozechner/pi-ai";
|
||||
import { discoverAuthStorage } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
import { resolveClawdisAgentDir } from "../agents/agent-paths.js";
|
||||
@@ -9,7 +9,7 @@ import type { ClawdisConfig } from "../config/config.js";
|
||||
import { CONFIG_DIR } from "../utils.js";
|
||||
|
||||
export async function writeOAuthCredentials(
|
||||
provider: "anthropic",
|
||||
provider: OAuthProvider,
|
||||
creds: OAuthCredentials,
|
||||
): Promise<void> {
|
||||
const dir = path.join(CONFIG_DIR, "credentials");
|
||||
|
||||
@@ -9,7 +9,11 @@ import {
|
||||
spinner,
|
||||
text,
|
||||
} from "@clack/prompts";
|
||||
import { loginAnthropic, type OAuthCredentials } from "@mariozechner/pi-ai";
|
||||
import {
|
||||
loginAnthropic,
|
||||
loginAntigravity,
|
||||
type OAuthCredentials,
|
||||
} from "@mariozechner/pi-ai";
|
||||
|
||||
import type { ClawdisConfig } from "../config/config.js";
|
||||
import {
|
||||
@@ -198,6 +202,10 @@ export async function runInteractiveOnboarding(
|
||||
message: "Model/auth choice",
|
||||
options: [
|
||||
{ value: "oauth", label: "Anthropic OAuth (Claude Pro/Max)" },
|
||||
{
|
||||
value: "antigravity",
|
||||
label: "Google Antigravity (Claude Opus 4.5, Gemini 3, etc.)",
|
||||
},
|
||||
{ value: "apiKey", label: "Anthropic API key" },
|
||||
{ value: "minimax", label: "Minimax M2.1 (LM Studio)" },
|
||||
{ value: "skip", label: "Skip for now" },
|
||||
@@ -239,6 +247,47 @@ export async function runInteractiveOnboarding(
|
||||
spin.stop("OAuth failed");
|
||||
runtime.error(String(err));
|
||||
}
|
||||
} else if (authChoice === "antigravity") {
|
||||
note(
|
||||
[
|
||||
"Browser will open for Google authentication.",
|
||||
"Sign in with your Google account that has Antigravity access.",
|
||||
"The callback will be captured automatically on localhost:51121.",
|
||||
].join("\n"),
|
||||
"Google Antigravity OAuth",
|
||||
);
|
||||
const spin = spinner();
|
||||
spin.start("Starting OAuth flow…");
|
||||
let oauthCreds: OAuthCredentials | null = null;
|
||||
try {
|
||||
oauthCreds = await loginAntigravity(
|
||||
async ({ url, instructions }) => {
|
||||
spin.message(instructions ?? "Complete sign-in in browser…");
|
||||
await openUrl(url);
|
||||
runtime.log(`Open: ${url}`);
|
||||
},
|
||||
(msg) => spin.message(msg),
|
||||
);
|
||||
spin.stop("Antigravity OAuth complete");
|
||||
if (oauthCreds) {
|
||||
await writeOAuthCredentials("google-antigravity", oauthCreds);
|
||||
// Set default model to Claude Opus 4.5 via Antigravity
|
||||
nextConfig = {
|
||||
...nextConfig,
|
||||
agent: {
|
||||
...nextConfig.agent,
|
||||
model: "google-antigravity/claude-opus-4-5",
|
||||
},
|
||||
};
|
||||
note(
|
||||
"Default model set to google-antigravity/claude-opus-4-5",
|
||||
"Model configured",
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
spin.stop("Antigravity OAuth failed");
|
||||
runtime.error(String(err));
|
||||
}
|
||||
} else if (authChoice === "apiKey") {
|
||||
const key = guardCancel(
|
||||
await text({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export type OnboardMode = "local" | "remote";
|
||||
export type AuthChoice = "oauth" | "apiKey" | "minimax" | "skip";
|
||||
export type AuthChoice = "oauth" | "antigravity" | "apiKey" | "minimax" | "skip";
|
||||
export type GatewayAuthChoice = "off" | "token" | "password";
|
||||
export type ResetScope = "config" | "config+creds+sessions" | "full";
|
||||
export type GatewayBind = "loopback" | "lan" | "tailnet" | "auto";
|
||||
|
||||
Reference in New Issue
Block a user