claude_code_acp/types/
meta.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
24pub struct SystemPromptMeta {
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub append: Option<String>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub replace: Option<String>,
32}
33
34impl SystemPromptMeta {
35 pub fn from_meta(meta: &serde_json::Value) -> Option<Self> {
37 meta.get("systemPrompt")
38 .and_then(|v| serde_json::from_value(v.clone()).ok())
39 }
40
41 pub fn is_configured(&self) -> bool {
43 self.append.is_some() || self.replace.is_some()
44 }
45}
46
47#[derive(Debug, Clone, Default, Serialize, Deserialize)]
64pub struct ClaudeCodeOptions {
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub resume: Option<String>,
68
69 #[serde(skip_serializing_if = "Option::is_none", rename = "maxThinkingTokens")]
72 pub max_thinking_tokens: Option<u32>,
73}
74
75#[derive(Debug, Clone, Default, Serialize, Deserialize)]
77pub struct ClaudeCodeMeta {
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub options: Option<ClaudeCodeOptions>,
81}
82
83impl ClaudeCodeMeta {
84 pub fn from_meta(meta: &serde_json::Value) -> Option<Self> {
86 meta.get("claudeCode")
87 .and_then(|v| serde_json::from_value(v.clone()).ok())
88 }
89
90 pub fn get_resume_session_id(&self) -> Option<&str> {
92 self.options.as_ref()?.resume.as_deref()
93 }
94
95 pub fn get_max_thinking_tokens(&self) -> Option<u32> {
97 self.options.as_ref()?.max_thinking_tokens
98 }
99}
100
101#[derive(Debug, Clone, Default)]
105pub struct NewSessionMeta {
106 pub system_prompt: Option<SystemPromptMeta>,
108
109 pub claude_code: Option<ClaudeCodeMeta>,
111
112 pub disable_built_in_tools: bool,
114}
115
116impl NewSessionMeta {
117 pub fn with_resume(session_id: &str) -> Self {
122 Self {
123 system_prompt: None,
124 claude_code: Some(ClaudeCodeMeta {
125 options: Some(ClaudeCodeOptions {
126 resume: Some(session_id.to_string()),
127 max_thinking_tokens: None,
128 }),
129 }),
130 disable_built_in_tools: false,
131 }
132 }
133
134 pub fn from_request_meta(meta: Option<&serde_json::Value>) -> Self {
144 let Some(meta) = meta else {
145 return Self::default();
146 };
147
148 Self {
149 system_prompt: SystemPromptMeta::from_meta(meta),
150 claude_code: ClaudeCodeMeta::from_meta(meta),
151 disable_built_in_tools: meta
152 .get("disableBuiltInTools")
153 .and_then(|v| v.as_bool())
154 .unwrap_or(false),
155 }
156 }
157
158 pub fn get_system_prompt_append(&self) -> Option<&str> {
160 self.system_prompt.as_ref()?.append.as_deref()
161 }
162
163 pub fn get_system_prompt_replace(&self) -> Option<&str> {
165 self.system_prompt.as_ref()?.replace.as_deref()
166 }
167
168 pub fn get_resume_session_id(&self) -> Option<&str> {
170 self.claude_code.as_ref()?.get_resume_session_id()
171 }
172
173 pub fn get_max_thinking_tokens(&self) -> Option<u32> {
175 self.claude_code.as_ref()?.get_max_thinking_tokens()
176 }
177
178 pub fn should_resume(&self) -> bool {
180 self.get_resume_session_id().is_some()
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use serde_json::json;
188
189 #[test]
190 fn test_system_prompt_meta_parse() {
191 let meta = json!({
192 "systemPrompt": {
193 "append": "Please respond in Chinese"
194 }
195 });
196
197 let parsed = SystemPromptMeta::from_meta(&meta).unwrap();
198 assert_eq!(parsed.append, Some("Please respond in Chinese".to_string()));
199 assert!(parsed.replace.is_none());
200 assert!(parsed.is_configured());
201 }
202
203 #[test]
204 fn test_claude_code_meta_parse() {
205 let meta = json!({
206 "claudeCode": {
207 "options": {
208 "resume": "session-uuid-12345"
209 }
210 }
211 });
212
213 let parsed = ClaudeCodeMeta::from_meta(&meta).unwrap();
214 assert_eq!(parsed.get_resume_session_id(), Some("session-uuid-12345"));
215 }
216
217 #[test]
218 fn test_claude_code_meta_with_thinking_tokens() {
219 let meta = json!({
220 "claudeCode": {
221 "options": {
222 "resume": "session-uuid-12345",
223 "maxThinkingTokens": 4096
224 }
225 }
226 });
227
228 let parsed = ClaudeCodeMeta::from_meta(&meta).unwrap();
229 assert_eq!(parsed.get_resume_session_id(), Some("session-uuid-12345"));
230 assert_eq!(parsed.get_max_thinking_tokens(), Some(4096));
231 }
232
233 #[test]
234 fn test_new_session_meta_full() {
235 let meta = json!({
236 "systemPrompt": {
237 "append": "Be concise"
238 },
239 "claudeCode": {
240 "options": {
241 "resume": "abc-123",
242 "maxThinkingTokens": 8000
243 }
244 },
245 "disableBuiltInTools": true
246 });
247
248 let parsed = NewSessionMeta::from_request_meta(Some(&meta));
249 assert_eq!(parsed.get_system_prompt_append(), Some("Be concise"));
250 assert_eq!(parsed.get_resume_session_id(), Some("abc-123"));
251 assert_eq!(parsed.get_max_thinking_tokens(), Some(8000));
252 assert!(parsed.disable_built_in_tools);
253 assert!(parsed.should_resume());
254 }
255
256 #[test]
257 fn test_new_session_meta_empty() {
258 let parsed = NewSessionMeta::from_request_meta(None);
259 assert!(parsed.system_prompt.is_none());
260 assert!(parsed.claude_code.is_none());
261 assert!(!parsed.disable_built_in_tools);
262 assert!(!parsed.should_resume());
263 }
264
265 #[test]
266 fn test_new_session_meta_partial() {
267 let meta = json!({
268 "systemPrompt": {
269 "replace": "You are a helpful assistant"
270 }
271 });
272
273 let parsed = NewSessionMeta::from_request_meta(Some(&meta));
274 assert_eq!(
275 parsed.get_system_prompt_replace(),
276 Some("You are a helpful assistant")
277 );
278 assert!(parsed.get_system_prompt_append().is_none());
279 assert!(parsed.get_resume_session_id().is_none());
280 }
281
282 #[test]
283 fn test_new_session_meta_with_resume() {
284 let meta = NewSessionMeta::with_resume("session-abc-123");
285 assert_eq!(meta.get_resume_session_id(), Some("session-abc-123"));
286 assert!(meta.should_resume());
287 assert!(meta.system_prompt.is_none());
288 assert!(!meta.disable_built_in_tools);
289 }
290}