Skip to main content

Overview

The OpenAI provider connects to GPT models including GPT-4, GPT-4o, o1, and GPT-3.5. It also serves as the base for OpenAI-compatible providers. Source: crates/goose/src/providers/openai.rs

Configuration

Environment Variables

OPENAI_API_KEY
string
Your OpenAI API key from https://platform.openai.com/api-keys (optional for some compatible providers)
OPENAI_HOST
string
default:"https://api.openai.com"
API endpoint URL
OPENAI_BASE_PATH
string
default:"v1/chat/completions"
API path for chat completions
OPENAI_ORGANIZATION
string
OpenAI organization ID (optional)
OPENAI_PROJECT
string
OpenAI project ID (optional)
OPENAI_TIMEOUT
number
default:"600"
Request timeout in seconds
OPENAI_CUSTOM_HEADERS
string
Custom headers in format: Header1=Value1,Header2=Value2 (stored securely)

Setup

# Configure using the CLI
goose configure

# Or set environment variables
export OPENAI_API_KEY="sk-..."
export OPENAI_HOST="https://api.openai.com"
export OPENAI_ORGANIZATION="org-..."
export OPENAI_PROJECT="proj_..."

Supported Models

GPT-4 Series

  • gpt-4o (default) - GPT-4 Optimized (128K context)
  • gpt-4o-mini (fast model) - Smaller, faster GPT-4o (128K context)
  • gpt-4.1 - Latest GPT-4 (128K context)
  • gpt-4.1-mini - Smaller GPT-4.1 (128K context)
  • gpt-4-turbo - GPT-4 Turbo (128K context)

Reasoning Models

  • o1 - Advanced reasoning model (200K context)
  • o3 - Next-generation reasoning (200K context)
  • o4-mini - Compact reasoning model (128K context)

GPT-5 Series (Future)

  • gpt-5-nano - Ultra-efficient model (400K context)
  • gpt-5.1-codex - Code-specialized model (400K context)
  • gpt-5-codex - Code generation model (400K context)

Legacy

  • gpt-3.5-turbo - GPT-3.5 Turbo (16K context)
Documentation: https://platform.openai.com/docs/models

Usage

Basic Usage

use goose::providers::create;
use goose::model::ModelConfig;
use goose::conversation::message::Message;

// Create with default model (gpt-4o)
let model_config = ModelConfig::new("gpt-4o")?;
let provider = create("openai", model_config, vec![]).await?;

// Stream a response
let messages = vec![Message::user().with_text("Hello, GPT-4!")];
let stream = provider.stream(
    &provider.get_model_config(),
    "session-123",
    "You are a helpful assistant.",
    &messages,
    &[],
).await?;

Custom Configuration

let model_config = ModelConfig::new("gpt-4-turbo")?
    .with_temperature(0.7)
    .with_max_tokens(2048)
    .with_top_p(0.95);

let provider = create("openai", model_config, vec![]).await?;

Using Fast Models

// Automatically tries gpt-4o-mini, falls back to main model on failure
let (response, usage) = provider.complete_fast(
    "session-123",
    "You are a helpful assistant.",
    &messages,
    &[],
).await?;

Advanced Features

Embeddings

The OpenAI provider supports text embeddings:
if provider.supports_embeddings() {
    let texts = vec![
        "Hello world".to_string(),
        "How are you?".to_string(),
    ];
    
    let embeddings = provider.create_embeddings(
        "session-123",
        texts,
    ).await?;
    
    // embeddings is Vec<Vec<f32>>
    println!("Embedding dimension: {}", embeddings[0].len());
}
Default embedding model: text-embedding-3-small (configure via GOOSE_EMBEDDING_MODEL)

Organization & Project Headers

For team accounts:
export OPENAI_ORGANIZATION="org-abc123"
export OPENAI_PROJECT="proj_xyz789"
These are sent as headers:
OpenAI-Organization: org-abc123
OpenAI-Project: proj_xyz789

Custom Headers

For proxies or special configurations:
export OPENAI_CUSTOM_HEADERS="X-Custom-Header=value1,X-Another=value2"

Responses API (GPT-5 Codex)

The provider automatically uses the Responses API for codex models:
let model_config = ModelConfig::new("gpt-5-codex")?;
let provider = create("openai", model_config, vec![]).await?;

