Skip to content

Commit 3f54164

Browse files
committed
Add basic time sense
1 parent d047a07 commit 3f54164

3 files changed

Lines changed: 304 additions & 27 deletions

File tree

src/agent/context.rs

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use std::path::Path;
44

5+
use time::OffsetDateTime;
6+
57
use crate::llm::{Message, Role};
68
use crate::workspace;
79

@@ -21,14 +23,14 @@ pub fn build_messages(
2123
) -> Vec<Message> {
2224
let mut system = String::new();
2325

24-
// Identity: time, workspace
25-
let now_utc = std::time::SystemTime::now()
26-
.duration_since(std::time::UNIX_EPOCH)
27-
.map(|d| d.as_secs())
28-
.unwrap_or(0);
26+
// Identity: current date/time (human-readable + timezone) and Unix, workspace
27+
let now = OffsetDateTime::now_utc();
28+
let now_unix = now.unix_timestamp();
2929
system.push_str("You are iCrab, a minimal personal AI assistant. ");
30-
system.push_str("Current time (Unix): ");
31-
system.push_str(&now_utc.to_string());
30+
system.push_str("Current time: ");
31+
system.push_str(&format!("{} {} {} UTC. ", now.weekday(), now.date(), now.time()));
32+
system.push_str("Unix: ");
33+
system.push_str(&now_unix.to_string());
3234
system.push_str(". Workspace: ");
3335
system.push_str(workspace_path.to_string_lossy().as_ref());
3436
system.push_str(".\n\n");
@@ -111,3 +113,56 @@ pub fn build_messages(
111113
});
112114
messages
113115
}
116+
117+
#[cfg(test)]
118+
mod tests {
119+
use super::*;
120+
121+
const WEEKDAYS: &[&str] = &[
122+
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday",
123+
];
124+
125+
#[test]
126+
fn system_prompt_includes_human_readable_time_and_unix() {
127+
let workspace = std::env::temp_dir();
128+
let messages = build_messages(
129+
&workspace,
130+
&[],
131+
"",
132+
"hello",
133+
None,
134+
"",
135+
&[],
136+
None,
137+
);
138+
let system = &messages[0].content;
139+
assert!(
140+
system.contains("Current time:"),
141+
"system prompt should include 'Current time:'"
142+
);
143+
assert!(
144+
system.contains(" UTC."),
145+
"system prompt should include ' UTC.'"
146+
);
147+
assert!(
148+
system.contains("Unix: "),
149+
"system prompt should include 'Unix: '"
150+
);
151+
let has_weekday = WEEKDAYS.iter().any(|w| system.contains(w));
152+
assert!(
153+
has_weekday,
154+
"system prompt should include a weekday (e.g. Wednesday)"
155+
);
156+
// Unix timestamp should be a positive number after "Unix: "
157+
let unix_prefix = "Unix: ";
158+
let start = system.find(unix_prefix).unwrap() + unix_prefix.len();
159+
let rest = &system[start..];
160+
let end = rest.find('.').unwrap_or(rest.len());
161+
let unix_str = rest[..end].trim();
162+
assert!(
163+
unix_str.parse::<u64>().is_ok(),
164+
"Unix value should be numeric, got: {}",
165+
unix_str
166+
);
167+
}
168+
}

src/cron_runner.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,24 +82,32 @@ mod tests {
8282
use super::*;
8383
use crate::tools::cron::{CronStore, Schedule};
8484

85+
fn unix_now() -> u64 {
86+
std::time::SystemTime::now()
87+
.duration_since(std::time::UNIX_EPOCH)
88+
.map(|d| d.as_secs())
89+
.unwrap_or(0)
90+
}
91+
8592
#[tokio::test]
8693
async fn tick_fires_due_direct_job() {
8794
let dir = std::env::temp_dir().join("icrab_cron_runner_direct");
8895
let _ = std::fs::remove_dir_all(&dir);
8996
std::fs::create_dir_all(&dir).unwrap();
9097
let store = CronStore::empty(&dir);
98+
let base = unix_now();
9199
store
92100
.add(
93101
None,
94102
"Reminder".to_string(),
95103
JobAction::Direct,
96-
Schedule::Once { at_unix: 100 },
104+
Schedule::Once { at_unix: base + 60 },
97105
12345,
98106
)
99107
.unwrap();
100108
let (inbound_tx, _inbound_rx) = mpsc::channel(8);
101109
let (outbound_tx, mut outbound_rx) = mpsc::channel(8);
102-
tick_once(&store, &inbound_tx, &outbound_tx, 500).await;
110+
tick_once(&store, &inbound_tx, &outbound_tx, base + 61).await;
103111
let msg = outbound_rx.try_recv().unwrap();
104112
assert_eq!(msg.chat_id, 12345);
105113
assert_eq!(msg.text, "Reminder");
@@ -116,18 +124,19 @@ mod tests {
116124
let _ = std::fs::remove_dir_all(&dir);
117125
std::fs::create_dir_all(&dir).unwrap();
118126
let store = CronStore::empty(&dir);
127+
let base = unix_now();
119128
store
120129
.add(
121130
None,
122131
"Agent task".to_string(),
123132
JobAction::Agent,
124-
Schedule::Once { at_unix: 100 },
133+
Schedule::Once { at_unix: base + 60 },
125134
999,
126135
)
127136
.unwrap();
128137
let (inbound_tx, mut inbound_rx) = mpsc::channel(8);
129138
let (outbound_tx, _outbound_rx) = mpsc::channel(8);
130-
tick_once(&store, &inbound_tx, &outbound_tx, 500).await;
139+
tick_once(&store, &inbound_tx, &outbound_tx, base + 61).await;
131140
let msg = inbound_rx.try_recv().unwrap();
132141
assert_eq!(msg.chat_id, 999);
133142
assert_eq!(msg.text, "Agent task");
@@ -142,18 +151,19 @@ mod tests {
142151
let _ = std::fs::remove_dir_all(&dir);
143152
std::fs::create_dir_all(&dir).unwrap();
144153
let store = CronStore::empty(&dir);
154+
let base = unix_now();
145155
store
146156
.add(
147157
None,
148158
"Later".to_string(),
149159
JobAction::Direct,
150-
Schedule::Once { at_unix: 99999 },
160+
Schedule::Once { at_unix: base + 1000 },
151161
1,
152162
)
153163
.unwrap();
154164
let (inbound_tx, _inbound_rx) = mpsc::channel(8);
155165
let (outbound_tx, mut outbound_rx) = mpsc::channel(8);
156-
tick_once(&store, &inbound_tx, &outbound_tx, 500).await;
166+
tick_once(&store, &inbound_tx, &outbound_tx, base + 500).await;
157167
assert!(outbound_rx.try_recv().is_err());
158168
let _ = std::fs::remove_dir_all(&dir);
159169
}

0 commit comments

Comments
 (0)