claude_api/messages/thinking.rs
1//! Configuration for extended thinking.
2//!
3//! Pass a [`ThinkingConfig::Enabled`] value in the request to have the model
4//! emit `thinking` blocks before its final answer. `budget_tokens` caps how
5//! much of `max_tokens` the model may spend on reasoning.
6//!
7//! Extended thinking is supported by Claude Sonnet 4.6+ and Claude Opus 4.x.
8//! See [`crate::models::ModelCapabilities`] to check model support at runtime.
9
10use serde::{Deserialize, Serialize};
11
12/// Whether and how the model should produce extended-thinking output.
13///
14/// When [`ThinkingConfig::Enabled`], the model emits one or more
15/// [`Thinking`](crate::messages::content::KnownBlock::Thinking) blocks
16/// before its final answer. `budget_tokens` caps the thinking length;
17/// it counts against `max_tokens`.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
19#[serde(tag = "type", rename_all = "snake_case")]
20#[non_exhaustive]
21pub enum ThinkingConfig {
22 /// Enable extended thinking with a per-turn token budget.
23 Enabled {
24 /// Maximum tokens the model may spend thinking on this turn.
25 budget_tokens: u32,
26 },
27 /// Disable extended thinking explicitly.
28 Disabled,
29}
30
31impl ThinkingConfig {
32 /// Convenience constructor for the [`ThinkingConfig::Enabled`] variant.
33 #[must_use]
34 pub fn enabled(budget_tokens: u32) -> Self {
35 Self::Enabled { budget_tokens }
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use pretty_assertions::assert_eq;
43 use serde_json::json;
44
45 #[test]
46 fn enabled_round_trips() {
47 let c = ThinkingConfig::enabled(8192);
48 let v = serde_json::to_value(c).unwrap();
49 assert_eq!(v, json!({"type": "enabled", "budget_tokens": 8192}));
50 let parsed: ThinkingConfig = serde_json::from_value(v).unwrap();
51 assert_eq!(parsed, c);
52 }
53
54 #[test]
55 fn disabled_round_trips() {
56 let c = ThinkingConfig::Disabled;
57 let v = serde_json::to_value(c).unwrap();
58 assert_eq!(v, json!({"type": "disabled"}));
59 let parsed: ThinkingConfig = serde_json::from_value(v).unwrap();
60 assert_eq!(parsed, c);
61 }
62}