cogito_openai/
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 the OpenAI API.
5//!
6//! This provider implements various traits from [cogito] to provide a uniform
7//! way to access the OpenAI API. This makes it easy to swap out other
8//! providers for OpenAI in your application, or vice versa.
9//!
10//! This library assumes you pass authentication tokens for the OpenAI 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 OpenAI access,
18//! even if OpenAI is a "non-profit" that is building its technology for the betterment of
19//! humanity (and not Sam Altman's bank account). When you create an OpenAI API client,
20//! you will need to select an [`OpenAIModel`]. Models are billed on a per-token basis, where
21//! a token is the smallest unit of text that the model reads and processes. There are three
22//! types of tokens: input tokens, cached input tokens, and output tokens.
23//!
24//! - **Input tokens** are the token used in any _requests_ made to the OpenAPI AI. This is
25//!   the "prompt" that users of this library send to OpenAI for summarization.
26//! - **Cached input tokens** are input tokens that have been reused by GPT. Input tokens are
27//!   reused by prompts that have a common prefix, as described
28//!   [here](https://openai.com/index/api-prompt-caching/).
29//! - **Output tokens** are tokens generated in the output that is sent back to a client in
30//!   response to a request.
31//!
32//! Prices are expressed in US dollars per $1 million tokens. As of 17 July 2025, the prices
33//! for each model are as follows.
34//!
35//! For the latest pricing, see OpenAI's [pricing][OpenAI's platform pricing documentation]
36//! docs.
37//!
38//! | Model      | Designation        | Input    | Cached Input | Output  |
39//! |------------|--------------------|---------:|-------------:|--------:|
40//! | Gpt5       | gpt-5              | $1.25    | $0.125       | $10.00  |
41//! | Gpt5mini   | gpt-5-mini         | $0.25    | $0.025       | $2.00   |
42//! | Gpt5nano   | gpt-5-nano         | $0.05    | $0.005       | $0.40   |
43//! | Gpt4_1nano | gpt-4.1-nano       | $0.10    | $0.025       | $0.40   |
44//! | Gpt4omini  | gpt-4o-mini        | $0.15    | $0.075       | $0.60   |
45//! | Gpt4_1mini | gpt-4.1-mini       | $0.40    | $0.10        | $1.60   |
46//! | O4mini     | o4-mini            | $1.10    | $0.275       | $4.40   |
47//! | O3mini     | o3-mini            | $1.10    | $0.55        | $4.40   |
48//! | Gpt4_1     | gpt-4.1            | $2.00    | $0.50        | $8.00   |
49//! | O3         | o3                 | $2.00    | $0.50        | $8.00   |
50//! | Gpt4o      | gpt-4o             | $2.50    | $1.25        | $10.00  |
51//! | ChatGpt4o  | chatgpt-4o-latest  | $5.00    | -            | $15.00  |
52//! | O1         | o1                 | $15.00   | $7.50        | $60.00  |
53//! | O3pro      | o3-pro             | $20.00   | -            | $80.00  |
54//! | 01pro      | o1-pro             | $150.00  | -            | $600.00 |
55//!
56//! [cogito]: https://docs.rs/cogito
57//! [`OpenAIClient::new()`]: client::OpenAIClient::new
58//! [`cogito::service::Auth`]: https://docs.rs/cogito/latest/cogito/service/struct.Auth.html
59//! [OpenAI's platform pricing documentation]: https://platform.openai.com/docs/pricing
60
61pub mod client;
62
63use cogito::AiModel;
64use serde::{Deserialize, Serialize};
65use std::fmt;
66
67/// Available OpenAI GPT models.
68///
69/// For more information on the differences between each model, see the
70/// [OpenAI model documentation].
71///
72/// The [default](OpenAIModel::default()) is [gpt-4o](OpenAIModel::Gpt4o),
73/// which OpenAI describes as "the best model to use for most tasks".
74/// [According to its docs][1], [gpt-4.1](OpenAIModel::Gpt4_1) "offers a solid
75/// combination of intelligence, speed, and cost effectiveness". If you are on
76/// a budget, consider using [gpt-4.1-nano](OpenAIModel::Gpt4_1nano), the
77/// [least expensive](OpenAIModel::cheapest()) model.
78///
79/// # Cost
80///
81/// OpenAI API usage has a cost, and the cost of each model differs;
82/// naturally, the more powerful models cost more to use. See the
83/// [cost breakdown] in the `cogito_openai` module documentation
84/// for more details, or visit OpenAI's [pricing] docs for the latest prices.
85///
86/// [1]: https://platform.openai.com/docs/guides/text?api-mode=responses#choosing-a-model
87/// [cost breakdown]: self#Cost
88/// [OpenAI model documentation]: https://platform.openai.com/docs/models
89/// [pricing]: https://platform.openai.com/docs/pricing
90#[derive(Clone, Copy, Debug, Default, PartialEq, Deserialize, Serialize)]
91pub enum OpenAIModel {
92    /// OpenAI's flagship model for coding, reasoning, and agentic tasks
93    /// across domains.
94    #[default]
95    #[serde(rename = "gpt-5")]
96    Gpt5,
97
98    /// A faster, more cost-efficient version of [`GPT-5`](OpenAIModel::Gpt5).
99    ///
100    /// It's great for well-defined tasks and precise prompts.
101    #[serde(rename = "gpt-5-mini")]
102    Gpt5mini,
103
104    /// Fastest, cheapest version of [`GPT-5`](OpenAIModel::Gpt5).
105    ///
106    /// It's great for summarization and classification tasks.
107    #[serde(rename = "gpt-5-nano")]
108    Gpt5nano,
109
110    /// Versatile, high-intelligence flagship model.
111    #[serde(rename = "gpt-4o")]
112    Gpt4o,
113
114    /// A fast, affordable model for focused tasks.
115    #[serde(rename = "gpt-4o-mini")]
116    Gpt4omini,
117
118    /// The flagship model for complex tasks.
119    ///
120    /// It is well-suited for problem-solving across domains.
121    #[serde(rename = "gpt-4.1")]
122    Gpt4_1,
123
124    /// Provides a balance between intelligence, speed, and cost.
125    ///
126    /// An attractive model for many use cases.
127    #[serde(rename = "gpt-4.1-mini")]
128    Gpt4_1mini,
129
130    /// The fastest, most cost-effective 4.1 model.
131    #[serde(rename = "gpt-4.1-nano")]
132    Gpt4_1nano,
133
134    /// Optimized for fast, effective reasoning with exceptionally efficient
135    /// performance in coding and visual tasks.
136    #[serde(rename = "o4-mini")]
137    O4mini,
138
139    /// A well-rounded and powerful reasoning model across domains.
140    ///
141    /// It sets a new standard for math, science, coding, and visual
142    /// reasoning tasks, and excels at technical writing and following
143    /// instructions.
144    #[serde(rename = "o3")]
145    O3,
146
147    /// A mini version of the o3 model, providing high intelligence with
148    /// the same cost and latency targets of o1-mini.
149    #[serde(rename = "o3-mini")]
150    O3mini,
151
152    /// Like the o3 model, but it uses more compute to think even harder.
153    #[serde(rename = "o3-pro")]
154    O3pro,
155
156    /// A model trained with reinforcement learning that thinks before it
157    /// answers and produces a long chain of thought before responding to
158    /// the user.
159    #[serde(rename = "o1")]
160    O1,
161
162    /// A version of the [`o1`](OpenAIModel::O1) model that thinks even harder
163    /// before responding.
164    #[serde(rename = "o1-pro")]
165    O1pro,
166}
167
168impl AiModel for OpenAIModel {
169    /// OpenAI's standard model.
170    fn flagship() -> Self {
171        OpenAIModel::default()
172    }
173
174    /// The "best" GPT model as defined by OpenAI.
175    fn best() -> Self {
176        OpenAIModel::default()
177    }
178
179    fn cheapest() -> Self {
180        OpenAIModel::Gpt5nano
181    }
182
183    fn fastest() -> Self {
184        // GPT 4.1-nano is noticeably faster than GPT 5-nano.
185        OpenAIModel::Gpt4_1nano
186    }
187}
188
189impl fmt::Display for OpenAIModel {
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        let s = serde_json::to_string(&self)
192            .unwrap_or_else(|_| panic!("could not serialize {:?}", self));
193        let s = s.trim_matches('"');
194        f.write_fmt(format_args!("{}", s))
195    }
196}
197
198/// Convenience module for splat imports.
199///
200/// You can import the most common traits and data structures into your
201/// project using
202///
203/// ```
204/// use cogito_openai::prelude::*;
205/// ```
206pub mod prelude {
207    pub use crate::OpenAIModel;
208    pub use crate::client::{OpenAIClient, OpenAIRequest, OpenAIResponse};
209    pub use cogito::AiModel;
210    pub use cogito::client::{AiClient, AiRequest, AiResponse};
211    pub use cogito::service::Service;
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217
218    #[test]
219    fn it_returns_a_valid_display_string() {
220        let test_cases = vec![
221            (OpenAIModel::Gpt5, "gpt-5"),
222            (OpenAIModel::Gpt5mini, "gpt-5-mini"),
223            (OpenAIModel::Gpt5nano, "gpt-5-nano"),
224            (OpenAIModel::Gpt4o, "gpt-4o"),
225            (OpenAIModel::Gpt4omini, "gpt-4o-mini"),
226            (OpenAIModel::Gpt4_1, "gpt-4.1"),
227            (OpenAIModel::Gpt4_1mini, "gpt-4.1-mini"),
228            (OpenAIModel::Gpt4_1nano, "gpt-4.1-nano"),
229            (OpenAIModel::O4mini, "o4-mini"),
230            (OpenAIModel::O3, "o3"),
231            (OpenAIModel::O3mini, "o3-mini"),
232            (OpenAIModel::O3pro, "o3-pro"),
233            (OpenAIModel::O1, "o1"),
234            (OpenAIModel::O1pro, "o1-pro"),
235        ];
236
237        for (model, descriptor) in test_cases {
238            assert_eq!(model.to_string(), descriptor, "OpenAIModel::{:?}", model);
239        }
240    }
241}