Skip to main content

Overview

The OpenAI provider (OpenAiLlm) provides access to GPT models including GPT-3.5, GPT-4, GPT-4o, o1, and o3 series with full streaming and function calling support. Source: packages/adk/src/models/openai-llm.ts:14

Supported Models

The OpenAI provider matches these model patterns:
// From openai-llm.ts:27-29
static supportedModels(): string[] {
  return ["gpt-3.5-.*", "gpt-4.*", "gpt-4o.*", "gpt-5.*", "o1-.*", "o3-.*"];
}

Model Examples

import { AgentBuilder } from '@iqai/adk';

const agent = AgentBuilder.withModel('gpt-4o').build();
Best for: Most capable multimodal model, excellent reasoning
  • Context: 128K tokens
  • Output: 16K tokens

Configuration

API Key Setup

Set your OpenAI API key:
.env
OPENAI_API_KEY=sk-proj-...
The provider automatically reads from environment:
// From openai-llm.ts:630-644
private get client(): OpenAI {
  if (!this._client) {
    const apiKey = process.env.OPENAI_API_KEY;
    
    if (!apiKey) {
      throw new Error(
        "OPENAI_API_KEY environment variable is required for OpenAI models"
      );
    }
    
    this._client = new OpenAI({ apiKey });
  }
  return this._client;
}

Basic Usage

import { AgentBuilder } from '@iqai/adk';

const agent = AgentBuilder.withModel('gpt-4o')
  .withInstruction('You are a helpful assistant')
  .build();

const response = await agent.ask('What is TypeScript?');
console.log(response.text);

Configuration Options

model
string
default:"gpt-4o-mini"
The OpenAI model to use
maxOutputTokens
number
Maximum tokens to generate (maps to max_tokens)
temperature
number
default:"1.0"
Controls randomness (0.0 - 2.0). Lower is more focused
topP
number
default:"1.0"
Nucleus sampling parameter (0.0 - 1.0)
const agent = AgentBuilder.withModel('gpt-4o')
  .withConfig({
    maxOutputTokens: 2048,
    temperature: 0.7,
    topP: 0.9
  })
  .build();

Streaming

OpenAI provider supports streaming for real-time responses:

Basic Streaming

const agent = AgentBuilder.withModel('gpt-4o').build();

for await (const chunk of agent.run('Write a story', { stream: true })) {
  process.stdout.write(chunk.text || '');
}

Streaming Implementation

From openai-llm.ts:79-215, the provider:
  1. Streams chunks with delta content
  2. Accumulates text and thought content separately
  3. Handles tool calls incrementally
  4. Yields final complete response with usage metadata
