Skip to content

Request configuration

StreamOptions contains settings shared by all protocols. Settings whose semantics differ between protocols are nested under ProtocolOptions.

temperature := 0.2
retries := 2
options := llm.StreamOptions{
    Temperature: &temperature,
    MaxTokens:   2048,
    MaxRetries:  &retries,
    Timeout:     30 * time.Second,
    Headers: map[string]string{
        "X-Request-ID": requestID,
    },
}

The shared options are:

Option Purpose
APIKey Override credential lookup for this request
Env Override named environment values without mutating the process environment
Temperature Override the model sampling temperature
MaxTokens Cap output tokens; zero leaves the model default
Headers Merge custom HTTP headers over model defaults
Reasoning Request a provider-neutral reasoning effort level
ProtocolOptions Carry settings for exactly one wire protocol
MaxRetries Override SDK retries; 0 disables them
Timeout Cap each HTTP attempt independently of context cancellation
OnRequest Observe every serialized HTTP request attempt
RewriteRequest Replace the serialized request body before it is sent
OnResponse Observe every HTTP response attempt

Supply credentials per request

By default the package reads the selected provider's key from the process environment. To override that for a single request—for example a multi-tenant server holding each user's key—set APIKey directly, or supply named environment values through Env without mutating the process environment.

// A literal key for this request only.
options := llm.StreamOptions{APIKey: userKey}

// Or resolve the provider's environment variable from a per-request source.
options := llm.StreamOptions{
    Env: llm.ProviderEnv{"DEEPSEEK_API_KEY": userKey},
}

APIKey takes precedence; Env is consulted before the process environment.

Observe HTTP requests and responses

The hooks are useful for logging, tracing, and debugging. Both fire once per attempt, so retries remain visible. OnRequest receives the exact request body serialized for the provider, including protocol-specific fields.

options := llm.StreamOptions{
    OnRequest: func(method, url string, body []byte) {
        log.Printf("→ %s %s\n%s", method, url, body)
    },
    OnResponse: func(status int, headers http.Header) {
        log.Printf("← %d", status)
    },
}

Hooks may expose prompts, tool arguments, credentials in URLs or headers, and provider response metadata. Redact sensitive data before sending it to logs or telemetry systems.

Rewrite the request body

RewriteRequest transforms the serialized request body before it is sent, an escape hatch for provider-specific fields the typed API does not expose. It receives the same method, URL, and body as OnRequest and returns the body to send; returning nil leaves it unchanged. Like the observers it fires once per attempt and always rewrites the original body, so retries stay consistent.

options := llm.StreamOptions{
    RewriteRequest: func(method, url string, body []byte) []byte {
        var payload map[string]any
        if err := json.Unmarshal(body, &payload); err != nil {
            return nil // leave the body unchanged on error
        }
        payload["custom_provider_field"] = true
        patched, err := json.Marshal(payload)
        if err != nil {
            return nil
        }
        return patched
    },
}

See Reasoning and Tools for the protocol-specific option types currently included with the package.