You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: per-chatter timezone for prompts and cron scheduling
The system prompt's date line and cron schedules were rendered/evaluated
in the server's timezone (UTC on hosted pods), so a SOUL.md instruction
like "use 东八区" reliably lost to the clock value, and "每天早上 9 点"
reminders fired at 下午 5 点 Beijing time.
Timezone is a property of the chatter, not the agent — different-timezone
users of the same agent each get their own wall clock:
- scope: new prefs namespace with chatter-first resolution
(chatter,agent) → (chatter) → (agent) → (system); SaveUserTimezone
writes at user scope so the preference follows the chatter across agents
- set_timezone tool: persists the chatter's IANA timezone where the
runtime reads it (also exposed in chatbot mode); a USER.md note alone
never affected scheduling
- system prompt: date line rendered in the chatter's local timezone via
ContextBuilder.tzResolver — the model never does offset arithmetic
- cron: jobs freeze the chatter's timezone at creation (was hardcoded
"UTC"); zone-less 'once' datetimes parse in it; recurrences evaluate in
it via NextOccurrenceIn. cron-type jobs no longer fire once immediately
on creation — first run is the actual next occurrence
- heartbeat: timestamps in the agent-default timezone
- deploy: TZ=Asia/Shanghai server-default fallback in compose/k8s/helm
Legacy rows keep their "UTC" semantics; empty timezone = server-local.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Chatter explicitly says "remember that X" (not about who they are) → `+bt+`MEMORY.md`+bt+`
@@ -840,7 +876,9 @@ You have the ability to update workspace files to maintain knowledge over time:
840
876
Use the write_file tool to update these files when appropriate. Keep entries concise and useful.
841
877
842
878
# Scheduling Time-Bound Tasks
843
-
When the user asks you to do something at a specific moment, after a delay, or on a recurring schedule (e.g. "5 分钟后提醒我", "每天 9 点", "every Monday morning"), call the create_cron_job tool. The scheduler fires precisely at the scheduled time and sends the message back to you on the same channel as a fresh inbound prompt — that's how reminders, recurring digests, and timed follow-ups should be implemented. NEVER write timed reminders into HEARTBEAT.md: that file is reviewed only on a coarse heartbeat tick and is wrong for any short-fuse or precise-timing request.`)
879
+
When the user asks you to do something at a specific moment, after a delay, or on a recurring schedule (e.g. "5 分钟后提醒我", "每天 9 点", "every Monday morning"), call the create_cron_job tool. The scheduler fires precisely at the scheduled time and sends the message back to you on the same channel as a fresh inbound prompt — that's how reminders, recurring digests, and timed follow-ups should be implemented. NEVER write timed reminders into HEARTBEAT.md: that file is reviewed only on a coarse heartbeat tick and is wrong for any short-fuse or precise-timing request.
880
+
881
+
Schedules are interpreted in the CHATTER'S local timezone — the same one your "Current date/time" line above is rendered in. Write "每天 9 点" as '0 9 * * *' directly; do NOT convert to UTC. If the chatter mentions being in a different timezone or city, call set_timezone first so both your clock and their schedules follow it.`)
// else server local): heartbeat has no chatter, but HEARTBEAT.md
73
+
// conditions are written in the operator's wall clock, not the
74
+
// pod's (UTC on hosted deployments).
75
+
now:=time.Now().In(hb.agent.chatterLocation(""))
72
76
heartbeatMsg:=fmt.Sprintf(
73
77
"[Heartbeat — %s]\nCurrent tasks from HEARTBEAT.md:\n%s\n\nReview these tasks and take action on any that need attention based on the current date/time.",
"description": "When to fire. For type='cron': a 5-field cron expression like '0 9 * * *'. For type='interval': a duration like '5m' / '30m' / '2h'. For type='once': an ISO-8601 datetime in UTC like '2026-05-02T15:56:52'.",
46
+
"description": "When to fire, in the CHATTER'S local timezone (the timezone shown on the 'Current date/time' line of your system prompt) — write '每天早上 9 点' as '0 9 * * *' directly, do NOT convert to UTC. For type='cron': a 5-field cron expression like '0 9 * * *'. For type='interval': a duration like '5m' / '30m' / '2h'. For type='once': an ISO-8601 datetime like '2026-05-02T15:56:52' (no offset = chatter's local time; an explicit offset like '+08:00' or 'Z' is honored as written).",
0 commit comments