[Rust Frontend] Add error context in tool parser failures (#46512)
Signed-off-by: Maria Guevara <kawaiiplush14@gmail.com>
This commit is contained in:
@@ -238,6 +238,9 @@ mod tests {
|
||||
|
||||
let error = parser.parse_chunk(&input).unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
|
||||
expect![[
|
||||
r#"tool parser parsing failed: near "tool<|tool▁sep|>get_weather\n```json\n{}": "#
|
||||
]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +242,7 @@ mod tests {
|
||||
|
||||
let error = parser.parse_chunk(&input).unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
|
||||
expect![[r#"tool parser parsing failed: near "<|tool▁sep|>{}": "#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,8 +540,10 @@ mod tests {
|
||||
.parse_chunk(r#"<tool_call>{"name":"f","arguments":42}</tool_call>"#)
|
||||
.unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: invalid Granite4 arguments"]
|
||||
.assert_eq(&error.to_report_string());
|
||||
expect![[
|
||||
r#"tool parser parsing failed: near "42}</tool_call>": invalid Granite4 arguments"#
|
||||
]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -335,7 +335,7 @@ mod tests {
|
||||
let error = parser.parse_chunk(&input).unwrap_err();
|
||||
|
||||
expect![[r#"
|
||||
tool parser parsing failed: invalid InternLM2
|
||||
tool parser parsing failed: near "{\"name\":\"get_weather\",\"params\":{\"location\":\"Tokyo\"}}<|action_end|>": invalid InternLM2
|
||||
expected `parameters`, `arguments`"#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ mod tests {
|
||||
.unwrap_err();
|
||||
|
||||
expect![[r#"
|
||||
tool parser parsing failed: invalid Llama JSON
|
||||
tool parser parsing failed: near "{\"name\":\"get_weather\",\"arguments\":{\"location\":\"Tokyo\"}}": invalid Llama JSON
|
||||
expected `parameters`"#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
@@ -474,7 +474,7 @@ mod tests {
|
||||
let error = parser.parse_chunk(r#"{"parameters":{},"name":"get_weather"}"#).unwrap_err();
|
||||
|
||||
expect![[r#"
|
||||
tool parser parsing failed: invalid Llama JSON
|
||||
tool parser parsing failed: near "{\"parameters\":{},\"name\":\"get_weather\"}": invalid Llama JSON
|
||||
expected `name`"#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
@@ -489,7 +489,7 @@ mod tests {
|
||||
))
|
||||
.unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: invalid Llama JSON"]
|
||||
expect![[r#"tool parser parsing failed: near " trailing": invalid Llama JSON"#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ mod tests {
|
||||
.unwrap_err();
|
||||
|
||||
expect![[r#"
|
||||
tool parser parsing failed: invalid Mistral
|
||||
tool parser parsing failed: near "{\"arguments\":{},\"name\":\"get_weather\"}]": invalid Mistral
|
||||
expected `name`"#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ mod tests {
|
||||
.unwrap_err();
|
||||
|
||||
expect![[r#"
|
||||
tool parser parsing failed: invalid Qwen XML
|
||||
tool parser parsing failed: near "{\"arguments\":{},\"name\":\"get_weather\"}\n</tool_call>": invalid Qwen XML
|
||||
expected `name`"#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
|
||||
@@ -594,6 +594,9 @@ mod tests {
|
||||
|
||||
let error = parser.parse_chunk(&input).unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
|
||||
expect![[
|
||||
r#"tool parser parsing failed: near "get_weather<|tool_call_argument_begin|>{}": "#
|
||||
]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,6 +593,7 @@ mod tests {
|
||||
let mut parser = MinimaxM2ToolParser::new(&test_tools());
|
||||
let error = parser.parse_chunk("<minimax:tool_call><bad></minimax:tool_call>").unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
|
||||
expect![[r#"tool parser parsing failed: near "<bad></minimax:tool_call>": "#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,7 +878,10 @@ mod tests {
|
||||
))
|
||||
.unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
|
||||
expect![[
|
||||
r#"tool parser parsing failed: near "]<]minimax[>[<bad>]<]minimax[>[</tool_call>": "#
|
||||
]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -685,7 +685,8 @@ mod tests {
|
||||
let mut parser = Qwen3CoderToolParser::new(&test_tools());
|
||||
let error = parser.parse_chunk("<tool_call>\n<bad>\n</tool_call>").unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
|
||||
expect![[r#"tool parser parsing failed: near "\n<bad>\n</tool_call>": "#]]
|
||||
.assert_eq(&error.to_report_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -697,7 +698,7 @@ mod tests {
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
|
||||
expect![[r#"tool parser parsing failed: near "\n<function=get_weather>\n<parameter=location>SF</function>\n</tool_call>": "#]].assert_eq(&error.to_report_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -395,9 +395,9 @@ pub fn parse_buffered_event<E>(
|
||||
Ok(event) => event,
|
||||
Err(ErrMode::Incomplete(_)) => return Ok(None),
|
||||
Err(ErrMode::Backtrack(e) | ErrMode::Cut(e)) => {
|
||||
// TODO: enrich context for error reporting
|
||||
let snippet = buffer.char_indices().nth(80).map_or(buffer, |(i, _)| &buffer[..i]);
|
||||
return Err(ToolParserError::ParsingFailed {
|
||||
message: e.to_string(),
|
||||
message: format!("near {snippet:?}: {e}"),
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -423,8 +423,9 @@ mod tests {
|
||||
use winnow::stream::{Offset, Partial, Stream};
|
||||
|
||||
use super::{
|
||||
JsonObjectScanState, JsonStringScanState, MarkerScanState, json_str, partial_prefix_len,
|
||||
safe_text_len, safe_text_len_mul, take_json_object, take_json_string, take_until_marker,
|
||||
JsonObjectScanState, JsonStringScanState, MarkerScanState, json_str, parse_buffered_event,
|
||||
partial_prefix_len, safe_text_len, safe_text_len_mul, take_json_object, take_json_string,
|
||||
take_until_marker,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -832,4 +833,27 @@ mod tests {
|
||||
|
||||
assert!(matches!(error, ErrMode::Incomplete(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_buffered_event_error_includes_input_snippet() {
|
||||
let result = parse_buffered_event(" {\"x\":1}", |input| {
|
||||
take_json_object(input, &mut JsonObjectScanState::default())
|
||||
});
|
||||
let err = result.unwrap_err().to_string();
|
||||
assert!(err.contains("near \""), "error must include snippet");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_buffered_event_error_truncates_long_input() {
|
||||
let long_input = format!(" {}", "x".repeat(100));
|
||||
let result = parse_buffered_event(&long_input, |input| {
|
||||
take_json_object(input, &mut JsonObjectScanState::default())
|
||||
});
|
||||
let err = result.unwrap_err().to_string();
|
||||
assert!(err.contains("near \""), "error must include snippet");
|
||||
assert!(
|
||||
!err.contains(&long_input),
|
||||
"snippet must be truncated for long input"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user