gglib_core/normalize/parsers/
standard.rs1use super::super::parser::{ParserOutput, ToolCallParser};
12
13#[derive(Default, Debug)]
15pub struct StandardJsonParser;
16
17impl StandardJsonParser {
18 #[must_use]
20 pub const fn new() -> Self {
21 Self
22 }
23}
24
25impl ToolCallParser for StandardJsonParser {
26 fn push_text(&mut self, chunk: &str) -> ParserOutput {
27 ParserOutput::text(chunk)
28 }
29
30 fn push_reasoning(&mut self, chunk: &str) -> ParserOutput {
31 ParserOutput::reasoning(chunk)
32 }
33
34 fn finish(&mut self) -> ParserOutput {
35 ParserOutput::default()
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn text_passthrough_is_byte_identical() {
45 let mut p = StandardJsonParser::new();
46 let out = p.push_text("hello world");
47 assert_eq!(out.forward_text, "hello world");
48 assert!(out.forward_reasoning.is_empty());
49 assert!(out.tool_calls.is_empty());
50 assert!(out.errors.is_empty());
51 }
52
53 #[test]
54 fn reasoning_passthrough_is_byte_identical() {
55 let mut p = StandardJsonParser::new();
56 let out = p.push_reasoning("thinking…");
57 assert_eq!(out.forward_reasoning, "thinking…");
58 assert!(out.forward_text.is_empty());
59 }
60
61 #[test]
62 fn finish_emits_nothing() {
63 let mut p = StandardJsonParser::new();
64 let _ = p.push_text("abc");
65 let out = p.finish();
66 assert!(out.is_empty());
67 }
68
69 #[test]
70 fn many_chunks_preserve_total_bytes() {
71 let mut p = StandardJsonParser::new();
72 let mut acc = String::new();
73 for c in [
74 "foo",
75 "<tool_call>",
76 "{\"name\":\"x\"}",
77 "</tool_call>",
78 "bar",
79 ] {
80 acc.push_str(&p.push_text(c).forward_text);
81 }
82 assert_eq!(acc, "foo<tool_call>{\"name\":\"x\"}</tool_call>bar");
86 }
87}