Providers and compatibility

All providers implement the same interface:

interface LLMProvider {
  name: string
  complete(params: CompletionParams): Promise<string>
  stream?(params: CompletionParams): AsyncIterable<string>
}

The provider only returns raw text. Parsing, repair retries, and validation stay in the core engine.

OpenAI chat.completions

new OpenAIProvider({ apiKey, baseURL, organization, defaultModel })
  • json_schema: response_format: { type: 'json_schema', json_schema: { strict: true } }
  • json_object / auto: response_format: { type: 'json_object' }
  • tool_call: tools + tool_choice; returns tool_calls[0].function.arguments
  • OpenAI-compatible gateways use the same provider with baseURL; if a gateway does not support native modes, use mode: 'json_object' or mode: 'prompt'.

OpenAI Responses API

new OpenAIResponsesProvider({ apiKey, baseURL, organization, defaultModel })
  • System messages are mapped to instructions; other messages become Responses input.
  • json_schema/json_object use text.format.
  • tool_call reads output[*].function_call.arguments.
  • Streaming currently yields the final text once so streamStructured shares the same validation path; incremental Responses events are not normalized yet.

Anthropic

new AnthropicProvider({ apiKey, defaultModel })
  • Non-tool modes move system messages into Anthropic system and append a raw-JSON instruction.
  • tool_call uses tools + tool_choice and serializes tool_use.input back to JSON text for the shared validator.

Google Gemini

new GoogleProvider({ apiKey, defaultModel })
  • Uses responseMimeType: 'application/json' and, for json_schema/auto, responseSchema.
  • Chat history is converted to Gemini contents with user/model roles.

Custom provider

Implement LLMProvider and return raw model text from complete. Add stream when the provider can emit text deltas. Keep provider-specific response parsing inside the provider so the core retry logic stays provider-agnostic.