1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use serde_json::Value;
use tokio_stream::{Stream, StreamExt};
use regex::Regex;


pub struct InvokeParser {
    buffer: String,
    regex: Regex,
    pub parsed_data: Vec<ParsedInvokeData>,
}

pub struct ParsedInvokeData {
    pub tool: String,
    pub action: String,
    pub parameters: serde_json::Value, 
}


impl InvokeParser {
    pub fn new() -> Self {
        InvokeParser {
            buffer: String::new(),
            regex: Regex::new(r#"<Invoke tool="(.*?)" action="(.*?)" parameters=(.*?)/>"#).unwrap(),
            parsed_data: Vec::new(),
        }
    }

    pub async fn parse_stream<S>(&mut self, mut stream: S)
    where
        S: Stream<Item = String> + Unpin,
    {
        while let Some(chunk) = stream.next().await {
            self.buffer.push_str(&chunk);

            while let Some(caps) = self.regex.captures(&self.buffer) {
                let tool = caps.get(1).map_or("", |m| m.as_str());
                let action = caps.get(2).map_or("", |m| m.as_str());
                let params_str = caps.get(3).map_or("{}", |m| m.as_str()); 
                let params: Value = serde_json::from_str(params_str)
                    .unwrap_or_else(|_| Value::Null);

                let invoke_data = ParsedInvokeData {
                    tool: tool.to_string(), 
                    action: action.to_string(),
                    parameters: params,
                };

                self.parsed_data.push(invoke_data);

                let match_end = caps.get(0).unwrap().end();
                self.buffer = self.buffer[match_end..].to_string();
            }
        }
    }

    pub fn parse(&mut self, msg: String) {
        self.buffer.push_str(&msg);

        while let Some(caps) = self.regex.captures(&self.buffer) {
            let tool = caps.get(1).map_or("", |m| m.as_str()).to_string();
            let action = caps.get(2).map_or("", |m| m.as_str()).to_string();
            let params_str = caps.get(3).map_or("{}", |m| m.as_str());
            let params: Value = serde_json::from_str(params_str)
                .unwrap_or_else(|_| Value::Null);

            let invoke_data = ParsedInvokeData {
                tool,
                action,
                parameters: params,
            };

            self.parsed_data.push(invoke_data);

            let match_end = caps.get(0).unwrap().end();
            self.buffer = self.buffer[match_end..].to_string();
        }
    }

    pub fn clear_buffer(&mut self) {
        self.buffer.clear();
    }
}


#[tokio::test]
async fn parses_nested_parameter_object() {
    let input_stream = tokio_stream::iter(vec![
        String::from("<Invoke tool=\"Translator\" action=\"translate\" parameters={\"text\": \"Hello\", \"options\": {\"from\": \"en\", \"to\": \"es\"}} />") 
    ]);

    let mut parser = InvokeParser::new();
    parser.parse_stream(input_stream).await;

    for data in &parser.parsed_data {
        println!("Tool: {}, Action: {} Params: {}", data.tool, data.action, data.parameters);
    }

    assert_eq!(parser.parsed_data.len(), 1); 
    let invoke_data = &parser.parsed_data[0];

    assert_eq!(invoke_data.tool, "Translator");
    assert_eq!(invoke_data.action, "translate");

    // Access nested parameters
    assert_eq!(invoke_data.parameters["text"].as_str(), Some("Hello")); 
    assert_eq!(invoke_data.parameters["options"]["from"].as_str(), Some("en"));
    assert_eq!(invoke_data.parameters["options"]["to"].as_str(), Some("es"));
}