hermes - ✅(Solved) Fix Consolidate live-time PRs around one ephemeral runtime context path [8 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#17476Fetched 2026-04-30 06:47:16
View on GitHub
Comments
0
Participants
1
Timeline
17
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×14labeled ×3

Consolidate the currently fragmented timestamp/timezone PRs around one core implementation path:

  • Keep volatile current time out of the cached system prompt.
  • Surface current time/timezone through the core ephemeral user-message/runtime context path.
  • Avoid separate gateway-specific timestamp-prefix mechanisms unless they are thin wrappers over the same core context.

This is the coordination fan-out from #17459.

Root Cause

Consolidate the currently fragmented timestamp/timezone PRs around one core implementation path:

  • Keep volatile current time out of the cached system prompt.
  • Surface current time/timezone through the core ephemeral user-message/runtime context path.
  • Avoid separate gateway-specific timestamp-prefix mechanisms unless they are thin wrappers over the same core context.

This is the coordination fan-out from #17459.

Fix Action

Fixed

PR fix notes

PR #15872: fix: prevent stale timestamp perception by injecting current time per-turn

Description (problem / solution / changelog)

Problem

The system prompt includes a timestamp frozen at session creation time (for prompt cache stability). However, the label "Conversation started: <time>" is ambiguous — agents interpret it as the current time, leading to incorrect time-sensitive behavior.

Observed: In a session started at 5:07 AM, the agent said "good night 🌙" at 9:00 AM because the only timestamp it saw was "Conversation started: Sunday, April 26, 2026 05:07 AM".

Solution

Split the timestamp into two layers, both using user-message injection to preserve prompt cache:

LayerContentLocationFrequency
System promptSession started: <time> (timezone)FrozenOnce per session (cache-stable)
User messageCurrent time: <time>\nTimezone: <tz>DynamicEvery turn (cache-safe)

Why user-message injection (not system prompt)?

PR #10448 addresses the same bug but injects Current time: into the system prompt via _build_turn_scoped_system_prompt(). This changes the system prompt content every turn, which breaks prompt cache prefix.

This PR injects into the user message — the same mechanism that plugins use (pre_llm_call context). The Hermes codebase itself documents this principle:

"Context is ALWAYS injected into the user message, never the system prompt. This preserves the prompt cache prefix — the system prompt stays identical across turns so cached tokens are reused."

User-message injection also composes naturally with the existing plugin system — time context merges with plugin context in _plugin_user_context.

Changes

  1. run_agent.py_build_system_prompt(): Rename "Conversation started""Session started" and add timezone name
  2. run_agent.pyrun_conversation(): Inject current time + timezone into _plugin_user_context on every turn
  3. run_agent.py_handle_max_iterations(): Inject current time into the summary request user message (recovery path)
  4. hermes_time.py: Add get_timezone_name() public API
  5. Comment update: Layer 6 comment now documents the split explicitly
  6. Tests: 4 new/updated tests covering cache safety, user-message injection, and max-iterations path

Test results

tests/run_agent/test_run_agent.py::TestBuildSystemPrompt::test_includes_datetime PASSED
tests/run_agent/test_run_agent.py::TestBuildSystemPrompt::test_excludes_current_time_from_cached_prompt PASSED
tests/run_agent/test_run_agent.py::TestHandleMaxIterations::test_summary_injects_current_time_into_user_message PASSED
tests/run_agent/test_run_agent.py::TestRunConversation::test_turn_level_time_injected_into_user_message PASSED

Relation to #10448

Same bug, different injection location. See my comment on #10448 for the full comparison. Key difference: this PR preserves prompt cache by using user-message injection; #10448 breaks cache by modifying the system prompt per turn.

Token impact

~50 tokens per turn (two lines: current time + timezone). This is minimal compared to typical tool schemas and memory blocks, and the information is essential for correct agent behavior.

Changed files

  • hermes_time.py (modified, +40/-0)
  • run_agent.py (modified, +48/-4)
  • tests/run_agent/test_run_agent.py (modified, +73/-2)
  • tests/run_agent/test_run_agent_codex_responses.py (modified, +31/-0)

PR #10061: fix(timezone): propagate configured timezone to agent prompt and terminals

Description (problem / solution / changelog)

What does this PR do?

When a user configured a timezone (HERMES_TIMEZONE env var or timezone: key in ~/.hermes/config.yaml), the agent didn't know about it. Two visible symptoms:

  1. The system prompt's timestamp had no zone marker, so the model fell back to server-local time. "What's today's date?" returned the server's date, not the user's.
  2. date (and any TZ-honouring runtime) inside the terminal tool reported the server's wall clock, so shell output disagreed with what the agent thought the time was.

Fixed end-to-end via two centralized injection points instead of touching each backend individually:

  • Agent prompt (run_agent.py): append a Timezone: <IANA> (UTC±HH:MM) line to the timestamp block when a timezone is configured.
  • Every terminal backend: BaseEnvironment._wrap_command injects export TZ=<name> once. That covers local, docker, ssh, singularity, modal, and daytona — all six flow through this method. Managed Modal uses a different exec path (BaseModalExecutionEnvironment._prepare_modal_exec), so it gets the same injection there.
  • Resolver (tools/environments/base.py): new _resolve_configured_tz_name() reads via hermes_time.get_timezone(), which checks both HERMES_TIMEZONE and ~/.hermes/config.yaml. CLI entry points like hermes chat don't bridge config.yaml → env var (only gateway/run.py does), so an env-var-only check would silently miss config.yaml-only setups. This resolver covers them.

Related Issue

N/A — no existing issue. Reproduced locally with timezone: Asia/Shanghai in ~/.hermes/config.yaml running on a UTC server.

Fixes #

Type of Change

<!-- Check the one that applies. -->
  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • run_agent.py — emit Timezone: <IANA> (UTC±HH:MM) after the timestamp when configured. Uses hermes_time.now() so the offset is computed in the user's zone.
  • tools/environments/base.py — new _resolve_configured_tz_name() helper; BaseEnvironment._wrap_command injects export TZ=<name> after the snapshot source so it overrides anything inherited.
  • tools/environments/modal_utils.pyBaseModalExecutionEnvironment._prepare_modal_exec prepends export TZ=<name>; after sudo wrapping (covers ManagedModalEnvironment).
  • tools/environments/local.py_make_run_env and _sanitize_subprocess_env set TZ=<name> on the subprocess env so PTY/background terminals (spawned via process_registry.spawn_local) and the init_session bootstrap that runs before the snapshot exists also agree. Refactored to use the shared helper.
  • Tests:
    • tests/run_agent/test_run_agent.pytest_includes_timezone_when_configured, test_omits_timezone_line_without_config.
    • tests/tools/test_base_environment.pyTestWrapCommandTimezone (4) and TestResolveConfiguredTzName (3).
    • tests/tools/test_modal_utils_tz.pyTestPrepareModalExecTimezone (4) [new file].
    • tests/tools/test_local_env_blocklist.pyTestTimezonePropagation (5).

How to Test

  1. Set timezone (pick one):
    • export HERMES_TIMEZONE=Asia/Shanghai, or
    • Add timezone: Asia/Shanghai to ~/.hermes/config.yaml (with no HERMES_TIMEZONE env var).
  2. Start hermes chat. The system prompt should include Timezone: Asia/Shanghai (UTC+08:00) right under the timestamp.
  3. In the chat, ask the agent to run date. Output should be Asia/Shanghai wall-clock time (CST), not the server's zone.
  4. Targeted unit tests:

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix: prefix; one squashed commit)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix (one squashed commit, eight files)
  • I've run pytest on the affected modules and all tests pass (301 passed); full pytest tests/ not re-run end-to-end
  • I've added tests for my changes
  • I've tested on my platform: macOS 15 (Darwin 25.4.0)

