claude_agent/client/messages/
context.rs1use 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}