Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/badlogic/pi-mono/llms.txt

Use this file to discover all available pages before exploring further.

OAuth Authentication

Several providers require OAuth authentication instead of static API keys:
  • OpenAI Codex - ChatGPT Plus/Pro subscription (GPT-5.x models with extended reasoning)
  • GitHub Copilot - Copilot subscription (GPT-4o, Claude via GitHub)
  • Google Gemini CLI - Google Cloud Code Assist (Gemini 2.0/2.5, free tier or paid)
  • Antigravity - Free Gemini 3, Claude, GPT-OSS via Google Cloud
  • Vertex AI - Google Cloud Vertex AI (uses Application Default Credentials)
  • Anthropic - Claude Pro/Max subscription (optional, alternative to API key)

Quick Start (CLI)

The fastest way to authenticate:
# Interactive provider selection
npx @mariozechner/pi-ai login

# Login to specific provider
npx @mariozechner/pi-ai login anthropic
npx @mariozechner/pi-ai login openai-codex
npx @mariozechner/pi-ai login github-copilot
npx @mariozechner/pi-ai login google-gemini-cli
npx @mariozechner/pi-ai login google-antigravity

# List available providers
npx @mariozechner/pi-ai list
Credentials are saved to auth.json in the current directory.

OpenAI Codex

Requirements: ChatGPT Plus or Pro subscription Models: gpt-5-mini, gpt-5-nano, gpt-5.1-omni Features: Extended reasoning, session-based caching, WebSocket support

CLI Login

npx @mariozechner/pi-ai login openai-codex

Programmatic Login

import { loginOpenAICodex } from '@mariozechner/pi-ai';
import { writeFileSync } from 'fs';

const credentials = await loginOpenAICodex({
  onAuth: (info) => {
    console.log(`Open: ${info.url}`);
    if (info.instructions) console.log(info.instructions);
  },
  onProgress: (message) => console.log(message)
});

// Store credentials
const auth = { 'openai-codex': { type: 'oauth', ...credentials } };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

Using OpenAI Codex

import { getModel, complete, getOAuthApiKey } from '@mariozechner/pi-ai';
import { readFileSync, writeFileSync } from 'fs';

// Load credentials
const auth = JSON.parse(readFileSync('auth.json', 'utf-8'));

// Get API key (auto-refreshes if expired)
const result = await getOAuthApiKey('openai-codex', auth);
if (!result) throw new Error('Not logged in');

// Save refreshed credentials
auth['openai-codex'] = { type: 'oauth', ...result.newCredentials };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

// Use the model
const model = getModel('openai-codex', 'gpt-5-mini');
const response = await complete(model, {
  messages: [{ role: 'user', content: 'Explain quantum computing' }]
}, { 
  apiKey: result.apiKey,
  sessionId: 'my-session',  // Enable session-based caching
  transport: 'websocket'     // 'sse' | 'websocket' | 'auto'
});

Session-Based Caching

OpenAI Codex supports automatic prompt caching when using session IDs:
const sessionId = 'user-123-session';

// First request - full cost
const response1 = await complete(model, context, {
  apiKey,
  sessionId
});

// Second request with same sessionId - reduced cost due to caching
context.messages.push(response1);
context.messages.push({ role: 'user', content: 'Tell me more' });

const response2 = await complete(model, context, {
  apiKey,
  sessionId  // Reuses cached prompt prefix
});

WebSocket vs SSE

OpenAI Codex supports two transport modes:
// Server-Sent Events (default)
const response1 = await complete(model, context, {
  apiKey,
  transport: 'sse'
});

// WebSocket (faster, connection reused per session)
const response2 = await complete(model, context, {
  apiKey,
  transport: 'websocket',
  sessionId: 'my-session'  // WebSocket connection reused for this session
});

// Auto (uses WebSocket if sessionId provided)
const response3 = await complete(model, context, {
  apiKey,
  transport: 'auto',
  sessionId: 'my-session'
});
WebSocket connections with sessionId are reused and expire after 5 minutes of inactivity.

GitHub Copilot

Requirements: GitHub Copilot subscription Models: gpt-4o, claude-3.5-sonnet (via GitHub)

CLI Login

npx @mariozechner/pi-ai login github-copilot

Programmatic Login

import { loginGitHubCopilot } from '@mariozechner/pi-ai';
import { writeFileSync } from 'fs';

const credentials = await loginGitHubCopilot({
  onAuth: (info) => {
    console.log(`Open: ${info.url}`);
  },
  onPrompt: async (prompt) => {
    // Prompt user for input (e.g., device code)
    return await getUserInput(prompt.message);
  },
  onProgress: (message) => console.log(message)
});

// Store credentials
const auth = { 'github-copilot': { type: 'oauth', ...credentials } };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

Using GitHub Copilot

import { getModel, complete, getOAuthApiKey } from '@mariozechner/pi-ai';
import { readFileSync, writeFileSync } from 'fs';

const auth = JSON.parse(readFileSync('auth.json', 'utf-8'));
const result = await getOAuthApiKey('github-copilot', auth);
if (!result) throw new Error('Not logged in');