Documentation & Housekeeping

  • I've updated relevant documentation — not done. Timezone configuration is currently undocumented anywhere on https://hermes-agent.nousresearch.com/docs (verified via the docs search). Worth a follow-up doc PR; this PR keeps its surface area to the bug.
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A: no new config keys; the existing timezone key just starts working in places where it was silently ignored.
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A: no architecture changes.
  • I've considered cross-platform impact — export TZ=<name> is POSIX; the change works on Linux, macOS, Termux, and Git Bash on Windows since every terminal backend already shells through bash.
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A: no tool schema or description changes.

Changed files

  • run_agent.py (modified, +11/-0)
  • tests/run_agent/test_run_agent.py (modified, +24/-0)
  • tests/tools/test_base_environment.py (modified, +72/-0)
  • tests/tools/test_local_env_blocklist.py (modified, +56/-0)
  • tests/tools/test_modal_utils_tz.py (added, +74/-0)
  • tools/environments/base.py (modified, +27/-0)
  • tools/environments/local.py (modified, +23/-1)
  • tools/environments/modal_utils.py (modified, +9/-0)

PR #8689: perf: stabilize system prompt timestamp across compression cycles

Description (problem / solution / changelog)

Summary

Stabilizes the "Conversation started" timestamp in the system prompt across compression cycles, preventing prefix cache invalidation on local LLM backends.

