How to Integrate Earendil PI with Google Cloud AI: A Complete Guide

Integrate Earendil PI with Google Cloud AI by installing @earendil-works/pi-ai, configuring credentials via API key or Application Default Credentials (ADC), and calling getModel('google-vertex', <model-id>) followed by stream() or complete().

Earendil PI provides a unified LLM API that abstracts Google Vertex AI into a provider-agnostic interface. This integration allows you to leverage Gemini models through the same Context and streaming patterns used across all PI providers. The implementation resides primarily in packages/ai/src/providers/google-vertex.ts and shares conversion logic with packages/ai/src/providers/google-shared.ts.

Prerequisites and Installation

Begin by installing the official PI AI package:

npm install @earendil-works/pi-ai

Ensure you have access to Google Cloud Platform with Vertex AI API enabled. You will need either a Gemini API key for key-based authentication or a GCP project with appropriate IAM roles for ADC authentication.

Authentication Methods

Earendil PI supports two authentication flows for Google Cloud AI, handled by the resolveApiKey, resolveProject, and resolveLocation functions in packages/ai/src/providers/google-vertex.ts.

Option A: API Key Authentication

Set the environment variable or pass the key directly in options:

export GOOGLE_CLOUD_API_KEY="YOUR_GEMINI_API_KEY"

When options.apiKey or GOOGLE_CLOUD_API_KEY is present, the provider calls createClientWithApiKey (lines 31-57) to build a GoogleGenAI instance that sends the key in request headers.

For production workloads, use ADC authentication:

gcloud auth application-default login
export GOOGLE_CLOUD_PROJECT="my-gcp-project"
export GOOGLE_CLOUD_LOCATION="us-central1"

Without an API key, the provider invokes createClient with vertexai: true, project, and location parameters (lines 38-48). The underlying @google/genai library automatically handles token refresh using your local ADC credentials.

Selecting Vertex AI Models

Retrieve a Vertex model handle using getModel() with the provider ID and model name:

import { getModel } from '@earendil-works/pi-ai';

const model = getModel('google-vertex', 'gemini-2.5-flash');

Available models include gemini-1.5-pro, gemini-2.5-flash, and gemini-2.5-flash-image. The getModel function returns a model object configured for Vertex AI endpoints.

Making Requests

The unified API supports both blocking completion and streaming responses.

Non-Streaming Completion

Use complete() for simple request-response patterns:

import { complete, Context } from '@earendil-works/pi-ai';

const ctx: Context = {
  messages: [{ role: 'user', content: 'Explain quantum entanglement in one sentence.' }],
};

const response = await complete(model, ctx);
console.log(response.content[0].text);

Streaming Responses

Use stream() for real-time token delivery:

import { stream } from '@earendil-works/pi-ai';

const s = stream(model, {
  messages: [{ role: 'user', content: 'Write a 200-word essay about AI.' }]
});

for await (const ev of s) {
  if (ev.type === 'text_delta') process.stdout.write(ev.delta);
  if (ev.type === 'done') console.log('\n[finished]', ev.reason);
}

Advanced Features: Thinking and Tool Calling

Gemini Thinking Configuration

The GoogleVertexOptions interface (lines 38-48) supports a thinking option that maps to Vertex's thinkingConfig. Configure via buildParams (lines 58-70):

const s = stream(model, ctx, {
  thinking: { enabled: true, level: 'MEDIUM' }  // or use budgetTokens
});

The provider translates thinking into either thinkingLevel (using THINKING_LEVEL_MAP) or thinkingBudget depending on your configuration.

Function Calling Integration

Define tools in your Context and specify toolChoice to enable agentic behaviors:

import { Tool, Type } from '@earendil-works/pi-ai';

const weatherTool: Tool = {
  name: 'get_weather',
  description: 'Retrieve current weather for a city',
  parameters: Type.Object({
    city: Type.String(),
    units: Type.Enum(['celsius', 'fahrenheit'])
  })
};

const ctx: Context = {
  messages: [{ role: 'user', content: 'What is the weather in Paris?' }],
  tools: [weatherTool],
};

const s = stream(model, ctx, { toolChoice: 'auto' });

for await (const ev of s) {
  switch (ev.type) {
    case 'toolcall_start':
      console.log('Tool call started');
      break;
    case 'toolcall_end':
      // Execute tool and append result to context
      ctx.messages.push({
        role: 'toolResult',
        toolCallId: ev.toolCall.id,
        toolName: ev.toolCall.name,
        content: [{ type: 'text', text: 'Paris: 12°C, clear sky' }],
        isError: false,
        timestamp: Date.now(),
      });
      break;
  }
}

When toolChoice is set, the provider adds a toolConfig block to the Vertex request (lines 48-55) and converts returning functionCall parts into PI toolCall events (lines 74-88).

Cross-Provider Handoffs

Earendil PI enables seamless migration of conversations between providers without losing context. Switch from Vertex to another provider mid-conversation:

import { getModel, complete } from '@earendil-works/pi-ai';

let ctx = { messages: [{ role: 'user', content: 'Describe a cat.' }] };

// First call with Vertex
const vertex = getModel('google-vertex', 'gemini-2.5-flash');
ctx.messages.push(await complete(vertex, ctx));

// Handoff to OpenAI for image generation
const openai = getModel('openai', 'gpt-4o-mini');
ctx.messages.push({ role: 'user', content: 'Generate an image of that cat.' });
const imgResp = await complete(openai, ctx);

This handoff logic requires no additional code—the Context object maintains conversation state across different provider implementations.

Summary

  • Install the @earendil-works/pi-ai package to access the unified API.
  • Authenticate using either GOOGLE_CLOUD_API_KEY or ADC with GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION environment variables.
  • Initialize Vertex models via getModel('google-vertex', <model-id>) defined in packages/ai/src/providers/google-vertex.ts.
  • Execute requests using complete() for blocking calls or stream() for real-time events.
  • Configure advanced features like Gemini thinking modes and toolChoice through the GoogleVertexOptions interface.
  • Migrate conversations between providers using PI's built-in cross-provider handoff capabilities.

Frequently Asked Questions

How does Earendil PI handle authentication when both API key and ADC are configured?

API key authentication takes precedence. The resolveApiKey function (lines 97-109) checks for options.apiKey or the GOOGLE_CLOUD_API_KEY environment variable first. Only if these are absent does the provider fall back to ADC mode using resolveProject and resolveLocation (lines 109-125), constructing the client with vertexai: true.

Can I use Gemini's thinking mode with streaming responses?

Yes. When you set thinking: { enabled: true, level: 'MEDIUM' } or specify budgetTokens, the buildParams function (lines 58-70) injects thinkingConfig into the Vertex request. The streaming loop (lines 106-190) emits thinking_delta events alongside text_delta events, allowing you to monitor the model's reasoning process in real-time.

What file handles the conversion between PI's Context format and Vertex's expected schema?

Conversion logic resides in packages/ai/src/providers/google-shared.ts. This module exports convertMessages and convertTools functions that transform PI's unified message format into Vertex's content structure. The google-vertex.ts provider imports these helpers to ensure consistent request formatting across Google Cloud AI integrations.

Is it possible to abort an ongoing streaming request?

Yes. Pass an AbortController signal through the options parameter. The streaming implementation in packages/ai/src/providers/google-vertex.ts respects the signal option, allowing you to cancel in-flight requests. Wrap your for await loop in try-catch blocks to handle AbortError exceptions gracefully.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →