use std::collections::BTreeMap;
use super::ToolChoiceFormat;
const ARGUMENT_ALIASES: [&str; 2] = ["arguments", "parameters"];
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct GuidedDelta {
pub tool_index: usize,
pub name: Option<String>,
pub arguments: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct StreamedCall {
pub arguments: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Mode {
Array,
Single { tool_name: String },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Slot {
Key,
Colon,
Value,
}
#[derive(Debug, Default, Clone)]
struct Element {
name: Option<String>,
args_start: Option<usize>,
args_end: Option<usize>,
in_args: bool,
alias_seen: bool,
blocked: bool,
committed: bool,
released: usize,
}
#[derive(Debug, Clone)]
pub(crate) struct GuidedStreamCursor {
mode: Mode,
scanned: usize,
depth: i32,
in_string: bool,
escape: bool,
literal_start: Option<usize>,
key_depth: i32,
root_seen: bool,
disabled: bool,
slot: Slot,
pending_key: Option<String>,
element: Element,
index: usize,
streamed: BTreeMap<usize, StreamedCall>,
}
impl GuidedStreamCursor {
pub(crate) fn new(format: &ToolChoiceFormat) -> Self {
let mode = match format {
ToolChoiceFormat::ArrayOfTools => Mode::Array,
ToolChoiceFormat::SingleObject { tool_name } => Mode::Single {
tool_name: tool_name.clone(),
},
};
Self::with_mode(mode)
}
fn with_mode(mode: Mode) -> Self {
Self {
mode,
scanned: 0,
depth: 0,
in_string: false,
escape: false,
literal_start: None,
key_depth: 1,
root_seen: false,
disabled: false,
slot: Slot::Key,
pending_key: None,
element: Element::default(),
index: 0,
streamed: BTreeMap::new(),
}
}
pub(crate) fn reset(&mut self) {
let mode = self.mode.clone();
*self = Self::with_mode(mode);
}
pub(crate) fn streamed(&self) -> &BTreeMap<usize, StreamedCall> {
&self.streamed
}
pub(crate) fn advance(&mut self, payload: &str, out: &mut Vec<GuidedDelta>) {
if self.disabled || payload.len() <= self.scanned {
return;
}
let mut cut = self.scanned;
for (relative, ch) in payload[self.scanned..].char_indices() {
let at = self.scanned + relative;
cut = at + ch.len_utf8();
match self.mode {
Mode::Array => self.step_array(payload, at, cut, ch, out),
Mode::Single { .. } => self.step_single(at, ch),
}
if self.disabled {
break;
}
}
self.scanned = cut;
self.maybe_commit(out);
self.flush(payload, cut, out);
}
fn step_single(&mut self, at: usize, ch: char) {
if !self.root_seen {
if ch == '{' {
self.root_seen = true;
self.depth = 1;
self.element.args_start = Some(at);
} else if !ch.is_whitespace() {
self.disabled = true;
}
return;
}
if self.element.args_end.is_some() {
return;
}
if self.in_string {
self.step_in_string_raw(ch);
return;
}
match ch {
'"' => self.in_string = true,
'{' | '[' => self.depth += 1,
'}' | ']' => {
self.depth -= 1;
if self.depth == 0 {
self.element.args_end = Some(at + ch.len_utf8());
}
}
_ => {}
}
}
fn step_array(
&mut self,
payload: &str,
at: usize,
cut: usize,
ch: char,
out: &mut Vec<GuidedDelta>,
) {
if self.in_string {
self.step_in_string(payload, at, ch);
return;
}
match ch {
'"' => {
if !self.root_seen {
self.disabled = true;
return;
}
self.in_string = true;
let wanted = self.depth == self.key_depth
&& match self.slot {
Slot::Key => true,
Slot::Value => self.pending_key.as_deref() == Some("name"),
Slot::Colon => false,
};
self.literal_start = wanted.then_some(at);
}
'{' | '[' => {
if !self.root_seen {
self.root_seen = true;
self.key_depth = if ch == '[' { 2 } else { 1 };
}
let opens_args = ch == '{'
&& self.depth == self.key_depth
&& self.slot == Slot::Value
&& is_alias(self.pending_key.as_deref());
let opens_element = ch == '{' && self.depth == self.key_depth - 1;
let name_is_not_a_string = self.depth == self.key_depth
&& self.slot == Slot::Value
&& self.pending_key.as_deref() == Some("name");
self.depth += 1;
if opens_args {
if self.element.args_start.is_some() {
self.element.blocked = true;
} else {
self.element.args_start = Some(at);
self.element.in_args = true;
}
} else if opens_element {
self.slot = Slot::Key;
self.pending_key = None;
} else if name_is_not_a_string {
self.element.blocked = true;
}
self.maybe_commit(out);
}
'}' | ']' => {
let closes_args =
ch == '}' && self.element.in_args && self.depth == self.key_depth + 1;
let closes_element = ch == '}' && self.depth == self.key_depth;
self.depth -= 1;
if closes_args {
self.element.args_end = Some(at + 1);
self.element.in_args = false;
self.maybe_commit(out);
self.flush(payload, cut, out);
} else if closes_element {
self.maybe_commit(out);
self.flush(payload, cut, out);
self.finish_element();
}
}
':' if self.depth == self.key_depth && self.slot == Slot::Colon => {
self.slot = Slot::Value;
}
',' if self.depth == self.key_depth => {
self.slot = Slot::Key;
self.pending_key = None;
}
_ if ch.is_whitespace() => {}
_ => {
if !self.root_seen {
self.disabled = true;
return;
}
if self.depth == self.key_depth
&& self.slot == Slot::Value
&& (is_alias(self.pending_key.as_deref())
|| self.pending_key.as_deref() == Some("name"))
{
self.element.blocked = true;
}
}
}
}
fn step_in_string(&mut self, payload: &str, at: usize, ch: char) {
if self.escape {
self.escape = false;
return;
}
match ch {
'\\' => self.escape = true,
'"' => {
self.in_string = false;
self.close_literal(payload, at);
}
_ => {}
}
}
fn step_in_string_raw(&mut self, ch: char) {
if self.escape {
self.escape = false;
return;
}
match ch {
'\\' => self.escape = true,
'"' => self.in_string = false,
_ => {}
}
}
fn close_literal(&mut self, payload: &str, end: usize) {
let Some(start) = self.literal_start.take() else {
return;
};
let Ok(literal) = serde_json::from_str::<String>(&payload[start..=end]) else {
return;
};
match self.slot {
Slot::Key => {
if is_alias(Some(literal.as_str())) {
if self.element.alias_seen {
self.element.blocked = true;
}
self.element.alias_seen = true;
}
self.pending_key = Some(literal);
self.slot = Slot::Colon;
}
Slot::Value => {
if self.pending_key.as_deref() == Some("name") {
self.element.name = Some(literal);
}
}
Slot::Colon => {}
}
}
fn maybe_commit(&mut self, out: &mut Vec<GuidedDelta>) {
if self.element.committed || self.element.blocked || self.element.args_start.is_none() {
return;
}
let name = match &self.mode {
Mode::Single { tool_name } => tool_name.clone(),
Mode::Array => match &self.element.name {
Some(name) => name.clone(),
None => return,
},
};
self.element.committed = true;
self.streamed.insert(
self.index,
StreamedCall {
arguments: String::new(),
},
);
out.push(GuidedDelta {
tool_index: self.index,
name: Some(name),
arguments: String::new(),
});
}
fn flush(&mut self, payload: &str, cut: usize, out: &mut Vec<GuidedDelta>) {
if !self.element.committed || self.element.blocked {
return;
}
let Some(start) = self.element.args_start else {
return;
};
let bound = self.element.args_end.unwrap_or(cut).min(cut);
let from = start + self.element.released;
if bound <= from {
return;
}
let fragment = payload[from..bound].to_string();
self.element.released = bound - start;
let Some(record) = self.streamed.get_mut(&self.index) else {
debug_assert!(
false,
"a committed element must have a streamed-call record at index {}",
self.index
);
tracing::error!(
tool_index = self.index,
"guided streaming committed an element with no streamed-call record; \
dropping the fragment"
);
return;
};
record.arguments.push_str(&fragment);
out.push(GuidedDelta {
tool_index: self.index,
name: None,
arguments: fragment,
});
}
fn finish_element(&mut self) {
self.index += 1;
self.element = Element::default();
self.slot = Slot::Key;
self.pending_key = None;
}
}
fn is_alias(key: Option<&str>) -> bool {
key.is_some_and(|key| ARGUMENT_ALIASES.contains(&key))
}
#[cfg(test)]
mod tests {
use super::*;
fn array_cursor() -> GuidedStreamCursor {
GuidedStreamCursor::new(&ToolChoiceFormat::ArrayOfTools)
}
fn named_cursor(tool_name: &str) -> GuidedStreamCursor {
GuidedStreamCursor::new(&ToolChoiceFormat::SingleObject {
tool_name: tool_name.to_string(),
})
}
fn stream(mut cursor: GuidedStreamCursor, payload: &str) -> Vec<GuidedDelta> {
let mut out = Vec::new();
let mut seen = String::new();
for ch in payload.chars() {
seen.push(ch);
cursor.advance(&seen, &mut out);
}
out
}
fn whole(mut cursor: GuidedStreamCursor, payload: &str) -> Vec<GuidedDelta> {
let mut out = Vec::new();
cursor.advance(payload, &mut out);
out
}
fn names(deltas: &[GuidedDelta]) -> Vec<(usize, String)> {
deltas
.iter()
.filter_map(|d| d.name.clone().map(|n| (d.tool_index, n)))
.collect()
}
fn arguments(deltas: &[GuidedDelta]) -> Vec<(usize, String)> {
let mut joined: Vec<(usize, String)> = Vec::new();
for delta in deltas {
if delta.arguments.is_empty() {
continue;
}
match joined
.iter_mut()
.find(|(index, _)| *index == delta.tool_index)
{
Some((_, text)) => text.push_str(&delta.arguments),
None => joined.push((delta.tool_index, delta.arguments.clone())),
}
}
joined
}
#[test]
fn required_splits_the_name_from_its_arguments() {
let payload = r#"[{"name":"get_weather","arguments":{"city":"Paris","unit":"c"}}]"#;
let expected = r#"{"city":"Paris","unit":"c"}"#;
let deltas = stream(array_cursor(), payload);
assert_eq!(names(&deltas), vec![(0, "get_weather".to_string())]);
let first = deltas.first().expect("a commit delta");
assert_eq!(first.name.as_deref(), Some("get_weather"));
assert!(first.arguments.is_empty());
assert_eq!(arguments(&deltas), vec![(0, expected.to_string())]);
let start = payload.find(expected).expect("the argument object");
assert_eq!(
arguments(&deltas)[0].1,
payload[start..start + expected.len()]
);
}
#[test]
fn required_accepts_the_parameters_spelling() {
let deltas = stream(
array_cursor(),
r#"[{"name":"get_weather","parameters":{"city":"Tokyo"}}]"#,
);
assert_eq!(names(&deltas), vec![(0, "get_weather".to_string())]);
assert_eq!(
arguments(&deltas),
vec![(0, r#"{"city":"Tokyo"}"#.to_string())]
);
}
#[test]
fn two_calls_in_one_array_get_distinct_indices() {
let payload = r#"[{"name":"a","arguments":{"x":1}},{"name":"b","parameters":{"y":[1,2]}}]"#;
let deltas = stream(array_cursor(), payload);
assert_eq!(
names(&deltas),
vec![(0, "a".to_string()), (1, "b".to_string())]
);
assert_eq!(
arguments(&deltas),
vec![
(0, r#"{"x":1}"#.to_string()),
(1, r#"{"y":[1,2]}"#.to_string())
]
);
let at_once = whole(array_cursor(), payload);
assert_eq!(names(&at_once), names(&deltas));
assert_eq!(arguments(&at_once), arguments(&deltas));
}
#[test]
fn a_non_object_argument_value_is_never_committed() {
for payload in [
r#"[{"name":"f","arguments":"just a string"}]"#,
r#"[{"name":"f","arguments":null}]"#,
r#"[{"name":"f","arguments":7}]"#,
r#"[{"name":"f","arguments":[1,2]}]"#,
r#"[{"name":"f","parameters":null}]"#,
r#"[{"name":"f"}]"#,
] {
assert!(
stream(array_cursor(), payload).is_empty(),
"{payload} put a call on the wire that has no argument object"
);
assert!(whole(array_cursor(), payload).is_empty(), "{payload}");
}
}
#[test]
fn both_argument_aliases_in_one_element_do_not_commit() {
for payload in [
r#"[{"parameters":{"b":2},"arguments":{"a":1},"name":"f"}]"#,
r#"[{"name":"f","parameters":null,"arguments":{"a":1}}]"#,
r#"[{"name":"f","arguments":[1,2],"parameters":{"b":2}}]"#,
] {
assert!(
stream(array_cursor(), payload).is_empty(),
"{payload} committed an ambiguous element"
);
assert!(whole(array_cursor(), payload).is_empty(), "{payload}");
}
for (payload, first_object) in [
(
r#"[{"name":"f","arguments":{"a":1},"parameters":{"b":2}}]"#,
r#"{"a":1}"#,
),
(
r#"[{"parameters":{"b":2},"name":"f","arguments":{"a":1}}]"#,
r#"{"b":2}"#,
),
] {
let deltas = stream(array_cursor(), payload);
assert_eq!(names(&deltas), vec![(0, "f".to_string())], "{payload}");
assert_eq!(
arguments(&deltas),
vec![(0, first_object.to_string())],
"{payload} released bytes from the ambiguous second object"
);
}
}
#[test]
fn the_word_name_as_a_value_is_not_the_call_name() {
for payload in [
r#"[{"x":"name","parameters":{}}]"#,
r#"[{"x":"name","arguments":{"city":"Paris"}}]"#,
r#"[{"arguments":{"name":"not the call name"}}]"#,
] {
let deltas = stream(array_cursor(), payload);
assert!(
deltas.is_empty(),
"{payload} invented a name: {deltas:?} — a nameless element must not stream"
);
}
}
#[test]
fn escapes_in_the_name_decode() {
let payload = "[{\"name\":\"get\\u005fweather\",\"arguments\":{}}]";
assert!(
payload.contains("\\u005f"),
"the escape must reach the lexer"
);
assert_eq!(
names(&stream(array_cursor(), payload)),
vec![(0, "get_weather".to_string())]
);
let payload = r#"[{"name":"a\"b\\c\nd","arguments":{}}]"#;
assert_eq!(
names(&stream(array_cursor(), payload)),
vec![(0, "a\"b\\c\nd".to_string())]
);
let payload = "[{\"name\":\"a\\ud83d\\ude00b\",\"arguments\":{}}]";
assert!(
payload.contains("\\ud83d"),
"the escape must reach the lexer"
);
assert_eq!(
names(&stream(array_cursor(), payload)),
vec![(0, "a\u{1F600}b".to_string())]
);
}
#[test]
fn a_brace_inside_an_argument_string_does_not_close_the_object() {
let payload = r#"[{"name":"f","arguments":{"s":"}}]","t":"\""}}]"#;
let deltas = stream(array_cursor(), payload);
assert_eq!(
arguments(&deltas),
vec![(0, r#"{"s":"}}]","t":"\""}"#.to_string())]
);
}
#[test]
fn a_name_that_closes_after_its_arguments_still_commits() {
let payload = r#"[{"arguments":{"city":"Paris"},"name":"get_weather"}]"#;
let deltas = stream(array_cursor(), payload);
assert_eq!(names(&deltas), vec![(0, "get_weather".to_string())]);
assert_eq!(
arguments(&deltas),
vec![(0, r#"{"city":"Paris"}"#.to_string())]
);
}
#[test]
fn a_payload_that_is_not_a_call_shape_emits_nothing() {
assert!(stream(array_cursor(), r#""just a string""#).is_empty());
assert!(stream(array_cursor(), "42").is_empty());
}
#[test]
fn reset_returns_the_cursor_to_a_fresh_stream() {
let mut cursor = array_cursor();
let mut out = Vec::new();
cursor.advance(r#"[{"name":"a","arguments":{"x":1}}]"#, &mut out);
assert_eq!(names(&out), vec![(0, "a".to_string())]);
cursor.reset();
let mut second = Vec::new();
cursor.advance(r#"[{"name":"b","arguments":{"y":2}}]"#, &mut second);
assert_eq!(names(&second), vec![(0, "b".to_string())]);
assert_eq!(arguments(&second), vec![(0, r#"{"y":2}"#.to_string())]);
}
#[test]
fn named_carries_the_name_on_the_first_delta_only() {
let payload = r#"{"city":"Paris","unit":"c"}"#;
let deltas = stream(named_cursor("get_weather"), payload);
let first = deltas.first().expect("a commit delta");
assert_eq!(first.name.as_deref(), Some("get_weather"));
assert!(first.arguments.is_empty());
assert!(
deltas[1..].iter().all(|d| d.name.is_none()),
"the name rode more than the first delta: {deltas:?}"
);
assert_eq!(arguments(&deltas), vec![(0, payload.to_string())]);
}
#[test]
fn named_skips_whitespace_before_the_object() {
let payload = " \n\t{\"city\":\"Paris\"}";
let deltas = stream(named_cursor("get_weather"), payload);
assert_eq!(names(&deltas), vec![(0, "get_weather".to_string())]);
assert_eq!(
arguments(&deltas),
vec![(0, r#"{"city":"Paris"}"#.to_string())]
);
}
#[test]
fn named_never_releases_past_the_closing_brace() {
let payload = "{\"a\":1}\n\ntrailing";
let deltas = stream(named_cursor("f"), payload);
assert_eq!(arguments(&deltas), vec![(0, r#"{"a":1}"#.to_string())]);
}
#[test]
fn named_handles_braces_inside_strings() {
let payload = r#"{"s":"}{ \" }","n":{"deep":[1,{"x":"}"}]}}"#;
let deltas = stream(named_cursor("f"), payload);
assert_eq!(arguments(&deltas), vec![(0, payload.to_string())]);
}
fn assert_every_split(build: impl Fn() -> GuidedStreamCursor, payload: &str, expected: &str) {
for split in 0..=payload.len() {
if !payload.is_char_boundary(split) {
continue;
}
let mut cursor = build();
let mut out = Vec::new();
cursor.advance(&payload[..split], &mut out);
cursor.advance(payload, &mut out);
let joined = arguments(&out);
assert_eq!(
joined,
vec![(0, expected.to_string())],
"reassembly differs at split {split}"
);
let mut offset = 0usize;
for delta in out.iter().filter(|d| !d.arguments.is_empty()) {
assert!(
expected.is_char_boundary(offset),
"fragment starts mid-character at {offset} (split {split})"
);
offset += delta.arguments.len();
assert!(
expected.is_char_boundary(offset),
"fragment ends mid-character at {offset} (split {split})"
);
}
assert_eq!(offset, expected.len());
}
}
#[test]
fn required_survives_every_char_boundary_split() {
let payload = r#"[{"name":"f","arguments":{"city":"東京","emoji":"😀","q":"a\"b"}}]"#;
let expected = r#"{"city":"東京","emoji":"😀","q":"a\"b"}"#;
assert!(
payload.chars().any(|c| c.len_utf8() > 1),
"the sweep needs a multi-byte character"
);
assert_every_split(array_cursor, payload, expected);
}
#[test]
fn named_survives_every_char_boundary_split() {
let payload = r#"{"city":"東京","emoji":"😀","q":"a\"b"}"#;
assert!(payload.chars().any(|c| c.len_utf8() > 1));
assert_every_split(|| named_cursor("get_weather"), payload, payload);
}
fn long_arguments() -> String {
let mut body = String::from(r#"{"note":"a \" quote and a } brace","items":["#);
for i in 0..120 {
if i > 0 {
body.push(',');
}
body.push_str(&format!(
r#"{{"k{i}":"v{i} }} \" x","nested":{{"deep":[{i},"文字"]}}}}"#
));
}
body.push_str(r#"],"last":"x"}"#);
assert!(body.len() > 2000, "body was only {} bytes", body.len());
body
}
fn stream_chunks(
mut cursor: GuidedStreamCursor,
payload: &str,
chunk: usize,
) -> Vec<GuidedDelta> {
let mut out = Vec::new();
let mut seen = String::new();
for (n, ch) in payload.chars().enumerate() {
seen.push(ch);
if (n + 1) % chunk == 0 {
cursor.advance(&seen, &mut out);
}
}
cursor.advance(payload, &mut out);
out
}
#[test]
fn required_streams_a_long_payload_in_many_fragments() {
let expected = long_arguments();
let payload = format!(r#"[{{"name":"f","arguments":{expected}}}]"#);
let deltas = stream_chunks(array_cursor(), &payload, 7);
assert_eq!(names(&deltas), vec![(0, "f".to_string())]);
assert_eq!(arguments(&deltas), vec![(0, expected.clone())]);
let fragments = deltas.iter().filter(|d| !d.arguments.is_empty()).count();
assert!(
fragments > 100,
"arguments arrived in {fragments} fragment(s), not a stream"
);
assert_eq!(
arguments(&whole(array_cursor(), &payload)),
vec![(0, expected)]
);
}
#[test]
fn named_native_markup_with_an_inner_brace_never_commits() {
let payload = "<minimax:tool_call><invoke name=\"get_weather\">\
<parameter name=\"location\">San Francisco {CA}</parameter></invoke></minimax:tool_call>";
let mut cursor = GuidedStreamCursor::new(&ToolChoiceFormat::SingleObject {
tool_name: "get_weather".to_string(),
});
let mut out = Vec::new();
cursor.advance(payload, &mut out);
assert!(
out.is_empty(),
"native markup must not be streamed as arguments, got {out:?}"
);
}
#[test]
fn named_streams_a_long_payload_in_many_fragments() {
let payload = long_arguments();
let deltas = stream_chunks(named_cursor("f"), &payload, 7);
assert_eq!(names(&deltas), vec![(0, "f".to_string())]);
assert_eq!(arguments(&deltas), vec![(0, payload.clone())]);
let fragments = deltas.iter().filter(|d| !d.arguments.is_empty()).count();
assert!(
fragments > 100,
"arguments arrived in {fragments} fragment(s), not a stream"
);
}
}