watsonx_rs/orchestrate/
thread.rs

1//! Thread management operations
2
3use crate::error::{Error, Result};
4use super::types::{ThreadInfo, Message};
5use super::OrchestrateClient;
6use serde_json::Value;
7
8#[derive(serde::Deserialize)]
9struct EventData {
10    event: String,
11    data: Value,
12}
13
14impl OrchestrateClient {
15    /// List all threads for an agent
16    pub async fn list_threads(&self, agent_id: Option<&str>) -> Result<Vec<ThreadInfo>> {
17        let api_key = self.access_token.as_ref().ok_or_else(|| {
18            Error::Authentication("Not authenticated. Set access token (API key) first.".to_string())
19        })?;
20
21        let base_url = self.config.get_base_url();
22        let url = if let Some(agent_id) = agent_id {
23            format!("{}/threads?agent_id={}", base_url, agent_id)
24        } else {
25            format!("{}/threads", base_url)
26        };
27
28        let response = self
29            .client
30            .get(&url)
31            .header("Authorization", format!("Bearer {}", api_key))
32            .header("Content-Type", "application/json")
33            .send()
34            .await
35            .map_err(|e| Error::Network(e.to_string()))?;
36
37        if !response.status().is_success() {
38            let status = response.status();
39            let error_text = response
40                .text()
41                .await
42                .unwrap_or_else(|_| "Unknown error".to_string());
43            return Err(Error::Api(format!(
44                "Failed to list threads: {} - {}",
45                status, error_text
46            )));
47        }
48
49        let threads: Vec<ThreadInfo> = response
50            .json()
51            .await
52            .map_err(|e| Error::Serialization(e.to_string()))?;
53
54        Ok(threads)
55    }
56
57    /// Create a new thread for conversation
58    pub async fn create_thread(&self, agent_id: Option<&str>) -> Result<ThreadInfo> {
59        let api_key = self.access_token.as_ref().ok_or_else(|| {
60            Error::Authentication("Not authenticated. Set access token (API key) first.".to_string())
61        })?;
62
63        let base_url = self.config.get_base_url();
64        let url = format!("{}/threads", base_url);
65
66        let mut body = serde_json::json!({});
67        if let Some(agent_id) = agent_id {
68            body["agent_id"] = serde_json::json!(agent_id);
69        }
70
71        let response = self
72            .client
73            .post(&url)
74            .header("Authorization", format!("Bearer {}", api_key))
75            .header("Content-Type", "application/json")
76            .json(&body)
77            .send()
78            .await
79            .map_err(|e| Error::Network(e.to_string()))?;
80
81        if !response.status().is_success() {
82            let status = response.status();
83            let error_text = response
84                .text()
85                .await
86                .unwrap_or_else(|_| "Unknown error".to_string());
87            return Err(Error::Api(format!(
88                "Failed to create thread: {} - {}",
89                status, error_text
90            )));
91        }
92
93        let thread: ThreadInfo = response
94            .json()
95            .await
96            .map_err(|e| Error::Serialization(e.to_string()))?;
97
98        Ok(thread)
99    }
100
101    /// Delete a thread
102    pub async fn delete_thread(&self, thread_id: &str) -> Result<()> {
103        let api_key = self.access_token.as_ref().ok_or_else(|| {
104            Error::Authentication("Not authenticated. Set access token (API key) first.".to_string())
105        })?;
106
107        let base_url = self.config.get_base_url();
108        let url = format!("{}/threads/{}", base_url, thread_id);
109
110        let response = self
111            .client
112            .delete(&url)
113            .header("Authorization", format!("Bearer {}", api_key))
114            .send()
115            .await
116            .map_err(|e| Error::Network(e.to_string()))?;
117
118        if !response.status().is_success() {
119            let status = response.status();
120            let error_text = response
121                .text()
122                .await
123                .unwrap_or_else(|_| "Unknown error".to_string());
124            return Err(Error::Api(format!(
125                "Failed to delete thread {}: {} - {}",
126                thread_id, status, error_text
127            )));
128        }
129
130        Ok(())
131    }
132
133    /// Get conversation history from a thread
134    pub async fn get_thread_messages(&self, thread_id: &str) -> Result<Vec<Message>> {
135        let api_key = self.access_token.as_ref().ok_or_else(|| {
136            Error::Authentication("Not authenticated. Set access token (API key) first.".to_string())
137        })?;
138
139        let base_url = self.config.get_base_url();
140        let url = format!("{}/threads/{}/messages", base_url, thread_id);
141
142        let response = self
143            .client
144            .get(&url)
145            .header("Authorization", format!("Bearer {}", api_key))
146            .header("Content-Type", "application/json")
147            .send()
148            .await
149            .map_err(|e| Error::Network(e.to_string()))?;
150
151        if !response.status().is_success() {
152            let status = response.status();
153            let error_text = response
154                .text()
155                .await
156                .unwrap_or_else(|_| "Unknown error".to_string());
157            return Err(Error::Api(format!(
158                "Failed to get thread messages: {} - {}",
159                status, error_text
160            )));
161        }
162
163        // Try to parse as direct array first
164        let text = response
165            .text()
166            .await
167            .map_err(|e| Error::Network(e.to_string()))?;
168
169        if let Ok(messages) = serde_json::from_str::<Vec<Message>>(&text) {
170            return Ok(messages);
171        }
172
173        // Try to extract from wrapper object
174        if let Ok(obj) = serde_json::from_str::<serde_json::Value>(&text) {
175            if let Some(messages_array) = obj.get("messages").and_then(|m| m.as_array()) {
176                let messages: Result<Vec<Message>> = messages_array
177                    .iter()
178                    .map(|item| {
179                        serde_json::from_value::<Message>(item.clone())
180                            .map_err(|e| Error::Serialization(e.to_string()))
181                    })
182                    .collect();
183                return messages;
184            }
185        }
186
187        // Fallback to empty vec
188        Ok(Vec::new())
189    }
190}