Refactor: deduplicate JSON parsing, provider constructors, and identity function

Agent: fowler

Eliminate code-path aliasing and near-duplicates across recent commits:

1. Deduplicate find_json_object_end: Three near-identical copies in
   streaming_parser.rs, context_window.rs, and acd.rs consolidated into
   a single canonical implementation in utils.rs. All callers now route
   through the canonical version. The utils.rs version uses the most
   defensive variant (with found_start guard). (-84 lines)

2. Deduplicate provider constructors: AnthropicProvider::new() and
   GeminiProvider::new() now delegate to their respective new_with_name()
   methods instead of duplicating the full constructor body.
   (OpenAI already delegated.) (-28 lines)

3. Inline convert_cache_control: Removed identity function that just
   cloned CacheControl. Call sites now use .map(|cc| cc.clone())
   directly. (-4 lines)

Net: -65 lines, 0 behavior changes, all 683 library tests pass.
This commit is contained in:
Dhanji R. Prasanna
2026-02-13 12:37:09 +11:00
parent bc98c65956
commit a7e0b0ef9e
6 changed files with 52 additions and 117 deletions

View File

@@ -246,31 +246,7 @@ fn extract_tool_name_from_content(content: &str) -> Option<String> {
/// Find the end of a JSON object (matching braces).
fn find_json_end(json_str: &str) -> Option<usize> {
let mut brace_count = 0;
let mut in_string = false;
let mut escape_next = false;
for (i, ch) in json_str.char_indices() {
if escape_next {
escape_next = false;
continue;
}
match ch {
'\\' => escape_next = true,
'"' if !escape_next => in_string = !in_string,
'{' if !in_string => brace_count += 1,
'}' if !in_string => {
brace_count -= 1;
if brace_count == 0 {
return Some(i);
}
}
_ => {}
}
}
None
crate::utils::find_json_object_end(json_str)
}
/// Estimate token count for messages.

View File

@@ -740,31 +740,7 @@ Format this as a detailed but concise summary that can be used to resume the con
/// Find the end position of a JSON object.
pub fn find_json_end(json_str: &str) -> Option<usize> {
let mut brace_count = 0;
let mut in_string = false;
let mut escape_next = false;
for (i, ch) in json_str.char_indices() {
if escape_next {
escape_next = false;
continue;
}
match ch {
'\\' => escape_next = true,
'"' if !escape_next => in_string = !in_string,
'{' if !in_string => brace_count += 1,
'}' if !in_string => {
brace_count -= 1;
if brace_count == 0 {
return Some(i);
}
}
_ => {}
}
}
None
crate::utils::find_json_object_end(json_str)
}
}

View File

@@ -116,38 +116,7 @@ fn is_position_in_fence_ranges(pos: usize, ranges: &[(usize, usize)]) -> bool {
// JSON Parsing Utilities
// ============================================================================
/// Find the end byte index of a complete JSON object, or None if incomplete.
fn find_json_object_end(text: &str) -> Option<usize> {
let mut brace_count = 0;
let mut in_string = false;
let mut escape_next = false;
let mut found_start = false;
for (i, ch) in text.char_indices() {
if escape_next {
escape_next = false;
continue;
}
match ch {
'\\' => escape_next = true,
'"' => in_string = !in_string,
'{' if !in_string => {
brace_count += 1;
found_start = true;
}
'}' if !in_string => {
brace_count -= 1;
if brace_count == 0 && found_start {
return Some(i);
}
}
_ => {}
}
}
None
}
use crate::utils::find_json_object_end;
/// Check if a partial JSON tool call has been invalidated.
///

View File

@@ -545,6 +545,49 @@ pub fn fix_mixed_quotes_in_json(json_str: &str) -> String {
result
}
// ============================================================================
// JSON Utilities
// ============================================================================
/// Find the end byte-index of a complete JSON object starting at the beginning of `text`.
///
/// Tracks brace nesting and string escaping to find the matching `}` for the
/// first `{`. Returns `None` if the JSON is incomplete or no `{` is found.
///
/// This is the single canonical implementation — used by streaming_parser,
/// context_window thinning, and ACD fragment parsing.
pub fn find_json_object_end(text: &str) -> Option<usize> {
let mut brace_count = 0;
let mut in_string = false;
let mut escape_next = false;
let mut found_start = false;
for (i, ch) in text.char_indices() {
if escape_next {
escape_next = false;
continue;
}
match ch {
'\\' => escape_next = true,
'"' => in_string = !in_string,
'{' if !in_string => {
brace_count += 1;
found_start = true;
}
'}' if !in_string => {
brace_count -= 1;
if brace_count == 0 && found_start {
return Some(i);
}
}
_ => {}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;