Skip to content

OpenAI

The OpenAI provider (rig::providers::openai) covers OpenAI’s completion, embedding, transcription, image and speech models. Its client, OpenAI, is also the client for every OpenAI-compatible vendor Rig supports (DeepSeek, Groq, OpenRouter, Together, …), each configured from its own module.

CapabilitySupportHow
CompletionYesclient.completion(id) (Responses API), client.chat(id) (Chat Completions)
StreamingYesagent.prompt(p).stream(), or model.stream(request)
ToolsYesAny Rig tool
Structured outputYesNative JSON-schema output, used by extractors and output_schema
Image inputYesVision-capable models
ReasoningYesGenerationOptions::reasoning; summaries through OpenAiOptions
EmbeddingsYesclient.embedding(id, None)
TranscriptionYesclient.transcription(openai::WHISPER_1)
Image generationimage featureclient.image_generation(openai::GPT_IMAGE_1)
Speechaudio featureclient.audio_generation(openai::TTS_1)
Websocket sessionswebsocket featuremodel.responses_websocket().connect()
use rig::prelude::*;
use rig::providers::openai::{self, OpenAI};
// Reads OPENAI_API_KEY (and OPENAI_BASE_URL, if set).
let client = OpenAI::from_env()?;
let agent = AgentBuilder::new(client.completion(openai::GPT_5_5))
.preamble("You are a helpful assistant.")
.build();
let answer = agent.prompt("Hello!").await?.output();
println!("{answer}");
use rig::providers::openai::{OpenAI, OpenAIConfig};
// From OPENAI_API_KEY and the optional OPENAI_BASE_URL.
let client = OpenAI::from_env()?;
// From an explicit key.
let client = OpenAI::new("your-api-key");
// From a configuration, for anything beyond the key.
let client = OpenAIConfig::new("your-api-key")
.with_base_url("https://your-gateway.example.com/v1")
.client();

OpenAIConfig is plain, serializable data (the key is never serialized), so you can store it with the rest of your settings and turn it into a client with .client(), or .connect(http) for your own HTTP client. For another OpenAI-shaped vendor, use its module: deepseek::from_env()?, openrouter::from_env()?, and so on. See Model Providers for the list.

OpenAI serves two completion APIs, and Rig has a model for each:

  • client.completion(id) builds the provider’s primary endpoint. For OpenAI that is the Responses API (POST /responses).
  • client.responses(id) always builds the Responses model.
  • client.chat(id) always builds the Chat Completions model (POST /chat/completions).
use rig::providers::openai::{self, OpenAI};
let client = OpenAI::from_env()?;
let responses = client.completion(openai::GPT_5_5); // Responses API
let chat = client.chat(openai::GPT_5_5); // Chat Completions

Both work with agents, extractors, tools and streaming. Use Chat Completions when a gateway or proxy only speaks that API, or when you need a Chat-only field such as logit_bias or prediction. To make completion pick Chat Completions for a whole configuration, set the route once:

use rig::providers::openai::{self, OpenAIConfig, Route};
let model = OpenAIConfig::from_env()?
.with_route(Route::Chat)
.client()
.completion(openai::GPT_5_5);

On the Responses API, Rig sends the agent’s preamble as top-level instructions. For a compatible backend that ignores or rejects that field, OpenAIConfig::with_system_instructions_as_messages() sends it as system messages in the input instead.

The module exports constants for OpenAI’s models, such as openai::GPT_5_6, openai::GPT_5_5, openai::GPT_5_4_MINI, openai::GPT_5_MINI and openai::O4_MINI. Any id string works too:

use rig::providers::openai::OpenAI;
let model = OpenAI::from_env()?.completion("gpt-5-mini");

client.list_models().await? returns the models your key can use, and client.verify().await? checks the key without spending tokens.

Reasoning effort, prompt-cache retention, service tier and verbosity are typed, provider-neutral options. Set them on the agent builder, on a single CompletionRequest, or build a reusable GenerationOptions and pass it to .options(..):

