chipp

Crates.iochipp
lib.rschipp
version0.3.0
created_at2025-12-05 00:09:14.224839+00
updated_at2025-12-08 23:48:41.628609+00
descriptionRust client for the Chipp.ai API - OpenAI-compatible chat completions with streaming support
homepagehttps://chipp.ai
repositoryhttps://github.com/paulbreuler/chipp-rs
max_upload_size
id1967358
size401,982
Paul Breuler (paulbreuler)

documentation

https://docs.rs/chipp

README

chipp

Crates.io docs.rs License CI MSRV Downloads

Rust client for the Chipp.ai API - OpenAI-compatible chat completions with streaming support.

Features

  • Non-streaming chat: Simple request/response with chat()
  • Streaming chat: Real-time text streaming with chat_stream()
  • Latency measurement: API connectivity testing with ping()
  • Session management: Automatic chatSessionId tracking for conversation continuity
  • Automatic retries: Exponential backoff for transient failures
  • Configurable timeouts: Per-request timeout configuration
  • Correlation IDs: Automatic UUID generation for request tracing
  • Comprehensive error handling: Typed errors with context
  • Full async/await: Built on tokio and reqwest
  • Security-first: API keys redacted from Debug output

Installation

Add 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

Quick Start

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(())
}

Examples

Non-Streaming Chat

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);

Streaming Chat

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),
    }
}

Session Continuity

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"

Latency Measurement

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);
}

Token Usage Tracking

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 text
  • usage() - Token counts
  • session_id() - Chat session ID
  • completion_id() - Completion ID for debugging
  • created_at() - Unix timestamp
  • finish_reason() - Why completion stopped
  • model() - Model/app ID

Running Examples

Set 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

Configuration

Using the Builder Pattern (Recommended)

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()?;

Direct Struct Initialization

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 tab
  • model (required): Your appNameId from the Chipp dashboard
  • base_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)

Error Handling

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),
}

Security Best Practices

This SDK is designed with security in mind. Follow these best practices to protect your API credentials:

Never Hardcode API Keys

// ❌ 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()?;

Use Environment Variables

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"

Avoid Logging Configuration Objects

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");

Production Recommendations

  • Use a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.) for production deployments
  • Rotate API keys regularly and update your environment variables
  • Audit logs to ensure no sensitive data is accidentally logged
  • Use .gitignore to exclude .env files from version control

Testing

Unit Tests

cargo test

Integration Tests (requires API key)

export CHIPP_API_KEY="your-api-key"
export CHIPP_APP_NAME_ID="your-app-name-id"
cargo test --features integration-tests -- --ignored

Documentation

Full API documentation is available on docs.rs.

Build documentation locally:

cargo doc --open

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

  1. Clone the repository:

    git clone https://github.com/paulbreuler/chipp-rs.git
    cd chipp-rs
    
  2. Run tests:

    cargo test
    
  3. Run examples:

    export CHIPP_API_KEY="your-api-key"
    export CHIPP_APP_NAME_ID="your-app-name-id"
    cargo run --example simple
    

Code Quality

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

License

Licensed under either of:

at your option.

Contribution

Contributions are welcome! Please see CONTRIBUTING.md for guidelines on:

  • Setting up pre-commit hooks
  • Code quality standards
  • Testing requirements
  • Pull request process

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.

Links

Commit count: 0

cargo fmt