feat: move date time inject from system prompt

This commit is contained in:
Richard Tang
2026-04-22 17:11:34 -07:00
parent 390038225b
commit 6744bea01a
3 changed files with 28 additions and 14 deletions
+8 -2
View File
@@ -587,7 +587,12 @@ class AgentLoop(AgentProtocol):
initial_message = self._build_initial_message(ctx)
if initial_message:
await conversation.add_user_message(initial_message)
# Stamp with arrival time so the conversation has a
# temporal anchor for the first turn, matching the
# stamping done by drain_injection_queue for every
# subsequent event.
_stamp = datetime.now().astimezone().strftime("%Y-%m-%d %H:%M %Z")
await conversation.add_user_message(f"[{_stamp}] {initial_message}")
await self._run_hooks("session_start", conversation, trigger=initial_message)
@@ -599,7 +604,8 @@ class AgentLoop(AgentProtocol):
initial_message = self._build_initial_message(ctx)
if not initial_message:
initial_message = "Hello"
await conversation.add_user_message(initial_message)
_stamp = datetime.now().astimezone().strftime("%Y-%m-%d %H:%M %Z")
await conversation.add_user_message(f"[{_stamp}] {initial_message}")
# 2b. Restore spill counter from existing files (resume safety)
self._restore_spill_counter()
@@ -12,6 +12,7 @@ import json
import logging
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from datetime import datetime
from typing import Any
from framework.agent_loop.conversation import ConversationStore, NodeConversation
@@ -191,15 +192,21 @@ async def drain_injection_queue(
else:
logger.info("[drain] no vision fallback available; images dropped")
image_content = None
# Real user input is stored as-is; external events get a prefix
# Stamp every injected event with its arrival time so the model
# has a consistent temporal log to reason over (and so the
# stamp lives inside byte-stable conversation history instead
# of a per-turn system-prompt tail). Minute precision is what
# the queen needs for conversational / scheduling context.
stamp = datetime.now().astimezone().strftime("%Y-%m-%d %H:%M %Z")
if is_client_input:
stamped = f"[{stamp}] {content}" if content else f"[{stamp}]"
await conversation.add_user_message(
content,
stamped,
is_client_input=True,
image_content=image_content,
)
else:
await conversation.add_user_message(f"[External event]: {content}")
await conversation.add_user_message(f"[{stamp}] [External event] {content}")
count += 1
except asyncio.QueueEmpty:
break
@@ -232,7 +239,8 @@ async def drain_trigger_queue(
payload_str = json.dumps(t.payload, default=str)
parts.append(f"[TRIGGER: {t.trigger_type}/{t.source_id}]{task_line}\n{payload_str}")
combined = "\n\n".join(parts)
stamp = datetime.now().astimezone().strftime("%Y-%m-%d %H:%M %Z")
combined = f"[{stamp}]\n" + "\n\n".join(parts)
logger.info("[drain] %d trigger(s): %s", len(triggers), combined[:200])
# Tag the message so the UI can render a banner instead of the raw
# `[TRIGGER: ...]` text. The LLM still sees `combined` verbatim.
@@ -337,21 +337,21 @@ class QueenPhaseState:
def refresh_dynamic_suffix(self) -> str:
"""Rebuild and cache the dynamic system-prompt suffix.
The suffix contains recall blocks and the current date/time the
pieces that genuinely change per user turn. Called from the
The suffix contains recall blocks only. Called from the
CLIENT_INPUT_RECEIVED subscriber so the suffix is byte-stable across
every AgentLoop iteration within a single user turn. Also called on
phase transition so the timestamp reflects the transition moment.
every AgentLoop iteration within a single user turn.
Timestamps used to live here too; they were moved into the
conversation itself as a ``[YYYY-MM-DD HH:MM TZ]`` prefix on each
injected event (see ``drain_injection_queue``) so they ride on
byte-stable conversation history instead of busting the
per-turn system-prompt cache tail.
"""
parts: list[str] = []
if self._cached_global_recall_block:
parts.append(self._cached_global_recall_block)
if self._cached_queen_recall_block:
parts.append(self._cached_queen_recall_block)
local = datetime.now().astimezone()
parts.append(
f"Current date and time: {local.strftime('%Y-%m-%d %H:%M %Z (UTC%z)')}"
)
self._cached_dynamic_suffix = "\n\n".join(parts)
return self._cached_dynamic_suffix