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:
@@ -1,4 +1,5 @@
|
||||
import { Channel, NewMessage } from './types.js';
|
||||
import { formatLocalTime } from './timezone.js';
|
||||
|
||||
export function escapeXml(s: string): string {
|
||||
if (!s) return '';
|
||||
@@ -9,12 +10,18 @@ export function escapeXml(s: string): string {
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
export function formatMessages(messages: NewMessage[]): string {
|
||||
const lines = messages.map(
|
||||
(m) =>
|
||||
`<message sender="${escapeXml(m.sender_name)}" time="${m.timestamp}">${escapeXml(m.content)}</message>`,
|
||||
);
|
||||
return `<messages>\n${lines.join('\n')}\n</messages>`;
|
||||
export function formatMessages(
|
||||
messages: NewMessage[],
|
||||
timezone: string,
|
||||
): string {
|
||||
const lines = messages.map((m) => {
|
||||
const displayTime = formatLocalTime(m.timestamp, timezone);
|
||||
return `<message sender="${escapeXml(m.sender_name)}" time="${escapeXml(displayTime)}">${escapeXml(m.content)}</message>`;
|
||||
});
|
||||
|
||||
const header = `<context timezone="${escapeXml(timezone)}" />\n`;
|
||||
|
||||
return `${header}<messages>\n${lines.join('\n')}\n</messages>`;
|
||||
}
|
||||
|
||||
export function stripInternalTags(text: string): string {
|
||||
|
||||
Reference in New Issue
Block a user