// Automatically uses /v1/responses endpoint instead of /v1/chat/completions
You can force the responses API with a custom base path:
export OPENAI_BASE_PATH="v1/responses"

OpenAI-Compatible Providers

Many providers offer OpenAI-compatible APIs. Configure by changing the host:

Example: Local LLM Server

export OPENAI_API_KEY="not-needed"
export OPENAI_HOST="http://localhost:8000"
export OPENAI_BASE_PATH="v1/chat/completions"

Example: Azure OpenAI

Use the dedicated Azure provider, or configure manually:
export OPENAI_API_KEY="your-azure-key"
export OPENAI_HOST="https://your-resource.openai.azure.com"
export OPENAI_BASE_PATH="openai/deployments/your-deployment/chat/completions?api-version=2024-02-15-preview"

Implementation Details

Provider Metadata

impl ProviderDef for OpenAiProvider {
    fn metadata() -> ProviderMetadata {
        ProviderMetadata::with_models(
            "openai",
            "OpenAI",
            "GPT-4 and other OpenAI models, including OpenAI compatible ones",
            "gpt-4o",
            models,
            "https://platform.openai.com/docs/models",
            vec![
                ConfigKey::new("OPENAI_API_KEY", false, true, None, true),
                ConfigKey::new("OPENAI_HOST", true, false, Some("https://api.openai.com"), false),
                ConfigKey::new("OPENAI_BASE_PATH", true, false, Some("v1/chat/completions"), false),
                ConfigKey::new("OPENAI_ORGANIZATION", false, false, None, false),
                ConfigKey::new("OPENAI_PROJECT", false, false, None, false),
                ConfigKey::new("OPENAI_CUSTOM_HEADERS", false, true, None, false),
                ConfigKey::new("OPENAI_TIMEOUT", false, false, Some("600"), false),
            ],
        )
    }
}

API Format

Chat Completions API:
{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant."
    },
    {
      "role": "user",
      "content": "Hello!"
    }
  ],
  "temperature": 0.7,
  "max_tokens": 2048,
  "stream": true
}

Authentication

Uses Bearer token authentication:
let auth = AuthMethod::BearerToken(api_key);
Or no authentication for compatible providers:
let auth = AuthMethod::NoAuth;

Streaming

Supports Server-Sent Events (SSE) streaming:
data: {"choices":[{"delta":{"content":"Hello"}}]}
data: {"choices":[{"delta":{"content":" world"}}]}
data: [DONE]

Path Mapping

The provider intelligently maps base paths:
// Automatically maps chat/completions to responses for codex models
if model_name.contains("codex") {
    // Uses /v1/responses instead of /v1/chat/completions
}

// Maps to models endpoint for model listing
let models_path = map_base_path(base_path, "models", "v1/models");

Error Handling

match provider.stream(...).await {
    Ok(stream) => { /* handle stream */ },
    Err(ProviderError::Authentication(msg)) => {
        eprintln!("Invalid API key: {}", msg);
    },
    Err(ProviderError::RateLimited { retry_after }) => {
        eprintln!("Rate limited");
    },
    Err(ProviderError::ContextLengthExceeded(msg)) => {
        eprintln!("Context too long: {}", msg);
    },
    Err(e) => eprintln!("Error: {}", e),
}

Fetching Models

// Get all available models
let models = provider.fetch_supported_models().await?;

// Returns Vec<String> of model IDs
for model in models {
    println!("Available model: {}", model);
}

Usage Tracking

let (message, usage) = provider.complete(...).await?;

println!("Model: {}", usage.model);
println!("Input tokens: {:?}", usage.usage.input_tokens);
println!("Output tokens: {:?}", usage.usage.output_tokens);
println!("Total tokens: {:?}", usage.usage.total_tokens);

Custom Provider Configuration

For advanced use cases, create a provider programmatically:
use goose::config::declarative_providers::DeclarativeProviderConfig;
use goose::providers::openai::OpenAiProvider;

let config = DeclarativeProviderConfig {
    name: "my-provider".to_string(),
    engine: ProviderEngine::OpenAI,
    base_url: "http://localhost:8000".to_string(),
    // ... other fields
};

let provider = OpenAiProvider::from_custom_config(model_config, config)?;

See Also

Build docs developers (and LLMs) love