Before

now = _hermes_now()  # current time — changes after every compression!
timestamp_line = f"Conversation started: {now.strftime(...)}"

After

_start = getattr(self, "session_start", None) or _hermes_now()  # set once at __init__
timestamp_line = f"Conversation started: {_start.strftime(...)}"
# Only after compression:
timestamp_line += f"\nLast context compaction: {_now.strftime(...)} (#{count})"

Evidence

MITM proxy analysis showed the timestamp was the ONLY difference between system prompts. On LM Studio with phi-3.5-mini (~17K token prompt): 3.6x latency penalty per cache miss (2.2s vs 8.0s).

After fix, validated via MITM: "Conversation started" stays stable. Post-compression adds exactly one line, preserving the prefix before it for partial cache matching.

Test plan

  • MITM proxy validation: "Conversation started" stable across compression
  • Post-compression prompt adds "Last context compaction: {date} (#{count})"
  • Defensive: handles missing session_start and context_compressor gracefully
  • CI tests pass

Closes #8687. Relates to #3353, #4319.

Changed files

  • run_agent.py (modified, +11/-2)

PR #5713: feat(caching): multi-block system prompt with tiered TTLs (v2)

Description (problem / solution / changelog)

Summary

Refactor Anthropic prompt caching to use a structured multi-block system prompt with per-block cache_control markers instead of a single monolithic system message. This maximizes cache hits by isolating volatile content (timestamps, platform hints) from stable content (identity, skills, memory).

Architecture

The system prompt is now assembled as three SystemPromptBlock instances with different cache TTLs:

BlockTTLContents
static1hSoul.md / default identity, tool-aware guidance (memory, session_search, skills), Nous subscription prompt, tool-use enforcement, model-specific operational guidance (Google/OpenAI), skills system prompt
session5mCustom system_message, memory store blocks (memory + user), external memory provider block, context files (AGENTS.md/CLAUDE.md/etc.)
ephemeralnoneTimestamp + session/model/provider line, Alibaba identity workaround, platform hints

At API call time, blocks are converted to Anthropic content block format (`[{type: text, text: ..., cache_control: ...}, ...]`) and sent as the system message. Non-caching models fall through to the flat-string path unchanged.

New public API in `agent/prompt_caching.py`

  • `SystemPromptBlock`, `CacheMetrics`, `AggregatedCacheMetrics` dataclasses
  • `build_system_content_blocks(blocks)` — convert blocks to Anthropic format
  • `apply_anthropic_cache_control_v2(messages, tools, cache_ttl, native_anthropic)` — multi-block + tool caching with budget management (max 4 breakpoints across tools + system + messages)
  • `extract_cache_metrics(usage, api_mode)` — per-call cache extraction supporting both native Anthropic (`cache_read_input_tokens`, `cache_creation_input_tokens`) and OpenRouter (`prompt_tokens_details.cached_tokens`) response formats
  • `aggregate_cache_metrics(metrics_list)` — cross-turn aggregation

