rai_sdk/lib.rs
1//! A unified Rust SDK for backend AI workflows across OpenAI, Anthropic, and
2//! OpenRouter.
3//!
4//! `rai-sdk` wraps three provider APIs behind one typed client so switching
5//! models does not mean rewriting request-building, streaming, or tool-calling
6//! code.
7//!
8//! # Capabilities
9//!
10//! - **Typed providers and models** — construct models with [`Model::gpt4o_mini`],
11//! [`Model::claude_sonnet_46`], or [`Model::openrouter_auto`], or pass any
12//! provider model ID directly.
13//! - **Typestate request builders** — [`RequestBuilder::generate`] only exists
14//! once a prompt and a model are present, so incomplete requests fail to
15//! compile rather than at runtime.
16//! - **Structured output** — derive [`JsonSchema`] and call
17//! [`RequestBuilder::generate_structured`] to validate the response against a
18//! generated schema and deserialize it into your own type.
19//! - **Tool calling** — register typed async tools with [`Tool`];
20//! [`RequestBuilder::generate`] runs the tool loop, feeding results back until
21//! the model produces a final answer.
22//! - **Streaming** — consume raw provider events, or use
23//! [`RequestBuilder::stream_accumulated`] to stream internally and return a
24//! complete [`Response`].
25//! - **Proxyable streams** — [`RequestBuilder::stream_wire_events`] yields
26//! serializable [`WireStreamEvent`]s so a server can re-emit a generation to
27//! its own clients over SSE, and [`StreamAccumulator`] reassembles them on the
28//! far end. See the [`wire`] module.
29//! - **Retries** — transient rate-limit, timeout, and HTTP failures are retried
30//! with configurable exponential backoff and jitter via [`RetryConfig`].
31//! - **Multimodal prompts** — build prompts from text, image, audio, video, and
32//! file [`ContentBlock`]s. Provider support varies.
33//! - **Local and self-hosted models** — point a client at any endpoint speaking
34//! the OpenAI Chat Completions format with
35//! [`ClientBuilder::openai_compatible_base_url`] (or
36//! [`ClientBuilder::ollama`]) and name models with
37//! [`Model::openai_compatible`]. See the `provider::openai_compatible`
38//! module, which the `openai` feature gates.
39//!
40//! # Quickstart
41//!
42//! ```no_run
43//! use rai_sdk::{ClientBuilder, Model};
44//!
45//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
46//! let client = ClientBuilder::new()
47//! .from_env()
48//! .model(Model::gpt4o_mini())
49//! .build()?;
50//!
51//! let response = client
52//! .request()
53//! .prompt("Explain Rust ownership in two sentences.")
54//! .generate()
55//! .await?;
56//!
57//! println!("{}", response.text());
58//! # Ok(())
59//! # }
60//! ```
61//!
62//! # Configuration
63//!
64//! [`ClientBuilder::from_env`] reads `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and
65//! `OPENROUTER_API_KEY`, along with optional base-URL, timeout, and retry
66//! overrides. Everything can also be set explicitly on [`ClientBuilder`] or
67//! [`Config`], and explicit values take precedence over the environment.
68//!
69//! # Cargo features
70//!
71//! The `openai`, `anthropic`, and `openrouter` features are all enabled by
72//! default and gate the corresponding provider support. Disable the defaults to
73//! compile against only the providers you use.
74//!
75//! `openai` additionally gates the OpenAI-compatible provider, which reuses
76//! that module's request builder and stream parser rather than duplicating
77//! them. A build that talks only to local models therefore enables `openai`
78//! and nothing else.
79//!
80//! Enabling a provider also requires at least one TLS backend:
81//!
82//! - `rustls-tls` (default) needs no system OpenSSL, but builds `aws-lc-rs`,
83//! which requires cmake and a C compiler.
84//! - `native-tls` uses the platform TLS stack instead, avoiding that build
85//! requirement.
86//!
87//! Because a TLS backend is part of the default feature set, disabling default
88//! features means re-enabling one explicitly:
89//!
90//! ```toml
91//! rai-sdk = { version = "0.1", default-features = false, features = ["anthropic", "native-tls"] }
92//! ```
93//!
94//! Cargo features are additive, so dependency feature unification can enable
95//! both backends. That configuration is supported and uses rustls; select only
96//! `native-tls` as shown above to avoid compiling `aws-lc-rs`.
97//!
98//! # Further reading
99//!
100//! The [guide](https://rmagatti.github.io/rai-sdk/) covers each capability in
101//! task-oriented chapters. Its examples are compile-checked against this crate,
102//! so they stay in sync with the API you see here.
103#![cfg_attr(docsrs, feature(doc_cfg))]
104
105// Catch a provider without a TLS backend at compile time. A featureless build
106// is valid because it cannot make provider requests and is still useful to
107// consumers that only need the crate's shared data types.
108#[cfg(all(
109 any(feature = "openai", feature = "anthropic", feature = "openrouter"),
110 not(any(feature = "rustls-tls", feature = "native-tls"))
111))]
112compile_error!(
113 "rai-sdk has a provider enabled but no TLS backend. \
114 This usually means `default-features = false` was set without re-enabling one. \
115 Add `rustls-tls` (the default), or `native-tls` if you cannot build aws-lc-rs, \
116 which requires cmake and a C compiler."
117);
118
119// Compile-check every Rust snippet in the mdBook guide as a doctest, so the
120// published guide cannot drift away from the real API. This module only exists
121// while rustdoc is collecting doctests, so it adds nothing to the built crate or
122// to the rendered documentation.
123#[cfg(doctest)]
124mod guide {
125 macro_rules! chapter {
126 ($name:ident, $path:literal) => {
127 #[doc = include_str!($path)]
128 pub struct $name;
129 };
130 }
131
132 chapter!(Introduction, "../docs/src/introduction.md");
133 chapter!(Installation, "../docs/src/installation.md");
134 chapter!(Quickstart, "../docs/src/quickstart.md");
135 chapter!(Configuration, "../docs/src/configuration.md");
136 chapter!(ProvidersAndModels, "../docs/src/providers-and-models.md");
137 chapter!(StructuredOutput, "../docs/src/structured-output.md");
138 chapter!(ToolCalling, "../docs/src/tool-calling.md");
139 chapter!(Streaming, "../docs/src/streaming.md");
140 chapter!(MultimodalPrompts, "../docs/src/multimodal-prompts.md");
141 chapter!(RetriesAndErrors, "../docs/src/retries-and-errors.md");
142 chapter!(Examples, "../docs/src/examples.md");
143 chapter!(Contributing, "../docs/src/contributing.md");
144}
145
146pub mod client;
147pub mod config;
148pub mod error;
149pub mod generation;
150pub mod message;
151pub mod model;
152pub mod provider;
153pub mod retry;
154pub mod tool;
155pub mod wire;
156
157pub use client::{Client, ClientBuilder, RequestBuilder};
158pub use config::{Config, EndpointCapabilities};
159pub use error::{Capability, Error, ProviderKind, Result, ToolArgumentIssue};
160pub use generation::GenerationConfig;
161pub use message::{
162 ContentBlock, ImageSource, Message, Prompt, Response, Role, StreamChunk, StructuredOutput,
163 ToolCall, ToolDefinition, Usage,
164};
165pub use model::{AnthropicModel, Model, OpenAICompatibleModel, OpenAIModel, OpenRouterModel};
166pub use retry::RetryConfig;
167pub use schemars::{self, JsonSchema};
168pub use tool::{Tool, ToolContext};
169pub use wire::{
170 StreamAccumulator, WIRE_PROTOCOL_VERSION, WireError, WireErrorKind, WireStreamEvent,
171};