Skip to content
This repository was archived by the owner on Sep 9, 2026. It is now read-only.
thesimonharmsPublic archive

About

MOVED to https://git.simonharms.com/thesimonharms/baochuan — A multi-provider AI API client for Rust — connecting your code to every major AI provider.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Moved. This GitHub copy is an archive. Use the Forgejo repository.

Canonical repository: https://git.simonharms.com/thesimonharms/baochuan

baochuan · 宝船

A multi-provider AI API client for Rust.

Crates.io docs.rs License: MIT


The Name

"宝船" (Bǎochuán) — Treasure Ship

In the early 15th century, Admiral Zheng He commanded the largest wooden fleet the world had ever seen. His colossal treasure ships — some reportedly over 400 feet long — sailed from China to the Persian Gulf, East Africa, and beyond, connecting civilizations that had never met. They carried silk, porcelain, and ideas across the Indian Ocean, opening the world to each other.

baochuan aspires to the same role: a vessel that carries your Rust code to every major AI provider through a single unified interface, regardless of where those providers sail.

The sister library ZhengHe does the same for Java — named after the explorer who famously introduced China to Java (the island). ZhengHe connects Java to the DeepSeek API; baochuan carries the voyage forward in Rust, with a whole fleet of providers.


Features

  • Fully async — built on tokio and reqwest
  • Multi-provider — swap providers without changing your business logic
  • Streaming — native SSE streaming support for real-time token delivery
  • Builder pattern — ergonomic, validated request construction
  • Own implementation — no third-party SDK wrappers; direct HTTP to each provider
  • Extensible — implement the Provider trait to add any model provider
  • Agent runtimes — optional AgentProvider trait for stateful agent APIs such as Hermes Agent
  • Reasoning support — thinking / reasoning_effort for DeepSeek V4, Kimi, and similar APIs
  • OpenAI-ready — max_tokens is remapped to max_completion_tokens for o-series models

Supported Providers

Provider Chat Streaming Model List API Env Var
OpenAI ✅ ✅ ✅ OpenAI Chat Completions OPENAI_API_KEY
Anthropic ✅ ✅ ✅ Anthropic Messages ANTHROPIC_API_KEY
Google Gemini ✅ ✅ ✅ Gemini generateContent GEMINI_API_KEY
xAI Grok ✅ ✅ ✅ OpenAI-compatible XAI_API_KEY
Mistral ✅ ✅ ✅ OpenAI-compatible MISTRAL_API_KEY
DeepSeek ✅ ✅ ✅ OpenAI-compatible DEEPSEEK_API_KEY
GitHub Copilot ✅ ✅ ✅ Copilot Chat Completions GITHUB_TOKEN
OpenRouter ✅ ✅ ✅ OpenAI-compatible OPENROUTER_API_KEY
Moonshot AI / Kimi ✅ ✅ ✅ OpenAI-compatible MOONSHOT_API_KEY
Perplexity ✅ ✅ ✅ Agent API /v1/agent PERPLEXITY_API_KEY
Nous Portal ✅ ✅ ✅ OpenAI-compatible NOUS_API_KEY
Alibaba Qwen ✅ ✅ ✅ DashScope compatible-mode DASHSCOPE_API_KEY
Groq ✅ ✅ ✅ OpenAI-compatible GROQ_API_KEY
Together AI ✅ ✅ ✅ OpenAI-compatible TOGETHER_API_KEY
Fireworks AI ✅ ✅ ✅ OpenAI-compatible FIREWORKS_API_KEY
Cerebras ✅ ✅ ✅ OpenAI-compatible CEREBRAS_API_KEY
SambaNova ✅ ✅ ✅ OpenAI-compatible SAMBANOVA_API_KEY
Zhipu AI / Z.ai (GLM) ✅ ✅ ✅ OpenAI-compatible ZHIPU_API_KEY
MiniMax ✅ ✅ ✅ OpenAI-compatible MINIMAX_API_KEY
Hugging Face ✅ ✅ ✅ OpenAI-compatible router HF_TOKEN
NVIDIA NIM ✅ ✅ ✅ OpenAI-compatible NVIDIA_API_KEY
DeepInfra ✅ ✅ ✅ OpenAI-compatible DEEPINFRA_API_KEY
Cloudflare Workers AI ✅ ✅ ✅ CF native /ai/run/ CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN
LM Studio ✅ ✅ ✅ LM Studio /api/v0/ (none)
Ollama ✅ ✅ ✅ Ollama /api/ (none)
llama.cpp ✅ ✅ ✅ llama-server /v1/ (none)
Hermes Agent API ✅ ✅ — Responses /v1/responses API_SERVER_KEY
More coming… — — — — —

Installation

Add baochuan to your Cargo.toml:

[dependencies]
baochuan = "0.3"
tokio = { version = "1", features = ["full"] }

Quickstart

DeepSeek

use baochuan::{providers::DeepSeekProvider, ChatMessage, ChatRequestBuilder, Provider, ThinkingConfig};

