From cd96771106897b8df02ae349117fa73602f71063 Mon Sep 17 00:00:00 2001 From: s0u7a Date: Mon, 9 Nov 2026 23:24:31 +0000 Subject: [PATCH] fix: parse the LLM query array as JSON instead of splitting on commas --- src/deep_research.rs | 45 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/deep_research.rs b/src/deep_research.rs index 7d62870..6d70b68 100644 --- a/src/deep_research.rs +++ b/src/deep_research.rs @@ -156,16 +156,20 @@ fn parse_string_array(text: &str, max: usize) -> Vec { let Some(end) = end.filter(|end| *end > start) else { return fallback_queries(text, max); }; - let inner = &text[start + 1..end]; - let items: Vec = inner - .split(',') - .map(|item| item.trim().trim_matches('"').trim().to_string()) + // The reply may wrap the array in prose or a markdown fence; the slice + // between the outermost brackets is the array itself. Parse it as JSON + // instead of splitting on commas, which corrupts entries that contain + // commas or escaped quotes. + let items: Vec = serde_json::from_str::>(&text[start..=end]) + .unwrap_or_default() + .into_iter() .filter(|item| !item.is_empty()) + .take(max) .collect(); if items.is_empty() { fallback_queries(text, max) } else { - items.into_iter().take(max).collect() + items } } @@ -277,6 +281,37 @@ mod tests { assert_eq!(items, vec!["a".to_string(), "b".to_string()]); } + #[test] + fn parses_entries_containing_commas() { + let items = parse_string_array( + "[\"Paris, Texas population\", \"Austin, Texas weather\"]", + 5, + ); + assert_eq!( + items, + vec![ + "Paris, Texas population".to_string(), + "Austin, Texas weather".to_string() + ] + ); + } + + #[test] + fn parses_escaped_quotes_in_entries() { + let items = parse_string_array("[\"Paris, Texas population\", \"a\\\"b\"]", 5); + assert_eq!( + items, + vec!["Paris, Texas population".to_string(), "a\"b".to_string()] + ); + } + + #[test] + fn falls_back_when_array_is_not_valid_json() { + let items = parse_string_array("[rust async, tokio runtime]", 3); + assert!(!items.is_empty()); + assert!(items[0].contains("[rust async, tokio runtime]")); + } + #[test] fn falls_back_when_no_array() { let items = parse_string_array("just some prose", 3);