feat: timezone-aware context injection for agent prompts (#691)

* feat: per-group timezone architecture with context injection (#483)

Implement a comprehensive timezone consistency layer so the AI agent always
receives timestamps in the user's local timezone. The framework handles all
UTC↔local conversion transparently — the agent never performs manual timezone
math.

Key changes:
- Per-group timezone stored in containerConfig (no DB migration needed)
- Context injection: <context timezone="..." current_time="..." /> header
  prepended to every agent prompt with local time and IANA timezone
- Message timestamps converted from UTC to local display in formatMessages()
- schedule_task translation layer: agent writes local times, framework
  converts to UTC using per-group timezone for cron, once, and interval types
- Container TZ env var now uses per-group timezone instead of global constant
- New set_timezone MCP tool for users to update their timezone dynamically
- NANOCLAW_TIMEZONE passed to MCP server environment for tool confirmations

Architecture: Store UTC everywhere, convert at boundaries (display to agent,
parse from agent). Groups without timezone configured fall back to the server
TIMEZONE constant for full backward compatibility.

Closes #483
Closes #526

Co-authored-by: shawnYJ <shawny011717@users.noreply.github.com>
Co-authored-by: Adrian <Lafunamor@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* style: apply prettier formatting

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: strip to minimalist context injection — global TIMEZONE only

Remove per-group timezone support, set_timezone MCP tool, and all
related IPC handlers. The implementation now uses the global system
TIMEZONE for all groups, keeping the diff focused on the message
formatting layer: mandatory timezone param in formatMessages(),
<context> header injection, and formatLocalTime/formatCurrentTime
helpers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: drop formatCurrentTime and simplify context header

Address PR review: remove redundant formatCurrentTime() since message
timestamps already carry localized times. Simplify <context> header to
only include timezone name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: shawnYJ <shawny011717@users.noreply.github.com>
Co-authored-by: Adrian <Lafunamor@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Gabi Simons
2026-03-06 18:28:29 +02:00
committed by GitHub
parent 47ad2e654c
commit 632713b208
7 changed files with 114 additions and 41 deletions

View File

@@ -236,15 +236,15 @@ export async function processTaskIpc(
}
nextRun = new Date(Date.now() + ms).toISOString();
} else if (scheduleType === 'once') {
const scheduled = new Date(data.schedule_value);
if (isNaN(scheduled.getTime())) {
const date = new Date(data.schedule_value);
if (isNaN(date.getTime())) {
logger.warn(
{ scheduleValue: data.schedule_value },
'Invalid timestamp',
);
break;
}
nextRun = scheduled.toISOString();
nextRun = date.toISOString();
}
const taskId =