refactor: improve readability of streaming parser and JSON filter
Agent: carmack
Changes:
- streaming_parser.rs: Unified find_first/last_tool_call_start into single
find_tool_call_start with SearchDirection enum, reducing duplication.
Simplified is_json_invalidated from 45 to 20 lines with clearer logic.
Fixed redundant !escape_next check in find_complete_json_object_end.
- filter_json.rs: Simplified check_tool_pattern from 40 to 24 lines.
Replaced repetitive prefix checks with loop over ["t", "to", "too", "tool"].
Reduced trailing return statements with direct expression returns.
- ui_writer_impl.rs: Added ansi module for duration color constants.
Simplified duration_color function by removing redundant comments.
- language_prompts.rs: Fixed test assertions to match actual prompt content
("obvious, readable Racket" instead of "RACKET-SPECIFIC GUIDANCE").
All 174+ tests pass. No behavior changes.
This commit is contained in:
@@ -106,64 +106,44 @@ fn check_tool_pattern(buffer: &str) -> Option<bool> {
|
||||
if !buffer.starts_with('{') {
|
||||
return Some(false);
|
||||
}
|
||||
|
||||
let after_brace = &buffer[1..];
|
||||
|
||||
// Skip leading whitespace after {
|
||||
let trimmed = after_brace.trim_start();
|
||||
|
||||
|
||||
let trimmed = buffer[1..].trim_start();
|
||||
|
||||
// Need at least `"tool":"` = 8 chars after whitespace
|
||||
if trimmed.len() < 8 {
|
||||
// Not enough data yet - but check for early rejection
|
||||
if trimmed.starts_with('"') {
|
||||
let after_quote = &trimmed[1..];
|
||||
// If we have chars after the quote, check if it starts with 't'
|
||||
if !after_quote.is_empty() && !after_quote.starts_with('t') {
|
||||
return Some(false); // Definitely not "tool
|
||||
}
|
||||
if after_quote.len() >= 2 && !after_quote.starts_with("to") {
|
||||
return Some(false);
|
||||
}
|
||||
if after_quote.len() >= 3 && !after_quote.starts_with("too") {
|
||||
return Some(false);
|
||||
}
|
||||
if after_quote.len() >= 4 && !after_quote.starts_with("tool") {
|
||||
return Some(false);
|
||||
// Early rejection: check progressive prefix of "tool
|
||||
if let Some(after_quote) = trimmed.strip_prefix('"') {
|
||||
// Check each prefix of "tool" we have so far
|
||||
for (i, expected) in ["t", "to", "too", "tool"].iter().enumerate() {
|
||||
if after_quote.len() > i && !after_quote.starts_with(expected) {
|
||||
return Some(false);
|
||||
}
|
||||
}
|
||||
} else if !trimmed.is_empty() && !trimmed.starts_with('"') {
|
||||
// First non-whitespace char after { is not " - not a tool call
|
||||
return Some(false);
|
||||
}
|
||||
return None; // Need more data
|
||||
return None;
|
||||
}
|
||||
|
||||
// We have enough data - check the full pattern
|
||||
// Must be: "tool" followed by optional whitespace, :, optional whitespace, "
|
||||
|
||||
// Full pattern check: "tool" : "
|
||||
if !trimmed.starts_with("\"tool\"") {
|
||||
return Some(false);
|
||||
}
|
||||
|
||||
let after_tool = trimmed[6..].trim_start(); // 6 = len of "tool"
|
||||
|
||||
|
||||
let after_tool = trimmed[6..].trim_start();
|
||||
if after_tool.is_empty() {
|
||||
return None; // Need more data
|
||||
return None;
|
||||
}
|
||||
|
||||
if !after_tool.starts_with(':') {
|
||||
return Some(false);
|
||||
}
|
||||
|
||||
|
||||
let after_colon = after_tool[1..].trim_start();
|
||||
|
||||
if after_colon.is_empty() {
|
||||
return None; // Need more data
|
||||
return None;
|
||||
}
|
||||
|
||||
if after_colon.starts_with('"') {
|
||||
return Some(true); // Confirmed tool call!
|
||||
}
|
||||
|
||||
Some(false) // Has : but not followed by "
|
||||
|
||||
Some(after_colon.starts_with('"'))
|
||||
}
|
||||
|
||||
/// Filters JSON tool calls from streaming LLM content.
|
||||
|
||||
@@ -224,7 +224,7 @@ mod tests {
|
||||
fn test_carmack_racket_prompt_embedded() {
|
||||
let prompt = get_agent_language_prompt("carmack", "racket");
|
||||
assert!(prompt.is_some());
|
||||
assert!(prompt.unwrap().contains("RACKET-SPECIFIC GUIDANCE"));
|
||||
assert!(prompt.unwrap().contains("obvious, readable Racket"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -242,6 +242,6 @@ mod tests {
|
||||
let prompts = get_agent_language_prompts_for_workspace(temp_dir.path(), "carmack");
|
||||
assert!(prompts.is_some());
|
||||
let content = prompts.unwrap();
|
||||
assert!(content.contains("RACKET-SPECIFIC GUIDANCE"));
|
||||
assert!(content.contains("obvious, readable Racket"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@ use termimad::MadSkin;
|
||||
/// Padding width for tool names in compact display (longest tool: "str_replace" = 11 chars)
|
||||
const TOOL_NAME_PADDING: usize = 11;
|
||||
|
||||
/// ANSI escape codes
|
||||
mod ansi {
|
||||
pub const YELLOW: &str = "\x1b[33m";
|
||||
pub const ORANGE: &str = "\x1b[38;5;208m";
|
||||
pub const RED: &str = "\x1b[31m";
|
||||
}
|
||||
|
||||
/// ANSI color codes for tool names
|
||||
const TOOL_COLOR_NORMAL: &str = "\x1b[32m";
|
||||
const TOOL_COLOR_NORMAL_BOLD: &str = "\x1b[1;32m";
|
||||
@@ -129,30 +136,27 @@ pub struct ConsoleUiWriter {
|
||||
/// ANSI color code for duration display based on elapsed time.
|
||||
/// Returns empty string for fast operations, yellow/orange/red for slower ones.
|
||||
fn duration_color(duration_str: &str) -> &'static str {
|
||||
// Format: "500ms", "1.5s", "2m 30.0s"
|
||||
if duration_str.ends_with("ms") {
|
||||
return ""; // Sub-second: no color
|
||||
return "";
|
||||
}
|
||||
|
||||
if let Some(m_pos) = duration_str.find('m') {
|
||||
// Contains minutes (e.g., "2m 30.0s")
|
||||
if let Ok(minutes) = duration_str[..m_pos].trim().parse::<u32>() {
|
||||
return match minutes {
|
||||
5.. => "\x1b[31m", // Red: >= 5 minutes
|
||||
1.. => "\x1b[38;5;208m", // Orange: 1-4 minutes
|
||||
5.. => ansi::RED,
|
||||
1.. => ansi::ORANGE,
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
} else if let Some(s_value) = duration_str.strip_suffix('s') {
|
||||
// Seconds only (e.g., "1.5s")
|
||||
if let Ok(seconds) = s_value.trim().parse::<f64>() {
|
||||
if seconds >= 1.0 {
|
||||
return "\x1b[33m"; // Yellow: >= 1 second
|
||||
return ansi::YELLOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"" // Default: no color
|
||||
""
|
||||
}
|
||||
|
||||
impl ConsoleUiWriter {
|
||||
|
||||
Reference in New Issue
Block a user