Skip to main content

Configuring the OpenAI-compatible adapter

adapters/openai connects Golato to any service that speaks OpenAI Chat Completions streaming and the OpenAI embeddings shape. It translates the provider's JSON payloads and HTTP responses into the shared types of generation, embedding, and message, so the rest of the library never sees provider-specific formats.

Configuring one endpoint

openai.EndpointConfig describes where to call and how to authenticate. One value serves a Generator, an Embedder, or both.

endpoint := openai.EndpointConfig{
APIKey: os.Getenv("GOLATO_API_KEY"),
BaseURL: os.Getenv("GOLATO_BASE_URL"),
HTTPClient: new(http.Client{Timeout: 60 * time.Second}),
Headers: map[string]string{"X-Application": "my-app"},
}

generator, err := openai.NewGenerator(openai.GeneratorConfig{
EndpointConfig: endpoint,
})
if err != nil {
return err
}

embedder, err := openai.NewEmbedder(endpoint)
if err != nil {
return err
}

The adapter never reads the environment. The application reads the variables and passes the values. An empty BaseURL uses https://api.openai.com/v1, and a non-empty value must have a scheme and host. The adapter appends /chat/completions or /embeddings itself.

A non-nil HTTPClient is used exactly as configured and must not be modified while requests are in flight. A nil client falls back to http.DefaultClient, which carries no timeout of its own. The API key becomes Authorization: Bearer ..., the configured Headers are applied afterward and may replace it or other defaults, and their values are copied when the client is built.

Configuring the Generator

GeneratorConfig adds the provider identity, the output-token field, and usage requests.

generator, err := openai.NewGenerator(openai.GeneratorConfig{
EndpointConfig: endpoint,
Provider: "openai-compatible",
OutputTokensField: openai.OutputTokensMaxCompletionTokens,
IncludeUsage: true,
})
  • Provider labels returned assistant messages and defaults to openai.
  • OutputTokensMaxTokens is the default and uses the max_tokens field.
  • OutputTokensMaxCompletionTokens selects the max_completion_tokens field.
  • IncludeUsage: true adds stream_options.include_usage.
  • An output limit is sent only when MaxOutputTokens is set, and it must be positive.

The request model name is forwarded as written. A complete provider usage snapshot is accepted even when IncludeUsage is false and replaces the previous complete snapshot. Incomplete snapshots are ignored. The adapter translates generation.ThinkingLevel to reasoning_effort, with off becoming none, and rejects unknown values.

Knowing the stream requirements

Generation uses an SSE response and requires the explicit [DONE] marker. Malformed JSON, an oversized SSE line, or a clean end before [DONE] publishes a protocol error through the generation stream while preserving accepted partial content. Other established read failures are *provider.TransportError values in the read phase. A content_filter finish reason returns provider.ErrContentFiltered, keeps its raw finish reason and partial content on the assistant message, and an Agent does not execute its tool calls.

The Using a Generator and Observing generation events chapters describe how to consume the stream and read the final result.

Sending embeddings

NewEmbedder returns an EmbeddingClient for the same endpoint. One Embed call is one POST to /embeddings, and the returned vectors arrive in input order. The details live in Embedding a batch of text.

Classifying errors

The error type, not the diagnostic string, determines what to do.

Shared HTTP failures

FailureError value
invalid adapter settingsopenai.ErrInvalidConfig
invalid input or request compilationprovider.ErrInvalidRequest
connection could not be established*provider.TransportError (establish)
non-success HTTP status*provider.HTTPStatusError

A non-success status stays an *provider.HTTPStatusError even when reading its body fails, and the read error is available as Cause. Its StatusCode, bounded response data, and truncation flag remain available. A recognized context-window message or code can join provider.ErrContextWindowExceeded to the status error, except for HTTP 429 and rate-limit messages.

Generation failures

FailureError value
provider error payload in an established SSE*provider.StreamError
established read failure other than SSE end*provider.TransportError (read)
malformed chunk, oversized line, or early SSE endprovider.ErrProtocol
content_filter finish reasonprovider.ErrContentFiltered
recognized context-window provider errorprovider.ErrContextWindowExceeded

Malformed chunk data and a clean end before [DONE] preserve accepted partial content and match provider.ErrProtocol. The context-window sentinel joins only recognized overflow message, type, or code fields, and rate-limit errors never use it.

Embedding failures

FailureError value
malformed or oversized successful bodyprovider.ErrInvalidResponse
io.ErrUnexpectedEOF in successful bodyprovider.ErrInvalidResponse
other successful body read failure*provider.TransportError (read)

Sentinels match with errors.Is, and typed fields read with errors.As. Provider messages are untrusted and capped at 4,000 runes in rendered error text, and an HTTP error body is retained up to 1 MiB with truncation marked. Caller cancellation and deadlines keep their context identity, and the adapter never retries. Compacting conversation context covers the one recovery an Agent can perform, while other retry policy belongs to the application.

API reference