Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

typesafe-sdk-rs

Crates.io docs.rs CI

Community-maintained Rust SDK for the TypeSafe AI API.

This is not an official TypeSafe AI product. For official SDKs, see the TypeSafe SDKs page.

TypeSafe answers typed questions about text or structured state. Create a client, describe the questions you want answered, and read the typed answers.

Installation

[dependencies]
typesafe-sdk-rs = "0.1"

The library is imported as typesafe_sdk:

use typesafe_sdk::{Client, SystemOneRequest};

Quickstart

Set your API key as an environment variable:

export TYPESAFE_API_KEY="sk-..."
use typesafe_sdk::{Client, SystemOneRequest, noul, choice, score};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::from_env()?;

    let response = client
        .system_one(
            SystemOneRequest::new("I was charged twice. Please fix this ASAP.")
                .question("is_billing", noul("Is this about billing?"))
                .question(
                    "department",
                    choice(
                        "Which department should handle this?",
                        [
                            ("billing", Some(json!("Payments"))),
                            ("technical", Some(json!("Bugs"))),
                            ("support", None::<serde_json::Value>),
                        ],
                    ),
                )
                .question(
                    "frustration",
                    score(
                        "How frustrated is the customer?",
                        [
                            Some(json!("Calm")),
                            Some(json!("Frustrated")),
                            Some(json!("Very angry")),
                        ],
                    ),
                ),
        )
        .await?;

    // Yes/no answers
    for (name, a) in response.nouls() {
        println!("{name}: noul = {:.2}", a.noul);
    }

    // Choice answers
    for (name, a) in response.choices() {
        println!("{name}: choice = {}, confidence = {:.2}", a.choice, a.confidence);
    }

    // Score answers
    for (name, a) in response.scores() {
        println!("{name}: score = {:.2}, confidence = {:.2}", a.score, a.confidence);
    }

    Ok(())
}

Question Types

Noul (yes/no)

use typesafe_sdk::{noul, noul_with_criteria, NoulCriteria};
use serde_json::json;

// Simple yes/no
let q = noul("Is this about billing?");

// With criteria descriptions
let q = noul_with_criteria(
    "Is this urgent?",
    NoulCriteria {
        r#true: Some(json!("Action required within 24 hours")),
        r#false: Some(json!("No immediate action needed")),
    },
);

Choice

use typesafe_sdk::choice;
use serde_json::json;

let q = choice(
    "Which department?",
    [
        ("billing", Some(json!("Payments and invoicing"))),
        ("technical", Some(json!("Bugs and outages"))),
        ("support", None::<serde_json::Value>), // undescribed label
    ],
);

Score

use typesafe_sdk::score;
use serde_json::json;

// At least two rubric levels are required
let q = score(
    "How frustrated is the customer?",
    [
        Some(json!("Calm")),
        Some(json!("Frustrated")),
        Some(json!("Very angry")),
    ],
);

Configuration

use std::time::Duration;
use typesafe_sdk::{ClientBuilder, RetryPolicy};

let client = ClientBuilder::new("sk-...")
    .base_url("https://custom.api.example.com")
    .default_model("jev-1.13.0")
    .timeout(Duration::from_secs(30))
    .retry(RetryPolicy {
        max_retries: 3,
        ..Default::default()
    })
    .build()?;

Environment Variables

Variable Description Default
TYPESAFE_API_KEY API key (required)
TYPESAFE_BASE_URL API root URL https://api.typesafe.ai
TYPESAFE_DEFAULT_MODEL Default model jev-latest
TYPESAFE_LOG_LEVEL Log verbosity (debug, info, warn, error, off) warn

Configuration priority: explicit builder settings > environment variables > SDK defaults.

Error Handling

use typesafe_sdk::Error;

match client.system_one(req).await {
    Ok(response) => { /* use response */ }
    Err(Error::Api(err)) => {
        eprintln!("API error {}: {}", err.status, err.message);
        if err.is_rate_limit() {
            eprintln!("Rate limited; retry after {:?}", err.retry_after());
        }
    }
    Err(Error::Connection(err)) => {
        eprintln!("Connection error: {}", err);
    }
    Err(Error::Timeout(err)) => {
        eprintln!("Timeout after {:?}", err.timeout);
    }
    Err(Error::Response(err)) => {
        eprintln!("Invalid response ({}): {}", err.status, err.raw_body);
    }
    Err(Error::Config(msg)) => {
        eprintln!("Configuration error: {}", msg);
    }
}

Error Classification

Method Status
is_bad_request() 400
is_authentication() 401
is_permission_denied() 403
is_not_found() 404
is_unprocessable_entity() 422
is_rate_limit() 429
is_server_error() 500–599

Retry Configuration

use std::time::Duration;
use typesafe_sdk::RetryPolicy;

let policy = RetryPolicy {
    max_retries: 3,                         // default: 2
    backoff_initial: Duration::from_secs(1),// default: 500ms
    backoff_max: Duration::from_secs(10),   // default: 5s
    backoff_jitter: 0.5,                    // default: 0.25
    respect_retry_after: true,              // default: true
    max_retry_after: Duration::from_secs(30), // default: 60s
    retry_connection_errors: true,          // default: true
    retry_timeout_errors: true,             // default: true
    ..Default::default()
};

The client retries 408, 429, and 5xx responses by default. Server retry delays from retry-after-ms or Retry-After headers are honored up to max_retry_after.

Forward Compatibility

Unknown answer types returned by a future API are preserved as Answer::Unknown(UnknownAnswer { kind, raw }), so your code doesn't break when new answer types are added.

Logging

Set TYPESAFE_LOG_LEVEL=debug to see request and response headers and bodies. Credential-bearing headers (Authorization, Cookie, etc.) are redacted.

use typesafe_sdk::ClientBuilder;
use typesafe_sdk::logging::LogLevel;

let client = ClientBuilder::new("sk-...")
    .log_level(LogLevel::Debug)
    .build()?;

The SDK uses the tracing crate. If you don't set up a subscriber, log output is silently discarded.

License

MIT. See LICENSE.

About

Rust SDK for the TypeSafe AI API: typed questions in, structured answers out. Published on crates.io as typesafe-sdk-rs.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages