claude_agent/client/messages/
context.rs

1//! Context management types for message requests.
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct ContextManagement {
7    pub edits: Vec<ContextEdit>,
8}
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(tag = "type")]
12pub enum ContextEdit {
13    #[serde(rename = "clear_tool_uses_20250919")]
14    ClearToolUses {
15        #[serde(skip_serializing_if = "Option::is_none")]
16        trigger: Option<ClearTrigger>,
17        #[serde(skip_serializing_if = "Option::is_none")]
18        keep: Option<KeepConfig>,
19        #[serde(skip_serializing_if = "Option::is_none")]
20        clear_at_least: Option<ClearConfig>,
21        #[serde(skip_serializing_if = "Option::is_none")]
22        exclude_tools: Option<Vec<String>>,
23        #[serde(skip_serializing_if = "Option::is_none")]
24        clear_tool_inputs: Option<bool>,
25    },
26    #[serde(rename = "clear_thinking_20251015")]
27    ClearThinking { keep: KeepThinkingConfig },
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(tag = "type", rename_all = "snake_case")]
32pub enum ClearTrigger {
33    InputTokens { value: u32 },
34    ToolUses { value: u32 },
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38#[serde(tag = "type", rename_all = "snake_case")]
39pub enum KeepConfig {
40    ToolUses { value: u32 },
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44#[serde(tag = "type", rename_all = "snake_case")]
45pub enum ClearConfig {
46    InputTokens { value: u32 },
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
50#[serde(tag = "type", rename_all = "snake_case")]
51pub enum KeepThinkingConfig {
52    ThinkingTurns {
53        value: u32,
54    },
55    #[serde(rename = "all")]
56    All,
57}
58
59impl ContextManagement {
60    pub fn new() -> Self {
61        Self { edits: Vec::new() }
62    }
63
64    pub fn clear_tool_uses() -> ContextEdit {
65        ContextEdit::ClearToolUses {
66            trigger: None,
67            keep: None,
68            clear_at_least: None,
69            exclude_tools: None,
70            clear_tool_inputs: None,
71        }
72    }
73
74    pub fn clear_thinking(keep_turns: u32) -> ContextEdit {
75        ContextEdit::ClearThinking {
76            keep: KeepThinkingConfig::ThinkingTurns { value: keep_turns },
77        }
78    }
79
80    pub fn clear_thinking_all() -> ContextEdit {
81        ContextEdit::ClearThinking {
82            keep: KeepThinkingConfig::All,
83        }
84    }
85
86    pub fn with_edit(mut self, edit: ContextEdit) -> Self {
87        self.edits.push(edit);
88        self
89    }
90}
91
92impl Default for ContextManagement {
93    fn default() -> Self {
94        Self::new()
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_context_management() {
104        let mgmt = ContextManagement::new()
105            .with_edit(ContextManagement::clear_tool_uses())
106            .with_edit(ContextManagement::clear_thinking(3));
107        assert_eq!(mgmt.edits.len(), 2);
108    }
109
110    #[test]
111    fn test_context_edit_serialization() {
112        let edit = ContextManagement::clear_tool_uses();
113        let json = serde_json::to_string(&edit).unwrap();
114        assert!(json.contains("clear_tool_uses_20250919"));
115
116        let edit = ContextManagement::clear_thinking(2);
117        let json = serde_json::to_string(&edit).unwrap();
118        assert!(json.contains("clear_thinking_20251015"));
119        assert!(json.contains("\"type\":\"thinking_turns\""));
120        assert!(json.contains("\"value\":2"));
121
122        let edit = ContextManagement::clear_thinking_all();
123        let json = serde_json::to_string(&edit).unwrap();
124        assert!(json.contains("\"type\":\"all\""));
125    }
126}