feat: time awareness subsystem for continuous temporal perception - #61837
feat: time awareness subsystem for continuous temporal perception#61837k-QRedHacker wants to merge 1 commit into
Conversation
Three-layer implementation gives the agent continuous perception of time flow across sessions and turns without breaking prompt caching: - Layer 1 (Dormancy Perception): Injected into system prompt volatile_parts at session-build time. Agent learns how long it was dormant between sessions. Cache-safe: computed once at build time, byte-stable for session lifetime. - Layer 2 (Heartbeat Rhythm): Injected into per-turn api_messages before each API call, throttled to once per 5 minutes. Agent learns current time and inter-turn intervals. Cache-safe: touches api_messages, not system prompt. - Layer 3 (Lifecycle Anchoring): Writes sleep timestamp on every session transition (/new, /reset, gateway expiry, agent close). State file: ~/.hermes/time_state.json (atomic writes, graceful degradation) Co-Authored-By: Claw F (量子红客组织)
Duplicate of #61731 -- same author, same title, and byte-identical 4-file set (agent/time_awareness.py, agent/system_prompt.py, agent/chat_completion_helpers.py, run_agent.py). #61731 is the earliest-open canonical of this Time Awareness cluster (the intermediate #61738 was already closed). Consolidating here; please continue on #61731. |
|
Quick clarification on the duplicate flag: #61731 was closed by us during the PR split — it bundled time-awareness core + session handoff together. #61837 is the clean, standalone time-awareness PR (4 files, 254 lines). #61731 and #61837 share the same commit history up to the split point, which is why the file sets look identical. #61837 is the current version. Thanks for the triage. |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for separating this from the earlier bundled PR. This needs lifecycle and state-ownership rework before it can provide the advertised guarantees.
Problems
- Proposed
run_agent.py:650sits after the compressor guard: currentrun_agent.py:635-637returns when no context compressor exists, so Layer 3 does not run in that supported configuration.AIAgent.close()(run_agent.py:3463) also does not call this transition helper, despite the PR claiming agent-close coverage. agent/time_awareness.py:43uses one profile-wide state file.on_api_call()reads and overwrites the single heartbeat timestamp at lines 160-182, so concurrent sessions affect each other's intervals and throttling. The fixed.tmppath at lines 74-81 can also collide between writers.- Current cache coverage deliberately rejects time-of-day in the system prompt (
tests/run_agent/test_run_agent.py:1275-1292), while the system-prompt builder can rebuild after compression (agent/system_prompt.py:507-519). This change needs a specific cache-stability test, not only comments.
Suggested changes
- Route lifecycle recording through all real session-boundary paths, independently of
context_compressor, and add tests for both compressor states. - Make timing state session-owned (or explicitly synchronize and document profile-wide semantics), then add temporary-
HERMES_HOMEconcurrency and throttling coverage.
Automated hermes-sweeper review.
| # gateway expiry, agent close). Enables Layer 1 dormancy computation. | ||
| try: | ||
| from agent.time_awareness import on_session_end as _ta_on_end | ||
| _ta_on_end() |
There was a problem hiding this comment.
This callback is after if not engine: return at line 636, so it never runs for agents without a context compressor. It also does not cover AIAgent.close(), which does not call this helper. Please route lifecycle recording through a compressor-independent session-boundary path.
| now = _now_iso() | ||
| now_ts = _now_ts() | ||
|
|
||
| last_hb_ts = state.get("last_heartbeat_ts") |
There was a problem hiding this comment.
last_heartbeat_ts is profile-global because _get_time_state_path() always returns one time_state.json. A second live session can suppress this session's heartbeat or make its reported interval describe another session. Please make state ownership session-specific or explicitly synchronize and define profile-wide semantics.
| # byte-stable for the session lifetime. | ||
| try: | ||
| from agent.time_awareness import on_session_start as _ta_on_start | ||
| _wake_ctx = _ta_on_start() |
There was a problem hiding this comment.
build_system_prompt_parts() is also called after context-compression invalidation. Please add a regression test showing that this side-effect and injected value preserve the intended prompt-cache invariant across all rebuild paths.
|
Hi @teknium1, thanks for the thorough review. Your feedback was spot-on and pushed the design from a working prototype to something architecturally sound. I've addressed all three points locally and the subsystem is now running stably:
Appreciate the detailed notes. |
Time Awareness: Three-Layer Temporal Perception
This PR implements a Time Awareness subsystem for Hermes Agent — giving the agent continuous perception of time flow across sessions and turns.
What This Does
Layer 1 — Dormancy Perception (system prompt, cache-safe)
~/.hermes/time_state.jsonfor the last sleep timestampbuild_system_prompt_parts()time, byte-stable for the session lifetimeLayer 2 — Heartbeat Rhythm (per-turn messages, not system prompt)
api_messagesLayer 3 — Lifecycle Anchoring (session transitions)
/new,/reset, gateway expiry, agent close), writes the sleep timestampFiles Changed
agent/time_awareness.pyagent/system_prompt.pybuild_system_prompt_parts()agent/chat_completion_helpers.pybuild_api_kwargs()run_agent.py_transition_context_engine_session()Total: 4 files, 254 insertions.
Cache Safety
This PR does NOT break prompt caching:
volatile_parts. The volatile_parts tier is rebuilt only at session boundary / compression events — not per-turn. The result is byte-stable for the session.api_messages(the per-turn message array), NOT the system prompt. Prefix-cached system prompt bytes are untouched.Design Decisions
os.replace(tmp, path)prevents state file corruption on crashtry/except— failure silently passes, never blocks prompt build or API callsget_hermes_home()for path resolutionOriginal
This supersedes #61731 and #61738 (which were duplicates and bundled unrelated changes). This PR contains only the time awareness subsystem.