feat(ai): date_info tool for exact date arithmetic
Small local models get weekdays, "how long ago" and day counts between dates wrong, confidently. Persona chats anchored on old SMS threads ask exactly those questions. date_info answers them exactly, in the owner's display zone: - no args: now (replaces get_current_datetime) - date: its weekday and how long ago / until - date + other_date: the gap in days, weeks and years/months/days, plus hours when both carry times - date + add_days: the date N days after (or before) Checked live on gemma4-26b-A4B and gemma4-31: each date question took one date_info call and came back correct. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7215c1bdfe
commit
edfa48d116
4 files changed
+378
-23
No files matched your search
+25
-21
@@ -1937,7 +1937,9 @@ Return ONLY the summary, nothing else."#,
|
||||
self.tool_supersede_fact(arguments, user_id, persona_id, model, backend_label)
|
||||
.await
|
||||
}
|
||||
"get_current_datetime" => Self::tool_get_current_datetime(),
|
||||
"date_info" => {
|
||||
crate::ai::date_info::date_info(arguments, Utc::now(), self.display_zone())
|
||||
}
|
||||
"get_thread_messages" => self.tool_get_thread_messages(arguments).await,
|
||||
"look_at_message_image" => {
|
||||
self.tool_look_at_message_image(arguments, backend.local())
|
||||
@@ -3703,21 +3705,11 @@ Return ONLY the summary, nothing else."#,
|
||||
}
|
||||
}
|
||||
|
||||
/// Tool: get_current_datetime — returns the current local date and time
|
||||
fn tool_get_current_datetime() -> String {
|
||||
let now = Local::now();
|
||||
format!(
|
||||
"Current date/time: {} ({})",
|
||||
now.format("%Y-%m-%d %H:%M:%S %Z"),
|
||||
now.format("%A")
|
||||
)
|
||||
}
|
||||
|
||||
// ── Agentic insight generation ──────────────────────────────────────
|
||||
|
||||
/// Build the list of tool definitions for the agentic loop, gated by
|
||||
/// `opts`. Always-on tools: `search_messages`, `get_sms_messages`,
|
||||
/// `get_file_tags`, `reverse_geocode`, `get_current_datetime`, the
|
||||
/// `get_file_tags`, `reverse_geocode`, `date_info`, the
|
||||
/// five knowledge-memory tools. Conditional: `describe_photo` (vision
|
||||
/// model), `get_personal_place_at` (Apollo configured), `search_rag`
|
||||
/// (daily_summaries populated), `get_calendar_events` (calendar
|
||||
@@ -4043,11 +4035,23 @@ Return ONLY the summary, nothing else."#,
|
||||
}
|
||||
|
||||
tools.push(Tool::function(
|
||||
"get_current_datetime",
|
||||
"Get the current date and time. Useful when reasoning about how long ago a photo was taken.",
|
||||
"date_info",
|
||||
"Exact date arithmetic — use it instead of working dates out yourself. With no arguments: \
|
||||
the current date and time. With `date`: that day's weekday and how long ago (or until) it \
|
||||
is. With `date` and `other_date`: the gap between them in days, weeks and years/months/days \
|
||||
(and hours, when both have times). With `date` and `add_days`: the date that many days \
|
||||
after (or, negative, before). Dates are YYYY-MM-DD, YYYY-MM-DD HH:MM, or unix seconds, in \
|
||||
the user's local time. \
|
||||
Examples: `{}` — now. `{date: \"2019-07-03\"}` — weekday and how long ago. \
|
||||
`{date: \"2019-07-03\", other_date: \"2019-08-14\"}` — time between. \
|
||||
`{date: \"2019-07-03\", add_days: 90}` — the date 90 days later.",
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
"properties": {
|
||||
"date": { "type": "string", "description": "YYYY-MM-DD, YYYY-MM-DD HH:MM, or unix seconds." },
|
||||
"other_date": { "type": "string", "description": "Second date, to measure the gap between the two." },
|
||||
"add_days": { "type": "integer", "description": "Days to add to `date` (negative to go back)." }
|
||||
}
|
||||
}),
|
||||
));
|
||||
|
||||
@@ -4305,7 +4309,7 @@ Return ONLY the summary, nothing else."#,
|
||||
.find_map(|tok| tok.strip_prefix("ID:"))
|
||||
.map(|id| format!("stored id={}", id.trim_end_matches(',')))
|
||||
.unwrap_or_else(|| "stored".to_string()),
|
||||
"get_current_datetime" => "time noted".to_string(),
|
||||
"date_info" => "date worked out".to_string(),
|
||||
"look_at_message_image" | "look_at_photo" => {
|
||||
let short: String = raw.chars().take(80).collect();
|
||||
format!("looked: \"{}...\"", short)
|
||||
@@ -5238,7 +5242,7 @@ mod tests {
|
||||
assert!(names.contains(&"get_sms_messages"));
|
||||
assert!(names.contains(&"get_file_tags"));
|
||||
assert!(names.contains(&"reverse_geocode"));
|
||||
assert!(names.contains(&"get_current_datetime"));
|
||||
assert!(names.contains(&"date_info"));
|
||||
assert!(names.contains(&"recall_entities"));
|
||||
assert!(names.contains(&"recall_facts_for_photo"));
|
||||
assert!(names.contains(&"recall_facts_for_entity"));
|
||||
@@ -5786,13 +5790,13 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarize_current_datetime() {
|
||||
fn summarize_date_info() {
|
||||
assert_eq!(
|
||||
InsightGenerator::summarize_tool_result(
|
||||
"get_current_datetime",
|
||||
"Current date/time: 2024-01-15 12:00:00 PST (Monday)"
|
||||
"date_info",
|
||||
"Now: 2024-01-15 12:00 (Monday), America/New_York"
|
||||
),
|
||||
"time noted"
|
||||
"date worked out"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user