Skip to content

fix(clients): reconcile tool activity lifecycles - #7617

Open
maria-rcks wants to merge 4 commits into
mainfrom
ui-refresh/tool-activity-turns
Open

fix(clients): reconcile tool activity lifecycles#7617
maria-rcks wants to merge 4 commits into
mainfrom
ui-refresh/tool-activity-turns

Conversation

@maria-rcks

@maria-rcks maria-rcks commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

What changed

Moves the deeper behavior out of #7152 into a follow-up layer:

  • reconciles interleaved tool lifecycle events by stable call ID without merging distinct or ambiguous calls
  • preserves terminal outcomes and turn-scoped identity on web and mobile
  • keeps live tool rows in timeline order and updates settled turn-fold anchoring
  • filters duplicate plan and terminal-input activity from work history
  • preserves composer task progress after removing the old active-plan fallback

Why

The one-line tool UI can be reviewed and merged independently. This PR contains the turn, lifecycle, and mobile behavior needed for complete provider histories.

Validation

  • 197 focused web and mobile tests
  • Web and mobile typechecks
  • Changed-file lint and formatting checks

Built with GPT-5.6-sol in the Codex harness.

Note

Reconcile tool activity lifecycles by toolCallId and overhaul MessagesTimeline rows

  • Tool lifecycle entries (tool.started, tool.updated, tool.completed) now collapse by stable toolCallId scoped to a turn, preventing cross-turn merges and ambiguous id-less completions. Applies to both session-logic.ts and threadActivity.ts.
  • deriveWorkLogEntries now surfaces tool.started rows (previously blanket-skipped), filters Codex terminal interactions and unkeyed statusless starts, and infers inProgress/completed statuses when missing.
  • Timeline introduces new row kinds: work-live for active expandable tool batches, enriched work-toggle with summaries and failure icons, and working rows with a showThinking flag. Turn folds anchor near the assistant response when collapsed and above the first hidden entry when expanded.
  • New shell tokenizer (tokenizeShellCommand, commandProgramName) extracts program names for live command labels; workEntryIconName delegates to toolGroupAction for icon selection.
  • deriveActivePlanState removed; activeComposerTaskSteps now sourced from turnPlans for the active turn. MessagesTimeline no longer accepts workingStepLabel or activeTurnInProgress props.
  • Risk: MessagesTimeline prop interface removes workingStepLabel and activeTurnInProgress; any external callers passing these props will break. deriveActiveWorkStartedAt signature gains latestUserMessageAt (defaults to null), and deriveActivePlanState is deleted from session-logic.ts.

Macroscope summarized befa511.


Note

Medium Risk
Changes are concentrated in client-side timeline and work-log derivation with broad test coverage, but incorrect collapse or fold anchoring could misrepresent tool history or hide activity in edge cases (parallel id-less tools, steers).

Overview
Tool lifecycle reconciliation on web and mobile collapses tool.started / tool.updated / tool.completed by turnId + toolCallId, including interleaved and late events, while refusing to merge ambiguous id-less completions or reuse IDs across turns. Terminal outcomes (completed, failed, etc.) win over stale in-progress updates.

Work log and timeline presentation now surfaces in-flight tool.started rows, filters duplicate plan updates, unkeyed statusless starts, Codex PTY terminal-input noise, and ExitPlanMode markers. Settled turn folds anchor before the next visible assistant reply when collapsed (fixes steer-superseded turns) and before the first hidden entry when expanded. Live tool batches stay expandable as entries append; lifecycle marker filtering and summarizeToolGroup labeling improve settled overflow rows.

Web chat drops deriveActivePlanState / workingStepLabel; composer task steps come from turnPlans for the active turn. The working row no longer shows plan step text. Subagent spawn UI shows coordinator failure states and uses a compact card with an Eye action instead of a full-width button.

Failure display splits metadata vs rendered output via workEntryDisplayIndicatesToolFailure so command text like rg 'command not found' does not show a false failure while still running.

Reviewed by Cursor Bugbot for commit befa511. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 13bf1df8-e1af-4326-91ef-270f71acb460

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 20, 2026
@maria-rcks maria-rcks changed the title ui refresh/tool activity turns fix(clients): reconcile tool activity lifecycles Aug 20, 2026
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for befa511.

This comment will update automatically after the next completed run.

@macroscopeapp

