OpenAI
OpenAI provider for GoAI - supports Chat Completions API and Responses API with automatic routing.
Setup
go get github.com/zendev-sh/goai@latestSet the OPENAI_API_KEY environment variable, or pass it explicitly:
import "github.com/zendev-sh/goai/provider/openai"
model := openai.Chat("gpt-4o", openai.WithAPIKey("sk-..."))The provider also reads OPENAI_BASE_URL from the environment when no explicit base URL is set.
Models
| Model ID | Type | Notes |
|---|---|---|
gpt-4o | Chat | Responses API by default |
gpt-4o-mini | Chat | Responses API by default |
gpt-5 | Chat | Reasoning model, Responses API by default |
gpt-5-mini | Chat | Reasoning model, Responses API by default |
o3 | Chat | Reasoning model, Responses API by default |
o4-mini | Chat | Reasoning model, Responses API by default |
codex-* | Chat | Reasoning model, Responses API by default |
text-embedding-3-small | Embedding | 1536 dimensions |
text-embedding-3-large | Embedding | 3072 dimensions |
text-embedding-ada-002 | Embedding | Legacy |
dall-e-3 | Image | Legacy image generation |
gpt-image-1 | Image | Defaults to b64_json |
Tested Models
Unit tested with mock HTTP server (100% coverage). Last run: 2026-03-15.
| Model | Generate | Stream | Status |
|---|---|---|---|
gpt-4o | PASS | PASS | Stable |
o3 | PASS | PASS | Stable |
text-embedding-3-small | PASS | N/A | Stable |
dall-e-3 | PASS | N/A | Stable |
gpt-image-1 | PASS | N/A | Stable |
OpenAI models are also E2E tested via the Azure provider (21 models PASS including gpt-4.1, gpt-5, gpt-5.1, o3).
Usage
Chat
import (
"context"
"fmt"
"github.com/zendev-sh/goai"
"github.com/zendev-sh/goai/provider/openai"
)
func main() {
model := openai.Chat("gpt-4o")
result, err := goai.GenerateText(context.Background(), model,
goai.WithPrompt("Explain Go interfaces in one paragraph."),
)
if err != nil {
panic(err)
}
fmt.Println(result.Text)
}Streaming
import (
"context"
"fmt"
"github.com/zendev-sh/goai"
"github.com/zendev-sh/goai/provider"
"github.com/zendev-sh/goai/provider/openai"
)
model := openai.Chat("gpt-4o")
stream, err := goai.StreamText(context.Background(), model,
goai.WithPrompt("Write a haiku about Go."),
)
if err != nil {
panic(err)
}
for chunk := range stream.Stream() {
if chunk.Type == provider.ChunkText {
fmt.Print(chunk.Text)
}
}Embedding
import (
"context"
"fmt"
"github.com/zendev-sh/goai"
"github.com/zendev-sh/goai/provider/openai"
)
model := openai.Embedding("text-embedding-3-small")
result, err := goai.Embed(context.Background(), model, "Hello world")
if err != nil {
panic(err)
}
fmt.Println(len(result.Embedding)) // 1536Image Generation
import (
"context"
"fmt"
"github.com/zendev-sh/goai"
"github.com/zendev-sh/goai/provider/openai"
)
model := openai.Image("gpt-image-1")
result, err := goai.GenerateImage(context.Background(), model,
goai.WithImagePrompt("A futuristic city skyline"),
)
if err != nil {
panic(err)
}
fmt.Printf("Generated %d bytes\n", len(result.Images[0].Data))API Routing
All models use the Responses API (/v1/responses) by default. To force Chat Completions:
result, err := goai.GenerateText(ctx, model,
goai.WithPrompt("Hello"),
goai.WithProviderOptions(map[string]any{
"useResponsesAPI": false,
}),
)Reasoning model detection is automatic based on model ID:
o1,o3,o4(o-series) - reasoning enabled, temperature disabledgpt-5*(exceptgpt-5-chat) - reasoning enabledcodex-*- reasoning enabled
Options
| Option | Type | Description |
|---|---|---|
WithAPIKey(key) | string | Static API key. Falls back to OPENAI_API_KEY env var. |
WithTokenSource(ts) | provider.TokenSource | Dynamic token resolution (OAuth, service accounts). |
WithBaseURL(url) | string | Override base URL. Falls back to OPENAI_BASE_URL env var. |
WithHeaders(h) | map[string]string | Additional HTTP headers on every request. |
WithHTTPClient(c) | *http.Client | Custom HTTP client for proxies, logging, URL rewriting. |
Provider Options (via goai.WithProviderOptions)
| Key | Type | Description |
|---|---|---|
useResponsesAPI | bool | Force Responses API (true) or Chat Completions (false). Default: true. |
store | bool | Persist responses for later retrieval. |
serviceTier | string | Service tier (e.g., "auto", "flex"). |
parallelToolCalls | bool | Allow parallel tool calls. |
reasoning_effort | string | Reasoning effort level ("low", "medium", "high"). |
reasoning_summary | string | Reasoning summary mode. |
text_verbosity | string | Text verbosity level. |
metadata | map[string]any | Request metadata. |
logprobs | bool or int | Enable log probabilities. |
truncation | string | Truncation strategy for Responses API. |
include | []string | Additional data to include in Responses API response. |
user | string | End-user identifier for abuse monitoring. |
instructions | string | System instructions (Responses API alternative to system message). |
previousResponseId | string | Chain responses (Responses API). |
maxToolCalls | int | Maximum number of tool calls per turn. |
conversation | map[string]any | Conversation context (Responses API). |
prompt_cache_key | string | Cache key for prompt caching (Responses API). |
safetyIdentifier | string | Safety identifier for content filtering. |
Provider Tools
Four built-in tools are available via openai.Tools. These require the Responses API.
| Tool | Description |
|---|---|
openai.Tools.WebSearch() | Server-side web search. Model decides when to search. |
openai.Tools.CodeInterpreter() | Server-side Python code execution in a sandbox. |
openai.Tools.FileSearch() | Semantic/keyword search over uploaded files via vector stores. |
openai.Tools.ImageGeneration() | Generate images within a conversation using GPT Image. |
WebSearch
def := openai.Tools.WebSearch(
openai.WithSearchContextSize("medium"),
openai.WithUserLocation(openai.WebSearchLocation{
Country: "US",
City: "San Francisco",
}),
)
result, err := goai.GenerateText(ctx, model,
goai.WithPrompt("What happened in tech news today?"),
goai.WithTools(goai.Tool{
Name: def.Name,
ProviderDefinedType: def.ProviderDefinedType,
ProviderDefinedOptions: def.ProviderDefinedOptions,
}),
)Options: WithSearchContextSize("low"|"medium"|"high"), WithUserLocation(...), WithSearchFilters(...), WithExternalWebAccess(bool).
CodeInterpreter
def := openai.Tools.CodeInterpreter()
result, err := goai.GenerateText(ctx, model,
goai.WithPrompt("Calculate the first 20 Fibonacci numbers."),
goai.WithTools(goai.Tool{
Name: def.Name,
ProviderDefinedType: def.ProviderDefinedType,
ProviderDefinedOptions: def.ProviderDefinedOptions,
}),
)Options: WithContainerID(containerID) for an existing container, or WithContainerFiles(&openai.CodeInterpreterContainer{FileIDs: [...]}) for auto-provisioned.
FileSearch
def := openai.Tools.FileSearch(
openai.WithVectorStoreIDs("vs_abc123"),
openai.WithMaxNumResults(5),
)
result, err := goai.GenerateText(ctx, model,
goai.WithPrompt("Find information about error handling."),
goai.WithTools(goai.Tool{
Name: def.Name,
ProviderDefinedType: def.ProviderDefinedType,
ProviderDefinedOptions: def.ProviderDefinedOptions,
}),
)Options: WithVectorStoreIDs(...), WithMaxNumResults(n), WithRanking(...), WithFileSearchFilters(...).
ImageGeneration
def := openai.Tools.ImageGeneration(
openai.WithImageQuality("high"),
openai.WithImageSize("1024x1024"),
)
result, err := goai.GenerateText(ctx, model,
goai.WithPrompt("Generate an image of a sunset over mountains."),
goai.WithTools(goai.Tool{
Name: def.Name,
ProviderDefinedType: def.ProviderDefinedType,
ProviderDefinedOptions: def.ProviderDefinedOptions,
}),
)Options: WithBackground("auto"|"opaque"|"transparent"), WithInputFidelity("low"|"high"), WithImageModel("gpt-image-1"), WithOutputFormat("png"|"jpeg"|"webp"), WithImageQuality("auto"|"low"|"medium"|"high"), WithImageSize("auto"|"1024x1024"|"1024x1536"|"1536x1024"), WithOutputCompression(0-100), WithPartialImages(0-3), WithModeration("auto"|"low"), WithInputImageMask(ImageGenerationMask{...}).
Custom Routing with WithHTTPClient
Use WithHTTPClient to inject a custom http.Client for proxy support, request logging, or custom auth flows:
// roundTripFunc adapts a function to http.RoundTripper.
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
// Example: route through a proxy with custom auth
transport := &http.Transport{}
client := &http.Client{
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
req.URL.Host = "my-proxy.example.com"
req.Header.Set("X-Custom-Auth", "token-here")
return transport.RoundTrip(req)
}),
}
model := openai.Chat("gpt-4o", openai.WithHTTPClient(client))This pattern supports Copilot (URL rewrite + OAuth token swap) and Codex (URL rewrite + session headers) without separate provider implementations.
Notes
- The embedding model supports up to 2048 values per batch call via
MaxValuesPerCall().goai.EmbedManyauto-chunks larger batches. - Image models
gpt-image-1,gpt-image-1-mini, andgpt-image-1.5default tob64_jsonresponse format and reject an explicitresponse_formatparameter. For older models likedall-e-3, the provider automatically setsresponse_formattob64_json. - Structured output uses
response_formatwithjson_schemafor both APIs. The Responses API places it undertext.format. - Per-request headers can be injected via
goai.WithHeaders(map[string]string{...})for features like Codex session tracking. - File upload: OpenAI supports remote file upload via the Files API. Use
model.FileUploader()to get aprovider.FileUploaderfor uploading and deleting files. Uploaded files are referenced viaPart.RemoteRefin messages. Compat providers map file parts to native OpenAI shapes (filefor PDFs,input_audiofor audio).