chat-core
Core traits, types, and engine for chat-rs — the foundation every provider crate builds on. Exposes the Chat engine, ChatBuilder, the CompletionProvider / StreamProvider / EmbeddingsProvider traits, the Transport trait (with built-in HTTP/SSE and WebSocket impls), and the core message/tool/response types.
You usually don't depend on this crate directly — instead, depend on a provider crate (e.g. chat-openai, chat-gemini, chat-completions) which brings chat-core in transitively. Bring chat-core in explicitly when you want the engine types in your code without pulling the umbrella chat-rs crate.
Install
[]
= "0.4.0"
What's in here
builder::ChatBuilder— the type-state builder that wires a provider into aChatenginechat::Chat— the engine; orchestrates the call loop, tool calls, retries, HITL, structured outputtraits—CompletionProvider,StreamProvider,EmbeddingsProvider,ChatProvidertransport—Transporttrait + three built-in impls (feature-gated):ReqwestTransport(HTTP/SSE, default),AsyncWsTransport(tokio-tungstenite),WsTransport(tungstenite)types—Messages,Content,Parts,Tool,ChatOptions,ChatResponse,StreamEvent,Metadata, etc.error—ChatError,ChatFailure
What's new in 0.4
-
Bidirectional streaming, redesigned.
Chat<CP, InputStreamed>::stream(&mut messages)now returns aChatStreaminstead of taking a caller-supplied input stream. It is the output stream you iterate with.next(), and it carries an input side you push to with.send()— the inverse of.next(), one verb for every input.split()peels it into independent(InputStream, OutputStream)halves (theInputStreamisClone + Send + 'static, so it drops into a task and clones into multiple producers);cancel()tears the exchange down. Builder transition:ChatBuilder::with_input_stream()(no longer generic).Pushed input rides as
PartEnum(audio =File, text =Text, tool result =Tool), mapped caller-side beforesend. It coalesces into the trailing user turn viaMessages::pushand restarts the provider stream — the same interrupt-and-restart pattern HITL uses, now push-driven. Completed tool work survives interrupts (tools run between steps, never mid-stream); only the in-flight partial generation is discarded.
What's new in 0.3
StreamEvent::Structured(Value)— providers can yield complete structured objects mid-stream (each event is a wholeserde_json::Value, not a fragment). The engine accumulates them intoChatResponse.content.partsasPartEnum::Structuredso non-streaming consumers see them too. Drop-in for robotics consumers that produce a stream of typed action steps.
Both are additive over Chat<CP, Unstructured>::stream, which is unchanged.
Feature Flags
| Feature | What it enables |
|---|---|
reqwest-transport |
HTTP/SSE transport via reqwest (default for most providers) |
tokio-tungstenite |
Async WebSocket transport |
tungstenite |
Sync WebSocket transport bridged via spawn_blocking |
stream |
StreamProvider trait + streaming machinery |
testing |
Test helpers for provider crates |
Writing a Custom Provider
Implement CompletionProvider (and optionally StreamProvider, EmbeddingsProvider) on your client struct. Use the Transport abstraction so users can swap reqwest for their own HTTP/WS client. See providers/AGENTS.md for the conventions every existing provider follows.