llmadapter

Provider Development

This guide is for contributors adding a provider, provider endpoint, API kind, endpoint codec, or shared smoke coverage.

Design Rule

Model each callable upstream surface as a provider endpoint:

Provider = who we talk to.
API kind = exact wire protocol used.
API family = compatibility shape.
Provider endpoint = provider + API kind + API family + client + capabilities.

Do not model a multi-surface provider as one API kind. OpenRouter and MiniMax are examples of one provider exposing multiple endpoint types.

Files To Read First

Inspect similar implementations:

Implementation Checklist

  1. Add or confirm adapt.ApiKind and adapt.ApiFamily.
  2. Add a provider package under providers/<provider>/<api-shape>/.
  3. Reuse an existing compatibility provider only when the upstream wire protocol is actually compatible.
  4. Implement request encoding tests with fake transport.
  5. Implement stream/event decoding tests with fake transport.
  6. Register a providerregistry.Descriptor with API kind, family, default capabilities, model env var, credential env vars, smoke model, and client factory.
  7. Add adapterconfig tests for provider endpoint metadata, defaults, modeldb service identity, and auto detection when relevant.
  8. Ensure gatewayserver can expose the provider through existing endpoint codecs when the API family is supported.
  9. Add shared e2e smoke entries gated by provider-specific env vars or local auth detection.
  10. Update PROVIDER_MATRIX.md, CONFIGURATION.md, and README.md if public provider support changes.

Capability Rules

Default capabilities are endpoint-family/provider defaults, not proof that every model supports a feature.

Only advertise a capability when:

Use modeldb exposure metadata or config overrides to narrow capabilities for specific models.

Testing Expectations

Minimum for a text provider:

Minimum for a tool-capable provider:

Minimum for reasoning:

Minimum for prompt caching:

Minimum for provider-specific transport behavior:

Validation Commands

Run before commit:

env GOCACHE=/tmp/go-cache go test ./...
env GOCACHE=/tmp/go-cache go vet ./...
env GOCACHE=/tmp/go-cache GOMODCACHE=/tmp/go-mod-cache go build ./...

Run relevant live slices when credentials are available:

env GOCACHE=/tmp/go-cache TEST_INTEGRATION=1 go test ./tests/e2e -run TestSmokeTextStream -count=1 -v
env GOCACHE=/tmp/go-cache TEST_INTEGRATION=1 go test ./tests/e2e -run TestSmokeToolUse -count=1 -v
env GOCACHE=/tmp/go-cache TEST_INTEGRATION=1 go test ./tests/e2e -run TestSmokeToolResultContinuation -count=1 -v
env GOCACHE=/tmp/go-cache TEST_INTEGRATION=1 go test ./tests/e2e -run TestGatewaySmoke -count=1 -v

Common Mistakes