Skip to content

rtb-ai v0.1

A single chat client across providers. genai covers the mainstream (OpenAI, Gemini, Ollama, OpenAI-compatible); the Claude backend additionally drops down to direct reqwest calls against the Anthropic Messages API for features genai does not surface — prompt caching, extended thinking, citations.

Public API

use rtb_ai::{AiClient, ChatRequest, Config, Message, Provider};

# async fn run() -> Result<(), rtb_ai::AiError> {
let client = AiClient::new(Config {
    provider: Provider::Claude,
    model: "claude-opus-4-7".into(),
    ..Config::default()
})?;

let reply = client.chat(ChatRequest {
    messages: vec![Message::user("Summarise this changelog in one line.")],
    cache_control: true,
    ..ChatRequest::default()
}).await?;
# Ok(())
# }

Config and ChatRequest are plain structs with public fields and a Default impl — set what you need, spread the rest. Provider is #[non_exhaustive].

Item Purpose
[AiClient] new / chat / chat_stream / chat_structured.
[Config], [Provider] Provider selection, model, endpoint, auth.
[Message], [Role], [ContentBlock], [Citation], [Usage] Request/response message model.
[ChatRequest], [ChatResponse], [ChatStream], [ChatStreamEvent] Call shapes — one-shot, streaming, and structured.
[ThinkingMode] Extended-thinking control on the Claude backend.
[AiError] thiserror + miette::Diagnostic error enum.
[validate_base_url] Endpoint allowlist guard (see below).

Structured output

chat_structured::<T>() takes any T: serde::Deserialize + schemars::JsonSchema. The generated JSON Schema is sent with the request and the response is validated with jsonschema before deserialising — a malformed model response surfaces as an AiError, never a partial T.

Endpoint safety

Every Config::base_url passes [validate_base_url]: non-HTTPS schemes, URLs carrying userinfo (user:pass@host), and placeholder hosts (example.com and subdomains) are rejected. Tests against a wiremock/httpmock server set Config::allow_insecure_base_url, which is #[serde(skip)] so config files can't downgrade HTTPS enforcement. Each successful AiClient::new logs the endpoint hostname at INFO — never the path or query.

Model defaults

New AI code defaults to Claude 4.7 models with prompt caching at every stable point (system prompt, tools, static context). Migration mapping: Opus 4.6 → Opus 4.7, Sonnet 4.5 → Sonnet 4.6, Haiku 4.5 (current).

Secrets

API keys cross the boundary as secrecy::SecretString and are resolved through the precedence chain documented in configure credentials. Never log the exposed form.

Spec

Authoritative contract: docs/development/specs/2026-05-01-rtb-ai-v0.1.md.