claude_agent/client/messages/
config.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum EffortLevel {
8 Low,
9 Medium,
10 High,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(tag = "type", rename_all = "snake_case")]
15pub enum ToolChoice {
16 Auto,
17 Any,
18 Tool { name: String },
19 None,
20}
21
22impl ToolChoice {
23 pub fn tool(name: impl Into<String>) -> Self {
24 Self::Tool { name: name.into() }
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct OutputConfig {
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub effort: Option<EffortLevel>,
32}
33
34impl OutputConfig {
35 pub fn with_effort(level: EffortLevel) -> Self {
36 Self {
37 effort: Some(level),
38 }
39 }
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ThinkingConfig {
44 #[serde(rename = "type")]
45 pub thinking_type: ThinkingType,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub budget_tokens: Option<u32>,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
51#[serde(rename_all = "snake_case")]
52pub enum ThinkingType {
53 Enabled,
54 Disabled,
55}
56
57impl ThinkingConfig {
58 pub fn enabled(budget_tokens: u32) -> Self {
59 Self {
60 thinking_type: ThinkingType::Enabled,
61 budget_tokens: Some(budget_tokens),
62 }
63 }
64
65 pub fn disabled() -> Self {
66 Self {
67 thinking_type: ThinkingType::Disabled,
68 budget_tokens: None,
69 }
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(tag = "type", rename_all = "snake_case")]
75pub enum OutputFormat {
76 JsonSchema {
77 #[serde(skip_serializing_if = "Option::is_none")]
78 name: Option<String>,
79 schema: serde_json::Value,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 description: Option<String>,
82 },
83}
84
85impl OutputFormat {
86 pub fn json_schema(schema: serde_json::Value) -> Self {
87 Self::JsonSchema {
88 name: None,
89 schema,
90 description: None,
91 }
92 }
93
94 pub fn json_schema_named(name: impl Into<String>, schema: serde_json::Value) -> Self {
95 Self::JsonSchema {
96 name: Some(name.into()),
97 schema,
98 description: None,
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_thinking_config_enabled() {
109 let config = ThinkingConfig::enabled(10000);
110 assert_eq!(config.thinking_type, ThinkingType::Enabled);
111 assert_eq!(config.budget_tokens, Some(10000));
112 }
113
114 #[test]
115 fn test_thinking_config_disabled() {
116 let config = ThinkingConfig::disabled();
117 assert_eq!(config.thinking_type, ThinkingType::Disabled);
118 assert_eq!(config.budget_tokens, None);
119 }
120
121 #[test]
122 fn test_thinking_config_serialization() {
123 let config = ThinkingConfig::enabled(5000);
124 let json = serde_json::to_string(&config).unwrap();
125 assert!(json.contains("\"type\":\"enabled\""));
126 assert!(json.contains("\"budget_tokens\":5000"));
127 }
128
129 #[test]
130 fn test_output_format_json_schema() {
131 let schema = serde_json::json!({
132 "type": "object",
133 "properties": {
134 "name": {"type": "string"}
135 }
136 });
137 let format = OutputFormat::json_schema(schema);
138 let json = serde_json::to_string(&format).unwrap();
139 assert!(json.contains("\"type\":\"json_schema\""));
140 assert!(json.contains("\"schema\""));
141 }
142
143 #[test]
144 fn test_output_format_named_schema() {
145 let schema = serde_json::json!({"type": "string"});
146 let format = OutputFormat::json_schema_named("PersonName", schema);
147 let json = serde_json::to_string(&format).unwrap();
148 assert!(json.contains("\"name\":\"PersonName\""));
149 }
150
151 #[test]
152 fn test_effort_level_serialization() {
153 let effort = EffortLevel::Low;
154 let json = serde_json::to_string(&effort).unwrap();
155 assert_eq!(json, "\"low\"");
156
157 let effort = EffortLevel::Medium;
158 let json = serde_json::to_string(&effort).unwrap();
159 assert_eq!(json, "\"medium\"");
160
161 let effort = EffortLevel::High;
162 let json = serde_json::to_string(&effort).unwrap();
163 assert_eq!(json, "\"high\"");
164 }
165
166 #[test]
167 fn test_output_config_serialization() {
168 let config = OutputConfig::with_effort(EffortLevel::High);
169 let json = serde_json::to_string(&config).unwrap();
170 assert!(json.contains("\"effort\":\"high\""));
171 }
172
173 #[test]
174 fn test_tool_choice_auto() {
175 let choice = ToolChoice::Auto;
176 let json = serde_json::to_string(&choice).unwrap();
177 assert_eq!(json, r#"{"type":"auto"}"#);
178 }
179
180 #[test]
181 fn test_tool_choice_any() {
182 let choice = ToolChoice::Any;
183 let json = serde_json::to_string(&choice).unwrap();
184 assert_eq!(json, r#"{"type":"any"}"#);
185 }
186
187 #[test]
188 fn test_tool_choice_none() {
189 let choice = ToolChoice::None;
190 let json = serde_json::to_string(&choice).unwrap();
191 assert_eq!(json, r#"{"type":"none"}"#);
192 }
193
194 #[test]
195 fn test_tool_choice_tool() {
196 let choice = ToolChoice::tool("Bash");
197 let json = serde_json::to_string(&choice).unwrap();
198 assert_eq!(json, r#"{"type":"tool","name":"Bash"}"#);
199 }
200}