jev-sdk 0.1.0

Unofficial Rust client for the TypeSafe AI System One API (Jev): typed decisions with calibrated probabilities
Documentation
//! Support-ticket triage: route, score, and gate on urgency in one call.
//!
//! Run with:
//!
//! ```sh
//! TYPESAFE_API_KEY=apikey_... cargo run --example triage
//! ```

use jev_sdk::{Choice, Noul, Question, Score, TypeSafeClient};

#[tokio::main]
async fn main() -> Result<(), jev_sdk::Error> {
    let client = TypeSafeClient::from_env()?;

    let ticket = "Hi, I've been trying to connect my Stripe account for 3 days \
                  and it keeps failing. I'm losing sales. Please help ASAP.";

    let response = client
        .system_one(
            ticket,
            [
                (
                    "department",
                    Question::from(Choice::new(
                        "Which team should handle this",
                        [
                            ("billing", Some("Payment or subscription issues")),
                            ("technical", Some("Bugs or integration problems")),
                            ("sales", Some("Pricing or account questions")),
                        ],
                    )),
                ),
                (
                    "frustration",
                    Question::from(Score::new(
                        "How frustrated the customer appears",
                        [
                            "Calm, just stating facts",
                            "Frustrated but civil",
                            "Very angry, strong language",
                        ],
                    )),
                ),
                (
                    "is_urgent",
                    Question::from(Noul::new("The message conveys urgency or time-sensitivity")),
                ),
            ],
        )
        .await?;

    // Accessors return `Option` so a missing or mistyped answer can never
    // panic: surface it as an ordinary error instead.
    let missing = |id: &str| jev_sdk::Error::Decode(format!("missing answer for {id:?}"));
    let department = response
        .choice("department")
        .ok_or_else(|| missing("department"))?;
    let frustration = response
        .score("frustration")
        .ok_or_else(|| missing("frustration"))?;
    let urgency = response
        .noul("is_urgent")
        .ok_or_else(|| missing("is_urgent"))?;

    println!("model:        {}", response.model);
    println!(
        "department:   {} (confidence {:.2})",
        department.choice, department.confidence
    );
    for (option, p) in &department.probabilities {
        println!("    {option:<10} {p:.3}");
    }
    println!(
        "frustration:  {:.2} / 2 (confidence {:.2})",
        frustration.score, frustration.confidence
    );
    println!("urgency:      {:.3}", urgency.noul);

    // Confidence-gated automation: act autonomously only when sure.
    if department.confidence >= 0.8 {
        println!("\n-> auto-routing to {}", department.choice);
    } else {
        println!("\n-> low confidence; queuing for human review");
    }

    println!(
        "usage:        {} input tokens, {} output tokens",
        response.usage.input_tokens, response.usage.output_tokens
    );

    Ok(())
}