Skip to main content

agixt_sdk/client/
agents.rs

1//! Agent operations using /v1 endpoints with ID-based parameters.
2
3use crate::error::Result;
4use std::collections::HashMap;
5
6impl super::AGiXTSDK {
7    // ==================== Agents ====================
8
9    /// Get list of all agents. Returns list of agents with their IDs.
10    pub async fn get_agents(&self) -> Result<Vec<HashMap<String, serde_json::Value>>> {
11        let response = self
12            .client
13            .get(&format!("{}/v1/agent", self.base_uri))
14            .headers(self.headers.lock().await.clone())
15            .send()
16            .await?;
17
18        let status = response.status();
19        let text = response.text().await?;
20
21        if self.verbose {
22            self.parse_response(status, &text).await?;
23        }
24
25        #[derive(serde::Deserialize)]
26        struct AgentsResponse {
27            agents: Vec<HashMap<String, serde_json::Value>>,
28        }
29
30        let result: AgentsResponse = serde_json::from_str(&text)?;
31        Ok(result.agents)
32    }
33
34    /// Get agent ID by name. Returns None if not found.
35    pub async fn get_agent_id_by_name(&self, agent_name: &str) -> Result<Option<String>> {
36        let agents = self.get_agents().await?;
37        for agent in agents {
38            if let Some(name) = agent.get("name").and_then(|v| v.as_str()) {
39                if name == agent_name {
40                    return Ok(agent.get("id").and_then(|v| v.as_str()).map(String::from));
41                }
42            }
43        }
44        Ok(None)
45    }
46
47    /// Add a new agent. Returns agent info including agent_id.
48    pub async fn add_agent(
49        &self,
50        agent_name: &str,
51        settings: Option<HashMap<String, serde_json::Value>>,
52        commands: Option<HashMap<String, serde_json::Value>>,
53        training_urls: Option<Vec<String>>,
54    ) -> Result<serde_json::Value> {
55        let response = self
56            .client
57            .post(&format!("{}/v1/agent", self.base_uri))
58            .headers(self.headers.lock().await.clone())
59            .json(&serde_json::json!({
60                "agent_name": agent_name,
61                "settings": settings.unwrap_or_default(),
62                "commands": commands.unwrap_or_default(),
63                "training_urls": training_urls.unwrap_or_default(),
64            }))
65            .send()
66            .await?;
67
68        let status = response.status();
69        let text = response.text().await?;
70
71        if self.verbose {
72            self.parse_response(status, &text).await?;
73        }
74
75        Ok(serde_json::from_str(&text)?)
76    }
77
78    /// Import an agent configuration.
79    pub async fn import_agent(
80        &self,
81        agent_name: &str,
82        settings: Option<HashMap<String, serde_json::Value>>,
83        commands: Option<HashMap<String, serde_json::Value>>,
84    ) -> Result<serde_json::Value> {
85        let response = self
86            .client
87            .post(&format!("{}/v1/agent/import", self.base_uri))
88            .headers(self.headers.lock().await.clone())
89            .json(&serde_json::json!({
90                "agent_name": agent_name,
91                "settings": settings.unwrap_or_default(),
92                "commands": commands.unwrap_or_default(),
93            }))
94            .send()
95            .await?;
96
97        let status = response.status();
98        let text = response.text().await?;
99
100        if self.verbose {
101            self.parse_response(status, &text).await?;
102        }
103
104        Ok(serde_json::from_str(&text)?)
105    }
106
107    /// Rename an agent by ID.
108    pub async fn rename_agent(&self, agent_id: &str, new_name: &str) -> Result<serde_json::Value> {
109        let response = self
110            .client
111            .patch(&format!("{}/v1/agent/{}", self.base_uri, agent_id))
112            .headers(self.headers.lock().await.clone())
113            .json(&serde_json::json!({ "new_name": new_name }))
114            .send()
115            .await?;
116
117        let status = response.status();
118        let text = response.text().await?;
119
120        if self.verbose {
121            self.parse_response(status, &text).await?;
122        }
123
124        Ok(serde_json::from_str(&text)?)
125    }
126
127    /// Update agent settings by ID.
128    pub async fn update_agent_settings(
129        &self,
130        agent_id: &str,
131        settings: HashMap<String, serde_json::Value>,
132        agent_name: Option<&str>,
133    ) -> Result<String> {
134        let response = self
135            .client
136            .put(&format!("{}/v1/agent/{}", self.base_uri, agent_id))
137            .headers(self.headers.lock().await.clone())
138            .json(&serde_json::json!({
139                "agent_name": agent_name.unwrap_or(""),
140                "settings": settings,
141                "commands": {},
142                "training_urls": [],
143            }))
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        #[derive(serde::Deserialize)]
155        struct MessageResponse {
156            message: String,
157        }
158
159        let result: MessageResponse = serde_json::from_str(&text)?;
160        Ok(result.message)
161    }
162
163    /// Update agent commands by ID.
164    pub async fn update_agent_commands(
165        &self,
166        agent_id: &str,
167        commands: HashMap<String, serde_json::Value>,
168    ) -> Result<String> {
169        let response = self
170            .client
171            .put(&format!("{}/v1/agent/{}/commands", self.base_uri, agent_id))
172            .headers(self.headers.lock().await.clone())
173            .json(&serde_json::json!({ "commands": commands }))
174            .send()
175            .await?;
176
177        let status = response.status();
178        let text = response.text().await?;
179
180        if self.verbose {
181            self.parse_response(status, &text).await?;
182        }
183
184        #[derive(serde::Deserialize)]
185        struct MessageResponse {
186            message: String,
187        }
188
189        let result: MessageResponse = serde_json::from_str(&text)?;
190        Ok(result.message)
191    }
192
193    /// Delete an agent by ID.
194    pub async fn delete_agent(&self, agent_id: &str) -> Result<String> {
195        let response = self
196            .client
197            .delete(&format!("{}/v1/agent/{}", self.base_uri, agent_id))
198            .headers(self.headers.lock().await.clone())
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        #[derive(serde::Deserialize)]
210        struct MessageResponse {
211            message: String,
212        }
213
214        let result: MessageResponse = serde_json::from_str(&text)?;
215        Ok(result.message)
216    }
217
218    /// Get agent configuration by ID.
219    pub async fn get_agentconfig(&self, agent_id: &str) -> Result<HashMap<String, serde_json::Value>> {
220        let response = self
221            .client
222            .get(&format!("{}/v1/agent/{}", self.base_uri, agent_id))
223            .headers(self.headers.lock().await.clone())
224            .send()
225            .await?;
226
227        let status = response.status();
228        let text = response.text().await?;
229
230        if self.verbose {
231            self.parse_response(status, &text).await?;
232        }
233
234        #[derive(serde::Deserialize)]
235        struct AgentResponse {
236            agent: HashMap<String, serde_json::Value>,
237        }
238
239        let result: AgentResponse = serde_json::from_str(&text)?;
240        Ok(result.agent)
241    }
242
243    // ==================== Commands ====================
244
245    /// Get available commands for an agent by ID.
246    pub async fn get_commands(&self, agent_id: &str) -> Result<HashMap<String, serde_json::Value>> {
247        let response = self
248            .client
249            .get(&format!("{}/v1/agent/{}/command", self.base_uri, agent_id))
250            .headers(self.headers.lock().await.clone())
251            .send()
252            .await?;
253
254        let status = response.status();
255        let text = response.text().await?;
256
257        if self.verbose {
258            self.parse_response(status, &text).await?;
259        }
260
261        #[derive(serde::Deserialize)]
262        struct CommandsResponse {
263            commands: HashMap<String, serde_json::Value>,
264        }
265
266        let result: CommandsResponse = serde_json::from_str(&text)?;
267        Ok(result.commands)
268    }
269
270    /// Toggle a command for an agent by ID.
271    pub async fn toggle_command(&self, agent_id: &str, command_name: &str, enable: bool) -> Result<String> {
272        let response = self
273            .client
274            .patch(&format!("{}/v1/agent/{}/command", self.base_uri, agent_id))
275            .headers(self.headers.lock().await.clone())
276            .json(&serde_json::json!({
277                "command_name": command_name,
278                "enable": enable,
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    /// Execute a command on an agent by ID.
300    pub async fn execute_command(
301        &self,
302        agent_id: &str,
303        command_name: &str,
304        command_args: HashMap<String, serde_json::Value>,
305        conversation_id: Option<&str>,
306    ) -> Result<serde_json::Value> {
307        let response = self
308            .client
309            .post(&format!("{}/v1/agent/{}/command", self.base_uri, agent_id))
310            .headers(self.headers.lock().await.clone())
311            .json(&serde_json::json!({
312                "command_name": command_name,
313                "command_args": command_args,
314                "conversation_name": conversation_id.unwrap_or(""),
315            }))
316            .send()
317            .await?;
318
319        let status = response.status();
320        let text = response.text().await?;
321
322        if self.verbose {
323            self.parse_response(status, &text).await?;
324        }
325
326        #[derive(serde::Deserialize)]
327        struct ResponseWrapper {
328            response: serde_json::Value,
329        }
330
331        let result: ResponseWrapper = serde_json::from_str(&text)?;
332        Ok(result.response)
333    }
334
335    // ==================== Prompting ====================
336
337    /// Send a prompt to an agent by ID.
338    pub async fn prompt_agent(
339        &self,
340        agent_id: &str,
341        prompt_name: &str,
342        prompt_args: HashMap<String, serde_json::Value>,
343    ) -> Result<String> {
344        let response = self
345            .client
346            .post(&format!("{}/v1/agent/{}/prompt", self.base_uri, agent_id))
347            .headers(self.headers.lock().await.clone())
348            .json(&serde_json::json!({
349                "prompt_name": prompt_name,
350                "prompt_args": prompt_args,
351            }))
352            .send()
353            .await?;
354
355        let status = response.status();
356        let text = response.text().await?;
357
358        if self.verbose {
359            self.parse_response(status, &text).await?;
360        }
361
362        #[derive(serde::Deserialize)]
363        struct ResponseWrapper {
364            response: String,
365        }
366
367        let result: ResponseWrapper = serde_json::from_str(&text)?;
368        Ok(result.response)
369    }
370
371    /// Send an instruction to an agent.
372    pub async fn instruct(&self, agent_id: &str, user_input: &str, conversation_id: &str) -> Result<String> {
373        let mut args = HashMap::new();
374        args.insert("user_input".to_string(), serde_json::json!(user_input));
375        args.insert("disable_memory".to_string(), serde_json::json!(true));
376        args.insert("conversation_name".to_string(), serde_json::json!(conversation_id));
377
378        self.prompt_agent(agent_id, "instruct", args).await
379    }
380
381    /// Chat with an agent.
382    pub async fn chat(
383        &self,
384        agent_id: &str,
385        user_input: &str,
386        conversation_id: &str,
387        context_results: Option<i32>,
388    ) -> Result<String> {
389        let mut args = HashMap::new();
390        args.insert("user_input".to_string(), serde_json::json!(user_input));
391        args.insert("context_results".to_string(), serde_json::json!(context_results.unwrap_or(4)));
392        args.insert("conversation_name".to_string(), serde_json::json!(conversation_id));
393        args.insert("disable_memory".to_string(), serde_json::json!(true));
394
395        self.prompt_agent(agent_id, "Chat", args).await
396    }
397
398    // ==================== Persona ====================
399
400    /// Get agent persona by ID.
401    pub async fn get_persona(&self, agent_id: &str) -> Result<serde_json::Value> {
402        let response = self
403            .client
404            .get(&format!("{}/v1/agent/{}/persona", self.base_uri, agent_id))
405            .headers(self.headers.lock().await.clone())
406            .send()
407            .await?;
408
409        let status = response.status();
410        let text = response.text().await?;
411
412        if self.verbose {
413            self.parse_response(status, &text).await?;
414        }
415
416        #[derive(serde::Deserialize)]
417        struct MessageResponse {
418            message: serde_json::Value,
419        }
420
421        let result: MessageResponse = serde_json::from_str(&text)?;
422        Ok(result.message)
423    }
424
425    /// Update agent persona by ID.
426    pub async fn update_persona(&self, agent_id: &str, persona: &str) -> Result<String> {
427        let response = self
428            .client
429            .put(&format!("{}/v1/agent/{}/persona", self.base_uri, agent_id))
430            .headers(self.headers.lock().await.clone())
431            .json(&serde_json::json!({ "persona": persona }))
432            .send()
433            .await?;
434
435        let status = response.status();
436        let text = response.text().await?;
437
438        if self.verbose {
439            self.parse_response(status, &text).await?;
440        }
441
442        #[derive(serde::Deserialize)]
443        struct MessageResponse {
444            message: String,
445        }
446
447        let result: MessageResponse = serde_json::from_str(&text)?;
448        Ok(result.message)
449    }
450
451    // ==================== Extensions ====================
452
453    /// Get extensions for an agent by ID.
454    pub async fn get_agent_extensions(&self, agent_id: &str) -> Result<Vec<serde_json::Value>> {
455        let response = self
456            .client
457            .get(&format!("{}/v1/agent/{}/extensions", self.base_uri, agent_id))
458            .headers(self.headers.lock().await.clone())
459            .send()
460            .await?;
461
462        let status = response.status();
463        let text = response.text().await?;
464
465        if self.verbose {
466            self.parse_response(status, &text).await?;
467        }
468
469        #[derive(serde::Deserialize)]
470        struct ExtensionsResponse {
471            extensions: Vec<serde_json::Value>,
472        }
473
474        let result: ExtensionsResponse = serde_json::from_str(&text)?;
475        Ok(result.extensions)
476    }
477
478    // ==================== Feedback ====================
479
480    /// Submit feedback for an agent response.
481    pub async fn submit_feedback(
482        &self,
483        agent_id: &str,
484        message: &str,
485        user_input: &str,
486        feedback: &str,
487        positive: bool,
488        conversation_id: Option<&str>,
489    ) -> Result<String> {
490        let response = self
491            .client
492            .post(&format!("{}/v1/agent/{}/feedback", self.base_uri, agent_id))
493            .headers(self.headers.lock().await.clone())
494            .json(&serde_json::json!({
495                "user_input": user_input,
496                "message": message,
497                "feedback": feedback,
498                "positive": positive,
499                "conversation_name": conversation_id.unwrap_or(""),
500            }))
501            .send()
502            .await?;
503
504        let status = response.status();
505        let text = response.text().await?;
506
507        if self.verbose {
508            self.parse_response(status, &text).await?;
509        }
510
511        #[derive(serde::Deserialize)]
512        struct MessageResponse {
513            message: String,
514        }
515
516        let result: MessageResponse = serde_json::from_str(&text)?;
517        Ok(result.message)
518    }
519
520    /// Submit positive feedback for an agent response.
521    pub async fn positive_feedback(
522        &self,
523        agent_id: &str,
524        message: &str,
525        user_input: &str,
526        feedback: &str,
527        conversation_id: Option<&str>,
528    ) -> Result<String> {
529        self.submit_feedback(agent_id, message, user_input, feedback, true, conversation_id).await
530    }
531
532    /// Submit negative feedback for an agent response.
533    pub async fn negative_feedback(
534        &self,
535        agent_id: &str,
536        message: &str,
537        user_input: &str,
538        feedback: &str,
539        conversation_id: Option<&str>,
540    ) -> Result<String> {
541        self.submit_feedback(agent_id, message, user_input, feedback, false, conversation_id).await
542    }
543
544    // ==================== Learning ====================
545
546    /// Teach agent text content by ID.
547    pub async fn learn_text(
548        &self,
549        agent_id: &str,
550        user_input: &str,
551        text: &str,
552        collection_number: Option<&str>,
553    ) -> Result<String> {
554        let response = self
555            .client
556            .post(&format!("{}/v1/agent/{}/learn/text", self.base_uri, agent_id))
557            .headers(self.headers.lock().await.clone())
558            .json(&serde_json::json!({
559                "user_input": user_input,
560                "text": text,
561                "collection_number": collection_number.unwrap_or("0"),
562            }))
563            .send()
564            .await?;
565
566        let status = response.status();
567        let text = response.text().await?;
568
569        if self.verbose {
570            self.parse_response(status, &text).await?;
571        }
572
573        #[derive(serde::Deserialize)]
574        struct MessageResponse {
575            message: String,
576        }
577
578        let result: MessageResponse = serde_json::from_str(&text)?;
579        Ok(result.message)
580    }
581
582    /// Teach agent content from a URL by ID.
583    pub async fn learn_url(
584        &self,
585        agent_id: &str,
586        url: &str,
587        collection_number: Option<&str>,
588    ) -> Result<String> {
589        let response = self
590            .client
591            .post(&format!("{}/v1/agent/{}/learn/url", self.base_uri, agent_id))
592            .headers(self.headers.lock().await.clone())
593            .json(&serde_json::json!({
594                "url": url,
595                "collection_number": collection_number.unwrap_or("0"),
596            }))
597            .send()
598            .await?;
599
600        let status = response.status();
601        let text = response.text().await?;
602
603        if self.verbose {
604            self.parse_response(status, &text).await?;
605        }
606
607        #[derive(serde::Deserialize)]
608        struct MessageResponse {
609            message: String,
610        }
611
612        let result: MessageResponse = serde_json::from_str(&text)?;
613        Ok(result.message)
614    }
615
616    /// Teach agent content from a file by ID.
617    pub async fn learn_file(
618        &self,
619        agent_id: &str,
620        file_name: &str,
621        file_content: &str,
622        collection_number: Option<&str>,
623    ) -> Result<String> {
624        let response = self
625            .client
626            .post(&format!("{}/v1/agent/{}/learn/file", self.base_uri, agent_id))
627            .headers(self.headers.lock().await.clone())
628            .json(&serde_json::json!({
629                "file_name": file_name,
630                "file_content": file_content,
631                "collection_number": collection_number.unwrap_or("0"),
632            }))
633            .send()
634            .await?;
635
636        let status = response.status();
637        let text = response.text().await?;
638
639        if self.verbose {
640            self.parse_response(status, &text).await?;
641        }
642
643        #[derive(serde::Deserialize)]
644        struct MessageResponse {
645            message: String,
646        }
647
648        let result: MessageResponse = serde_json::from_str(&text)?;
649        Ok(result.message)
650    }
651
652    // ==================== Memory ====================
653
654    /// Get agent memories.
655    pub async fn get_agent_memories(
656        &self,
657        agent_id: &str,
658        user_input: &str,
659        limit: Option<i32>,
660        min_relevance: Option<f32>,
661        collection_number: Option<&str>,
662    ) -> Result<Vec<serde_json::Value>> {
663        let response = self
664            .client
665            .post(&format!("{}/v1/agent/{}/memory/query", self.base_uri, agent_id))
666            .headers(self.headers.lock().await.clone())
667            .json(&serde_json::json!({
668                "user_input": user_input,
669                "limit": limit.unwrap_or(10),
670                "min_relevance_score": min_relevance.unwrap_or(0.0),
671                "collection_number": collection_number.unwrap_or("0"),
672            }))
673            .send()
674            .await?;
675
676        let status = response.status();
677        let text = response.text().await?;
678
679        if self.verbose {
680            self.parse_response(status, &text).await?;
681        }
682
683        #[derive(serde::Deserialize)]
684        struct MemoriesResponse {
685            memories: Vec<serde_json::Value>,
686        }
687
688        let result: MemoriesResponse = serde_json::from_str(&text)?;
689        Ok(result.memories)
690    }
691
692    /// Delete agent memory.
693    pub async fn delete_agent_memory(
694        &self,
695        agent_id: &str,
696        memory_id: &str,
697        collection_number: Option<&str>,
698    ) -> Result<String> {
699        let response = self
700            .client
701            .delete(&format!("{}/v1/agent/{}/memory/{}", self.base_uri, agent_id, memory_id))
702            .headers(self.headers.lock().await.clone())
703            .json(&serde_json::json!({
704                "collection_number": collection_number.unwrap_or("0"),
705            }))
706            .send()
707            .await?;
708
709        let status = response.status();
710        let text = response.text().await?;
711
712        if self.verbose {
713            self.parse_response(status, &text).await?;
714        }
715
716        #[derive(serde::Deserialize)]
717        struct MessageResponse {
718            message: String,
719        }
720
721        let result: MessageResponse = serde_json::from_str(&text)?;
722        Ok(result.message)
723    }
724
725    /// Wipe agent memory.
726    pub async fn wipe_agent_memory(
727        &self,
728        agent_id: &str,
729        collection_number: Option<&str>,
730    ) -> Result<String> {
731        let response = self
732            .client
733            .delete(&format!("{}/v1/agent/{}/memory", self.base_uri, agent_id))
734            .headers(self.headers.lock().await.clone())
735            .json(&serde_json::json!({
736                "collection_number": collection_number.unwrap_or(""),
737            }))
738            .send()
739            .await?;
740
741        let status = response.status();
742        let text = response.text().await?;
743
744        if self.verbose {
745            self.parse_response(status, &text).await?;
746        }
747
748        #[derive(serde::Deserialize)]
749        struct MessageResponse {
750            message: String,
751        }
752
753        let result: MessageResponse = serde_json::from_str(&text)?;
754        Ok(result.message)
755    }
756}