cloud-code-ai-provider
Version:
Google Cloud Code provider for the AI SDK
1,031 lines (1,022 loc) • 32.9 kB
JavaScript
// src/google-cloud-code-provider.ts
import {
NoSuchModelError
} from "@ai-sdk/provider";
import {
resolve as resolve2,
withoutTrailingSlash
} from "@ai-sdk/provider-utils";
// src/google-cloud-code-language-model.ts
import {
combineHeaders,
createEventSourceResponseHandler,
createJsonResponseHandler,
postJsonToApi,
resolve,
injectJsonInstructionIntoMessages
} from "@ai-sdk/provider-utils";
import { z as z2 } from "zod/v4";
// src/convert-to-cloud-code-messages.ts
import {
UnsupportedFunctionalityError
} from "@ai-sdk/provider";
import { convertUint8ArrayToBase64 } from "@ai-sdk/provider-utils";
function convertToCloudCodeMessages(prompt) {
const messages = [];
let systemInstruction;
for (const message of prompt) {
const { role, content } = message;
switch (role) {
case "system": {
systemInstruction = systemInstruction ? `${systemInstruction}
${content}` : content;
break;
}
case "user": {
const parts = [];
for (const part of content) {
switch (part.type) {
case "text": {
const p = part;
parts.push({ text: p.text });
break;
}
case "file": {
const file = part;
if (file.data instanceof URL) {
throw new UnsupportedFunctionalityError({
functionality: "File URL parts in messages"
});
}
parts.push({
inlineData: {
mimeType: file.mediaType ?? "application/octet-stream",
data: typeof file.data === "string" ? file.data : convertUint8ArrayToBase64(file.data)
}
});
break;
}
}
}
messages.push({
role: "user",
parts
});
break;
}
case "assistant": {
const parts = [];
for (const part of content) {
switch (part.type) {
case "text": {
const text = part.text;
if (text.length > 0) {
parts.push({ text });
}
break;
}
case "tool-call": {
const toolCall = part;
parts.push({
functionCall: {
name: toolCall.toolName,
args: toolCall.input
}
});
break;
}
}
}
if (parts.length > 0) {
messages.push({
role: "model",
parts
});
}
break;
}
case "tool": {
const parts = [];
for (const toolResponse of content) {
let response;
if ("output" in toolResponse) {
const out = toolResponse.output;
switch (out.type) {
case "text":
response = out.value;
break;
case "json":
response = out.value;
break;
case "error-text":
response = { error: out.value };
break;
case "error-json":
response = { error: out.value };
break;
case "content":
response = out.value.map(
(v) => v.type === "text" ? { text: v.text } : { inlineData: { mimeType: v.mediaType, data: v.data } }
);
break;
default:
response = out;
}
} else if ("result" in toolResponse) {
response = toolResponse.result;
}
parts.push({
functionResponse: {
name: toolResponse.toolName,
response
}
});
}
messages.push({
role: "function",
parts
});
break;
}
default: {
const _exhaustiveCheck = role;
throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
}
}
}
const result = { contents: messages };
if (systemInstruction) {
result.systemInstruction = {
role: "user",
parts: [{ text: systemInstruction }]
};
}
return result;
}
// src/map-cloud-code-finish-reason.ts
function mapCloudCodeFinishReason(finishReason) {
switch (finishReason) {
case "STOP":
return "stop";
case "MAX_TOKENS":
return "length";
case "SAFETY":
return "content-filter";
case "RECITATION":
return "content-filter";
case "OTHER":
return "other";
default:
return "unknown";
}
}
// src/google-cloud-code-error.ts
import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils";
import { z } from "zod";
var cloudCodeErrorDataSchema = z.object({
error: z.object({
code: z.number(),
message: z.string(),
status: z.string().optional(),
details: z.array(z.any()).optional()
})
});
var cloudCodeFailedResponseHandler = createJsonErrorResponseHandler({
errorSchema: cloudCodeErrorDataSchema,
errorToMessage: (data) => data.error.message
});
// src/google-cloud-code-prepare-tools.ts
function prepareTools(mode) {
const toolWarnings = [];
if (!mode.tools || mode.tools.length === 0) {
return { toolWarnings };
}
const functionDeclarations = mode.tools.map((tool) => {
if (tool.type === "provider-defined") {
toolWarnings.push({
type: "unsupported-tool",
tool,
details: "Provider-defined tools are not supported by this provider."
});
return void 0;
}
let params = tool.inputSchema;
if (params && typeof params === "object" && "$schema" in params) {
const { $schema, ...cleanParams } = params;
params = cleanParams;
}
return {
name: tool.name,
description: tool.description,
parameters: params
};
}).filter((decl) => decl != null);
const tools = [{
functionDeclarations
}];
let toolConfig;
if (mode.toolChoice) {
if (mode.toolChoice.type === "none") {
toolConfig = {
functionCallingConfig: {
mode: "NONE"
}
};
} else if (mode.toolChoice.type === "required") {
toolConfig = {
functionCallingConfig: {
mode: "ANY"
}
};
} else if (mode.toolChoice.type === "tool") {
toolConfig = {
functionCallingConfig: {
mode: "ANY",
allowedFunctionNames: [mode.toolChoice.toolName]
}
};
} else {
toolConfig = {
functionCallingConfig: {
mode: "AUTO"
}
};
}
} else {
toolConfig = {
functionCallingConfig: {
mode: "AUTO"
}
};
}
return {
tools,
toolConfig,
toolWarnings
};
}
// src/google-cloud-code-language-model.ts
var GoogleCloudCodeLanguageModel = class {
specificationVersion = "v2";
supportedUrls = { "*/*": [/^https:\/\//] };
modelId;
settings;
config;
constructor(modelId, settings, config) {
this.modelId = modelId;
this.settings = settings;
this.config = config;
}
get provider() {
return this.config.provider;
}
async getArgs(options) {
const {
prompt,
maxOutputTokens,
temperature,
topP,
topK,
frequencyPenalty,
presencePenalty,
stopSequences,
responseFormat,
seed,
tools,
toolChoice,
providerOptions
} = options;
const warnings = [];
if (frequencyPenalty != null) {
warnings.push({ type: "unsupported-setting", setting: "frequencyPenalty" });
}
if (presencePenalty != null) {
warnings.push({ type: "unsupported-setting", setting: "presencePenalty" });
}
if (seed != null) {
warnings.push({ type: "unsupported-setting", setting: "seed" });
}
const projectId = await this.config.getProjectId();
if (!projectId) {
throw new Error("Project ID is required for Google Cloud Code API");
}
const googleProviderOptions = providerOptions?.["google-cloud-code"] ?? {};
const generationConfig = {
temperature,
topP,
topK: topK ?? this.settings.topK,
maxOutputTokens,
stopSequences,
responseMimeType: responseFormat?.type === "json" ? "application/json" : void 0,
// Reduce thought tokens by default to avoid hitting MAX_TOKENS before tool calls/completions
thinkingConfig: googleProviderOptions.thinkingConfig ?? { includeThoughts: false }
};
const { tools: ccTools, toolConfig, toolWarnings } = prepareTools({ tools, toolChoice });
warnings.push(...toolWarnings);
const promptWithSchema = responseFormat?.type === "json" ? injectJsonInstructionIntoMessages({
messages: prompt,
schema: responseFormat.schema
}) : prompt;
const converted = convertToCloudCodeMessages(promptWithSchema);
const baseRequest = {
contents: converted.contents,
systemInstruction: converted.systemInstruction,
generationConfig,
safetySettings: this.settings.safetySettings,
tools: ccTools,
toolConfig
};
const args = {
model: this.modelId,
project: projectId,
request: baseRequest
};
return { args, warnings };
}
async doGenerate(options) {
const { args, warnings } = await this.getArgs(options);
let headers;
try {
headers = await resolve(this.config.headers);
} catch (error) {
throw new Error(
`Authentication failed: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
const {
responseHeaders,
value: response,
rawValue: rawResponse
} = await postJsonToApi({
url: `${this.config.baseURL}/v1internal:generateContent`,
headers: combineHeaders(headers, options.headers),
body: args,
failedResponseHandler: cloudCodeFailedResponseHandler,
successfulResponseHandler: createJsonResponseHandler(
cloudCodeGenerateContentResponseSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
const actualResponse = response.response;
const candidate = actualResponse.candidates?.[0];
if (!candidate) {
throw new Error("No candidates in response");
}
const content = candidate.content;
if (!content || !Array.isArray(content.parts)) {
return {
content: [],
finishReason: mapCloudCodeFinishReason(candidate.finishReason),
usage: {
inputTokens: actualResponse.usageMetadata?.promptTokenCount ?? void 0,
outputTokens: actualResponse.usageMetadata?.candidatesTokenCount ?? void 0,
totalTokens: actualResponse.usageMetadata?.totalTokenCount ?? void 0
},
request: { body: args },
response: {
headers: responseHeaders,
body: rawResponse
},
warnings
};
}
const generatedContent = [];
for (const part of content.parts) {
if (part.text != null) {
generatedContent.push({ type: "text", text: part.text });
}
if (part.functionCall != null) {
generatedContent.push({
type: "tool-call",
toolCallId: crypto.randomUUID(),
toolName: part.functionCall.name,
input: JSON.stringify(part.functionCall.args ?? {})
});
}
}
return {
content: generatedContent,
finishReason: mapCloudCodeFinishReason(candidate.finishReason),
usage: {
inputTokens: actualResponse.usageMetadata?.promptTokenCount ?? void 0,
outputTokens: actualResponse.usageMetadata?.candidatesTokenCount ?? void 0,
totalTokens: actualResponse.usageMetadata?.totalTokenCount ?? void 0
},
request: { body: args },
response: {
headers: responseHeaders,
body: rawResponse
},
warnings
};
}
async doStream(options) {
const { args, warnings } = await this.getArgs(options);
let headers;
try {
headers = await resolve(this.config.headers);
} catch (error) {
throw new Error(
`Authentication failed: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
const { responseHeaders, value: response } = await postJsonToApi({
url: `${this.config.baseURL}/v1internal:streamGenerateContent?alt=sse`,
headers: combineHeaders(headers, options.headers),
body: args,
failedResponseHandler: cloudCodeFailedResponseHandler,
successfulResponseHandler: createEventSourceResponseHandler(
cloudCodeStreamContentChunkSchema
),
abortSignal: options.abortSignal,
fetch: this.config.fetch
});
let finishReason = "unknown";
let usage = {
inputTokens: void 0,
outputTokens: void 0,
totalTokens: void 0
};
const stream = new ReadableStream({
async start(controller) {
controller.enqueue({ type: "stream-start", warnings });
const reader = response.getReader();
try {
while (true) {
const { value: chunk, done } = await reader.read();
if (done) break;
if (!chunk.success) {
controller.enqueue({ type: "error", error: chunk.error });
continue;
}
const value = chunk.value;
const actualResponse = value.response;
if (!actualResponse) continue;
if (actualResponse.usageMetadata) {
usage = {
inputTokens: actualResponse.usageMetadata.promptTokenCount ?? void 0,
outputTokens: actualResponse.usageMetadata.candidatesTokenCount ?? void 0,
totalTokens: actualResponse.usageMetadata.totalTokenCount ?? void 0
};
}
const candidate = actualResponse.candidates?.[0];
if (!candidate) continue;
if (candidate.finishReason) {
finishReason = mapCloudCodeFinishReason(candidate.finishReason);
}
const content = candidate.content;
if (!content || !content.parts) continue;
for (const part of content.parts) {
if (part.text != null) {
const id = crypto.randomUUID();
controller.enqueue({ type: "text-start", id });
controller.enqueue({ type: "text-delta", id, delta: part.text });
controller.enqueue({ type: "text-end", id });
}
if (part.functionCall != null) {
const toolCallId = crypto.randomUUID();
controller.enqueue({
type: "tool-call",
toolCallId,
toolName: part.functionCall.name,
input: JSON.stringify(part.functionCall.args ?? {})
});
}
}
}
} finally {
controller.enqueue({ type: "finish", finishReason, usage });
controller.close();
}
}
});
return {
stream,
request: { body: args },
response: { headers: responseHeaders }
};
}
};
var cloudCodeContentSchema = z2.object({
role: z2.string(),
parts: z2.array(
z2.object({
text: z2.string().optional(),
functionCall: z2.object({
name: z2.string(),
args: z2.record(z2.string(), z2.any()).optional()
}).optional()
})
).optional()
});
var cloudCodeCandidateSchema = z2.object({
content: cloudCodeContentSchema,
finishReason: z2.string().optional()
});
var cloudCodeUsageMetadataSchema = z2.object({
promptTokenCount: z2.number().optional(),
candidatesTokenCount: z2.number().optional(),
totalTokenCount: z2.number().optional()
});
var cloudCodeGenerateContentResponseSchema = z2.object({
response: z2.object({
candidates: z2.array(cloudCodeCandidateSchema).optional(),
promptFeedback: z2.any().optional(),
usageMetadata: cloudCodeUsageMetadataSchema.optional()
})
});
var cloudCodeStreamContentChunkSchema = z2.object({
response: z2.object({
candidates: z2.array(cloudCodeCandidateSchema).optional(),
usageMetadata: cloudCodeUsageMetadataSchema.optional()
}).optional()
});
// src/google-cloud-code-auth.ts
import { OAuth2Client } from "google-auth-library";
import * as os from "os";
import * as path from "path";
import * as fs from "fs/promises";
import * as http from "http";
import * as url from "url";
import * as crypto2 from "crypto";
import * as net from "net";
import open from "open";
var CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
var CLIENT_SECRET = "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";
var SCOPES = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
];
var CODE_ASSIST_ENDPOINT = process.env["CODE_ASSIST_ENDPOINT"] || "https://cloudcode-pa.googleapis.com";
var CODE_ASSIST_API_VERSION = "v1internal";
var DEFAULT_GEMINI_DIR = ".gemini";
var CREDENTIAL_FILENAME = "oauth_creds.json";
var GoogleCloudCodeAuth = class {
static oauthClient = null;
static cachedProjectId = null;
static customCredentialDir = null;
static async getOAuthClient() {
if (!this.oauthClient) {
this.oauthClient = new OAuth2Client({
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET
});
}
if (await this.loadCachedCredentials()) {
return this.oauthClient;
}
return this.oauthClient;
}
static async setCredentials(credentials) {
const client = await this.getOAuthClient();
client.setCredentials(credentials);
await this.cacheCredentials(credentials);
}
static async getAccessToken() {
const client = await this.getOAuthClient();
try {
const { token } = await client.getAccessToken();
return token || void 0;
} catch {
return void 0;
}
}
static generateAuthUrl(redirectUri, state) {
const client = new OAuth2Client({
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET
});
return client.generateAuthUrl({
redirect_uri: redirectUri,
access_type: "offline",
scope: SCOPES,
state
});
}
// Cloud Code Assist API methods
static async callEndpoint(client, method, body) {
const res = await client.request({
url: `${CODE_ASSIST_ENDPOINT}/${CODE_ASSIST_API_VERSION}:${method}`,
method: "POST",
headers: {
"Content-Type": "application/json"
},
data: body
});
return res.data;
}
static async loadCodeAssist(client, projectId) {
const metadata = this.getClientMetadata(projectId);
const request = {
cloudaicompanionProject: projectId,
metadata
};
return this.callEndpoint(client, "loadCodeAssist", request);
}
static async onboardUser(client, tierId, projectId) {
const metadata = this.getClientMetadata(projectId);
const request = {
tierId,
cloudaicompanionProject: projectId,
metadata
};
return this.callEndpoint(client, "onboardUser", request);
}
static getClientMetadata(projectId) {
const platform2 = this.getPlatform();
return {
ideType: "IDE_UNSPECIFIED",
platform: platform2,
pluginType: "GEMINI",
duetProject: projectId
};
}
static getPlatform() {
const platform2 = os.platform();
const arch2 = os.arch();
if (platform2 === "darwin") {
return arch2 === "arm64" ? "DARWIN_ARM64" : "DARWIN_AMD64";
} else if (platform2 === "linux") {
return arch2 === "arm64" ? "LINUX_ARM64" : "LINUX_AMD64";
} else if (platform2 === "win32") {
return "WINDOWS_AMD64";
}
return "PLATFORM_UNSPECIFIED";
}
static async setupUser() {
if (this.cachedProjectId) {
return this.cachedProjectId;
}
const envProjectId = process.env["GOOGLE_CLOUD_PROJECT"];
if (envProjectId) {
this.cachedProjectId = envProjectId;
return envProjectId;
}
const client = await this.getOAuthClient();
try {
const loadRes = await this.loadCodeAssist(client, envProjectId);
if (!loadRes.allowedTiers || loadRes.allowedTiers.length === 0) {
throw new Error("No available tiers for Code Assist. Your account may not have access.");
}
const defaultTier = loadRes.allowedTiers.find((tier) => tier.isDefault);
const selectedTier = defaultTier || loadRes.allowedTiers[0];
const projectId = loadRes.cloudaicompanionProject || envProjectId || "";
let operation = await this.onboardUser(client, selectedTier.id, projectId);
const maxAttempts = 12;
let attempts = 0;
while (!operation.done && attempts < maxAttempts) {
await new Promise((resolve3) => setTimeout(resolve3, 5e3));
operation = await this.onboardUser(client, selectedTier.id, projectId);
attempts++;
}
if (!operation.done) {
throw new Error("Onboarding timeout - operation did not complete");
}
if (operation.error) {
throw new Error(`Onboarding failed: ${operation.error.message}`);
}
const resolvedProjectId = operation.response?.cloudaicompanionProject?.id;
if (!resolvedProjectId) {
throw new Error("No project ID returned from onboarding");
}
this.cachedProjectId = resolvedProjectId;
return resolvedProjectId;
} catch (error) {
if (error instanceof Error && error.message.includes("Workspace")) {
throw new Error(
"Google Workspace Account detected. Please set GOOGLE_CLOUD_PROJECT environment variable."
);
}
console.error("Failed to setup Code Assist:", error);
const fallbackProjectId = "elegant-machine-vq6tl";
this.cachedProjectId = fallbackProjectId;
return fallbackProjectId;
}
}
static async getProjectId() {
return this.setupUser();
}
static async clearCache() {
this.cachedProjectId = null;
try {
await fs.unlink(this.getCachedCredentialPath());
} catch {
}
}
/**
* Complete OAuth authentication flow with browser
* Opens browser for authentication and handles the OAuth callback
* @param options - Optional configuration for the auth flow
* @returns Promise that resolves when authentication is complete
*/
static async authenticate(options) {
const {
force = false,
successUrl = "https://developers.google.com/gemini-code-assist/auth_success_gemini",
failureUrl = "https://developers.google.com/gemini-code-assist/auth_failure_gemini",
skipBrowser = false,
credentialDirectory
} = options || {};
if (credentialDirectory) {
this.setCredentialDirectory(credentialDirectory);
}
if (!force && await this.loadCachedCredentials()) {
console.log("\u2705 Already authenticated. Use { force: true } to re-authenticate.");
return;
}
if (force) {
await this.clearCache();
}
const port = await this.getAvailablePort();
const redirectUri = `http://localhost:${port}/oauth2callback`;
const state = crypto2.randomBytes(32).toString("hex");
const authUrl = this.generateAuthUrl(redirectUri, state);
const authPromise = this.createOAuthCallbackServer(port, state, redirectUri, successUrl, failureUrl);
if (!skipBrowser) {
console.log("\n\u{1F510} Google Cloud Code Authentication");
console.log("Opening browser for authentication...\n");
try {
await open(authUrl);
} catch (e) {
console.log("Failed to open browser automatically.");
}
}
console.log("Visit this URL to authenticate:");
console.log(`
${authUrl}
`);
console.log("Waiting for authentication...");
try {
await authPromise;
console.log("\n\u2705 Authentication successful!");
const projectId = await this.setupUser();
console.log(`\u{1F4C1} Project ID: ${projectId}`);
console.log(`\u{1F4C2} Credentials saved to: ${this.getCachedCredentialPath()}
`);
} catch (error) {
console.error("\n\u274C Authentication failed:", error);
throw error;
}
}
/**
* Check if the user is authenticated
* @returns True if authenticated with valid credentials
*/
static async isAuthenticated() {
try {
const client = await this.getOAuthClient();
const hasCredentials = await this.loadCachedCredentials();
if (!hasCredentials) return false;
const { token } = await client.getAccessToken();
return !!token;
} catch {
return false;
}
}
/**
* Get information about the authenticated user
* @returns User information including email
*/
static async getUserInfo() {
const client = await this.getOAuthClient();
const { token } = await client.getAccessToken();
if (!token) {
throw new Error("Not authenticated");
}
const res = await client.request({
url: "https://www.googleapis.com/oauth2/v1/userinfo"
});
return res.data;
}
/**
* Find an available port for the OAuth callback server
*/
static getAvailablePort() {
return new Promise((resolve3, reject) => {
let port = 0;
try {
const server = net.createServer();
server.listen(0, () => {
const address = server.address();
port = address.port;
});
server.on("listening", () => {
server.close();
server.unref();
});
server.on("error", (e) => reject(e));
server.on("close", () => resolve3(port));
} catch (e) {
reject(e);
}
});
}
/**
* Create OAuth callback server
*/
static createOAuthCallbackServer(port, expectedState, redirectUri, successUrl, failureUrl) {
return new Promise((resolve3, reject) => {
const server = http.createServer(async (req, res) => {
try {
const parsedUrl = new url.URL(req.url, `http://localhost:${port}`);
console.log(`OAuth callback received: ${req.url}`);
if (parsedUrl.pathname !== "/oauth2callback") {
res.writeHead(404);
res.end("Not found");
return;
}
const code = parsedUrl.searchParams.get("code");
const state = parsedUrl.searchParams.get("state");
const error = parsedUrl.searchParams.get("error");
if (error) {
res.writeHead(301, { Location: failureUrl });
res.end();
server.close(() => reject(new Error(`OAuth error: ${error}`)));
return;
}
if (state !== expectedState) {
res.writeHead(301, { Location: failureUrl });
res.end();
server.close(() => reject(new Error("State mismatch - possible CSRF attack")));
return;
}
if (!code) {
res.writeHead(301, { Location: failureUrl });
res.end();
server.close(() => reject(new Error("No authorization code received")));
return;
}
console.log("Exchanging authorization code for tokens...");
const client = new OAuth2Client({
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
redirectUri
});
const { tokens } = await client.getToken(code);
console.log("Token exchange successful");
await this.setCredentials(tokens);
console.log("Credentials saved");
res.writeHead(301, { Location: successUrl });
res.end();
setImmediate(() => {
server.close(() => {
console.log("OAuth server closed");
resolve3();
});
});
} catch (error) {
console.error("OAuth callback error:", error);
res.writeHead(500, { "Content-Type": "text/html" });
res.end(`
<html>
<body style="font-family: system-ui; padding: 40px; text-align: center;">
<h1>\u274C Authentication Error</h1>
<p>An error occurred during authentication. Please check the console and try again.</p>
<p style="color: #666; font-size: 14px;">${error instanceof Error ? error.message : "Unknown error"}</p>
</body>
</html>
`);
server.close(() => reject(error));
}
});
server.listen(port, () => {
console.log(`OAuth callback server listening on port ${port}`);
});
const timeout = setTimeout(() => {
server.close(() => reject(new Error("Authentication timeout")));
}, 5 * 60 * 1e3);
server.on("close", () => {
clearTimeout(timeout);
});
});
}
static setCredentialDirectory(directory) {
this.customCredentialDir = directory;
}
static getCredentialDirectory() {
return this.customCredentialDir || DEFAULT_GEMINI_DIR;
}
static getCachedCredentialPath() {
if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
return process.env.GOOGLE_APPLICATION_CREDENTIALS;
}
const baseDir = this.customCredentialDir || DEFAULT_GEMINI_DIR;
return path.join(os.homedir(), baseDir, CREDENTIAL_FILENAME);
}
static async loadCachedCredentials() {
try {
const keyFile = process.env.GOOGLE_APPLICATION_CREDENTIALS || this.getCachedCredentialPath();
const creds = await fs.readFile(keyFile, "utf-8");
this.oauthClient.setCredentials(JSON.parse(creds));
const { token } = await this.oauthClient.getAccessToken();
if (!token) {
return false;
}
await this.oauthClient.getTokenInfo(token);
return true;
} catch {
return false;
}
}
static async cacheCredentials(credentials) {
const filePath = this.getCachedCredentialPath();
await fs.mkdir(path.dirname(filePath), { recursive: true });
const credString = JSON.stringify(credentials, null, 2);
await fs.writeFile(filePath, credString);
}
};
// src/google-cloud-code-provider.ts
function createGoogleCloudCode(options = {}) {
const baseURL = withoutTrailingSlash(
options.baseURL ?? "https://cloudcode-pa.googleapis.com"
);
if (options.credentialDirectory) {
GoogleCloudCodeAuth.setCredentialDirectory(options.credentialDirectory);
}
if (options.credentials) {
GoogleCloudCodeAuth.setCredentials(options.credentials);
}
const getHeaders = async () => {
const headers = await resolve2(options.headers);
const directAccessToken = await resolve2(options.accessToken);
if (directAccessToken) {
return {
...headers,
Authorization: `Bearer ${directAccessToken}`
};
}
const useOAuth = options.useOAuth !== false;
if (useOAuth) {
const oauthToken = await GoogleCloudCodeAuth.getAccessToken();
if (oauthToken) {
return {
...headers,
Authorization: `Bearer ${oauthToken}`
};
}
throw new Error(
"Authentication required. Please run the auth flow first or provide an access token."
);
}
throw new Error(
"No authentication credentials provided. Either enable OAuth or provide an access token."
);
};
const getProjectId = async () => {
const directProjectId = await resolve2(options.projectId);
if (directProjectId) {
return directProjectId;
}
const useOAuth = options.useOAuth !== false;
if (useOAuth) {
try {
return await GoogleCloudCodeAuth.getProjectId();
} catch (error) {
console.warn("Failed to get project ID through OAuth:", error);
}
}
return void 0;
};
const createLanguageModel = (modelId, settings = {}) => new GoogleCloudCodeLanguageModel(modelId, settings, {
provider: "google-cloud-code",
baseURL: baseURL ?? "https://cloudcode-pa.googleapis.com",
headers: getHeaders,
getProjectId,
fetch: options.fetch
});
const createTextEmbeddingModel = () => {
throw new NoSuchModelError({
errorName: "NoSuchModelError",
modelId: "text-embedding-001",
modelType: "textEmbeddingModel",
message: "Text embedding model not supported"
});
};
const provider = function(modelId, settings) {
if (new.target) {
throw new Error(
"The Google Cloud Code model function cannot be called with the new keyword."
);
}
return createLanguageModel(modelId, settings);
};
provider.languageModel = createLanguageModel;
provider.textEmbeddingModel = createTextEmbeddingModel;
provider.imageModel = () => {
throw new NoSuchModelError({
modelId: "image-generation",
modelType: "imageModel",
message: "Image model not supported"
});
};
return provider;
}
var googleCloudCode = createGoogleCloudCode();
export {
GoogleCloudCodeAuth,
createGoogleCloudCode,
googleCloudCode
};
//# sourceMappingURL=index.js.map