// From openai-llm.ts:79-83
if (stream) {
  const streamResponse = await this.client.chat.completions.create({
    ...requestParams,
    stream: true,
  });

Function Calling

OpenAI models support function calling through ADK tools:

With ADK Tools

import { AgentBuilder, BaseTool } from '@iqai/adk';
import { z } from 'zod/v4';

class WeatherTool extends BaseTool {
  name = 'get_weather';
  description = 'Get current weather for a location';
  inputSchema = z.object({
    location: z.string().describe('City name or coordinates'),
    units: z.enum(['celsius', 'fahrenheit']).default('celsius')
  });

  async execute(input: { location: string; units: string }) {
    // Call weather API
    return {
      location: input.location,
      temperature: 72,
      condition: 'sunny',
      units: input.units
    };
  }
}

const agent = AgentBuilder.withModel('gpt-4o')
  .withTools(new WeatherTool())
  .build();

const response = await agent.ask('What\'s the weather in San Francisco?');

Tool Call Processing

The provider converts ADK function declarations to OpenAI tools:
// From openai-llm.ts:514-527
private functionDeclarationToOpenAiTool(
  functionDeclaration: any
): OpenAI.ChatCompletionTool {
  return {
    type: "function",
    function: {
      name: functionDeclaration.name,
      description: functionDeclaration.description || "",
      parameters: this.transformSchemaForOpenAi(
        functionDeclaration.parameters || {}
      ),
    },
  };
}

Vision Support

GPT-4o and GPT-4 Turbo support image inputs:
import { AgentBuilder } from '@iqai/adk';
import fs from 'fs';

const agent = AgentBuilder.withModel('gpt-4o').build();

// Read image and encode to base64
const imageBuffer = fs.readFileSync('image.jpg');
const base64Image = imageBuffer.toString('base64');

const response = await agent.ask({
  contents: [{
    role: 'user',
    parts: [
      { text: 'What is in this image?' },
      {
        inline_data: {
          mime_type: 'image/jpeg',
          data: base64Image
        }
      }
    ]
  }]
});

Message Format

The provider converts ADK messages to OpenAI’s format:

Role Mapping

// From openai-llm.ts:532-540
private toOpenAiRole(role?: string): OpenAIRole {
  if (role === "model") {
    return "assistant";
  }
  if (role === "system") {
    return "system";
  }
  return "user";
}

System Instructions

System instructions are added as the first message:
// From openai-llm.ts:54-60
const systemContent = llmRequest.getSystemInstructionText();
if (systemContent) {
  messages.unshift({
    role: "system",
    content: systemContent,
  });
}

Error Handling

Rate Limit Errors

The provider detects and throws structured rate limit errors:
// From openai-llm.ts:257-262
catch (error: any) {
  if (RateLimitError.isRateLimitError(error)) {
    throw RateLimitError.fromError(error, "openai", model);
  }
  throw error;
}
Handle in your application:
import { RateLimitError } from '@iqai/adk';

try {
  const response = await agent.ask('Hello');
} catch (error) {
  if (error instanceof RateLimitError) {
    console.log('Rate limited!');
    console.log('Provider:', error.provider); // 'openai'
    console.log('Model:', error.model);
    console.log('Retry after:', error.retryAfter);
    
    // Implement exponential backoff
    await new Promise(resolve => 
      setTimeout(resolve, error.retryAfter * 1000)
    );
  }
}

Advanced Features

Thought Content

The provider supports thought tagging for reasoning chains:
// From openai-llm.ts:603-615
private getContentType(content: string): "thought" | "regular" {
  // Simple heuristic - you may want to implement more sophisticated logic
  // based on your specific use case and how you identify "thought" content
  
  // Example: if content starts with certain markers or patterns
  if (content.includes("<thinking>") || content.includes("[thinking]")) {
    return "thought";
  }
  
  // Default to regular content
  return "regular";
}

Custom Configuration

import { OpenAiLlm } from '@iqai/adk';

// Direct instantiation for advanced use cases
const llm = new OpenAiLlm('gpt-4o');

// Generate with custom request
const request = {
  model: 'gpt-4o',
  contents: [
    {
      role: 'user',
      parts: [{ text: 'Hello!' }]
    }
  ],
  config: {
    maxOutputTokens: 1024,
    temperature: 0.7
  }
};

for await (const response of llm.generateContentAsync(request)) {
  console.log(response.text);
}

Best Practices

  • Use gpt-4o-mini for most applications (fast, affordable)
  • Use gpt-4o for complex reasoning and multimodal tasks
  • Use o1-preview for advanced reasoning problems
  • Use gpt-3.5-turbo only for simple, cost-sensitive tasks
  • 0.0-0.3: Focused, deterministic (code, data extraction)
  • 0.4-0.7: Balanced (general conversation)
  • 0.8-1.0: Creative (stories, brainstorming)
  • 1.0+: Highly creative (experimental use)
  • Set maxOutputTokens to prevent runaway generation
  • Monitor usage with response.usageMetadata
  • Use streaming for long responses to show progress
  • Implement exponential backoff for rate limit errors
  • Cache responses when possible
  • Use batch requests for multiple independent queries

Limitations

No Context Caching: OpenAI does not currently support context caching. Consider Anthropic or Google for high-volume applications with repeated context.
No Live Connections: OpenAI models do not support live/bidirectional connections. The connect() method will throw an error.

Next Steps

Anthropic Provider

Explore Claude models with prompt caching

Tools & Function Calling

Learn more about ADK tools

Registry System

Understand provider registration

Error Handling

Handle errors gracefully

Build docs developers (and LLMs) love