The v1 `apply_anthropic_cache_control` function and `_apply_cache_marker` helper are preserved unchanged for backward compatibility.

Integration in `run_agent.py`

  • New `_build_system_prompt_blocks()` method assembles the three tiered blocks and caches them on `self._cached_system_blocks`
  • The existing `_build_system_prompt()` method still returns a flat string (for backward compatibility with code paths that expect one) but now delegates to the block builder
  • Cached blocks are invalidated on context compression (`_cached_system_blocks = None` alongside `_cached_system_prompt = None`)
  • At API call time, when `_use_prompt_caching` is enabled and `_cached_system_blocks` is populated, a multi-block path builds `{role: system, content: [...]}` with cache_control markers already set per block
  • Plugin turn context (`_plugin_turn_context`) remains reserved for future system-level plugin instructions; plugin context from pre_llm_call hooks still goes into user messages (unchanged)
  • Fallback flat-string path handles non-caching models and pre-structured content correctly

Test coverage

  • `tests/agent/test_prompt_caching.py` — 46 unit tests covering v1 (preserved) and v2 functions: data structures, cache markers, content block conversion, pre-structured detection, breakpoint budgeting, metrics extraction and aggregation
  • `tests/agent/test_prompt_caching_v2.py` — 38 additional integration tests for v2 behavior (tool caching interaction with system blocks, budget with pre-structured content, backward compatibility with v1 code paths)
  • `tests/test_prompt_caching_integration.py` — 10 integration tests against `run_agent.py` block assembly (three-block structure, tier TTLs, timestamp in ephemeral block only, cache invalidation, backward-compat string return, non-caching models unaffected)

Verified: 317 tests passing (all of the above plus `tests/test_run_agent.py` regression suite).

Test plan

  • All new v2 unit tests pass (`pytest tests/agent/test_prompt_caching.py tests/agent/test_prompt_caching_v2.py`)
  • Integration tests against `run_agent.py` block assembly pass (`pytest tests/test_prompt_caching_integration.py`)
  • Full run_agent.py regression suite passes (`pytest tests/test_run_agent.py`)
  • `run_agent` imports cleanly
  • Manual: verify cache hit rate improves on a multi-turn conversation with stable context files (reviewer action)
  • Manual: verify non-caching models (e.g. local Ollama) still work via flat-string fallback (reviewer action)

Platforms tested

Linux (WSL2, Ubuntu 22.04), Python 3.11

🤖 Generated with Claude Code

Changed files

  • agent/prompt_caching.py (modified, +252/-6)
  • run_agent.py (modified, +169/-83)
  • tests/agent/test_prompt_caching.py (modified, +316/-0)
  • tests/agent/test_prompt_caching_v2.py (added, +469/-0)
  • tests/test_prompt_caching_integration.py (added, +209/-0)

PR #10006: fix: codex_responses prompt caching — session routing headers + cache_write_tokens field

Description (problem / solution / changelog)

Problem

Prompt caching does not work when using codex_responses API mode with OpenAI-compatible providers (e.g. theclawbay). Every request is a cache miss despite prompt_cache_key being set in the request body.

Root cause

Two issues:

1. Missing session routing headers (run_agent.py)

The OpenAI client is initialized without session_id or x-client-request-id headers for codex providers. These headers are required for server-side cache routing — they tell the backend to route requests to the same server that holds the cached prompt prefix.

The official Codex CLI sends these unconditionally. Hermes sets default_headers for OpenRouter, GitHub Copilot, Kimi, and Qwen — but never for Codex/theclawbay.

2. Wrong field name for cache_write_tokens (agent/usage_pricing.py)

The codex_responses branch reads cache_creation_tokens (Anthropic naming convention) instead of cache_write_tokens (OpenAI Responses API naming). This means cache write tokens are always reported as 0.

Fix

Patch 1: Session routing headers

