Skip to content

fix(desktop/llm): cache-efficient datetime injector; stop 2026-is-wrong Insight/Focus cards - #12236

Merged
Git-on-my-level merged 8 commits into
mainfrom
fix/agent-datetime-injector
Aug 27, 2026
Merged

fix(desktop/llm): cache-efficient datetime injector; stop 2026-is-wrong Insight/Focus cards#12236
Git-on-my-level merged 8 commits into
mainfrom
fix/agent-datetime-injector

Conversation

@Git-on-my-level

@Git-on-my-level Git-on-my-level commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

fix(desktop/llm): cache-efficient datetime injector; stop 2026-is-wrong Insight/Focus cards

Closes SCA-358

Base: origin/main @ b059e8cdf08af55d72dc2cd69376615c69e06919

Why

Community report (desktop-app, ~2026-08-21): Omi Insight/Focus cards claimed the
system clock is stuck in 2026 and that an email dated 2026 should be
double-checked — while the real calendar date IS 2026. Root cause (verified on
main, swarm-reviewed in SCA-358):

  1. The shipped Insight and Suggestion (Focus) default prompts carried a GOOD
    EXAMPLE teaching the model that 2026 dates are mistakes
    ("You've scheduled this for 2026 — double-check the year"), with a verbatim
    port on Windows.
  2. Those lanes never told the model the current date: Insight's user prompt sent
    Time: h:mm a, EEEE (time-of-day + weekday, no year), Suggestion sent no
    date at all. With no anchor the model fell back to its training-cutoff year —
    and the example confirmed the misread.

What changed

