llmshim
A blazing-fast LLM API translation layer written in pure Rust. One request format, every provider — OpenAI, Anthropic, Google Gemini, and xAI.
Send an OpenAI-style request, pick any model, and llmshim translates it to that provider's native API (and translates the response back). Switch providers by changing one string.
Three ways to use it:
| Surface | For | Install |
|---|---|---|
| Rust crate | Rust apps that call LLMs directly, in-process | cargo add llmshim |
| CLI | Interactive chat + a local proxy, from your terminal | brew install sanjay920/tap/llmshim |
| HTTP proxy | Any language (Python, JS, Go, …) over HTTP | run llmshim proxy, or pip install llmshim |
The Rust crate is the engine. The CLI and proxy wrap it. The Python package is a thin client that bundles the Rust binary, starts the proxy for you, and talks to it over HTTP — so you get the Rust engine behind a Python API.
Benchmarks
Median of 5 runs, each p50 over 20 warm requests. Same prompt, same models, same machine.
| Metric | llmshim | litellm | langchain |
|---|---|---|---|
| Anthropic (p50) | 999ms | 981ms | 973ms |
| OpenAI (p50) | 511ms | 613ms | 602ms |
| Streaming TTFT | 1,023ms | 906ms | 1,249ms |
| Memory (RSS) | 12 MB | 281 MB | 281 MB |
| Transform overhead | 1.5µs | — | — |
All three libraries hit the same APIs (Responses API for OpenAI, Messages API for Anthropic), so latency is dominated by the network round-trip — llmshim's own translation work is ~1.5µs, roughly a millionth of the request time.[^bench] The differences between libraries on any single latency row are within network noise and reshuffle run-to-run; the durable wins are memory footprint (~24× leaner than the Python stacks) and near-zero startup/overhead.
[^bench]: Because latency is >99.9% network, per-request p50s vary by more between runs of the same library than between libraries, which is why these are medians of 5 full runs rather than a single sample. Numbers were measured with gpt-5.4 and claude-sonnet-4-6; your absolute values will differ by region and time of day.
Run it yourself:
Configure API keys
llmshim reads keys from environment variables or ~/.llmshim/config.toml. Precedence: env vars > config file.
Or persist them to the config file (used by all three surfaces):
Use it from Rust
use json;
async
Switch providers by changing the "model" string — everything else stays the same.
Streaming:
use StreamExt;
use json;
let router = from_env;
let request = json!;
let mut stream = stream.await.unwrap;
while let Some = stream.next.await
See examples/chat.rs and examples/stream.rs for runnable programs (cargo run --example chat).
Use it from the CLI
Use it from any language (HTTP proxy)
Run llmshim as a local HTTP server and call it from any language. It has its own compact API (not OpenAI-shaped).
# Listening on http://localhost:3000
| Method | Path | Description |
|---|---|---|
POST |
/v1/chat |
Chat completion (or streaming with stream: true) |
POST |
/v1/chat/stream |
Always-streaming SSE with typed events |
GET |
/v1/models |
List available models |
GET |
/health |
Health check |
Full API spec: api/openapi.yaml.
Python client
pip install llmshim gives you a Python wrapper that bundles the Rust binary, starts the proxy on first use, and stops it on exit — no server to manage.
# Keys can also come from env vars or `llmshim configure`.
=
Streaming:
Multi-model conversation — switch providers mid-chat, history carries over:
=
=
=
Tool use — pass tools in OpenAI Chat Completions format; llmshim translates to each provider's native format:
=
=
Reasoning / thinking:
=
# thinking content
# answer
Fallback chains — automatic failover across providers:
=
These capabilities (streaming, multi-model, tools, reasoning, fallback) are all provided by the Rust core, so they work identically from the Rust crate and the proxy — the Python snippets above are just the most concise way to show them.
Supported models
| Provider | Models | Reasoning visible |
|---|---|---|
| OpenAI | gpt-5.5, gpt-5.5-pro, gpt-5.4, gpt-5.4-pro, gpt-5.4-mini, gpt-5.4-nano |
Yes (summaries) |
| Anthropic | claude-opus-4-8, claude-sonnet-5, claude-opus-4-7, claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5-20251001 |
Yes (full thinking) |
| Google Gemini | gemini-3.5-flash, gemini-3.1-pro-preview, gemini-3.1-flash-lite-preview, gemini-3-flash-preview |
Yes (thought summaries) |
| xAI | grok-4.3, grok-4.20-multi-agent-beta-0309, grok-4.20-beta-0309-reasoning, grok-4.20-beta-0309-non-reasoning, grok-4-1-fast-reasoning, grok-4-1-fast-non-reasoning |
No (hidden) |
Use a bare model name (auto-detected by prefix) or an explicit provider/model string.
Docker
How it works
No canonical struct. Requests flow as serde_json::Value — each provider maps only what it understands. Adding a provider = implementing one trait with three methods.
llmshim::completion(router, request)
→ router.resolve("anthropic/claude-sonnet-4-6")
→ provider.transform_request(model, &value)
→ HTTP
→ provider.transform_response(model, body)
Key features
- Multi-model conversations — switch providers mid-chat, history carries over
- Reasoning/thinking — visible chain-of-thought from OpenAI, Anthropic, and Gemini
- Streaming — token-by-token, with thinking surfaced separately
- Tool use — Chat Completions format auto-translated to each provider
- Vision/images — send images in any format, auto-translated between providers
- Fallback chains — automatic failover across providers with exponential backoff
- Cross-provider translation — system messages, tool calls, and provider-specific fields all handled
Build & test