chat-rs
Traits

Traits

The four provider traits and the type-state builder that ties them together.

Everything in chat-rs is built on a small set of traits. A provider advertises what it can do by implementing them, and the ChatBuilder turns a provider into a Chat whose methods match exactly what the provider supports.

The provider traits

TraitMethodEnables
CompletionProvidercompleteone completion step (the foundation)
StreamProviderstreamtoken-by-token streaming
ChatProviderbotha supertrait, auto-implemented for providers that do both
EmbeddingsProviderembedvector embeddings

ChatProvider has a blanket implementation, so any type that is both a CompletionProvider and a StreamProvider is automatically a ChatProvider:

pub trait ChatProvider: CompletionProvider + StreamProvider {}
impl<T: CompletionProvider + StreamProvider> ChatProvider for T {}

The type-state builder

ChatBuilder<CP, Output> carries a second type parameter that tracks the output shape. Each builder method moves you into a new state, and only the methods valid for that state exist:

Builder callStateMethod you get
(default)Unstructuredcomplete, resume, plus stream when CP: StreamProvider
.with_structured_output::<T>()Structured<T>complete returns T
.with_input_stream()InputStreamedstream (full duplex)
.with_embeddings()Embeddedembed

Output streaming needs no special builder call, and there is no "streaming state". stream lives on the default chat but is bound on CP: StreamProvider, so it only appears when the provider can actually stream. A completion-only provider exposes complete and resume and nothing else; calling .stream() on it is a compile error, not a runtime panic. Likewise with_input_stream and with_embeddings are only reachable when the provider implements StreamProvider and EmbeddingsProvider respectively.

use chat_rs::{ChatBuilder, openai::OpenAIBuilder};

let client = OpenAIBuilder::new().with_model("gpt-4o").build();

// Unstructured by default: complete + resume.
let chat = ChatBuilder::new().with_model(client).build();

Bring your own provider

Because everything is a trait, you can write your own provider. Implement CompletionProvider and it plugs into the same reason-and-act loop, tools, retries, and middleware as the built-in ones. See Providers: bring your own.

On this page