Skip to content

feat(web): show tool call duration in the detail dialog#1036

Open
junmo-kim wants to merge 3 commits into
tiann:mainfrom
junmo-kim:feat/tool-call-duration
Open

feat(web): show tool call duration in the detail dialog#1036
junmo-kim wants to merge 3 commits into
tiann:mainfrom
junmo-kim:feat/tool-call-duration

Conversation

@junmo-kim

Copy link
Copy Markdown
Contributor

Problem

While a tool call is running, its card header shows a live elapsed timer, but once the tool finishes that timer disappears — so there's no way to see how long a completed tool actually took. Showing it permanently on every card would be noisy, so it fits better in the detail dialog that opens on click.

Solution

Add a single Duration row at the top of the tool detail dialog for completed and errored tools. The value is derived from the Claude entry's own timestamp fields (the execution machine's wall clock, already present in the stored message payload) rather than the hub's message-receive time, so it reflects the tool's actual execution time rather than transport/queue timing. It is used only when both the tool_use and tool_result entries carry a real Claude timestamp; if either side is missing one (a hub-synthesized result for a denied/timed-out/cancelled tool, a malformed entry, or a non-Claude agent flavor), the duration falls back to the hub receive times on both sides — the two clocks are never mixed.

Running and pending tools show nothing here (their live progress is already in the card header), the running-state live timer is unchanged, and clock skew is guarded against. Reuses the existing formatDuration formatter. No DB/schema changes.

Screenshots

Duration row in the detail dialog on a completed tool, from a live Claude session:

Bash sleep 2 — Duration 2.3s Read — Duration ~0.0s

Tests

Unit tests cover the ISO timestamp parser (valid/missing/malformed), the duration helper's both-or-neither selection (exec pair vs. hub pair, clock-skew guard, running/pending/instantaneous cases), and a render test for the dialog row. Reducer-level tests cover exec-timestamp recording distinct from the hub receive time, the non-Claude fallback, and the reorder case where the tool_result entry is processed before its tool_use. Manually verified end-to-end with a live Claude session in an isolated hub instance.

Follow-up: message-level Duration (replacing turn_duration) and per-tool token counts are out of scope.

Show a completed tool's execution duration at the top of its detail
dialog. The value is derived from the Claude entry's own timestamps
(the execution machine's wall clock) rather than the hub's
message-receive time, and is used only when both the tool_use and
tool_result entries carry a real timestamp — otherwise it falls back to
the hub receive times on both sides, so the two clocks are never mixed.
Running/pending tools show nothing, the running-state live timer is
unchanged, and clock skew is guarded against. Reuses the existing
formatDuration formatter. No schema changes.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Major] Result-before-call fallback can display 0.0s instead of the hub-time duration — when a tool_result is reduced before its tool_use, the placeholder tool is created with startedAt equal to the result message time. The later tool-use path now backfills execStartedAt, but it still does not backfill startedAt; when exec timestamps are incomplete or missing, toolDurationMs falls back to startedAt ?? createdAt, so the newly added duration row uses the result timestamp for both ends. Evidence web/src/components/ToolCard/toolDuration.ts:22, related context web/src/chat/reducerTimeline.ts:896.
    Suggested fix:
    if (block.tool.state === 'pending') {
        block.tool = { ...block.tool, state: 'running' }
    }
    setEarliestStartedAt(block, msg.createdAt)
    setEarliestExecStartedAt(block, msg.agentTimestamp ?? null)

Questions

  • None.

Summary

  • Review mode: initial
  • One Major finding: the new displayed duration is wrong for the existing result-before-use ordering when the exec timestamp pair is unavailable or incomplete.

Testing

  • Not run (review automation; PR content not executed). Add a reducer/helper test for result-before-use with missing exec start that asserts the hub fallback duration.

HAPI Bot

const useExec = tool.execStartedAt != null && tool.execCompletedAt != null
const end = useExec ? tool.execCompletedAt : tool.completedAt
if (end == null) return null
const start = useExec ? tool.execStartedAt : (tool.startedAt ?? tool.createdAt)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] This fallback can still use the wrong start time for the result-before-use ordering. In that path, ensureToolBlock creates the placeholder from the tool_result, so startedAt is the result message time; when the later tool_use arrives, this PR backfills only execStartedAt, not the hub startedAt. If the exec pair is incomplete/missing, this line falls back to startedAt ?? createdAt and the dialog displays 0.0s instead of the hub receive window.

Suggested fix:

if (block.tool.state === 'pending') {
    block.tool = { ...block.tool, state: 'running' }
}
setEarliestStartedAt(block, msg.createdAt)
setEarliestExecStartedAt(block, msg.agentTimestamp ?? null)

When a tool_result entry is reduced before its tool_use, the tool block
is created from the result, so the hub startedAt is the result receive
time. The tool_use path only lowered the exec start, not the hub
startedAt, so a timestamp-less pair (no exec duration available) fell
back to startedAt === completedAt and the detail dialog showed 0.0s.
Lower the hub startedAt to the earlier tool_use receive time as well.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • None.

Questions

  • None.

Summary

  • Review mode: follow-up after new commits
  • No high-confidence issues found in the latest full PR diff. The prior bot finding about result-before-use hub fallback has been addressed by backfilling startedAt from the later tool_use path.
  • Residual risk: I did not execute the PR tests in this automation pass; review was based on diff/source inspection only.

Testing

  • Not run (review automation; PR content not executed).

HAPI Bot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant