cogito_claude/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2025 Michael Dippery <michael@monkey-robot.com>
3
4//! An implementation of a client for Anthropic's Claude API.
5//!
6//! This provider implements traits from [cogito] to provide a uniform way
7//! to access Anthropic's Claude API. This makes it easy to swap out other
8//! providers for Anthropic's Claude in your application, or vice versa.
9//!
10//! This library assumes you pass authentication tokens for the Anthropic API
11//! using [`cogito::service::Auth`]. **This means that you are solely
12//! responsible for paying the costs of API access; the Cogito developers
13//! are not responsible for costs you incur while using this library.**
14//!
15//! # Cost
16//!
17//! There's no such thing as a free lunch, and there's no such thing as free
18//! Claude access. When you create a Claude API client, you will need to
19//! select a [`ClaudeModel`]. Models are billed on a per-token basis, where
20//! a token is the smallest unit of text that the model reads and processes.
21//! There are two types of tokens: input tokens and output tokens.
22//!
23//! - **Input tokens** are the token used in any _requests_ made to the
24//!   Claude AI. This is the "prompt" that users of this library send to
25//!   Claude for summarization.
26//! - **Output tokens** are tokens generated in the output that is sent back
27//!   to a client in response to a request.
28//!
29//! Prices are expressed in US dollars per $1 million tokens. As of
30//! 25 November 2025, the prices for each model are as follows.
31//!
32//! For the latest pricing, see the [pricing documentation] in the Claude
33//! platform documentation.
34//!
35//! | Model      | Designation       | Input | Output |
36//! |------------|-------------------|------:|-------:|
37//! | Sonnet 4.5 | claude-sonnet-4-5 | $3    | $15    |
38//! | Haiku 4.5  | claude-haiku-4-5  | $1    | $5     |
39//! | Opus 4.5   | claude-opus-4-5   | $5    | $25    |
40//! | Opus 4.1   | claude-opus-4-1   | $15   | $75    |
41//!
42//! [`cogito::service::Auth`]: https://docs.rs/cogito/latest/cogito/service/struct.Auth.html
43//! [pricing documentation]: https://platform.claude.com/docs/en/about-claude/pricing
44
45pub mod client;
46pub mod service;
47
48use cogito::AiModel;
49use serde::{Deserialize, Serialize};
50use std::fmt;
51
52/// Available Claude AI models.
53///
54/// For more information on the differences between each model, see the
55/// [model overview] in the Claude platform documentation.
56///
57/// The [default model] is [Sonnet 4.5], which Anthropic describes as "our
58/// smartest model for complex agents and coding". The cheapest and fastest
59/// model, [Haiku 4.5], is the "fastest model with near-frontier intelligence".
60/// [Opus 4.5] is a "premium model combining maximum intelligence with
61/// practical performance", and [Opus 4.1] is an "exceptional model for
62/// specialized reasoning tasks" (and also the most expensive!).
63///
64/// # Cost
65///
66/// Claude API usage has a cost, and the cost of each model differs; naturally,
67/// the more powerful models cost more to use. See the [cost breakdown] in the
68/// `cogito_claude` module documentation for more details, or visit Anthropic's
69/// [pricing] documentation for the latest prices.
70///
71/// [cost breakdown]: self#Cost
72/// [default model]: ClaudeModel::default()
73/// [model overview]: https://platform.claude.com/docs/en/about-claude/models/overview
74/// [pricing]: https://platform.claude.com/docs/en/about-claude/pricing
75/// [Haiku 4.5]: ClaudeModel::Haiku45
76/// [Opus 4.1]: ClaudeModel::Opus41
77/// [Opus 4.5]: ClaudeModel::Opus45
78/// [Sonnet 4.5]: ClaudeModel::Sonnet45
79#[derive(Clone, Copy, Debug, Default, PartialEq, Deserialize, Serialize)]
80pub enum ClaudeModel {
81    /// Anthropic's flagship model.
82    ///
83    /// According to Anthropic, this model is "our smartest model for
84    /// complex agents and coding".
85    #[default]
86    #[serde(rename = "claude-sonnet-4-5")]
87    Sonnet45,
88
89    /// Anthropic's fastest and cheapest model.
90    ///
91    /// According to Anthropic, this model is "our fastest model with
92    /// near-frontier intelligence".
93    #[serde(rename = "claude-haiku-4-5")]
94    Haiku45,
95
96    /// A premium model.
97    ///
98    /// This model "combines maximum intelligence with practical performance".
99    #[serde(rename = "claude-opus-4-5")]
100    Opus45,
101
102    /// An expensive, premium model.
103    ///
104    /// According to Anthropic, an "exceptional model for specialize
105    /// reasoning tasks".
106    #[serde(rename = "claude-opus-4-1")]
107    Opus41,
108}
109
110impl AiModel for ClaudeModel {
111    /// Anthropic's standard model.
112    fn flagship() -> Self {
113        ClaudeModel::default()
114    }
115
116    /// The "best" model as defined by Anthropic.
117    fn best() -> Self {
118        ClaudeModel::default()
119    }
120
121    /// Anthropic's cheapest model.
122    fn cheapest() -> Self {
123        ClaudeModel::Haiku45
124    }
125
126    /// Anthropic's fastest model.
127    fn fastest() -> Self {
128        ClaudeModel::Haiku45
129    }
130}
131
132impl fmt::Display for ClaudeModel {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        let s = serde_json::to_string(&self)
135            .unwrap_or_else(|_| panic!("could not serialize {:?}", self));
136        let s = s.trim_matches('"');
137        f.write_fmt(format_args!("{}", s))
138    }
139}
140
141/// Convenience module for splat imports.
142///
143/// To import the most common data structures and traits from this crate,
144/// add
145///
146/// ```
147/// use cogito_claude::prelude::*;
148/// ```
149///
150/// in your project.
151pub mod prelude {
152    pub use crate::ClaudeModel;
153    pub use crate::client::{ClaudeClient, ClaudeRequest, ClaudeResponse};
154    pub use crate::service::ClaudeService;
155    pub use cogito::AiModel;
156    pub use cogito::client::{AiClient, AiRequest, AiResponse};
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    #[test]
164    fn it_returns_a_valid_display_string() {
165        let test_cases = vec![
166            (ClaudeModel::Sonnet45, "claude-sonnet-4-5"),
167            (ClaudeModel::Haiku45, "claude-haiku-4-5"),
168            (ClaudeModel::Opus45, "claude-opus-4-5"),
169            (ClaudeModel::Opus41, "claude-opus-4-1"),
170        ];
171
172        for (model, descriptor) in test_cases {
173            assert_eq!(model.to_string(), descriptor, "ClaudeModel::{:?}", model);
174        }
175    }
176}