DOCS / PROVIDERS / OPENAI, ANTHROPIC & GOOGLE

Cloud Providers

OpenAI

The simplest adapter: it's a thin wrapper over the shared openai-compatible factory (the same one Ollama and vLLM use), pointed at OpenAI's own endpoint — since OpenAI's API is definitionally OpenAI-shaped.

Endpointhttps://api.openai.com/v1/chat/completions
Authauthorization: Bearer <OPENAI_API_KEY>
Env varOPENAI_API_KEY

Anthropic

A bespoke adapter, since the Messages API isn't OpenAI-shaped.

Endpointhttps://api.anthropic.com/v1/messages
Authx-api-key: <ANTHROPIC_API_KEY>, anthropic-version: 2023-06-01
Env varANTHROPIC_API_KEY

Request mapping: Anthropic has no system role in its messages array — any system messages in the incoming request are pulled out and joined (\n\n) into a top-level system field instead. max_tokens defaults to 4096 if the client didn't set one (Anthropic requires it; OpenAI-shaped APIs don't). stop is normalized into Anthropic's stop_sequences.

Response mapping: all content blocks of type text are concatenated into the single message.content string Lattice's response shape expects. stop_reason: 'max_tokens' maps to finish_reason: 'length'; everything else maps to 'stop'.

Streaming: Anthropic's stream is a sequence of named SSE events, not self-contained chunks, so the stream adapter is a small stateful reducer: message_start emits the initial role: 'assistant' chunk and captures input_tokens for later; content_block_delta (text deltas) emits content chunks; message_delta emits the terminal chunk carrying finish_reason and usage (using the input_tokens captured earlier, since Anthropic only reports output-token deltas incrementally); content_block_start/stop, ping, and message_stop produce no chunk.

Google (Gemini)

Also bespoke — the most structurally different of the three.

Endpoint https://generativelanguage.googleapis.com/v1beta/models/{providerModel}:{generateContent|streamGenerateContent}?key=<GOOGLE_API_KEY>[&alt=sse]
AuthAPI key as a query parameter, not a header
Env varGOOGLE_API_KEY

Unlike the other two, the model name is a URL path segment, not a body field — providerModel gets interpolated directly into the endpoint URL, and the method name itself (generateContent vs. streamGenerateContent) changes based on whether the request is streaming.

Request mapping: assistant role maps to Gemini's model role. System messages are joined into systemInstruction.parts[0].text. temperature, top_p, max_tokens, and stop map into generationConfig.{temperature, topP, maxOutputTokens, stopSequences}.

Response mapping: finishReason: 'MAX_TOKENS' → 'length'; finishReason: 'SAFETY' → 'content_filter'; everything else → 'stop'. Gemini responses carry no response id, so one is synthesized: `gemini-${Bun.randomUUIDv7()}`.

Streaming: unlike Anthropic, each Gemini stream chunk is self-contained (the full shape, not an incremental delta against prior state), so the stream mapper is a stateless per-chunk transform rather than a reducer. usageMetadata only appears on the terminal chunk.

At a glance

OpenAIAnthropicGoogle
Adapter kindopenai-compatible factoryBespokeBespoke
Auth transportHeaderHeader (x-api-key)Query param
System roleNativeMerged into systemMerged into systemInstruction
Stream shapeDeltasNamed events, stateful reduceSelf-contained chunks, stateless map
Synthesized idNo (upstream provides one)NoYes
LATTICE — INTERNAL AI INFRASTRUCTURE
GITHUB © 2026