auth['github-copilot'] = { type: 'oauth', ...result.newCredentials };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

const model = getModel('github-copilot', 'gpt-4o');
const response = await complete(model, {
  messages: [{ role: 'user', content: 'Hello!' }]
}, { apiKey: result.apiKey });
If you get “model not supported” error, enable the model manually in VS Code:
  1. Open Copilot Chat
  2. Click model selector
  3. Select the model (warning icon)
  4. Click “Enable”

Google Gemini CLI

Requirements: Google account (free tier or paid Cloud Code Assist) Models: gemini-2.0-flash-thinking, gemini-2.5-flash, gemini-2.5-pro

CLI Login

npx @mariozechner/pi-ai login google-gemini-cli

Programmatic Login

import { loginGeminiCli } from '@mariozechner/pi-ai';
import { writeFileSync } from 'fs';

const credentials = await loginGeminiCli({
  onAuth: (info) => {
    console.log(`Open: ${info.url}`);
  },
  onProgress: (message) => console.log(message)
});

const auth = { 'google-gemini-cli': { type: 'oauth', ...credentials } };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

Using Google Gemini CLI

import { getModel, complete, getOAuthApiKey } from '@mariozechner/pi-ai';
import { readFileSync, writeFileSync } from 'fs';

const auth = JSON.parse(readFileSync('auth.json', 'utf-8'));
const result = await getOAuthApiKey('google-gemini-cli', auth);
if (!result) throw new Error('Not logged in');

auth['google-gemini-cli'] = { type: 'oauth', ...result.newCredentials };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

const model = getModel('google-gemini-cli', 'gemini-2.5-flash');
const response = await complete(model, {
  messages: [{ role: 'user', content: 'Hello!' }]
}, { apiKey: result.apiKey });
For paid Cloud Code Assist subscriptions, set your project ID:
export GOOGLE_CLOUD_PROJECT="my-project-id"
# or
export GOOGLE_CLOUD_PROJECT_ID="my-project-id"

Antigravity

Requirements: Google account Models: Free Gemini 3, Claude, GPT-OSS models via Google Cloud

CLI Login

npx @mariozechner/pi-ai login google-antigravity

Programmatic Login

import { loginAntigravity } from '@mariozechner/pi-ai';
import { writeFileSync } from 'fs';

const credentials = await loginAntigravity({
  onAuth: (info) => {
    console.log(`Open: ${info.url}`);
  },
  onProgress: (message) => console.log(message)
});

const auth = { 'google-antigravity': { type: 'oauth', ...credentials } };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

Using Antigravity

import { getModel, complete, getOAuthApiKey } from '@mariozechner/pi-ai';
import { readFileSync, writeFileSync } from 'fs';

const auth = JSON.parse(readFileSync('auth.json', 'utf-8'));
const result = await getOAuthApiKey('google-antigravity', auth);
if (!result) throw new Error('Not logged in');

auth['google-antigravity'] = { type: 'oauth', ...result.newCredentials };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

const model = getModel('google-antigravity', 'gemini-3-flash');
const response = await complete(model, {
  messages: [{ role: 'user', content: 'Hello!' }]
}, { apiKey: result.apiKey });

Version Override

If Google updates their requirements, override the Antigravity version:
export PI_AI_ANTIGRAVITY_VERSION="1.23.0"

Vertex AI

Requirements: Google Cloud account with Vertex AI enabled Models: Gemini models via Vertex AI Authentication: Application Default Credentials (ADC)

Local Development

# Login with your Google account
gcloud auth application-default login

# Set project and location
export GOOGLE_CLOUD_PROJECT="my-project"
export GOOGLE_CLOUD_LOCATION="us-central1"

Production (Service Account)

# Point to service account key file
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"

# Or set in code
import { getModel, complete } from '@mariozechner/pi-ai';

const model = getModel('google-vertex', 'gemini-2.5-flash');
const response = await complete(model, context, {
  project: 'my-project',
  location: 'us-central1'
});

Using Vertex AI

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

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

const response = await complete(model, {
  messages: [{ role: 'user', content: 'Hello from Vertex AI' }]
});

for (const block of response.content) {
  if (block.type === 'text') console.log(block.text);
}
Official docs: Application Default Credentials

Anthropic (OAuth)

Requirements: Claude Pro or Max subscription Alternative to: ANTHROPIC_API_KEY

CLI Login

npx @mariozechner/pi-ai login anthropic

Programmatic Login

import { loginAnthropic } from '@mariozechner/pi-ai';
import { writeFileSync } from 'fs';

const credentials = await loginAnthropic({
  onAuth: (info) => {
    console.log(`Open: ${info.url}`);
  },
  onProgress: (message) => console.log(message)
});

const auth = { 'anthropic': { type: 'oauth', ...credentials } };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

Using Anthropic OAuth

import { getModel, complete, getOAuthApiKey } from '@mariozechner/pi-ai';
import { readFileSync, writeFileSync } from 'fs';

