You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(daemon): anchor ACP tool-first turns at the tool's start
Three findings from the fifth review round.
ACP accumulates `tool_call` frames and emits the canonical `tool_use` only once
the call reaches terminal status, carrying `startedAt` set to the first frame's
arrival. The universal `send()` path stamped the anchor with `Date.now()` when
that delayed event arrived, so a tool-only ACP turn put its anchor at tool
COMPLETION -- measuring the whole tool loop as runtime init. That is precisely
the case this PR exists to fix, still fully present for the ACP family. The
stream-event markers now carry the producer's `startedAt` (daemon clock, same
domain as our own marks) and the tracer stamps that instead of arrival time.
Tool ids are reused across a retry: sequential ids like `call_0` restart in the
retry's fresh session, and `openTools` is keyed by id alone. A killed
attempt's still-open `call_0` therefore merged with the retry's genuinely new
`call_0`, pairing attempt one's opening with attempt two's close and reporting
a 19s tool that never ran -- inflating `tool_duration_ms` as well as phase
occupancy. A still-open entry observed before the current attempt began is now
replaced rather than merged.
The Langfuse `model-active` diagnostic used different boundaries from the
metric it exists to be compared against: it preferred `firstModelEventAt` over
the earliest mark, and ended at `finalizeStartAt` rather than run end. On a
text-first stream those differ, so the same run reported two windows. It now
mirrors the canonical rules; the shared "earliest finite mark" logic is a named
helper.
0 commit comments