diff --git a/CHANGELOG.md b/CHANGELOG.md index db1157c679e..b4222fb3337 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Docs: https://docs.openclaw.ai - Agents/Anthropic replay: preserve immutable signed-thinking replay safety across stored and live reruns, keep non-thinking embedded `tool_result` user blocks intact, and drop conflicting preserved tool IDs before validation so retries stop degrading into omitted tool calls. (#65126) Thanks @shakkernerd. - Telegram/direct sessions: keep commentary-only assistant fallback payloads out of visible direct delivery, so Codex planning chatter cannot leak into Telegram DMs when a run has no `final_answer` text. (#65112) Thanks @vincentkoc. - Infra/net: fix multipart FormData fields (including `model`) being silently dropped when a guarded runtime fetch body crosses a FormData implementation boundary, restoring OpenAI audio transcription requests that failed with HTTP 400. (#64349) Thanks @petr-sloup. +- Dreaming/diary: use the host local timezone for diary timestamps when `dreaming.timezone` is unset, so `DREAMS.md` and the UI stop defaulting to UTC. (#65034) Thanks @neo1027144-creator and @vincentkoc. - Plugins/memory: restore cached memory capability public artifacts on plugin-registry cache hits so memory-backed artifact surfaces stay visible after warm loads. Thanks @sercada and @vincentkoc. - Gateway/cron: preserve requested isolated-agent config across runtime reloads so subagent jobs and heartbeat overrides keep the right workspace and heartbeat settings when the hot-loaded snapshot is stale. Thanks @l0cka and @vincentkoc. - Cron/isolated sessions: persist the right transcript path for each isolated run, including fresh session rollovers, so cron runs stop appending to stale session files. Thanks @samrusani and @vincentkoc. diff --git a/extensions/memory-core/src/dreaming-narrative.test.ts b/extensions/memory-core/src/dreaming-narrative.test.ts index e07e770d140..8e3ed5daa1b 100644 --- a/extensions/memory-core/src/dreaming-narrative.test.ts +++ b/extensions/memory-core/src/dreaming-narrative.test.ts @@ -122,6 +122,36 @@ describe("formatNarrativeDate", () => { expect(date).toContain("2026"); expect(date).toContain("3:00"); }); + + it("applies an explicit timezone", () => { + // 2026-04-11T21:46:55Z in America/Los_Angeles (PDT, UTC-7) → 2:46 PM + const date = formatNarrativeDate( + Date.parse("2026-04-11T21:46:55Z"), + "America/Los_Angeles", + ); + expect(date).toContain("2:46"); + expect(date).toContain("PM"); + }); + + it("uses host local timezone when timezone is undefined (#65027)", () => { + // Force a non-UTC host timezone so this test is meaningful on UTC CI + // runners where the old `?? "UTC"` fallback would silently pass. + const originalTZ = process.env.TZ; + try { + process.env.TZ = "America/Los_Angeles"; // PDT = UTC-7 + const epochMs = Date.parse("2026-04-11T21:46:55Z"); + const result = formatNarrativeDate(epochMs); + // 21:46 UTC → 14:46 PDT → "2:46 PM" + expect(result).toContain("2:46"); + expect(result).toContain("PM"); + } finally { + if (originalTZ === undefined) { + delete process.env.TZ; + } else { + process.env.TZ = originalTZ; + } + } + }); }); describe("buildDiaryEntry", () => { diff --git a/extensions/memory-core/src/dreaming-narrative.ts b/extensions/memory-core/src/dreaming-narrative.ts index 804a1672444..5314b794714 100644 --- a/extensions/memory-core/src/dreaming-narrative.ts +++ b/extensions/memory-core/src/dreaming-narrative.ts @@ -231,7 +231,7 @@ export function extractNarrativeText(messages: unknown[]): string | null { export function formatNarrativeDate(epochMs: number, timezone?: string): string { const opts: Intl.DateTimeFormatOptions = { - timeZone: timezone ?? "UTC", + timeZone: timezone, year: "numeric", month: "long", day: "numeric",