#[tokio::main]
async fn main() {
    let provider = DeepSeekProvider::new(
        std::env::var("DEEPSEEK_API_KEY").expect("DEEPSEEK_API_KEY not set"),
    );

    let request = ChatRequestBuilder::new("deepseek-v4-flash")
        .message(ChatMessage::user("Tell me about the treasure ships of Zheng He."))
        .thinking(ThinkingConfig::disabled())
        .max_tokens(512)
        .build()
        .unwrap();

    let response = provider.chat(&request).await.unwrap();
    println!("{}", response.content().unwrap_or("(no response)"));
}

Nous Portal

use baochuan::{providers::NousProvider, ChatMessage, ChatRequestBuilder, Provider};

#[tokio::main]
async fn main() {
    let provider = NousProvider::new(
        std::env::var("NOUS_API_KEY").expect("NOUS_API_KEY not set"),
    );

    let request = ChatRequestBuilder::new("Hermes-4-405B")
        .message(ChatMessage::user("Carry the Zheng He voyage onward."))
        .build()
        .unwrap();

    let response = provider.chat(&request).await.unwrap();
    println!("{}", response.content().unwrap_or("(no response)"));
}

OpenRouter

use baochuan::{providers::OpenRouterProvider, ChatMessage, ChatRequestBuilder, Provider};

#[tokio::main]
async fn main() {
    let provider = OpenRouterProvider::new(
        std::env::var("OPENROUTER_API_KEY").expect("OPENROUTER_API_KEY not set"),
    )
    .site_name("My App");

    // OpenRouter gives you access to hundreds of models:
    let request = ChatRequestBuilder::new("anthropic/claude-sonnet-4")
        .message(ChatMessage::user("What is the speed of light?"))
        .build()
        .unwrap();

    let response = provider.chat(&request).await.unwrap();
    println!("{}", response.content().unwrap_or("(no response)"));
}

Streaming

use baochuan::{providers::DeepSeekProvider, ChatMessage, ChatRequestBuilder, Provider};
use futures_util::StreamExt;

#[tokio::main]
async fn main() {
    let provider = DeepSeekProvider::new(
        std::env::var("DEEPSEEK_API_KEY").unwrap(),
    );

    let request = ChatRequestBuilder::new("deepseek-v4-flash")
        .message(ChatMessage::user("Write a haiku about Rust."))
        .build()
        .unwrap();

    let mut stream = provider.stream_chat(&request).await.unwrap();

    while let Some(chunk) = stream.next().await {
        let chunk = chunk.unwrap();
        if let Some(text) = chunk.delta_content() {
            print!("{text}");
        }
    }
    println!();
}

Provider-agnostic code

use baochuan::{ChatMessage, ChatRequestBuilder, Provider};

async fn ask(provider: &dyn Provider, model: &str, question: &str) -> String {
    let request = ChatRequestBuilder::new(model)
        .message(ChatMessage::user(question))
        .build()
        .unwrap();

    provider
        .chat(&request)
        .await
        .unwrap()
        .content()
        .unwrap_or("")
        .to_string()
}

AgentProvider for Hermes Agent

use baochuan::{providers::HermesAgentProvider, AgentProvider, AgentRunRequestBuilder};

#[tokio::main]
async fn main() {
    let provider = HermesAgentProvider::new(
        std::env::var("API_SERVER_KEY").expect("API_SERVER_KEY not set"),
    );

    let request = AgentRunRequestBuilder::new("hermes-agent", "What files are in my project?")
        .instructions("You are a helpful coding assistant.")
        .store(true)
        .build()
        .unwrap();

    let response = provider.run(&request).await.unwrap();
    println!("{}", response.output_text());
}

Conversation with System Prompt

use baochuan::{providers::DeepSeekProvider, ChatMessage, ChatRequestBuilder, Provider};

#[tokio::main]
async fn main() {
    let provider = DeepSeekProvider::new(std::env::var("DEEPSEEK_API_KEY").unwrap());

    let request = ChatRequestBuilder::new("deepseek-v4-flash")
        .message(ChatMessage::system("You are a concise assistant. Reply in one sentence."))
        .message(ChatMessage::user("What is baochuan?"))
        .temperature(0.7)
        .max_tokens(128)
        .build()
        .unwrap();

    let response = provider.chat(&request).await.unwrap();
    println!("{}", response.content().unwrap_or(""));
}

Adding a Provider

Implement the Provider trait for any HTTP-based AI API:

use async_trait::async_trait;
use baochuan::{
    BaochuanError, ChatRequest, ChatResponse, Provider,
    provider::ChunkStream,
};

pub struct MyProvider { /* ... */ }

#[async_trait]
impl Provider for MyProvider {
    fn name(&self) -> &str { "my-provider" }

    async fn chat(&self, request: &ChatRequest) -> Result<ChatResponse, BaochuanError> {
        todo!()
    }

    async fn stream_chat(&self, request: &ChatRequest) -> Result<ChunkStream, BaochuanError> {
        todo!()
    }
}

Security

  • Never hard‑code API keys. Always read them from environment variables or a secrets manager.
  • Use .gitignore to exclude .env files from version control.
  • Rotate keys immediately if you suspect they have been exposed.
export DEEPSEEK_API_KEY="sk-..."
export OPENROUTER_API_KEY="sk-or-..."

License

MIT — see LICENSE.

About

MOVED to https://git.simonharms.com/thesimonharms/baochuan — A multi-provider AI API client for Rust — connecting your code to every major AI provider.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages