Skip to main content

agixt_sdk/client/
conversations.rs

1//! Conversation operations using /v1 endpoints with ID-based parameters.
2
3use crate::error::Result;
4use crate::models::Message;
5use std::collections::HashMap;
6
7impl super::AGiXTSDK {
8    // ==================== Conversations ====================
9
10    /// Get all conversations. Returns list with conversation IDs.
11    pub async fn get_conversations(&self) -> Result<Vec<serde_json::Value>> {
12        let response = self
13            .client
14            .get(&format!("{}/v1/conversations", self.base_uri))
15            .headers(self.headers.lock().await.clone())
16            .send()
17            .await?;
18
19        let status = response.status();
20        let text = response.text().await?;
21
22        if self.verbose {
23            self.parse_response(status, &text).await?;
24        }
25
26        // Handle both list (v1) and dict (legacy) responses
27        let data: serde_json::Value = serde_json::from_str(&text)?;
28        if let Some(arr) = data.as_array() {
29            return Ok(arr.clone());
30        }
31        if let Some(obj) = data.as_object() {
32            if let Some(convs) = obj.get("conversations").and_then(|v| v.as_array()) {
33                return Ok(convs.clone());
34            }
35        }
36        Ok(vec![])
37    }
38
39    /// Get all conversations with their IDs.
40    pub async fn get_conversations_with_ids(&self) -> Result<Vec<HashMap<String, String>>> {
41        let response = self
42            .client
43            .get(&format!("{}/v1/conversations", self.base_uri))
44            .headers(self.headers.lock().await.clone())
45            .send()
46            .await?;
47
48        let status = response.status();
49        let text = response.text().await?;
50
51        if self.verbose {
52            self.parse_response(status, &text).await?;
53        }
54
55        // Parse as list of objects with id and name
56        let data: serde_json::Value = serde_json::from_str(&text)?;
57        let mut result = Vec::new();
58        
59        let conversations = if let Some(arr) = data.as_array() {
60            arr.clone()
61        } else if let Some(obj) = data.as_object() {
62            obj.get("conversations_with_ids")
63                .or(obj.get("conversations"))
64                .and_then(|v| v.as_array())
65                .cloned()
66                .unwrap_or_default()
67        } else {
68            vec![]
69        };
70
71        for conv in conversations {
72            if let Some(obj) = conv.as_object() {
73                let mut map = HashMap::new();
74                if let Some(id) = obj.get("id").and_then(|v| v.as_str()) {
75                    map.insert("id".to_string(), id.to_string());
76                }
77                if let Some(name) = obj.get("name").and_then(|v| v.as_str()) {
78                    map.insert("name".to_string(), name.to_string());
79                }
80                result.push(map);
81            }
82        }
83        
84        Ok(result)
85    }
86
87    /// Get conversation ID by name. Returns None if not found.
88    pub async fn get_conversation_id_by_name(&self, conversation_name: &str) -> Result<Option<String>> {
89        let conversations = self.get_conversations_with_ids().await?;
90        for conv in conversations {
91            if let Some(name) = conv.get("name") {
92                if name == conversation_name {
93                    return Ok(conv.get("id").cloned());
94                }
95            }
96        }
97        Ok(None)
98    }
99
100    /// Get conversation history by ID.
101    pub async fn get_conversation(
102        &self,
103        conversation_id: &str,
104        limit: Option<i32>,
105        page: Option<i32>,
106    ) -> Result<Vec<Message>> {
107        let response = self
108            .client
109            .get(&format!("{}/v1/conversation/{}", self.base_uri, conversation_id))
110            .headers(self.headers.lock().await.clone())
111            .query(&[
112                ("limit", limit.unwrap_or(100).to_string()),
113                ("page", page.unwrap_or(1).to_string()),
114            ])
115            .send()
116            .await?;
117
118        let status = response.status();
119        let text = response.text().await?;
120
121        if self.verbose {
122            self.parse_response(status, &text).await?;
123        }
124
125        #[derive(serde::Deserialize)]
126        struct ConversationResponse {
127            conversation_history: Vec<Message>,
128        }
129
130        let result: ConversationResponse = serde_json::from_str(&text)?;
131        Ok(result.conversation_history)
132    }
133
134    /// Fork a conversation from a specific message.
135    pub async fn fork_conversation(
136        &self,
137        conversation_id: &str,
138        message_id: &str,
139    ) -> Result<serde_json::Value> {
140        let response = self
141            .client
142            .post(&format!("{}/v1/conversation/fork/{}/{}", self.base_uri, conversation_id, message_id))
143            .headers(self.headers.lock().await.clone())
144            .send()
145            .await?;
146
147        let status = response.status();
148        let text = response.text().await?;
149
150        if self.verbose {
151            self.parse_response(status, &text).await?;
152        }
153
154        Ok(serde_json::from_str(&text)?)
155    }
156
157    /// Create a new conversation. Returns conversation with ID.
158    pub async fn new_conversation(
159        &self,
160        agent_id: &str,
161        conversation_name: &str,
162        conversation_content: Option<Vec<Message>>,
163    ) -> Result<serde_json::Value> {
164        let response = self
165            .client
166            .post(&format!("{}/v1/conversation", self.base_uri))
167            .headers(self.headers.lock().await.clone())
168            .json(&serde_json::json!({
169                "conversation_name": conversation_name,
170                "agent_id": agent_id,
171                "conversation_content": conversation_content.unwrap_or_default(),
172            }))
173            .send()
174            .await?;
175
176        let status = response.status();
177        let text = response.text().await?;
178
179        if self.verbose {
180            self.parse_response(status, &text).await?;
181        }
182
183        Ok(serde_json::from_str(&text)?)
184    }
185
186    /// Rename a conversation by ID.
187    pub async fn rename_conversation(
188        &self,
189        conversation_id: &str,
190        new_name: &str,
191    ) -> Result<serde_json::Value> {
192        let response = self
193            .client
194            .put(&format!("{}/v1/conversation/{}", self.base_uri, conversation_id))
195            .headers(self.headers.lock().await.clone())
196            .json(&serde_json::json!({
197                "new_conversation_name": new_name,
198            }))
199            .send()
200            .await?;
201
202        let status = response.status();
203        let text = response.text().await?;
204
205        if self.verbose {
206            self.parse_response(status, &text).await?;
207        }
208
209        Ok(serde_json::from_str(&text)?)
210    }
211
212    /// Delete a conversation by ID.
213    pub async fn delete_conversation(&self, conversation_id: &str) -> Result<String> {
214        let response = self
215            .client
216            .delete(&format!("{}/v1/conversation/{}", self.base_uri, conversation_id))
217            .headers(self.headers.lock().await.clone())
218            .send()
219            .await?;
220
221        let status = response.status();
222        let text = response.text().await?;
223
224        if self.verbose {
225            self.parse_response(status, &text).await?;
226        }
227
228        #[derive(serde::Deserialize)]
229        struct MessageResponse {
230            message: String,
231        }
232
233        let result: MessageResponse = serde_json::from_str(&text)?;
234        Ok(result.message)
235    }
236
237    /// Delete a message from a conversation by IDs.
238    pub async fn delete_conversation_message(
239        &self,
240        conversation_id: &str,
241        message_id: &str,
242    ) -> Result<String> {
243        let response = self
244            .client
245            .delete(&format!("{}/v1/conversation/{}/message/{}", self.base_uri, conversation_id, message_id))
246            .headers(self.headers.lock().await.clone())
247            .send()
248            .await?;
249
250        let status = response.status();
251        let text = response.text().await?;
252
253        if self.verbose {
254            self.parse_response(status, &text).await?;
255        }
256
257        #[derive(serde::Deserialize)]
258        struct MessageResponse {
259            message: String,
260        }
261
262        let result: MessageResponse = serde_json::from_str(&text)?;
263        Ok(result.message)
264    }
265
266    /// Update a message in a conversation by IDs.
267    pub async fn update_conversation_message(
268        &self,
269        conversation_id: &str,
270        message_id: &str,
271        new_message: &str,
272    ) -> Result<String> {
273        let response = self
274            .client
275            .put(&format!("{}/v1/conversation/{}/message/{}", self.base_uri, conversation_id, message_id))
276            .headers(self.headers.lock().await.clone())
277            .json(&serde_json::json!({
278                "new_message": new_message,
279            }))
280            .send()
281            .await?;
282
283        let status = response.status();
284        let text = response.text().await?;
285
286        if self.verbose {
287            self.parse_response(status, &text).await?;
288        }
289
290        #[derive(serde::Deserialize)]
291        struct MessageResponse {
292            message: String,
293        }
294
295        let result: MessageResponse = serde_json::from_str(&text)?;
296        Ok(result.message)
297    }
298
299    /// Add a new message to a conversation.
300    pub async fn new_conversation_message(
301        &self,
302        role: &str,
303        message: &str,
304        conversation_id: &str,
305    ) -> Result<String> {
306        let response = self
307            .client
308            .post(&format!("{}/v1/conversation/{}/message", self.base_uri, conversation_id))
309            .headers(self.headers.lock().await.clone())
310            .json(&serde_json::json!({
311                "role": role,
312                "message": message,
313            }))
314            .send()
315            .await?;
316
317        let status = response.status();
318        let text = response.text().await?;
319
320        if self.verbose {
321            self.parse_response(status, &text).await?;
322        }
323
324        #[derive(serde::Deserialize)]
325        struct MessageResponse {
326            message: String,
327        }
328
329        let result: MessageResponse = serde_json::from_str(&text)?;
330        Ok(result.message)
331    }
332}