macroscopeapp Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces significant new runtime behavior for tool activity lifecycle reconciliation with complex merging logic. Two Medium severity findings identify bugs in the lifecycle merging code (duplicate completions from approval.requested rows, parallel tools merging incorrectly). The scope and complexity of the changes warrant careful human review.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@maria-rcks
maria-rcks force-pushed the ui-refresh/tool-activity-turns branch from c5101c8 to 29acbf9 Compare August 20, 2026 01:08
(candidate) =>
candidate.activityKind !== "tool.completed" &&
candidate.turnId === previous.turnId &&
candidate.itemType === previous.itemType &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium src/session-logic.ts:1146

An earlier approval.requested row can make an id-less tool.completed appear ambiguous, so the keyed tool.started remains visible as running and a duplicate completion row is emitted. The candidate check must consider only tool.started and tool.updated rows as competing lifecycle targets.

-            candidate.activityKind !== "tool.completed" &&
+            (candidate.activityKind === "tool.started" ||
+              candidate.activityKind === "tool.updated") &&
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/session-logic.ts around line 1146:

An earlier `approval.requested` row can make an id-less `tool.completed` appear ambiguous, so the keyed `tool.started` remains visible as running and a duplicate completion row is emitted. The candidate check must consider only `tool.started` and `tool.updated` rows as competing lifecycle targets.

Comment thread apps/web/src/session-logic.ts
Comment thread apps/web/src/session-logic.ts
@maria-rcks
maria-rcks force-pushed the ui-refresh/tool-activity-turns branch from 29acbf9 to befa511 Compare August 20, 2026 01:28

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit befa511. Configure here.

return true;
}
return (
(previous.activityKind !== "tool.started" || next.activityKind === "tool.completed") &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Id-less updates merge parallel tools

Medium Severity

The new id-less collapse rule attaches an unkeyed tool.updated to the previous keyed row whenever label and itemType match. The competing-target check only runs for tool.completed, so a parallel same-label update without a call id can fuse into the adjacent call and hide a distinct in-flight tool.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit befa511. Configure here.

Base automatically changed from ui-refresh/tool-activity-web to main August 20, 2026 02:55

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI files for shared-primitive usage, Tailwind/CSS ownership, and accessibility. The new live-activity row, tool-group summary row, and the live-activity-focus mask/animation utilities look consistent with the existing timeline row idiom (the mask + keyframes are exactly the kind of behaviorally complex CSS that belongs in index.css), and the AgentSpawnCtaRow rework correctly routes its action through the shared Button/Tooltip primitives.

Two findings, both in MessagesTimeline.test.tsx, where the tests no longer match the component contract this PR introduces.

Posted via Macroscope — UI Consistency

expect(markup).toContain("Thinking");
expect(markup).not.toContain("Thinking ·");
expect(markup).not.toContain('aria-hidden="true" class="size-6 shrink-0"');
expect(markup).toContain("gap-1.5 px-0.5 py-0.5");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This assertion doesn't match what the iconless Thinking row emits. LiveActivityContent builds cn("flex min-h-6 min-w-0 items-center gap-1.5 py-0.5", resolvedIconName ? "px-0.5" : "px-1", …), and with no icon (ThinkingActivityRow) the rendered order is gap-1.5 py-0.5 px-1px-0.5 is only emitted when an icon is present. cn (twMerge) does not reorder classes, so this test fails as written; the later "aligns the iconless Thinking row" test asserts the correct string.

Suggested change
expect(markup).toContain("gap-1.5 px-0.5 py-0.5");
expect(markup).toContain("gap-1.5 py-0.5 px-1");

Posted via Macroscope — UI Consistency

Comment on lines +1209 to +1211
isWorking
activeTurnInProgress
activeTurnStartedAt={MESSAGE_CREATED_AT}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

activeTurnInProgress was removed from MessagesTimelineProps in this PR, so this explicit JSX attribute no longer type-checks (Property 'activeTurnInProgress' does not exist on type 'IntrinsicAttributes & MessagesTimelineProps'). Consider dropping it — the row now derives its state from showThinking.

Suggested change
isWorking
activeTurnInProgress
activeTurnStartedAt={MESSAGE_CREATED_AT}
isWorking
activeTurnStartedAt={MESSAGE_CREATED_AT}

Posted via Macroscope — UI Consistency

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

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant