Harden provider security and build dependencies

This commit is contained in:
ZacharyZhang-NY committed 2026-06-07 14:04:32 -04:00
1 parent 67d2cf5649
commit abe578b1a0
10 files changed
+783 -285

No files matched your search

@@ -9,7 +9,7 @@ import { generatePkce } from "./pkce";
import type { OAuthCredentials, OAuthFlow, OAuthLoginCallbacks } from "./oauth-types";
const CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
const CLIENT_SECRET = "***REMOVED***";
const CLIENT_SECRET_ENV = "AGENTCOMPANY_GOOGLE_ANTIGRAVITY_CLIENT_SECRET";
const CALLBACK_PORT = 51121;
const CALLBACK_PATH = "/oauth-callback";
const REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
@@ -22,9 +22,14 @@ const SCOPES = [
];
const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
const TOKEN_URL = "https://oauth2.googleapis.com/token";
const DEFAULT_PROJECT_ID = "rising-fact-p41fc";
const CODE_ASSIST_ENDPOINTS = ["https://cloudcode-pa.googleapis.com", "https://daily-cloudcode-pa.sandbox.googleapis.com"];
export function resolveAntigravityClientSecret(env: NodeJS.ProcessEnv = process.env): string {
const secret = env[CLIENT_SECRET_ENV]?.trim();
if (!secret) throw new Error(`${CLIENT_SECRET_ENV} is required for Google Antigravity OAuth.`);
return secret;
}
function buildAuthorizeUrl(challenge: string, state: string): string {
const params = new URLSearchParams({
client_id: CLIENT_ID,
@@ -46,7 +51,7 @@ async function exchangeCode(code: string, verifier: string): Promise<{ access: s
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
client_secret: resolveAntigravityClientSecret(),
code,
grant_type: "authorization_code",
redirect_uri: REDIRECT_URI,
@@ -96,7 +101,7 @@ async function discoverProject(accessToken: string): Promise<string> {
// Try the next endpoint.
}
}
return DEFAULT_PROJECT_ID;
throw new Error("Antigravity project discovery failed.");
}
/** Refresh an expired Antigravity access token, retaining the project id. */
@@ -104,7 +109,12 @@ export async function refreshAntigravity(refreshToken: string, projectId: string
const response = await fetch(TOKEN_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ client_id: CLIENT_ID, client_secret: CLIENT_SECRET, refresh_token: refreshToken, grant_type: "refresh_token" }),
body: new URLSearchParams({
client_id: CLIENT_ID,
client_secret: resolveAntigravityClientSecret(),
refresh_token: refreshToken,
grant_type: "refresh_token",
}),
});
const text = await response.text();
if (!response.ok) throw new Error(`Antigravity token refresh failed: ${response.status} ${text}`);
@@ -66,13 +66,10 @@ function errorText(data: JsonRecord): string {
/**
* Accumulate a Responses SSE stream (Codex/Copilot) into the final result. The
* authoritative output arrives on the completion event's `response.output`; the
* incremental events are accumulated only as a fallback.
* result is accepted from the completion event's `response.output`.
*/
export async function accumulateResponsesStream(messages: AsyncIterable<ProviderEventStreamMessage>): Promise<AgentTurnResult> {
const raw: string[] = [];
const textParts: string[] = [];
const calls = new Map<string, { id: string; name: string; args: string }>();
for await (const message of messages) {
raw.push(message.rawData);
const type = eventType(message);
@@ -84,23 +81,8 @@ export async function accumulateResponsesStream(messages: AsyncIterable<Provider
const parsed = parseResponsesOutput(response);
return { text: parsed.text, toolCalls: parsed.toolCalls, rawResponseJson: JSON.stringify(raw) };
}
break;
}
if (type === "response.output_text.delta" && typeof message.data.delta === "string") {
textParts.push(message.data.delta);
} else if (type === "response.output_item.added" && isRecord(message.data.item) && message.data.item.type === "function_call") {
const item = message.data.item;
const key = typeof item.id === "string" ? item.id : typeof item.call_id === "string" ? item.call_id : "";
const id = typeof item.call_id === "string" ? item.call_id : key;
if (key) calls.set(key, { id, name: typeof item.name === "string" ? item.name : "", args: typeof item.arguments === "string" ? item.arguments : "" });
} else if (type === "response.function_call_arguments.delta" && typeof message.data.item_id === "string" && typeof message.data.delta === "string") {
const entry = calls.get(message.data.item_id);
if (entry) entry.args += message.data.delta;
} else if (type === "response.function_call_arguments.done" && typeof message.data.item_id === "string" && typeof message.data.arguments === "string") {
const entry = calls.get(message.data.item_id);
if (entry) entry.args = message.data.arguments;
throw new Error("Responses completion event was missing response.output.");
}
}
const toolCalls = [...calls.values()].filter((entry) => entry.name).map((entry) => ({ id: entry.id, name: entry.name, arguments: parseArguments(entry.args) }));
return { text: textParts.join("").trim(), toolCalls, rawResponseJson: JSON.stringify(raw) };
throw new Error("Responses stream ended before a completion event.");
}