Skip to main content

clark_agent_compaction/
plain.rs

1use crate::TranscriptMessage;
2
3/// Simple test/example transcript shape.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub enum PlainMessage {
6    System(String),
7    User(String),
8    Assistant {
9        text: String,
10        tool_calls: Vec<PlainToolCall>,
11    },
12    ToolResult {
13        tool_call_id: String,
14        tool_name: String,
15        content: String,
16        is_error: bool,
17    },
18    Custom {
19        kind: String,
20        payload: String,
21    },
22}
23
24impl PlainMessage {
25    pub fn system(text: impl Into<String>) -> Self {
26        Self::System(text.into())
27    }
28
29    pub fn user(text: impl Into<String>) -> Self {
30        Self::User(text.into())
31    }
32
33    pub fn assistant(text: impl Into<String>) -> Self {
34        Self::Assistant {
35            text: text.into(),
36            tool_calls: Vec::new(),
37        }
38    }
39
40    pub fn assistant_with_tool_calls(
41        text: impl Into<String>,
42        tool_calls: Vec<PlainToolCall>,
43    ) -> Self {
44        Self::Assistant {
45            text: text.into(),
46            tool_calls,
47        }
48    }
49
50    pub fn tool_result(
51        tool_call_id: impl Into<String>,
52        tool_name: impl Into<String>,
53        content: impl Into<String>,
54        is_error: bool,
55    ) -> Self {
56        Self::ToolResult {
57            tool_call_id: tool_call_id.into(),
58            tool_name: tool_name.into(),
59            content: content.into(),
60            is_error,
61        }
62    }
63}
64
65/// Tool-call rendering helper for [`PlainMessage`].
66#[derive(Clone, Debug, PartialEq, Eq)]
67pub struct PlainToolCall {
68    pub name: String,
69    pub arguments: String,
70}
71
72impl PlainToolCall {
73    pub fn new(name: impl Into<String>, arguments: impl Into<String>) -> Self {
74        Self {
75            name: name.into(),
76            arguments: arguments.into(),
77        }
78    }
79}
80
81impl TranscriptMessage for PlainMessage {
82    fn render_for_compaction(&self, out: &mut String) {
83        match self {
84            PlainMessage::System(text) => {
85                out.push_str("[system]\n");
86                out.push_str(text);
87            }
88            PlainMessage::User(text) => {
89                out.push_str("[user]\n");
90                out.push_str(text);
91            }
92            PlainMessage::Assistant { text, tool_calls } => {
93                out.push_str("[assistant]\n");
94                let mut wrote = false;
95                if !text.is_empty() {
96                    out.push_str(text);
97                    wrote = true;
98                }
99                if !tool_calls.is_empty() {
100                    if wrote {
101                        out.push('\n');
102                    }
103                    out.push_str("tool calls: ");
104                    for (idx, call) in tool_calls.iter().enumerate() {
105                        if idx > 0 {
106                            out.push_str(", ");
107                        }
108                        out.push_str(&call.name);
109                        out.push('(');
110                        out.push_str(&call.arguments);
111                        out.push(')');
112                    }
113                    wrote = true;
114                }
115                if !wrote {
116                    out.push_str("(empty)");
117                }
118            }
119            PlainMessage::ToolResult {
120                tool_call_id,
121                tool_name,
122                content,
123                is_error,
124            } => {
125                let status = if *is_error { "error" } else { "ok" };
126                out.push_str("[tool result ");
127                out.push_str(tool_call_id);
128                out.push(' ');
129                out.push_str(tool_name);
130                out.push(' ');
131                out.push_str(status);
132                out.push_str("]\n");
133                out.push_str(content);
134            }
135            PlainMessage::Custom { kind, payload } => {
136                out.push_str("[custom ");
137                out.push_str(kind);
138                out.push_str("]\n");
139                out.push_str(payload);
140            }
141        }
142    }
143
144    fn user_text_for_compaction(&self, out: &mut String) -> bool {
145        if let PlainMessage::User(text) = self {
146            out.push_str(text);
147            true
148        } else {
149            false
150        }
151    }
152}