After session_id is assigned during __init__, inject session_id and x-client-request-id into default_headers for codex_responses mode. Also applied in _apply_client_headers_for_base_url() so headers survive /model switches.

Patch 2: cache_write_tokens field

Read cache_write_tokens first (OpenAI naming), fall back to cache_creation_tokens for backward compatibility.

Tests

  • test_codex_responses_reads_cache_write_tokens_field — verifies correct field is read
  • test_codex_responses_falls_back_to_cache_creation_tokens — backward compat
  • test_codex_responses_injects_session_routing_headers — verifies headers are set

Affected files

FileChange
run_agent.pyInject session routing headers for codex_responses mode (+22 lines)
agent/usage_pricing.pyRead cache_write_tokens before cache_creation_tokens (+3/-1 lines)
tests/agent/test_usage_pricing.py2 new tests
tests/run_agent/test_run_agent.py1 new test

Changed files

  • agent/usage_pricing.py (modified, +3/-1)
  • run_agent.py (modified, +22/-0)
  • tests/agent/test_usage_pricing.py (modified, +36/-0)
  • tests/run_agent/test_run_agent.py (modified, +19/-0)

PR #10448: fix(agent): inject turn-level live time context

Description (problem / solution / changelog)

Summary

Hermes currently has a session-level Conversation started: ... timestamp, but it does not provide a reliable turn-level live sense of "now" for each API call.

This PR adds a turn-scoped Current time: YYYY-MM-DD HH:MM (TZ) hint at API-call time instead of baking live time into the cached session prompt.

What changed

  • add _build_live_time_context() in run_agent.py
  • add _build_turn_scoped_system_prompt() so live time is injected per API call, not into _build_system_prompt()
  • use that helper in both:
    • run_conversation()
    • _handle_max_iterations()
  • add targeted tests for:
    • cached system prompt stays free of Current time:
    • chat-completions run path injects live time
    • max-iteration summary path injects live time
    • codex responses path injects live time

Why this shape

This is intentionally aligned with the request in #10421:

  • live time is turn-scoped
  • it is injected at API-call time
  • it does not mutate the session-cached system prompt
  • it works for both chat-completions and codex-responses paths

Relation to other work

This PR is intentionally narrower than #10061.

  • #10061 focuses on timezone propagation to prompts and terminal environments
  • this PR only addresses turn-level live current-time injection

They are adjacent, but not the same fix.

Repro verified

I re-verified the gap locally on:

  • latest stable v0.9.0 released on April 13, 2026
  • current main at 422f2866 on April 16, 2026

In both cases, Hermes still had only the session-start timestamp and no turn-level live Current time: context.

How to test

python -m pytest tests/run_agent/test_run_agent.py -k 'turn_level_live_time or excludes_turn_level or summary_injects'
python -m pytest tests/run_agent/test_run_agent_codex_responses.py -k 'turn_level_live_time'

Refs #10421

Changed files

  • run_agent.py (modified, +23/-6)
  • tests/run_agent/test_run_agent.py (modified, +52/-0)
  • tests/run_agent/test_run_agent_codex_responses.py (modified, +24/-0)

PR #9784: feat(gateway): add optional inbound message timestamp prefix

Description (problem / solution / changelog)

What does this PR do?

<!-- Describe the change clearly. What problem does it solve? Why is this approach the right one? -->

This PR adds an optional configuration flag message_timestamp_prefix that prepends a compact timestamp to inbound user messages before they are passed to the agent.

When enabled, Hermes will prefix inbound messages like:

[04-14 23:47] hello

Related Issue

<!-- Link the issue this PR addresses. If no issue exists, consider creating one first. -->

Fixes #9628

Type of Change

<!-- Check the one that applies. -->
  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • [着 ] ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

<!-- List the specific changes. Include file paths for code changes. -->

Config support

Added new optional gateway config:

gateway.message_timestamp_prefix: true

Implemented:

  • config parsing support
  • nested gateway: YAML compatibility
  • serialization/deserialization handling

Files:

gateway/config.py

