From 659e7bd973e0721548643c01d84f1313cec8ce8f Mon Sep 17 00:00:00 2001 From: Cameron Cordes Date: Thu, 7 May 2026 14:42:42 -0400 Subject: [PATCH] insight-chat: get_sms_messages tool now honors days_radius MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The agentic tool definition advertised a days_radius parameter but sms_client::fetch_messages_for_contact was hardcoded to ±4 days, silently ignoring whatever value the LLM chose. Plumb the parameter through; default 4 retained at the tool level for back-compat. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/ai/insight_generator.rs | 6 ++--- src/ai/sms_client.rs | 51 +++++++++++++++++++++++++++---------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/ai/insight_generator.rs b/src/ai/insight_generator.rs index bd51b32..ca28115 100644 --- a/src/ai/insight_generator.rs +++ b/src/ai/insight_generator.rs @@ -983,7 +983,7 @@ impl InsightGenerator { // Step 1: Get FULL immediate temporal context (±4 days, ALL messages) let immediate_messages = self .sms_client - .fetch_messages_for_contact(contact.as_deref(), timestamp) + .fetch_messages_for_contact(contact.as_deref(), timestamp, 4) .await .unwrap_or_else(|e| { log::error!("Failed to fetch immediate messages: {}", e); @@ -1129,7 +1129,7 @@ impl InsightGenerator { log::info!("Using traditional time-based message retrieval (±4 days)"); let sms_messages = self .sms_client - .fetch_messages_for_contact(contact.as_deref(), timestamp) + .fetch_messages_for_contact(contact.as_deref(), timestamp, 4) .await .unwrap_or_else(|e| { log::error!("Failed to fetch SMS messages: {}", e); @@ -1835,7 +1835,7 @@ Return ONLY the summary, nothing else."#, match self .sms_client - .fetch_messages_for_contact(contact.as_deref(), timestamp) + .fetch_messages_for_contact(contact.as_deref(), timestamp, days_radius) .await { Ok(messages) if !messages.is_empty() => { diff --git a/src/ai/sms_client.rs b/src/ai/sms_client.rs index ad6d28e..46db005 100644 --- a/src/ai/sms_client.rs +++ b/src/ai/sms_client.rs @@ -20,31 +20,35 @@ impl SmsApiClient { } } - /// Fetch messages for a specific contact within ±4 days of the given timestamp - /// Falls back to all contacts if no messages found for the specific contact - /// Messages are sorted by proximity to the center timestamp + /// Compute a `[start, end]` unix-second window of `2 * radius_days` + /// centered on `center_ts`. `radius_days < 1` is clamped to 1 to avoid + /// degenerate zero-width windows. + pub(crate) fn window_for_radius(center_ts: i64, radius_days: i64) -> (i64, i64) { + let r = radius_days.max(1); + let span = r * 86400; + (center_ts - span, center_ts + span) + } + + /// Fetch messages for a specific contact within ±`radius_days` of the + /// given timestamp. Falls back to all contacts when no messages found + /// for the named contact. Sorted by proximity to the center timestamp. pub async fn fetch_messages_for_contact( &self, contact: Option<&str>, center_timestamp: i64, + radius_days: i64, ) -> Result> { - use chrono::Duration; + let (start_ts, end_ts) = Self::window_for_radius(center_timestamp, radius_days); - // Calculate ±4 days range around the center timestamp let center_dt = chrono::DateTime::from_timestamp(center_timestamp, 0) .ok_or_else(|| anyhow::anyhow!("Invalid timestamp"))?; - let start_dt = center_dt - Duration::days(4); - let end_dt = center_dt + Duration::days(4); - - let start_ts = start_dt.timestamp(); - let end_ts = end_dt.timestamp(); - // If contact specified, try fetching for that contact first if let Some(contact_name) = contact { log::info!( - "Fetching SMS for contact: {} (±4 days from {})", + "Fetching SMS for contact: {} (±{} days from {})", contact_name, + radius_days.max(1), center_dt.format("%Y-%m-%d %H:%M:%S") ); let messages = self @@ -68,7 +72,8 @@ impl SmsApiClient { // Fallback to all contacts log::info!( - "Fetching all SMS messages (±4 days from {})", + "Fetching all SMS messages (±{} days from {})", + radius_days.max(1), center_dt.format("%Y-%m-%d %H:%M:%S") ); self.fetch_messages(start_ts, end_ts, None, Some(center_timestamp)) @@ -379,3 +384,23 @@ struct SmsSearchResponse { #[serde(default)] search_method: String, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn window_for_radius_produces_2n_day_span() { + let center: i64 = 1_700_000_000; + let (start, end) = SmsApiClient::window_for_radius(center, 7); + assert_eq!(end - start, 14 * 86400); + assert_eq!(start + 7 * 86400, center); + assert_eq!(end - 7 * 86400, center); + } + + #[test] + fn window_for_radius_clamps_negative_to_one() { + let (start, end) = SmsApiClient::window_for_radius(100_000, 0); + assert_eq!(end - start, 2 * 86400); + } +}