Use custom endpoints and gateways

Connect a company gateway, self-hosted server, or OpenAI-compatible proxy.

Covers Examples/Features/04-ProviderSwap.swift and 23-WorkflowGuides.swift. Use this when an endpoint speaks OpenAI Chat Completions but does not have a dedicated model type in the SDK.

Prefer a first-class provider when one exists

Named provider types carry the correct endpoint and environment variable:

let hosted: any LanguageModel = TogetherAIModel("MiniMaxAI/MiniMax-M3")
let local: any LanguageModel = OllamaModel("gemma4")

Use OpenAICompatibleProvider for your own gateway, proxy, vLLM server, or another compatible service. Do not wrap a named provider merely because its wire format happens to be OpenAI-compatible.

Configure the gateway once

let gateway = OpenAICompatibleProvider(
  name: "company-gateway",
  baseURL: URL(string: "https://llm.example.com/v1")!,
  apiKey: ProcessInfo.processInfo.environment["GATEWAY_API_KEY"],
  headers: ["x-team": "ios"],
  queryParams: ["api-version": "2026-01-01"]
)

The provider name appears in telemetry and result metadata. Headers and query parameters are attached to every model request.

Create language and embedding models

Pass model ids exactly as your server exposes them:

let chat = gateway("openai/gpt-oss-20b")
let embeddings = gateway.textEmbeddingModel("BAAI/bge-large-en-v1.5")

let answer = try await generateText(
  model: chat,
  prompt: "Explain Swift actors in three sentences."
)
let vector = try await embed(model: embeddings, value: answer.text)

Tools, structured output, vision, and reasoning are encoded on the compatible wire. The selected upstream model still decides which features it actually supports.

Select models by string

ProviderRegistry is useful when configuration, feature flags, or a server response chooses the model:

let registry = ProviderRegistry(providers: [
  "gateway": .init(
    languageModel: { gateway($0) },
    embeddingModel: { gateway.textEmbeddingModel($0) }
  ),
  "ollama": .init { OllamaModel($0) }
])

let model = try registry.languageModel("gateway:openai/gpt-oss-20b")

The separator defaults to : and can be changed when model ids already use that character.

Keep credentials off untrusted clients

If the endpoint uses a privileged provider key, call it from your backend or issue a short-lived, scoped gateway token. Custom headers are convenient for routing and tenant context, but they are not a secret store.

Final code

CompanyGateway.swift
import AI
import Foundation

let companyGateway = OpenAICompatibleProvider(
  name: "company-gateway",
  baseURL: URL(string: "https://llm.example.com/v1")!,
  apiKey: ProcessInfo.processInfo.environment["GATEWAY_API_KEY"],
  headers: ["x-team": "ios"],
  queryParams: ["api-version": "2026-01-01"]
)

func askGateway(_ prompt: String) async throws -> String {
  try await generateText(
    model: companyGateway("openai/gpt-oss-20b"),
    prompt: prompt
  ).text
}

See Custom OpenAI-compatible endpoints for the reference API and Compatibility for the feature matrix.