chipp 0.1.0

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

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()
  • Session management: Automatic chatSessionId tracking for conversation continuity
  • 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
  • Production-ready: Comprehensive tests and documentation

Installation

Add this to your Cargo.toml:

[dependencies]
chipp = "0.1"
tokio = { version = "1", features = ["full"] }

Quick Start

use chipp::{ChippClient, ChippConfig, ChippMessage, ChippSession, MessageRole};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ChippConfig {
        api_key: std::env::var("CHIPP_API_KEY")?,
        base_url: "https://app.chipp.ai/api/v1".to_string(),
        model: "your-app-name-id".to_string(),
        timeout: Duration::from_secs(30),
        max_retries: 3,
        initial_retry_delay: Duration::from_millis(100),
        max_retry_delay: Duration::from_secs(10),
    };

    let client = ChippClient::new(config)?;
    let mut session = ChippSession::new();

    let messages = vec![ChippMessage {
        role: MessageRole::User,
        content: "Hello!".to_string(),
    }];

    let response = client.chat(&mut session, &messages).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 {
    role: MessageRole::User,
    content: "Remember this number: 42".to_string(),
}];
client.chat(&mut session, &messages1).await?;

// Second message (remembers context)
let messages2 = vec![ChippMessage {
    role: MessageRole::User,
    content: "What number did I tell you?".to_string(),
}];
let response = client.chat(&mut session, &messages2).await?;
// Response will mention "42"

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

pub struct ChippConfig {
    pub api_key: String,              // Your Chipp API key
    pub base_url: String,             // Default: "https://app.chipp.ai/api/v1"
    pub model: String,                // Your appNameId from Chipp dashboard
    pub timeout: Duration,            // Request timeout (default: 30s)
    pub max_retries: usize,           // Max retry attempts (default: 3)
    pub initial_retry_delay: Duration, // Initial backoff delay (default: 100ms)
    pub max_retry_delay: Duration,    // Max backoff delay (default: 10s)
}

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

Important Notes

Streaming Format

⚠️ The actual Chipp API streaming format differs from the official documentation!

  • Documentation shows: Standard SSE with data: prefix and OpenAI-compatible JSON chunks
  • Actual API returns: Custom format with prefixes like 0:, e:, d:, f:, 8:

This client handles the actual format automatically - you don't need to worry about the format differences.

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