1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! A unified Rust SDK for backend AI workflows across OpenAI, Anthropic, and
//! OpenRouter.
//!
//! `rai-sdk` wraps three provider APIs behind one typed client so switching
//! models does not mean rewriting request-building, streaming, or tool-calling
//! code.
//!
//! # Capabilities
//!
//! - **Typed providers and models** — construct models with [`Model::gpt4o_mini`],
//! [`Model::claude_sonnet_46`], or [`Model::openrouter_auto`], or pass any
//! provider model ID directly.
//! - **Typestate request builders** — [`RequestBuilder::generate`] only exists
//! once a prompt and a model are present, so incomplete requests fail to
//! compile rather than at runtime.
//! - **Structured output** — derive [`JsonSchema`] and call
//! [`RequestBuilder::generate_structured`] to validate the response against a
//! generated schema and deserialize it into your own type.
//! - **Tool calling** — register typed async tools with [`Tool`];
//! [`RequestBuilder::generate`] runs the tool loop, feeding results back until
//! the model produces a final answer.
//! - **Streaming** — consume raw provider events, or use
//! [`RequestBuilder::stream_accumulated`] to stream internally and return a
//! complete [`Response`].
//! - **Retries** — transient rate-limit, timeout, and HTTP failures are retried
//! with configurable exponential backoff and jitter via [`RetryConfig`].
//! - **Multimodal prompts** — build prompts from text, image, audio, video, and
//! file [`ContentBlock`]s. Provider support varies.
//!
//! # Quickstart
//!
//! ```no_run
//! use rai_sdk::{ClientBuilder, Model};
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! let client = ClientBuilder::new()
//! .from_env()
//! .model(Model::gpt4o_mini())
//! .build()?;
//!
//! let response = client
//! .request()
//! .prompt("Explain Rust ownership in two sentences.")
//! .generate()
//! .await?;
//!
//! println!("{}", response.text());
//! # Ok(())
//! # }
//! ```
//!
//! # Configuration
//!
//! [`ClientBuilder::from_env`] reads `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and
//! `OPENROUTER_API_KEY`, along with optional base-URL, timeout, and retry
//! overrides. Everything can also be set explicitly on [`ClientBuilder`] or
//! [`Config`], and explicit values take precedence over the environment.
//!
//! # Cargo features
//!
//! The `openai`, `anthropic`, and `openrouter` features are all enabled by
//! default and gate the corresponding provider support. Disable the defaults to
//! compile against only the providers you use.
//!
//! Enabling a provider also requires at least one TLS backend:
//!
//! - `rustls-tls` (default) needs no system OpenSSL, but builds `aws-lc-rs`,
//! which requires cmake and a C compiler.
//! - `native-tls` uses the platform TLS stack instead, avoiding that build
//! requirement.
//!
//! Because a TLS backend is part of the default feature set, disabling default
//! features means re-enabling one explicitly:
//!
//! ```toml
//! rai-sdk = { version = "0.1", default-features = false, features = ["anthropic", "native-tls"] }
//! ```
//!
//! Cargo features are additive, so dependency feature unification can enable
//! both backends. That configuration is supported and uses rustls; select only
//! `native-tls` as shown above to avoid compiling `aws-lc-rs`.
//!
//! # Further reading
//!
//! The [guide](https://rmagatti.github.io/rai-sdk/) covers each capability in
//! task-oriented chapters. Its examples are compile-checked against this crate,
//! so they stay in sync with the API you see here.
// Catch a provider without a TLS backend at compile time. A featureless build
// is valid because it cannot make provider requests and is still useful to
// consumers that only need the crate's shared data types.
compile_error!;
// Compile-check every Rust snippet in the mdBook guide as a doctest, so the
// published guide cannot drift away from the real API. This module only exists
// while rustdoc is collecting doctests, so it adds nothing to the built crate or
// to the rendered documentation.