hermes - 💡(How to fix) Fix [Feature]: Persist and replay ACP tool-call timing metadata [1 pull requests]

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…

Root Cause

  • #31076 (feat(acp): expose session provenance metadata) is complementary. It uses _meta.hermes for session-level provenance; this request is tool-call/message-level timing. The two surfaces should be compatible but this issue should not depend on #31076.
  • #28538 (feat: expose tool_call_log and metadata from run_conversation()) is related because it introduces structured tool-call results with duration_ms, but appears scoped to run_conversation() return metadata rather than ACP session/update events or replay persistence.
  • #28474 / #28431 / #28453 are adjacent structured response metadata work, not a direct ACP replay timing contract.
  • #30376 / #30283 are related monotonic-duration fixes; this implementation should follow the same monotonic-clock direction.
  • #28065 and #22362 expose tool traces/events in other surfaces, but not ACP replay timing.

Fix Action

Fixed

Code Example

{
  "sessionUpdate": "tool_call_update",
  "toolCallId": "call_123",
  "status": "completed",
  "_meta": {
    "hermes": {
      "durationMs": 1234,
      "durationSource": "monotonic",
      "startedAt": "2026-05-23T18:42:11.123Z",
      "completedAt": "2026-05-23T18:42:12.357Z"
    }
  }
}
RAW_BUFFERClick to expand / collapse

Problem or Use Case

ACP session/update tool-call frames do not currently carry durable timing metadata for clients to render trustworthy tool durations after reconnect, session/load, or session/resume.

Live attached UIs can measure elapsed time locally while a tool is running, but replay/bootstrap history is emitted back-to-back. If a client derives duration from local receive time, every historical completed tool appears to have taken nearly 0ms; if the client suppresses replay-derived durations, historical tools have no duration at all.

The source of truth should be Hermes' tool execution/session history, not each ACP client's local cache.

Proposed Solution

Persist and emit explicit per-tool timing metadata on ACP tool-call lifecycle updates using ACP _meta as the backwards-compatible extension point.

Suggested Hermes metadata shape:

{
  "sessionUpdate": "tool_call_update",
  "toolCallId": "call_123",
  "status": "completed",
  "_meta": {
    "hermes": {
      "durationMs": 1234,
      "durationSource": "monotonic",
      "startedAt": "2026-05-23T18:42:11.123Z",
      "completedAt": "2026-05-23T18:42:12.357Z"
    }
  }
}

Proposed contract:

  • On tool_call start:
    • _meta.hermes.startedAt: RFC3339/ISO-8601 wall-clock timestamp for display/debugging.
  • On terminal tool_call_update statuses such as completed or failed:
    • _meta.hermes.completedAt: RFC3339/ISO-8601 wall-clock timestamp for display/debugging.
    • _meta.hermes.durationMs: elapsed duration in milliseconds.
    • _meta.hermes.durationSource: e.g. monotonic, so clients know the elapsed duration came from a monotonic clock rather than wall-clock subtraction.

Implementation notes:

  • Compute elapsed duration with time.monotonic() / equivalent monotonic timing.
  • Use wall-clock timestamps only for display/debugging/timeline views.
  • Persist the timing metadata with the session/tool history used for ACP replay.
  • Thread persisted metadata through both live ACP event emission and replay reconstruction.
  • Keep existing public fields unchanged so ACP clients that ignore _meta continue to work.
  • Other Hermes environments such as TUI can keep their existing live timing paths; this metadata is additive for ACP/replay consumers and can be adopted by other UIs later.

Alternatives Considered

  • Client-local cache: brittle across clients/devices/restarts and makes replay fidelity depend on whichever client happened to observe the live run.
  • Top-level timing fields: nicer long-term, but current ACP tool-call schemas appear to accept _meta rather than first-class top-level startedAt, completedAt, or durationMs fields. _meta.hermes is safer until ACP standardizes timing fields.
  • Wait for broader structured run_conversation() metadata work: related PRs exist, but they appear scoped to returned run metadata rather than ACP session/update events and replay persistence. This can align field names without depending on that work landing first.

Feature Type

Other — ACP / session replay reliability / client rendering metadata.

Scope

Medium (few files, < 300 lines conceptually; touches executor timing, ACP event builders, persistence/replay, and tests).

Contribution

  • I'd like to implement this myself and submit a PR

Debug Report (optional)

N/A — this is a protocol/session-history behavior request based on code-path inspection, not a local environment crash.

Acceptance Criteria

  • A live ACP tool_call_update for a completed/failed tool includes enough metadata to display real elapsed duration.
  • A replayed ACP tool_call_update after session/load, session/resume, reconnect, or restart includes the same durable duration metadata.
  • Timing data is persisted with session/tool history, not only held in an attached client's runtime state.
  • Duration is measured with a monotonic clock and exposed as elapsed milliseconds.
  • Existing ACP clients that ignore _meta continue to work unchanged.
  • Provider-facing model messages do not leak Hermes-internal _meta fields.

Related Activity

I did not find an exact open issue/PR that solves this ACP replay timing contract directly.

Related but not direct fixes:

  • #31076 (feat(acp): expose session provenance metadata) is complementary. It uses _meta.hermes for session-level provenance; this request is tool-call/message-level timing. The two surfaces should be compatible but this issue should not depend on #31076.
  • #28538 (feat: expose tool_call_log and metadata from run_conversation()) is related because it introduces structured tool-call results with duration_ms, but appears scoped to run_conversation() return metadata rather than ACP session/update events or replay persistence.
  • #28474 / #28431 / #28453 are adjacent structured response metadata work, not a direct ACP replay timing contract.
  • #30376 / #30283 are related monotonic-duration fixes; this implementation should follow the same monotonic-clock direction.
  • #28065 and #22362 expose tool traces/events in other surfaces, but not ACP replay timing.

Notes

A follow-up PR can be scoped narrowly to ACP/session replay: capture timing at existing executor timing points, persist it in durable message metadata, emit it under _meta.hermes, and keep legacy fields unchanged.

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 - 💡(How to fix) Fix [Feature]: Persist and replay ACP tool-call timing metadata [1 pull requests]