glean/providers/openai_compatible

Shared implementation for all OpenAI-compatible Chat Completions APIs. OpenAI, DeepSeek, Mistral, OpenRouter, Moonshot/Kimi, Qwen and MiniMax all use this format, and so can any other compatible endpoint:

config.new(api_key: key, model: "my-model")
|> config.base_url("https://my-gateway.example.com/v1")
|> openai_compatible.create(name: "my-gateway", config: _)

Reasoning returned as reasoning_content (DeepSeek, Qwen, Kimi, MiniMax) or reasoning (OpenRouter) is surfaced as reasoning content and ReasoningDelta stream events.

Types

Accumulator for streaming state — threaded through a pure receive loop.

pub opaque type StreamAccumulator

Values

pub fn accumulated_content(
  acc: StreamAccumulator,
) -> List(provider.GeneratedContent)

Everything accumulated, in the order a non-streaming response has it: reasoning, text, then tool calls. Public for tests.

pub fn accumulated_text(acc: StreamAccumulator) -> String

The text accumulated so far. Public for tests.

pub fn create(
  name provider_name: String,
  config config: config.ProviderConfig,
) -> provider.Provider

Create a Provider from an OpenAI-compatible config.

pub fn decode_response(
  model_id: String,
  body: String,
) -> Result(provider.GenerateResult, error.GleanError)

Decode a non-streaming Chat Completions response body. Public for tests.

pub fn encode_request(
  config: config.ProviderConfig,
  gen_request: provider.GenerateRequest,
  stream: Bool,
) -> String

Encode a Chat Completions request body. Public for tests.

pub fn new_stream_accumulator() -> StreamAccumulator

A fresh accumulator. Public for tests.

pub fn stream_loop(
  events: @internal Stream,
  acc: StreamAccumulator,
  on_event: fn(stream.StreamEvent) -> Nil,
  provider_name: String,
  model: String,
  timeout_ms: Int,
) -> Result(StreamAccumulator, error.GleanError)

Receive SSE events until the stream completes.

Returns an error — never a partial success — when the stream times out, gets a non-2xx response, closes before the provider signalled completion, or carries an error payload.

Public so tests can drive it with sse.from_events.

✨ Search Document