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 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}