llmleaf-client (Rust)
Async Rust SDK for the llmleaf LLM proxy.
llmleaf speaks OpenAI/OpenRouter-shaped JSON over HTTP, so the public types are plain serde
structs and the transport is reqwest over rustls (no system OpenSSL). The
proto is the source of truth: build.rs compiles it with
prost-build on every build and exposes the messages under pb as a codegen check — the
serde types at the crate root are what you actually use.
Install
This crate is its own standalone workspace inside the monorepo (intentionally not a member of the root workspace). Depend on it by path or git:
[]
= { = "https://github.com/codefionn/llmleaf", = "main" }
= { = "1", = ["macros", "rt-multi-thread"] }
= "0.3"
You need protoc (libprotoc 35) on PATH at build time — prost shells out to it.
Example
use StreamExt;
use ;
async
Need a timeout, an admin token, or your own reqwest::Client? Use the builder:
use Duration;
let client = builder
.timeout
.admin_token // adds per-model `endpoints` to GET /v1/models
.build?;
Endpoints
| Call | Method | Notes |
|---|---|---|
| Chat | chat / chat_stream |
stream yields ChatCompletionChunk, stops on [DONE] |
| Embeddings | embeddings |
decodes base64 vectors → Vec<f32> |
| Models | list_models |
type filter + search |
| Speech (TTS) | speech |
returns (bytes, content_type) |
| Voices | voices |
|
| Transcribe (STT) | transcribe |
multipart; Transcription::Json or ::Text |
| Batches | create_batch / get_batch / cancel_batch / batch_results |
results stream BatchResultLine |
Gateway errors come back as Error::Api { status, message }, parsed from
{"error":{"message":"..."}}.
Run the example
It lists models, does a non-streaming chat, and streams one (printing deltas live).
Regenerate from the proto
Codegen is wired into build.rs, so a build is a regeneration — after editing
../proto/llmleaf/v1/llmleaf.proto, just rebuild
(cargo build, or make gen-rust from clients/).
Notes
- The
pb(prost) types are the codegen proof, not the wire types — use the serde types at the crate root for anything over HTTP. - Free-form JSON fields (
extra,ResponseFormat.json_schema, …) are spliced verbatim and not validated (intentional passthrough);ChatRequest.extrakeys merge at the top level. - No retries/backoff. The realtime WebSocket surface is out of scope.
License
Dual-licensed under Apache-2.0 or MIT at your option. Copyright (C) 2026 Fionn Langhans.