const auth = JSON.parse(readFileSync('auth.json', 'utf-8'));
const result = await getOAuthApiKey('anthropic', auth);
if (!result) throw new Error('Not logged in');

auth['anthropic'] = { type: 'oauth', ...result.newCredentials };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

const model = getModel('anthropic', 'claude-3.5-sonnet-20241022');
const response = await complete(model, {
  messages: [{ role: 'user', content: 'Hello!' }]
}, { apiKey: result.apiKey });
You can also use ANTHROPIC_API_KEY environment variable instead of OAuth for standard API access.

Credential Management

The library provides helpers for credential management:

Refresh Expired Tokens

import { refreshOAuthToken } from '@mariozechner/pi-ai';
import { readFileSync, writeFileSync } from 'fs';

const auth = JSON.parse(readFileSync('auth.json', 'utf-8'));
const credentials = auth['github-copilot'];

// Check if expired
if (credentials.expires < Date.now()) {
  // Refresh
  const newCredentials = await refreshOAuthToken('github-copilot', credentials);
  auth['github-copilot'] = { type: 'oauth', ...newCredentials };
  writeFileSync('auth.json', JSON.stringify(auth, null, 2));
}

Get API Key (Auto-Refresh)

import { getOAuthApiKey } from '@mariozechner/pi-ai';

// Automatically refreshes if expired
const result = await getOAuthApiKey('github-copilot', auth);
if (!result) {
  throw new Error('Not logged in to GitHub Copilot');
}

// Use the API key
const response = await complete(model, context, {
  apiKey: result.apiKey
});

// Save refreshed credentials
auth['github-copilot'] = { type: 'oauth', ...result.newCredentials };
writeFileSync('auth.json', JSON.stringify(auth, null, 2));

Environment Variables

For OAuth providers, you can also set tokens via environment variables:
# GitHub Copilot
export COPILOT_GITHUB_TOKEN="gho_..."
# or
export GH_TOKEN="gho_..."
# or
export GITHUB_TOKEN="gho_..."

# Anthropic (OAuth alternative)
export ANTHROPIC_OAUTH_TOKEN="..."

Complete Example

Full OAuth workflow:
import {
  loginGitHubCopilot,
  getOAuthApiKey,
  getModel,
  complete
} from '@mariozechner/pi-ai';
import { readFileSync, writeFileSync, existsSync } from 'fs';

const AUTH_FILE = 'auth.json';
const PROVIDER = 'github-copilot';

async function main() {
  let auth = {};
  
  // Load existing auth if available
  if (existsSync(AUTH_FILE)) {
    auth = JSON.parse(readFileSync(AUTH_FILE, 'utf-8'));
  }
  
  // Check if we have credentials
  if (!auth[PROVIDER]) {
    console.log('Not logged in, starting OAuth flow...');
    const credentials = await loginGitHubCopilot({
      onAuth: (info) => {
        console.log(`\nOpen this URL: ${info.url}\n`);
      },
      onPrompt: async (prompt) => {
        const readline = await import('readline');
        const rl = readline.createInterface({
          input: process.stdin,
          output: process.stdout
        });
        return new Promise((resolve) => {
          rl.question(prompt.message + ' ', (answer) => {
            rl.close();
            resolve(answer);
          });
        });
      },
      onProgress: (msg) => console.log(msg)
    });
    
    auth[PROVIDER] = { type: 'oauth', ...credentials };
    writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2));
    console.log('Credentials saved to auth.json');
  }
  
  // Get API key (auto-refreshes if expired)
  const result = await getOAuthApiKey(PROVIDER, auth);
  if (!result) {
    throw new Error(`Not logged in to ${PROVIDER}`);
  }
  
  // Save refreshed credentials
  auth[PROVIDER] = { type: 'oauth', ...result.newCredentials };
  writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2));
  
  // Use the API
  const model = getModel('github-copilot', 'gpt-4o');
  const response = await complete(model, {
    messages: [{ role: 'user', content: 'Write a haiku about coding' }]
  }, { apiKey: result.apiKey });
  
  for (const block of response.content) {
    if (block.type === 'text') {
      console.log(block.text);
    }
  }
  
  console.log(`\nTokens: ${response.usage.totalTokens}`);
  console.log(`Cost: $${response.usage.cost.total.toFixed(4)}`);
}

main().catch(console.error);

Troubleshooting

Token Expired

Use getOAuthApiKey - it automatically refreshes:
const result = await getOAuthApiKey(provider, auth);
if (!result) {
  // Re-login required
  const credentials = await loginGitHubCopilot(...);
}

Model Not Available

GitHub Copilot: Enable model in VS Code Copilot Chat settings Google Gemini CLI: Ensure you’re logged in with correct account OpenAI Codex: Requires ChatGPT Plus/Pro subscription

Invalid Credentials

Delete auth.json and re-login:
rm auth.json
npx @mariozechner/pi-ai login <provider>

Next Steps

Providers

Explore all supported providers

Streaming

Learn about streaming API

Build docs developers (and LLMs) love