Runtime timestamp injection

Prepends timestamp during inbound message preprocessing:

gateway/run.py::_prepare_inbound_message_text()

Adds helper:

_format_inbound_message_timestamp()

Behavior:

  • format: [MM-DD HH:MM]
  • default timezone: UTC
  • override via:
HERMES_TIMEZONE=America/New_York

Gracefully falls back to UTC if timezone invalid.

Ordering guarantees

Preserves sender-prefix ordering in shared threads:

[timestamp] [username] message

Example:

[04-14 23:47] [alice] can you check this later?

Tests added

Added coverage for:

  • config parsing via nested gateway: dict
  • config.yaml loading bridge behavior
  • timestamp prefix formatting
  • ordering with username prefixes
  • UTC default handling

Files:

tests/gateway/test_stt_config.py

How to Test

<!-- Steps to verify this change works. For bugs: reproduction steps + proof that the fix works. -->
  1. Enable the feature in config:
gateway:
  message_timestamp_prefix: true
  1. Run Hermes normally
hermes
  1. Send a message from any platform

Expected:

[MM-DD HH:MM] your message

Optional timezone override:

export HERMES_TIMEZONE=America/New_York

Restart Hermes and verify updated timestamps.

Checklist

<!-- Complete these before requesting review. -->

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: <!-- e.g. Ubuntu 24.04, macOS 15.2, Windows 11 -->

Documentation & Housekeeping

<!-- Check all that apply. It's OK to check "N/A" if a category doesn't apply to your change. -->
  • [] I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • [] I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • [] I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

For New Skills

<!-- Only fill this out if you're adding a skill. Delete this section otherwise. -->
  • This skill is broadly useful to most users (if bundled) — see Contributing Guide
  • SKILL.md follows the standard format (frontmatter, trigger conditions, steps, pitfalls)
  • No external dependencies that aren't already available (prefer stdlib, curl, existing Hermes tools)
  • I've tested the skill end-to-end: hermes --toolsets skills -q "Use the X skill to do Y"

Screenshots / Logs

<!-- If applicable, add screenshots or log output showing the fix/feature in action. -->

Changed files

  • gateway/config.py (modified, +14/-0)
  • gateway/run.py (modified, +14/-0)
  • scripts/release.py (modified, +1/-0)
  • tests/gateway/test_stt_config.py (modified, +89/-1)

PR #5487: feat(gateway): inject current timestamp into user messages

Description (problem / solution / changelog)

Summary

Injects a human-readable timestamp at the top of every user message before it reaches the agent, so the agent always knows the current date and time without needing to invoke a tool call.

Format: [Current time: Monday, April 06, 2026 07:36 AM]

Why

Agents running long conversations often lose track of time. The only built-in mechanism is the Conversation started: header, which becomes stale after minutes or hours of back-and-forth. Currently the agent must spend a date tool call just to answer "what time is it?" or "what day is today?" — wasting tokens and latency.

This is especially important for:

  • Cron-scheduled tasks — the agent wakes up with no conversation history and no time context
  • Long multi-turn conversations — the original timestamp is hours old
  • Time-sensitive instructions — "remind me at 3pm", "is it past midnight?", etc.

What Changed

Core Injection (gateway/run.py)

Inside _run_agent(), right before agent.run_conversation():

  • Check display.gateway_timestamp config (default: true)
  • Get current time via datetime.now()
  • Set locale to en_US.UTF-8 for consistent day/month names (with graceful fallback)
  • Format as human-readable string: Monday, April 06, %Y %I:%M %p
  • Prepend [Current time: ...]\n\n to the message

Config Toggle (hermes_cli/config.py)

  • Add display.gateway_timestamp: true to DEFAULT_CONFIG
  • Persisted in config.yaml — survives restarts

Slash Command (hermes_cli/commands.py + gateway/run.py)

  • Add /timestamps (alias /ts) command — toggles injection on/off
  • Available in both CLI and messaging gateway
  • Takes effect immediately without restart
  • Persists to config.yaml

Design Decisions

