API Integration
Provider code formats requests and parses responses in core. The host carries them out asynchronously: the Zellij adapter uses its web-request API, while Montana implements the component’s HTTP import with a native client and sends the completion back as a host event. Provider logic does not depend on a terminal or Zellij panes. Proxy routing, credentials and network policy still depend on the deployment.
Source: crates/core/src/provider/.
Providers
Six providers implement the LlmProvider trait, selected by ProviderType:
ClaudeProvider(Anthropic Messages API)OpenAIProvider(Chat Completions / Responses API)CodexProvider(ChatGPT subscription Responses API with SSE)OpenRouterProviderVercelProvider(Vercel AI Gateway, Chat Completions)OllamaProvider(local, keyless)
The LlmProvider trait
The trait does not perform transport I/O. It only serializes requests and deserializes responses:
#![allow(unused)]
fn main() {
pub trait LlmProvider {
fn name(&self) -> &str;
fn format_request(
&self,
messages: &[Message],
tools: &[Tool],
system: &str,
) -> (String, BTreeMap<String, String>, Vec<u8>);
fn parse_response(&self, body: &[u8]) -> Result<LlmResponse, ProviderError>;
fn parse_error(&self, status: u16, body: &[u8]) -> ProviderError;
fn set_model(&mut self, model: &str);
fn api_key(&self) -> &str;
}
}
The request flow is:
format_request()produces(url, headers, body).- Core requests HTTP through its host interface.
- The host delivers the correlated HTTP result: a Zellij event or, through Montana, a WIT host event mapped back into core.
parse_response()(on HTTP 200) orparse_error()(otherwise) interprets it.
set_model() supports switching the model at runtime (the /model command).
Credentials
In the managed credential-proxy deployment
(services.cowboy.secretsProxy.enable), the agent sends placeholder keys and
the proxy injects the real credentials on the wire based on per-domain mappings.
Codex is the same pattern: its rotating ChatGPT subscription token is injected
outside the agent. Local and ordinary Docker launches hold credentials.
See Security Model. For keyless
providers (Ollama) api_key() is empty.
Provider defaults
ClaudeProvider targets /v1/messages. Its defaults: model
claude-sonnet-4-20250514, max_tokens 8192, extended thinking enabled with a
token budget. OpenAIProvider defaults to gpt-4o and auto-selects the
Responses API for reasoning models (o-series, gpt-5, codex) to capture reasoning
summaries, which are mapped onto thinking content blocks.
Message model
Messages carry a string role and a vector of ContentBlocks, matching the
Claude API’s native content-block model. A block’s block_type is one of
text, tool_use, tool_result, or thinking.
Errors and retries
ProviderError includes ParseError, ApiError, NetworkError,
RateLimited, Timeout, InvalidRequest, AuthenticationError, and
Overloaded. is_retryable() marks rate limits (429), network errors, server
errors (5xx), and timeouts as retryable; auth and other 4xx errors are not.
Automatic retry is wired in: a RetryState with exponential backoff drives a
bounded retry of failed LLM calls from the ranch handlers
(crates/core/src/handlers.rs, schedule_llm_retry) — a retryable error
schedules a backed-off retry until max_attempts is exhausted, after which the
failure surfaces as an error message.
Bridges
Bridge services (Discord, email) do not use the provider layer. They reach the agent through the pub/sub message system: inbound messages are polled and processed as user input, and replies flow back out the same way. See Approvals & Outbox.