> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hrns.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Package reference: openai

> OpenAI-compatible request, response, and streaming primitives used by hrns.

## Purpose

The `openai` package is a small client plus a few data structures for model listing, chat completions, and streamed deltas.

## Client construction

Create a client with:

```go theme={null}
client := openai.NewClient(
    openai.WithBaseURL("https://your-provider.example/v1"),
    openai.WithAPIKey("your-api-key"),
    openai.WithHTTPClient(customHTTPClient),
)
```

Defaults:

* base URL: `https://api.openai.com/v1`
* request timeout on the default client: 5 minutes

## Request methods

### `ListModels`

Sends a `GET` request to:

```text theme={null}
/models
```

It returns the non-empty model IDs from the response body and surfaces non-2xx responses as `*openai.APIError`.

### `CreateChatCompletion`

Sends a non-streaming `POST` request to:

```text theme={null}
/chat/completions
```

It returns validation errors if `model` or `messages` are missing.

### `StreamChatCompletion`

Also posts to `/chat/completions`, but forces `stream=true`, requests `text/event-stream`, and returns a channel of `StreamEvent`.

Each `StreamEvent` can contain:

* `Data`: a parsed response chunk
* `Done`: true when `[DONE]` is received
* `Raw`: the raw payload bytes
* `Error`: a parse or scan error

## Extra-field preservation

The package is intentionally tolerant of provider-specific fields.

* `ChatCompletionRequest.Extra` is merged into outbound JSON.
* `Message.Extra`, `ToolCall.Extra`, and `ChatCompletionChoice.Extra` preserve unknown inbound fields.
* `ChatCompletionResponse.Raw` stores raw JSON fragments by top-level key.

That makes the package useful against OpenAI-compatible providers that add extra fields.

## Stream accumulation

`ChatCompletionAccumulator` merges partial deltas into full choices. In particular, it:

* concatenates text content
* merges partial tool calls by index
* stitches fragmented tool-call argument strings together
* preserves extra fields and logprobs
* preserves structured content when no text concatenation is possible

This is what `loop.RunLoop` relies on before executing tools.

## Helper constructors

Use:

* `openai.SystemMessage(...)`
* `openai.UserMessage(...)`
* `openai.ToolMessage(...)`

Use `openai.MessageText(...)` when you expect plain string content and want the helper's type assertion behavior.

## Error model

Non-2xx API responses from `ListModels`, `CreateChatCompletion`, and `StreamChatCompletion` return `*openai.APIError`, which includes:

* `StatusCode`
* `Message`
* `Body`

That gives callers access to both a concise error string and the raw response body.
