feat: standardize timestamps to UTC

This commit is contained in:
Peter Steinberger
2026-01-05 23:02:13 +00:00
parent f790f3f3ba
commit ac3dedaa1b
15 changed files with 140 additions and 54 deletions

View File

@@ -116,6 +116,46 @@ function resolveGlobalLane(lane?: string) {
return cleaned ? cleaned : "main";
}
function resolveUserTimezone(configured?: string): string {
const trimmed = configured?.trim();
if (trimmed) {
try {
new Intl.DateTimeFormat("en-US", { timeZone: trimmed }).format(
new Date(),
);
return trimmed;
} catch {
// ignore invalid timezone
}
}
const host = Intl.DateTimeFormat().resolvedOptions().timeZone;
return host?.trim() || "UTC";
}
function formatUserTime(date: Date, timeZone: string): string | undefined {
try {
const parts = new Intl.DateTimeFormat("en-CA", {
timeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hourCycle: "h23",
}).formatToParts(date);
const map: Record<string, string> = {};
for (const part of parts) {
if (part.type !== "literal") map[part.type] = part.value;
}
if (!map.year || !map.month || !map.day || !map.hour || !map.minute) {
return undefined;
}
return `${map.year}-${map.month}-${map.day} ${map.hour}:${map.minute}`;
} catch {
return undefined;
}
}
export function buildEmbeddedSandboxInfo(
sandbox?: Awaited<ReturnType<typeof resolveSandboxContext>>,
): EmbeddedSandboxInfo | undefined {
@@ -398,6 +438,10 @@ export async function runEmbeddedPiAgent(params: {
};
const sandboxInfo = buildEmbeddedSandboxInfo(sandbox);
const reasoningTagHint = provider === "ollama";
const userTimezone = resolveUserTimezone(
params.config?.agent?.userTimezone,
);
const userTime = formatUserTime(new Date(), userTimezone);
const systemPrompt = buildSystemPrompt({
appendPrompt: buildAgentSystemPromptAppend({
workspaceDir: resolvedWorkspace,
@@ -408,6 +452,8 @@ export async function runEmbeddedPiAgent(params: {
runtimeInfo,
sandboxInfo,
toolNames: tools.map((tool) => tool.name),
userTimezone,
userTime,
}),
contextFiles,
skills: promptSkills,

View File

@@ -46,4 +46,16 @@ describe("buildAgentSystemPromptAppend", () => {
expect(prompt).toContain("sessions_send");
expect(prompt).toContain("Unavailable tools (do not call):");
});
it("includes user time when provided", () => {
const prompt = buildAgentSystemPromptAppend({
workspaceDir: "/tmp/clawd",
userTimezone: "America/Chicago",
userTime: "2026-01-05 15:26",
});
expect(prompt).toContain("## Time");
expect(prompt).toContain("User timezone: America/Chicago");
expect(prompt).toContain("Current user time: 2026-01-05 15:26");
});
});

View File

@@ -7,6 +7,8 @@ export function buildAgentSystemPromptAppend(params: {
ownerNumbers?: string[];
reasoningTagHint?: boolean;
toolNames?: string[];
userTimezone?: string;
userTime?: string;
runtimeInfo?: {
host?: string;
os?: string;
@@ -109,6 +111,8 @@ export function buildAgentSystemPromptAppend(params: {
"<final>Hey there! What would you like to do next?</final>",
].join(" ")
: undefined;
const userTimezone = params.userTimezone?.trim();
const userTime = params.userTime?.trim();
const runtimeInfo = params.runtimeInfo;
const runtimeLines: string[] = [];
if (runtimeInfo?.host) runtimeLines.push(`Host: ${runtimeInfo.host}`);
@@ -182,6 +186,10 @@ export function buildAgentSystemPromptAppend(params: {
"Never send streaming/partial replies to external messaging surfaces; only final replies should be delivered there.",
"Clawdbot handles message transport automatically; respond normally and your reply will be delivered to the current chat.",
"",
userTimezone || userTime ? "## Time" : "",
userTimezone ? `User timezone: ${userTimezone}` : "",
userTime ? `Current user time: ${userTime}` : "",
userTimezone || userTime ? "" : "",
"## Reply Tags",
"To request a native reply/quote on supported surfaces, include one tag in your reply:",
"- [[reply_to_current]] replies to the triggering message.",