typesafe/lib.rs
1//! Rust client for the [TypeSafe AI](https://typesafe.ai) System One API.
2//!
3//! Send a `state` and a map of typed questions — [`Noul`] (yes/no probability), [`Choice`]
4//! (one of N labels) and [`Score`] (ordered levels) — and get typed answers back.
5//!
6//! Behaviour follows the official Python SDK (`typesafe-sdk`): the same environment variables,
7//! defaults, retry semantics, error classification and forward-compatible decoding.
8//!
9//! Enable the `blocking` feature for a synchronous client in [`blocking`], `reqwest-client`
10//! to supply your own `reqwest::Client`, and `derive` for `#[derive(Rubric)]`: a struct that
11//! describes the questions and receives the answers (see [`rubric`]).
12//!
13//! # Example
14//!
15//! With the `derive` feature, a struct is the rubric: each field is a question, and the answers
16//! come back into it, typed.
17//!
18//! ```no_run
19//! # #[cfg(feature = "derive")] {
20//! use typesafe::{ChoiceOf, Client, NoulAnswer, Rubric, RubricChoice, ScoreAnswer};
21//!
22//! #[derive(Rubric)]
23//! struct Triage {
24//! #[noul("The message conveys urgency")]
25//! is_urgent: NoulAnswer,
26//! #[choice("Which team should handle this")]
27//! department: ChoiceOf<Department>,
28//! #[score("How frustrated", levels = ["Calm", "Frustrated but civil", "Very angry"])]
29//! frustration: ScoreAnswer,
30//! }
31//!
32//! #[derive(Debug, RubricChoice)]
33//! enum Department {
34//! /// Payment or subscription issues
35//! Billing,
36//! /// Bugs or integration problems
37//! Technical,
38//! }
39//!
40//! # async fn run() -> typesafe::Result<()> {
41//! let client = Client::from_env()?; // TYPESAFE_API_KEY
42//! let triage = client
43//! .ask::<Triage>("I've been trying to connect Stripe for 3 days. Please help ASAP.")
44//! .await?;
45//! println!("route to {:?}", *triage.department);
46//! println!("urgent: {}", triage.is_urgent.is_yes(0.8));
47//! println!("frustration: {:.2}", triage.frustration.score);
48//! # Ok(()) }
49//! # }
50//! ```
51//!
52//! Without the derive, [`Client::system_one`] takes a [`Questions`] map built at runtime and
53//! returns a [`SystemOneResponse`] to look answers up in by name.
54#![cfg_attr(docsrs, feature(doc_cfg))]
55#![warn(missing_docs)]
56
57pub mod cassette;
58mod client;
59pub mod constants;
60pub mod error;
61pub mod question;
62pub mod response;
63pub mod retry;
64pub mod rubric;
65
66#[cfg(feature = "blocking")]
67#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
68pub mod blocking;
69
70pub use client::{Client, ClientBuilder, ListModelsRequest, Models, SystemOneRequest};
71pub use error::{ApiError, ApiErrorKind, Error, ResponseValidationError, Result};
72/// The HTTP status type of [`Error::status`], [`ApiError::status`], [`ResponseMeta::status`] and
73/// [`RetryPolicy::statuses`], with constants such as `StatusCode::TOO_MANY_REQUESTS`.
74pub use http::StatusCode;
75pub use question::{Choice, Noul, NoulCriteria, Question, Questions, Score};
76pub use response::{
77 Answer, AnswerKind, ChoiceAnswer, ListModelsResponse, ModelMetadata, NoulAnswer, ResponseMeta,
78 ScoreAnswer, SystemOneResponse, Usage,
79};
80pub use retry::RetryPolicy;
81pub use rubric::{AskRequest, ChoiceOf, Rubric, RubricChoice};
82/// `#[derive(Rubric)]` and `#[derive(RubricChoice)]` (feature `derive`); see [`rubric`].
83#[cfg(feature = "derive")]
84#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
85pub use typesafe_derive::{Rubric, RubricChoice};
86
87/// Re-exported so callers can build headers without adding a dependency.
88pub use http;
89/// Re-exported so callers can build structured instructions/state without adding a dependency.
90pub use serde_json::{self, json};
91
92/// Compiles the README's code samples as doctests (they are not part of the rendered docs). The
93/// quick start uses `#[derive(Rubric)]`, so they are checked with the `derive` feature on.
94#[cfg(all(doctest, feature = "derive"))]
95#[doc = include_str!("../README.md")]
96pub struct ReadmeDoctests;