| Crates.io | chipp |
| lib.rs | chipp |
| version | 0.3.0 |
| created_at | 2025-12-05 00:09:14.224839+00 |
| updated_at | 2025-12-08 23:48:41.628609+00 |
| description | Rust client for the Chipp.ai API - OpenAI-compatible chat completions with streaming support |
| homepage | https://chipp.ai |
| repository | https://github.com/paulbreuler/chipp-rs |
| max_upload_size | |
| id | 1967358 |
| size | 401,982 |
Rust client for the Chipp.ai API - OpenAI-compatible chat completions with streaming support.
chat()chat_stream()ping()chatSessionId tracking for conversation continuitytokio and reqwestAdd this to your Cargo.toml:
[dependencies]
chipp = "0.1.1" # x-release-please-version
tokio = { version = "1", features = ["full"] }
Or install via cargo:
cargo add chipp tokio --features tokio/full
use chipp::{ChippClient, ChippConfig, ChippMessage, ChippSession};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Use the builder pattern for ergonomic configuration
let config = ChippConfig::builder()
.api_key(std::env::var("CHIPP_API_KEY")?)
.model(std::env::var("CHIPP_APP_NAME_ID")?)
.build()?;
let client = ChippClient::new(config)?;
let mut session = ChippSession::new();
let response = client
.chat(&mut session, &[ChippMessage::user("Hello!")])
.await?;
println!("Response: {}", response);
Ok(())
}
use chipp::{ChippClient, ChippConfig, ChippMessage, ChippSession, MessageRole};
let client = ChippClient::new(config)?;
let mut session = ChippSession::new();
let messages = vec![ChippMessage {
role: MessageRole::User,
content: "Tell me a joke".to_string(),
}];
let response = client.chat(&mut session, &messages).await?;
println!("{}", response);
use chipp::{ChippClient, ChippMessage, MessageRole};
use futures::StreamExt;
let mut stream = client.chat_stream(&mut session, &messages).await?;
while let Some(chunk) = stream.next().await {
match chunk {
Ok(text) => print!("{}", text),
Err(e) => eprintln!("Error: {}", e),
}
}
The client automatically manages chatSessionId for conversation continuity:
// First message
let messages1 = vec![ChippMessage::user("Remember this number: 42")];
client.chat(&mut session, &messages1).await?;
// Second message (remembers context)
let messages2 = vec![ChippMessage::user("What number did I tell you?")];
let response = client.chat(&mut session, &messages2).await?;
// Response will mention "42"
Measure API latency for performance monitoring:
use std::time::Duration;
// Measure API latency
let latency = client.ping().await?;
if latency < Duration::from_secs(2) {
println!("Low latency: {:?}", latency);
}
Use chat_detailed() to get token counts for rate limiting:
use chipp::{ChippClient, ChippConfig, ChippMessage, ChippSession};
let client = ChippClient::new(config)?;
let mut session = ChippSession::new();
let response = client
.chat_detailed(&mut session, &[ChippMessage::user("Hello!")])
.await?;
println!("Response: {}", response.content());
println!("Prompt tokens: {}", response.usage().prompt_tokens);
println!("Completion tokens: {}", response.usage().completion_tokens);
println!("Total tokens: {}", response.usage().total_tokens);
ChatResponse accessors:
content() - Response textusage() - Token countssession_id() - Chat session IDcompletion_id() - Completion ID for debuggingcreated_at() - Unix timestampfinish_reason() - Why completion stoppedmodel() - Model/app IDSet your API credentials:
export CHIPP_API_KEY="your-api-key"
export CHIPP_APP_NAME_ID="your-app-name-id"
Run the examples:
# Simple non-streaming example
cargo run --example simple
# Streaming example
cargo run --example streaming
# Session continuity example
cargo run --example session
# Error handling example (demonstrates retry logic, fallback strategies, etc.)
cargo run --example error_handling
use chipp::ChippConfig;
let config = ChippConfig::builder()
.api_key("YOUR_API_KEY_HERE")
.model("your-app-name-id")
.timeout(std::time::Duration::from_secs(60)) // Optional: default is 30s
.max_retries(5) // Optional: default is 3
.build()?;
use chipp::ChippConfig;
use std::time::Duration;
let config = ChippConfig {
api_key: "YOUR_API_KEY_HERE".to_string(),
model: "your-app-name-id".to_string(),
base_url: "https://app.chipp.ai/api/v1".to_string(), // Default
timeout: Duration::from_secs(30), // Default
max_retries: 3, // Default
initial_retry_delay: Duration::from_millis(100), // Default
max_retry_delay: Duration::from_secs(10), // Default
};
Configuration Options:
api_key (required): Your Chipp API key from the Share → API tabmodel (required): Your appNameId from the Chipp dashboardbase_url: API endpoint (default: https://app.chipp.ai/api/v1)timeout: Request timeout (default: 30 seconds)max_retries: Maximum retry attempts for transient failures (default: 3)initial_retry_delay: Initial backoff delay (default: 100ms)max_retry_delay: Maximum backoff delay (default: 10 seconds)use chipp::ChippClientError;
match client.chat(&mut session, &messages).await {
Ok(response) => println!("Success: {}", response),
Err(ChippClientError::ApiError { status, message }) => {
eprintln!("API error {}: {}", status, message);
}
Err(ChippClientError::HttpError(e)) => {
eprintln!("Network error: {}", e);
}
Err(e) => eprintln!("Other error: {}", e),
}
This SDK is designed with security in mind. Follow these best practices to protect your API credentials:
// ❌ BAD: Hardcoded API key
let config = ChippConfig::builder()
.api_key("live_abc123...") // NEVER do this!
.build()?;
// ✅ GOOD: Load from environment variable
let config = ChippConfig::builder()
.api_key(std::env::var("CHIPP_API_KEY")?)
.build()?;
Store credentials in environment variables, not in source code or config files:
# Set in your shell or .env file (which is gitignored)
export CHIPP_API_KEY="your-api-key"
export CHIPP_APP_NAME_ID="your-app-id"
The ChippConfig struct implements a custom Debug trait that redacts the API key:
let config = ChippConfig::builder()
.api_key("secret-key")
.model("my-app")
.build()?;
// Safe to log - API key is redacted
println!("{:?}", config);
// Output: ChippConfig { api_key: "[REDACTED]", base_url: "...", model: "my-app", ... }
However, avoid logging raw API key strings directly:
// ❌ BAD: Logging the raw API key
let api_key = std::env::var("CHIPP_API_KEY")?;
tracing::debug!("Using API key: {}", api_key); // NEVER do this!
// ✅ GOOD: Log without exposing secrets
tracing::info!("Initializing Chipp client");
.gitignore to exclude .env files from version controlcargo test
export CHIPP_API_KEY="your-api-key"
export CHIPP_APP_NAME_ID="your-app-name-id"
cargo test --features integration-tests -- --ignored
Full API documentation is available on docs.rs.
Build documentation locally:
cargo doc --open
Contributions are welcome! Please feel free to submit a Pull Request.
Clone the repository:
git clone https://github.com/paulbreuler/chipp-rs.git
cd chipp-rs
Run tests:
cargo test
Run examples:
export CHIPP_API_KEY="your-api-key"
export CHIPP_APP_NAME_ID="your-app-name-id"
cargo run --example simple
Before submitting a PR, please ensure:
# Format code
cargo fmt
# Run clippy
cargo clippy -- -D warnings
# Run tests
cargo test
# Build docs
cargo doc --no-deps
Licensed under either of:
at your option.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines on:
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.