DecisionRationale
datetime.now() instead of injecting into system promptThe message-level approach works for ALL model providers (some strip system prompts)
Locale en_US.UTF-8 with try/except fallbackServer locale may be non-English; we want consistent English output
Prepend to message, not modify agent APIZero-impact change — no changes to agent interface, prompt builder, or context files
Only in _run_agent (gateway path)CLI mode has direct terminal access; gateway agents need the injection
Config toggle + slash commandSome users may not want the token overhead; easy on/off without code changes
Default trueTime awareness is universally useful; users who don't want it can opt-out

Testing

Manual testing on self-hosted instance:

  • Agent correctly reports current time without any tool calls
  • Works across long multi-turn conversations (timestamp updated per message)
  • Cron jobs also receive timestamps (they pass through the same _run_agent path)
  • Gracefully handles missing en_US locale (falls back to server default)
  • /timestamps toggle works — ON/OFF states persist across messages and restarts
  • Config display.gateway_timestamp: false correctly disables injection

Changed files

  • gateway/run.py (modified, +76/-0)
  • hermes_cli/commands.py (modified, +2/-0)
  • hermes_cli/config.py (modified, +1/-0)
RAW_BUFFERClick to expand / collapse

Summary

Consolidate the currently fragmented timestamp/timezone PRs around one core implementation path:

  • Keep volatile current time out of the cached system prompt.
  • Surface current time/timezone through the core ephemeral user-message/runtime context path.
  • Avoid separate gateway-specific timestamp-prefix mechanisms unless they are thin wrappers over the same core context.

This is the coordination fan-out from #17459.

Current candidates

Preferred/salvage path:

  • #15872 — injects current time + timezone through a per-turn context path and explicitly addresses stale timestamp perception.

Useful adjacent work:

  • #10061 — timezone propagation to prompt/terminal environments.
  • #8689 — stabilizes session-start timestamp across compression cycles.

Likely superseded as standalone approaches:

  • #10448 — similar problem, but creates a turn-scoped system-prompt path; should be rebased into the selected ephemeral context approach or closed.
  • #9784 — gateway-only configurable message timestamp prefix; should not become a parallel timestamp mechanism.
  • #5487 — gateway-only/current timestamp injection; should not become a parallel timestamp mechanism.
  • #5241 — already closed; per-call system prompt timestamp should remain closed/superseded.

Acceptance criteria

  • Choose and land one canonical core path for live time context, preferably based on #15872.
  • Rebase or close duplicate PRs that inject timestamps in system prompt or gateway-only paths.
  • Ensure timezone resolution aligns with #10061.
  • Preserve prompt-cache stability by excluding volatile time from cached system prompt.
  • Add tests proving the system prompt/cacheable prefix is stable while turn-level runtime context updates.
  • Link/close superseded PRs with comments pointing here and to #17459.

Related

Parent: #17459 Core feature request: #10421 Preferred PR: #15872

extent analysis

TL;DR

Choose and land one canonical core path for live time context, preferably based on #15872, to consolidate timestamp/timezone PRs.

Guidance

  • Review #15872 and assess its feasibility as the core implementation path for injecting current time and timezone through the ephemeral user-message/runtime context.
  • Rebase or close duplicate PRs (#10448, #9784, #5487) that inject timestamps in system prompt or gateway-only paths to avoid parallel mechanisms.
  • Ensure timezone resolution aligns with #10061 to maintain consistency across the system.
  • Develop tests to prove the system prompt/cacheable prefix stability while turn-level runtime context updates.

Example

No code snippet is provided as the issue focuses on PR consolidation and high-level design.

Notes

The chosen solution may require adjustments based on the specific requirements and constraints of the system, and careful evaluation of the related PRs is necessary to ensure a cohesive implementation.

Recommendation

Apply workaround by choosing and landing one canonical core path for live time context, preferably based on #15872, to consolidate timestamp/timezone PRs and avoid parallel mechanisms.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix Consolidate live-time PRs around one ephemeral runtime context path [8 pull requests, 1 participants]