kind_openai/endpoints/
chat_reasoning.rs

1use std::{borrow::Cow, collections::HashMap};
2
3use bon::{builder, Builder};
4use reqwest::Method;
5use serde::{Deserialize, Serialize};
6
7use super::OpenAIRequestProvider;
8
9/// The model to use to create a chat reasoning completion.
10#[derive(Serialize, Clone, Copy, Debug)]
11#[allow(non_camel_case_types)]
12pub enum ReasoningModel {
13    #[serde(rename = "o1-preview")]
14    O1Preview,
15    #[serde(rename = "o1-mini")]
16    O1Mini,
17    #[serde(rename = "o1-mini-2024-09-12")]
18    O1Mini_2024_09_12,
19    #[serde(rename = "o1")]
20    O1,
21    #[serde(rename = "o1-2024-12-17")]
22    O1_2024_12_17,
23    #[serde(rename = "o3-mini")]
24    O3Mini,
25    #[serde(rename = "o3-mini-2025-01-31")]
26    O3Mini_2025_01_31,
27}
28
29/// The role in the reasoning completion message (currently doesn't support system messages).
30#[derive(Serialize, Debug, Deserialize, Clone, Copy)]
31#[serde(rename_all = "snake_case")]
32pub enum Role {
33    /// The user message, containing the instructions for the model _and_ the payload to be used.
34    User,
35    /// The assistant message, containing the model's response.
36    Assistant,
37    /// The developer message which provides instructions to the model to follow.
38    Developer,
39}
40
41/// The amount of effort the model puts into the reasoning. This is essentially the length of the reasoning tokens.
42/// Default is medium.
43#[derive(Serialize, Debug, Clone, Copy)]
44#[serde(rename_all = "snake_case")]
45pub enum ReasoningEffort {
46    Low,
47    Medium,
48    High,
49}
50
51/// A chat reasoning completion request. This currently does not support structured outputs.
52#[derive(Serialize, Debug, Clone, Builder)]
53#[builder(start_fn = model, state_mod(vis = "pub"))]
54pub struct ChatReasoningCompletion<'a> {
55    #[builder(start_fn)]
56    model: ReasoningModel,
57    messages: Vec<ReasoningMessage<'a>>,
58    store: Option<bool>,
59    metadata: Option<HashMap<String, String>>,
60    reasoning_effort: Option<ReasoningEffort>,
61}
62
63impl OpenAIRequestProvider for ChatReasoningCompletion<'_> {
64    type Response = ChatReasoningCompletionResponse;
65
66    const METHOD: Method = Method::POST;
67
68    fn path_with_leading_slash() -> String {
69        "/chat/completions".to_string()
70    }
71}
72
73impl super::private::Sealed for ChatReasoningCompletion<'_> {}
74
75/// A chat reasoning completion message. This currently does not support structured outputs.
76#[derive(Serialize, Debug, Clone, Builder)]
77#[builder(start_fn = role)]
78pub struct ReasoningMessage<'a> {
79    #[builder(start_fn)]
80    role: Role,
81    content: Cow<'a, str>,
82}
83
84#[macro_export]
85macro_rules! reasoning_developer_message {
86    ($($arg:tt)*) => {
87        ::kind_openai::endpoints::chat_reasoning::ReasoningMessage::role(
88            ::kind_openai::endpoints::chat_reasoning::Role::Developer
89        )
90        .content(format!($($arg)*).into())
91        .build();
92    };
93}
94
95#[macro_export]
96macro_rules! reasoning_user_message {
97    ($($arg:tt)*) => {
98        ::kind_openai::endpoints::chat_reasoning::ReasoningMessage::role(
99            ::kind_openai::endpoints::chat_reasoning::Role::User
100        )
101        .content(format!($($arg)*).into())
102        .build();
103    };
104}
105
106#[macro_export]
107macro_rules! reasoning_assistant_message {
108    ($($arg:tt)*) => {
109        ::kind_openai::endpoints::chat_reasoning::ReasoningMessage::role(
110            ::kind_openai::endpoints::chat_reasoning::Role::Assistant
111        )
112        .content(format!($($arg)*).into())
113        .build();
114    };
115}
116
117#[derive(Deserialize)]
118pub struct ChatReasoningCompletionResponse {
119    choices: Vec<ChatReasoningCompletionResponseChoice>,
120}
121
122impl ChatReasoningCompletionResponse {
123    pub fn take_first_choice(self) -> Option<ChatReasoningCompletionResponseChoice> {
124        self.choices.into_iter().next()
125    }
126}
127
128#[derive(Deserialize)]
129pub struct ChatReasoningCompletionResponseChoice {
130    message: ChatReasoningCompletionResponseMessage,
131}
132
133impl ChatReasoningCompletionResponseChoice {
134    pub fn message(self) -> String {
135        self.message.content
136    }
137}
138
139#[derive(Deserialize)]
140pub struct ChatReasoningCompletionResponseMessage {
141    content: String,
142}