or/llm developer guide¶
This page explains the module relationships, initialization choices, request
path, state boundaries, and extension routes of or/llm. It is intended for
developers integrating several model services, configuring an independent
client, diagnosing request execution, or implementing a protocol adapter.
For one concrete task, start from the guides. Use the API reference to locate exported symbols and the pages under API and concepts for field and behavioral contracts.
Architectural role¶
Model services represent messages, tools, reasoning options, streamed output,
usage, and failures differently. llm uses its own Context, Message,
Model, Event, ToolDefinition, and AssistantMessage types for application
input and output, then delegates request and response conversion to a protocol
adapter.
The abstraction covers one model call:
- resolve the model, credentials, service address, and request options;
- transform history for the target model before sending;
- normalize service increments into common events;
- return content, stop reason, usage, estimated cost, and diagnostics.
Conversation databases, context compaction, tool execution, agent loops, RAG, and provider scheduling are outside this layer.
Main modules¶
| Module | Primary source | Responsibility |
|---|---|---|
| Messages and models | llm/message.go, llm/model.go |
Messages, content blocks, model capability, usage, and stop reasons |
| Request entry | llm/default.go, llm/client.go |
Validate options, resolve provider configuration, select an adapter |
| Adapter registration | llm/adapters.go |
Map Protocol to ProtocolAdapter |
| Provider configuration | llm/provider.go, llm/provider_registry.go |
Credentials, service address, headers, overrides, and auth status |
| Model catalog | llm/catalog.go, llm/model_registry.go |
Built-in catalog and application model registries |
| History transformation | llm/transform.go |
Image degradation, reasoning handling, and tool-call repair |
| Streaming events | llm/events.go, llm/stream.go |
Common events, partial messages, and terminal guarantees |
| Tools | llm/tools.go, llm/validation.go, llm/jsonschema.go |
Schema generation, recovery, validation, and decoding |
| Built-in adapters | llm/openai/, llm/anthropic/ |
Conversion for implemented request and response formats |
The modules relate as follows:
flowchart LR
app["Application"] --> client["Client"]
app -. "select model" .-> models["Catalog / ModelRegistry"]
client --> providers["ProviderRegistry<br/><small>credentials · address · headers</small>"]
client --> adapters["AdapterRegistry<br/><small>Protocol → adapter</small>"]
adapters --> adapter["ProtocolAdapter"]
adapter --> service["Model service HTTP API"]
service --> adapter --> events["Normalized events"] --> app
ModelRegistry supports model lookup and does not participate in client
dispatch. A request depends on the Model value, ProviderRegistry, and
AdapterRegistry. See Clients and registries for
the exact differences.
Default or explicit client¶
Most applications use package-level Complete and Stream. Importing a
protocol package runs its init function and registers an adapter with the
default AdapterRegistry; the default ProviderRegistry is built from embedded
configuration.
Use an explicit Client when:
- tenants or subsystems require independent provider overrides;
- a custom proxy, TLS configuration, pool, or transport is required;
- tests must not mutate process-wide default registries;
- only an allowlist of protocols may be used;
- a custom
ProtocolAdaptermust be registered.
See Creating a custom client for the complete
program. A Client does not store conversations or create a model catalog for
each request.
Request execution¶
One Stream call passes through the client, provider registry, and protocol
adapter:
sequenceDiagram
participant App as Application
participant Client
participant Registry as ProviderRegistry
participant Adapter as ProtocolAdapter
participant Service as Model service
App->>Client: Stream(model, context, options)
Client->>Client: StreamOptions.Validate
Client->>Registry: ResolveRequest
Registry-->>Client: effective model and options
Client->>Adapter: Stream(model, context, options)
Adapter->>Adapter: TransformMessages
Adapter->>Service: streaming HTTP request
Service-->>Adapter: service response increments
Adapter-->>App: EventStart / content events / terminal event
Complete reuses the same streaming path, consumes events internally, and
returns an AssistantMessage after EventDone or EventError. Both entry
points therefore share history transformation, failure mapping, usage, and
diagnostics.
The event channel is unbuffered. A Stream caller must receive until close,
including after context cancellation or after the application stops displaying
increments. See Streaming events for ordering and termination.
Configuration scope¶
| Scope | Type | Appropriate values |
|---|---|---|
| One request | StreamOptions |
User credentials, sampling, output cap, timeout, headers, and hooks |
| One provider | ProviderOverride |
Gateway address, shared credentials, common headers, and environment overrides |
| One client | AdapterRegistry, ProviderRegistry |
Tenant isolation, protocol allowlists, and test state |
| One model | Model, ModelCompatibility |
Service address, capabilities, context limits, and interface differences |
Precedence between request values and provider overrides is maintained only in
Request options. Use ProviderRegistry.ResolveRequest when
diagnostics need the effective values passed to the adapter; do not reproduce
the merge logic in application code.
OnRequest, RewriteRequest, and OnResponse run for every SDK attempt. They
execute on the request path, so a blocking callback directly adds latency. See
Recording and rewriting requests.
State, concurrency, and resources¶
Clientstores no session state. The application ownsContext.Messagesand decides when to persist them.- Registry types support concurrent reads and mutations; the default provider registry is process-shared state.
- An in-flight request that already completed
ResolveRequestis unaffected by later override changes. Clientand registry types have noClosemethod.- An adapter closes the response stream for one request; the application owns
an injected
http.Clientand transport. - Reuse HTTP clients and transports instead of rebuilding connection pools per request.
- Context controls the whole call;
StreamOptions.Timeoutcontrols one HTTP attempt.
See Saving and restoring conversations for concurrent turn updates, storage versioning, and restore flow.
Extension routes¶
First determine whether the target changes configuration or the request and response format:
| Goal | Recommended extension point |
|---|---|
| Change an existing provider's service address or credentials | ProviderOverride |
| Connect one service compatible with an existing protocol | Construct a Model directly |
| Register a provider, credential variables, and a model set | NewSpecProvider, ProviderRegistry.Register |
| Change proxy, TLS, pool, or transport | Inject *http.Client into a built-in adapter |
| Observe requests or add a field not yet typed | OnRequest, RewriteRequest, OnResponse |
| Support a new request and response format | Implement ProtocolAdapter and required ProtocolStreamOptions |
StreamWriter helps a custom adapter preserve the shared event lifecycle. See
Custom protocols for implementation requirements. Message and
content interfaces contain unexported marker methods, so external packages
cannot add roles or content blocks.
Pre-production checklist¶
- Use
LookupModelfor configured or user-supplied model IDs so unknown input does not panic. - Use
GetRunnableModelsorSupportsProtocolto confirm that the target adapter is registered in the current process. - Use
AuthStatusto check credential resolution, then make a real request to verify authorization. - Set a context deadline for the whole call and define the boundary between SDK retries and application retries.
- Consume a stream until close. On client disconnect, cancel context and keep draining.
- Apply authorization, deadlines, idempotency keys, concurrency limits, and loop bounds to tool execution.
- Redact and control access to prompts, images, tool arguments, request bodies, history, and reasoning signatures.
- Record original
Usageseparately from estimated cost;Usage.Costis not a model-service invoice. - Verify authentication, streaming, tools, reasoning, usage, and failures against every production model service.
The package has no built-in log file, metrics exporter, billing reconciliation, or official throughput benchmark.
Troubleshooting entry points¶
| Symptom | Start here |
|---|---|
| Request returns an error before starting | Failure signals |
| Stream does not close after cancellation | Troubleshooting |
| Model exists but cannot be called | Finding models and checking credentials |
| Output is truncated or context overflows | Handling request failures |
| Tool arguments are incomplete or invalid | Tool definitions and calls |
| Custom service request is incompatible | Connecting a custom model service |
See Internals for source-level invariants and adapter implementation details.