agentscript/
lib.rs

1use serde_json::Value;
2use tokio_stream::{Stream, StreamExt};
3use regex::Regex;
4
5
6pub struct InvokeParser {
7    buffer: String,
8    regex: Regex,
9    pub parsed_data: Vec<ParsedInvokeData>,
10}
11
12pub struct ParsedInvokeData {
13    pub tool: String,
14    pub action: String,
15    pub parameters: serde_json::Value, 
16}
17
18
19impl InvokeParser {
20    pub fn new() -> Self {
21        InvokeParser {
22            buffer: String::new(),
23            regex: Regex::new(r#"<Invoke tool="(.*?)" action="(.*?)" parameters=(.*?)/>"#).unwrap(),
24            parsed_data: Vec::new(),
25        }
26    }
27
28    pub async fn parse_stream<S>(&mut self, mut stream: S)
29    where
30        S: Stream<Item = String> + Unpin,
31    {
32        while let Some(chunk) = stream.next().await {
33            self.buffer.push_str(&chunk);
34
35            while let Some(caps) = self.regex.captures(&self.buffer) {
36                let tool = caps.get(1).map_or("", |m| m.as_str());
37                let action = caps.get(2).map_or("", |m| m.as_str());
38                let params_str = caps.get(3).map_or("{}", |m| m.as_str()); 
39                let params: Value = serde_json::from_str(params_str)
40                    .unwrap_or_else(|_| Value::Null);
41
42                let invoke_data = ParsedInvokeData {
43                    tool: tool.to_string(), 
44                    action: action.to_string(),
45                    parameters: params,
46                };
47
48                self.parsed_data.push(invoke_data);
49
50                let match_end = caps.get(0).unwrap().end();
51                self.buffer = self.buffer[match_end..].to_string();
52            }
53        }
54    }
55
56    pub fn parse(&mut self, msg: String) {
57        self.buffer.push_str(&msg);
58
59        while let Some(caps) = self.regex.captures(&self.buffer) {
60            let tool = caps.get(1).map_or("", |m| m.as_str()).to_string();
61            let action = caps.get(2).map_or("", |m| m.as_str()).to_string();
62            let params_str = caps.get(3).map_or("{}", |m| m.as_str());
63            let params: Value = serde_json::from_str(params_str)
64                .unwrap_or_else(|_| Value::Null);
65
66            let invoke_data = ParsedInvokeData {
67                tool,
68                action,
69                parameters: params,
70            };
71
72            self.parsed_data.push(invoke_data);
73
74            let match_end = caps.get(0).unwrap().end();
75            self.buffer = self.buffer[match_end..].to_string();
76        }
77    }
78
79    pub fn clear_buffer(&mut self) {
80        self.buffer.clear();
81    }
82}
83
84
85#[tokio::test]
86async fn parses_nested_parameter_object() {
87    let input_stream = tokio_stream::iter(vec![
88        String::from("<Invoke tool=\"Translator\" action=\"translate\" parameters={\"text\": \"Hello\", \"options\": {\"from\": \"en\", \"to\": \"es\"}} />") 
89    ]);
90
91    let mut parser = InvokeParser::new();
92    parser.parse_stream(input_stream).await;
93
94    for data in &parser.parsed_data {
95        println!("Tool: {}, Action: {} Params: {}", data.tool, data.action, data.parameters);
96    }
97
98    assert_eq!(parser.parsed_data.len(), 1); 
99    let invoke_data = &parser.parsed_data[0];
100
101    assert_eq!(invoke_data.tool, "Translator");
102    assert_eq!(invoke_data.action, "translate");
103
104    // Access nested parameters
105    assert_eq!(invoke_data.parameters["text"].as_str(), Some("Hello")); 
106    assert_eq!(invoke_data.parameters["options"]["from"].as_str(), Some("en"));
107    assert_eq!(invoke_data.parameters["options"]["to"].as_str(), Some("es"));
108}