The reported bug (macOS + Windows):

  • InsightAssistantSettings v3 / SuggestionAssistantSettings v8 (mac) and
    insight CURRENT_PROMPT_VERSION 3 (Windows): retire the wrong-year example in
    favor of the year-agnostic "scheduled this for yesterday — double-check the date", and add a DATE GROUNDING section — dates in the current year or
    later are normal; never say the clock/calendar/year is wrong; flag a date only
    when it is wrong on its own terms (fix(backend): ground proactive insights and memory extraction in the current date #8501-style critic). Version bumps wipe
    saved custom prompts via the existing migration paths.
  • Insight's per-call user prompt now carries
    Date/Time: Tuesday, August 25, 2026 at 3:45 PM (America/New_York) — the
    model also hand-writes SQL over UTC timestamps and needed the anchor.
    Suggestion's user prompt carries Today is yyyy-MM-dd (EEEE).

Shared injector (extend, don't reinvent):

  • macOS ChatPromptBuilder (beside the existing currentTimePrompt):
    currentCalendarDay(at:timeZone:)yyyy-MM-dd (EEEE) (day-stable) and
    currentLocalDatetime(at:timeZone:) → full local datetime + IANA zone.
  • Windows: currentTimeBlock extracted from desktopChatPrompt.currentTimePrompt.
  • Backend: utils.llm.temporal.current_date_for_uid (existing).

Other sites the swarm verified as judging "now" (refuter dropped goals,
director, home suggestions, profile merge, and working-observations as not
date-dependent or already anchored):

  • macOS task re-ranking (TaskPrioritizationService.rerankPrompt): states
    today + labels dues as UTC ISO (was: due-proximity judged with no anchor).
  • macOS TaskChatRuntime.query: wraps the user prompt with
    ChatPromptBuilder.currentTimePrompt — the same wrap main chat applies.
  • Backend proactive notifications: _process_mentor_proactive_notification now
    passes current_date_for_uid(uid) to gate/generate/critic (was: silent UTC
    fallback, wrong by up to a day for non-UTC users; desynced the year guard
    near local midnight).
  • Windows assembleTurnContext: injects the current-time block for every
    surface except main_chat (which wraps upstream in mainChat.ts) — pill/task/
    workstream agents resolve "Friday"/"due next week" against
    create_action_item due_at and previously had no clock anywhere.

Cache contract

Every static/cached system prompt stays byte-stable: no live clock enters a
cached prefix. Live datetime rides only in per-call user turns (or Gemini
uncachedPrompt-style volatile sections); calendar-day agents get date-only
yyyy-MM-dd (EEEE), day-stable within a timezone; full local datetime + IANA
zone where local times or UTC timestamps are discussed.

Tests

  • macOS ProactiveDateGroundingTests: (a) wrong-year example retired from both
    defaults + DATE GROUNDING present, (b) user prompts carry today's date from a
    controllable clock seam (analysisClockLine, SuggestionAssistant.userPrompt,
    rerankPrompt), (c) default system prompts contain no live timestamp,
    (d) rerank prompt labels UTC dues.
  • macOS TaskChatKernelIdentityTests: source tripwire pins the task-chat
    current-time wrap (with omi-test-quality annotation).
  • Windows insight/prompt.test.ts: example retired, version bump wipes saved
    custom prompts, deterministic formatDateTime, Phase-1 head regex.
    turnContext.test.ts: clock block for floating/task surfaces, absent for
    main_chat, injected clock used. desktopChatPrompt.test.ts unchanged and
    green against the refactored helper.
  • Backend test_pipeline_anchors_prompts_to_user_timezone_date: drives the real
    3-step pipeline with a sentinel date; every rendered prompt must carry it.

Verification

  • macOS: xcrun swift test --package-path Desktop --filter 'ProactiveDateGroundingTests|TaskChatKernelIdentityTests' — 34 tests, 0
    failures; broader affected suites (SuggestionAssistantTests,
    SuggestionPromptContractTests, TaskAssistantPromptTests, ChatPromptsTests,
    ContextBucketPromptAssemblerTests) — 38 tests, 0 failures.
  • Windows: pnpm vitest run src/main/assistants/insight/ src/main/agentKernel/desktopChatPrompt.test.ts src/main/agentKernel/turnContext.test.ts src/main/ipc/mainChat.test.ts
    156 passed; pnpm typecheck:node clean.
  • Backend: backend/.venv/bin/python -m pytest tests/unit/test_mentor_notifications.py — 50 passed;
    test_insight_date_grounding.py — 16 passed;
    test_connector_synthesis_helper.py — 6 passed.
  • Not dogfooded in a signed production app (per task constraints: no launch of
    /Applications/Omi.app); the changed surfaces are prompt builders exercised
    through the above tests.

Product invariants

  • INV-CHAT-1 — chat turn recording paths touched only additively
    (TaskChatRuntime prompt wrap; no journal/dedup semantics changed); the
    double-record guard suites above pass.
  • INV-TASK-2 — no new automatic task-writing path; re-ranking prompt change
    only adds date grounding to the existing review prompt.

Failure-Class: FC-machine-timezone-timestamp-in-prompt

Review in cubic

…26 wrong-year example

SCA-358: Insight and Suggestion (Focus) cards told users the system clock was
'stuck in 2026' and to double-check 2026-dated email. Two defects in the same
lanes: the shipped default prompts carried a GOOD EXAMPLE teaching that 2026
dates are mistakes, and the analysis requests never stated the year — Insight
sent 'h:mm a, EEEE' (time + weekday only), Suggestion sent no date at all.

- InsightAssistantSettings v3 / SuggestionAssistantSettings v8: replace the
  'scheduled this for 2026 — double-check the year' example with the year-
  agnostic 'scheduled this for yesterday — double-check the date', and add a
  DATE GROUNDING section (dates in the current year or later are normal; never
  say the clock/calendar/year is wrong).
- Insight user prompt now carries the full local date, time, and IANA timezone
  via InsightAssistant.analysisClockLine (SCA-358 class fix; the model also
  writes SQL over UTC timestamps and needed the anchor).
- Suggestion user prompt carries 'Today is yyyy-MM-dd (EEEE)' via
  SuggestionAssistant.userPrompt, now a static seam with an injectable clock.
- New shared helpers on ChatPromptBuilder — currentCalendarDay (date-only,
  day-stable) and currentLocalDatetime (full local datetime + IANA) — beside
  currentTimePrompt, for every proactive lane that judges dates. All injection
  is in the uncached user turn; the static system prompts stay byte-stable for
  prefix caching (pinned by test).

Tests: ProactiveDateGroundingTests — (a) wrong-year example retired from both
defaults, (b) user prompts carry today's date from a controllable clock seam,
(c) default system prompts contain no live timestamp.

Verification: xcrun swift test --package-path Desktop --filter
ProactiveDateGroundingTests — 7 tests, 0 failures.

Failure-Class: FC-machine-timezone-timestamp-in-prompt
…t turns a clock

SCA-358, Windows half. The Insight prompt is Mac's verbatim port and carried
the same two defects: the 'scheduled this for 2026 — double-check the year'
teaching example in the cached system prompt, and a Phase-1 user prompt that
stated only 'Time: 3:07 PM, Monday' — no year, no timezone.

- insight/prompt.ts v3: retire the wrong-year example (same year-agnostic
  replacement as Mac), add the DATE GROUNDING section, and render the Phase-1
  head as 'Date/Time: <full local date> at <time> (<IANA zone>)' via a new
  exported formatDateTime (mirrors Mac's analysisClockLine). promptStore wipes
  saved custom prompts on the version bump.
- agentKernel: extract currentTimeBlock from desktopChatPrompt.currentTimePrompt
  and inject it into assembleTurnContext for every surface except main_chat
  (mainChat.ts already wraps that surface's text upstream — injecting here too
  would double it). Pill/task/workstream agents resolve 'Friday'/'due next
  week' against tool timestamps (create_action_item due_at) and previously had
  no clock anywhere. The block rides in the volatile turn section, never in
  the byte-stable system prompt the pi binding hash keys on.

Tests: insight/prompt.test.ts (example retired, version bump wipes custom
prompts, deterministic formatDateTime, Phase-1 head regex) and
agentKernel/turnContext.test.ts (block present for floating_chat/task_chat,
absent for main_chat, injected clock used). desktopChatPrompt.test.ts still
passes unchanged against the refactored helper.

Verification: pnpm vitest run src/main/assistants/insight/prompt.test.ts
src/main/agentKernel/turnContext.test.ts
src/main/agentKernel/desktopChatPrompt.test.ts — 27 passed; pnpm
typecheck:node clean.

Failure-Class: FC-machine-timezone-timestamp-in-prompt
…ezone date

SCA-358 sibling: _process_mentor_proactive_notification never passed
current_date to evaluate_relevance / generate_notification /
validate_notification, so all three prompts fell back to
current_date_in_tz(None) — UTC. For non-UTC users 'Today is <date>' was
wrong by up to a day, and the #8501 never-say-the-year-is-wrong guard
desynced near local midnight (and across New Year in e.g. UTC+13).

Compute current_date_for_uid(uid) once per pipeline run (lazy user-tz
lookup, UTC fallback on any error — temporal.py) and pass it to all three
steps so gate/generate/critic share one 'today'. Same in-repo pattern as
connector_synthesis.py and memories.py.

Test: test_pipeline_anchors_prompts_to_user_timezone_date drives the real
pipeline with a sentinel date and asserts every rendered prompt carries it
(a caller that dropped the parameter would render the runner's UTC date).

Verification: backend/.venv/bin/python -m pytest
tests/unit/test_mentor_notifications.py — 50 passed.

Failure-Class: FC-machine-timezone-timestamp-in-prompt
…e/time

SCA-358 wiring pass over the two remaining macOS lanes the swarm verified
as judging 'now' with no anchor (refuter dropped goals/director/home-
suggestions/profile-merge as not date-dependent or already anchored):

- TaskPrioritizationService: the re-rank prompt weighs 'Time urgency (due
  date proximity)' against due dates rendered as UTC ISO strings, so the
  model anchored proximity on its training-cutoff date. The prompt
  (extracted to a static, clock-injectable rerankPrompt seam) now states
  'Today is yyyy-MM-dd (EEEE)' and labels the dues as UTC ISO timestamps.
- TaskChatRuntime.query: wrap the user prompt with
  ChatPromptBuilder.currentTimePrompt — the same wrap main chat applies
  (ChatProvider.swift:2846/:4959). The task context packet carries due_at
  ISO strings and the agent resolves relative dates; the block rides in
  the user turn, nothing downstream hashes it into a cached prefix.

Tests: rerankPrompt carries today + UTC labeling (behavioral, injected
clock); TaskChatRuntime source tripwire pins the wrap with the repo's
omi-test-quality static-contract annotation.

Verification: xcrun swift test --package-path Desktop --filter
'ProactiveDateGroundingTests|TaskChatKernelIdentityTests' — 34 tests,
0 failures.

Failure-Class: FC-machine-timezone-timestamp-in-prompt
The scenario-13 send path reaches the kernel through TaskChatRuntime.query,
which this PR grounds in the current time (SCA-358). Registers the file in
the flow's covers so the strict e2e-coverage gate stays green.

Failure-Class: none
…g tests

Replace the two force-unwraps (fixed IANA zone, gregorian date math) with
documented fallbacks; the exact-string assertions fail loudly if either
fallback ever engaged, so the tests cannot pass vacuously.

Failure-Class: none
The PR body is passed via --pr-body-file at preflight time; it is not a
repo artifact.

Failure-Class: none
@Git-on-my-level
Git-on-my-level merged commit 61dcb94 into main Aug 27, 2026
45 checks passed
@Git-on-my-level
Git-on-my-level deleted the fix/agent-datetime-injector branch August 27, 2026 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant