prompt: cache-stable assembly (2a) — task-anchored date + memory at tail#194
Conversation
Make the system-prompt prefix byte-stable across a task's turns so providers can prefix-cache it (and so behavior is deterministic): - date is task-anchored + date-only (ChatSessionConfig.clock, e.g. the conversation's created_at) instead of a per-turn minute clock; - the relevance-filtered memory snapshot moves to the very end (volatile tail) so it never invalidates the stable content above it. Stacked on the act_first branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| # every turn so the system-prompt prefix stays cache-stable; a per-turn | ||
| # wall clock with minute precision would invalidate the cache each turn. | ||
| # The agent fetches precise time via a tool when it actually needs it. | ||
| _now = self._clock or _dt.datetime.now() |
There was a problem hiding this comment.
@torrmal I understand the need for prefix caching, but with Cowork, we will be passing the date/time when the task (conversation) created here, but according to the system prompt template that we have, this will be indicated to the agent as the current date and time. Do we need to change this template somehow? Otherwise, say that a user came back to a conversation days or even weeks later, that will still be treated as the 'current' date and time, yes?
There was a problem hiding this comment.
good point, yes, you are right let me fix that
Rework _summarize_history: - 3b-light: frame the summary as REFERENCE ONLY (latest user message wins; don't resume superseded/cancelled work) — protects Anton's auto-continue verifier from resurrecting stale tasks after a compaction. - 3b-full: emit a structured STATE RECORD (Goal/Constraints/Completed/Active state/Blocked/Decisions/Remaining) instead of freeform bullets, and UPDATE a prior summary in place (via a sentinel marker) rather than summarizing a summary, so 'Remaining' work survives across compactions. Stacked on the cache-stable-prompt chain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
compaction: structured, reference-only, in-place summary (Phase 3b)
…mmary keeps dates
PR feedback: anchoring the date to created_at but labeling it 'current' meant a
conversation resumed days/weeks later reported the wrong current time. Fix:
- prefix carries a FIXED 'Conversation started: {date}' line (cache-stable);
- the real wall clock is emitted in the volatile tail ('Current date and time: …'),
recomputed each turn, so it's always accurate and never busts the cached prefix;
- rename ChatSessionConfig.clock → started_at to match;
- the 3b summarizer now preserves key event dates so the timeline survives compaction
(per-message timestamps come from the harness embedding each message's created_at).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Good catch — addressed. The date is no longer anchored-as-"current". What changed:
Plus, per your "what time was something said" point: the cowork-server harness now embeds each message's So: prefix = started, history = per-message stamps, tail = live now — full temporal grounding, cache intact. |
Summary (Phase 2a)
Make Anton's system-prompt prefix byte-stable across a task's turns so providers can prefix-cache it and behavior is deterministic.
Changes
ChatSessionConfig.clock(e.g. the conversation'screated_at) replaces the per-turndatetime.now()minute clock in_build_system_prompt. Same task → identical date every turn → the prefix stops changing each minute. Falls back to today's date for the CLI. The agent fetches precise time via a tool when it needs it.Notes
cache_controlmarkers — Anthropic still needs those to actually cache (Phase 2b); OpenAI-compatible providers auto-cache identical prefixes and benefit immediately.feat/act-and-surface-assumptions(prompt: act-first posture (do first, surface assumptions) + execution discipline #193) — merge that first; this PR's base will retarget tostagingafter.clock=conversation.created_at).🤖 Generated with Claude Code