use rig::completion::{CacheRetention, Effort, ServiceTier, Verbosity};
use rig::prelude::*;
use rig::providers::openai::{self, OpenAI};
let agent = AgentBuilder::new(OpenAI::from_env()?.completion(openai::GPT_5_5))
.reasoning(Effort::High) // reasoning.effort / reasoning_effort
.cache(CacheRetention::Long) // extended prompt-cache retention
.service_tier(ServiceTier::Flex) // service_tier
.verbosity(Verbosity::Low) // text.verbosity / verbosity
.build();

Each option is checked against the model before the request is sent. OpenAI caches prompts automatically; CacheRetention chooses how long the cache is kept on models that offer a choice. An option the model can’t take (say an effort level it doesn’t offer) fails with ProviderError::UnsupportedOption rather than being dropped silently. Call .on_unsupported(OnUnsupported::Ignore) to skip such options with a warning instead.

Fields only OpenAI has are typed in openai::extension. OpenAiOptions has three sections: shared fields both APIs take (store, metadata, prompt_cache_key, safety_identifier), Responses-only fields (reasoning_summary, include, conversation, truncation, background, max_tool_calls, …), and Chat-only fields in ChatOptions (logit_bias, prediction, logprobs, penalties, audio output, web search options). Each section is sent only on its own API.

use rig::prelude::*;
use rig::providers::openai::extension::{ChatOptions, OpenAiOptions, ReasoningSummary};
use rig::providers::openai::{self, OpenAI};
let options = OpenAiOptions::new()
.store(false)
.prompt_cache_key("support-bot")
.reasoning_summary(ReasoningSummary::Auto)
.chat(ChatOptions::new().logprobs(true));
let agent = AgentBuilder::new(OpenAI::from_env()?.completion(openai::GPT_5_5))
.provider_option(options)
.build();

The same extension types the reply fields only OpenAI returns, such as service_tier, the reasoning settings the model used, system_fingerprint, and token details. Read them with extras::<OpenAiExt>() on a CompletionResponse; it returns None for a reply from another provider.

use rig::completion::CompletionRequest;
use rig::providers::openai::extension::OpenAiExt;
use rig::providers::openai::{self, OpenAI};
let model = OpenAI::from_env()?.completion(openai::GPT_5_5);
let response = model.call(CompletionRequest::new("Name a prime number.")).await?;
println!("{}", response.text());
if let Some(Ok(extras)) = response.extras::<OpenAiExt>() {
println!("served on tier {:?}", extras.service_tier);
}

Inside an agent, an on_outcome hook sees the same CompletionResponse for every model call. The full reply is always available as response.raw.

ConstantDimensionsNotes
TEXT_EMBEDDING_3_LARGE3072
TEXT_EMBEDDING_3_SMALL1536
TEXT_EMBEDDING_ADA_0021536legacy
use rig::providers::openai::{self, OpenAI};
let client = OpenAI::from_env()?;
// The model's default width...
let embedder = client.embedding(openai::TEXT_EMBEDDING_3_SMALL, None);
// ...or a shorter vector, for models that support `dimensions`.
let small = client.embedding(openai::TEXT_EMBEDDING_3_LARGE, Some(256));

The width matters when you create a vector store collection or index: it must match the model you embed with. See Embeddings and Vector Stores.

OpenAI’s Responses API also runs over a websocket: one connection serves many turns, and each turn continues from the previous response. With the websocket feature, a Responses model opens a session:

[dependencies]
rig = { version = "0.44.0", features = ["websocket"] }
use rig::completion::CompletionRequest;
use rig::providers::openai::{self, OpenAI};
let model = OpenAI::from_env()?.responses(openai::GPT_5_5);
let mut session = model.responses_websocket().connect().await?;
let first = session.completion(CompletionRequest::new("What is ownership in Rust?")).await?;
println!("{}", first.text());
// The session sends the previous response id for you.
let second = session.completion(CompletionRequest::new("And borrowing?")).await?;
println!("{}", second.text());
session.close().await?;

A session runs one turn at a time. session.warmup(request) prepares request state without generating output, send plus next_event gives you the raw event stream, and clear_previous_response_id starts a fresh chain. The builder sets a 30-second connect timeout by default (connect_timeout, event_timeout). Without the websocket feature, open a session with connect_with(&backend) and your own WebSocketClientExt implementation.

OpenAI models call any tool you register on an agent. Rig converts tool definitions to OpenAI’s function format and parses tool calls back into its own types, on both APIs. See Tools.