Skip to content

fix(ui): hide synthetic stop tool part when loop action is "stop" (closes #267)#551

Merged
Astro-Han merged 1 commit into
devfrom
fix/hide-synthetic-stop-tool
May 11, 2026
Merged

fix(ui): hide synthetic stop tool part when loop action is "stop" (closes #267)#551
Astro-Han merged 1 commit into
devfrom
fix/hide-synthetic-stop-tool

Conversation

@Astro-Han

Copy link
Copy Markdown
Owner

Summary

Hide synthetic stop tool parts from the conversation UI when their metadata carries diagnostics.loop.loopAction === "stop".

Why

Closes #267. The loop gate already renders a user-facing synthetic summary text part when it stops a loop. The paired synthetic tool part is only an internal audit carrier, so rendering it as a failed tool bubble is redundant and confusing.

Related Issue

Closes #267

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.

Review Focus

  • Confirm the hide is reactive via createMemo + <Show>, not a top-level return.
  • Confirm only the UI render layer changed; loop diagnostics metadata and export behavior are untouched.
  • Confirm the tests lock both metadata-based hiding and the combined <Show> condition.

Risk Notes

Low UI-rendering risk. The underlying tool part and metadata remain in session data and exports. Manual stop-scenario smoke was skipped because the deterministic UI source test and existing export audit tests cover the changed behavior without requiring a live loop-gate repro.

Behavior

Synthetic tool parts that carry metadata.diagnostics.loop.loopAction === "stop" are now hidden from the conversation UI via a reactive createMemo + <Show> pattern, parallel to the existing hideQuestion hide for pending question tools.

The metadata stays on the part:

  • Export.deriveSnapshotDiagnostics still emits diagnostics.loop.last with the full audit trail
  • The synthetic Chinese summary text part remains the user-facing stop message
  • Only the redundant failed-tool bubble is suppressed

How To Verify

bun --cwd packages/ui test src/components/message-part-stale.test.ts: 8 pass, 0 fail
bun --cwd packages/opencode test test/session/export.test.ts: 32 pass, 0 fail
bun --cwd packages/ui typecheck: passed
bun --cwd packages/app typecheck: passed
rg -n 'loopAction === "stop"' packages/ui/src: one source hit in message-part.tsx
git diff --check: passed
Manual smoke: skipped; deterministic UI source test and export audit test cover this narrow render-only change

Screenshots or Recordings

Not applicable. The target state is absence of the redundant failed-tool bubble, covered by the deterministic UI render contract test.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, primary area, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

@Astro-Han Astro-Han added enhancement New feature or request P2 Medium priority app Application behavior and product flows ui Design system and user interface harness Model harness, prompts, tool descriptions, and session mechanics task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work labels May 11, 2026
@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Astro-Han has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 16 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3443def0-7926-412d-87ce-8ac7de05f648

📥 Commits

Reviewing files that changed from the base of the PR and between 59465cd and 45fdd05.

📒 Files selected for processing (2)
  • packages/ui/src/components/message-part-stale.test.ts
  • packages/ui/src/components/message-part.tsx
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/hide-synthetic-stop-tool

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 and usage tips.

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Opus second-pass review (product layer / three questions / live-stream behavior)

Conclusion: approve

Diff is exactly the brief shape. Reactive hide pattern, no unintended surface touched.

Three questions

Could this be even less? 17 added lines plus 1 changed <Show> condition plus 2 source-level lock tests. The lock tests are not optional — they protect both the reactive pattern and the <Show> composition from drifting in future edits. This is already the minimum that preserves the contract. Check.

Is what remains good enough?

  • hideSyntheticStop placed after partMetadata() declaration, matching the order GPT-X specified.
  • <Show when={!hideQuestion() && !hideSyntheticStop()}> composes cleanly with the existing question-pending hide; no precedence or short-circuit surprises.
  • The synthetic stop tool part disappears from the conversation transcript; the rendered Chinese summary text part remains the user-facing stop message.
  • Check.

Is it reassuring? Live-stream path traced:

  • Tool part starts as status: "running" (no metadata) → hideSyntheticStop() returns false → bubble renders briefly.
  • Wrapper writes status: "error" with metadata.diagnostics.loop.loopAction = "stop"partMetadata() accessor reads fresh state → memo recomputes to true<Show> hides the bubble.
  • Export untouched: Export.deriveSnapshotDiagnostics keeps reading the metadata directly off the part; the 32 passing export tests are the audit trail proof.
  • Check.

Findings

P3-1 (consider in follow-up, not blocking): there is a brief visible flicker between tool-input-start and the wrapper's stop settle. The user might see a "running" tool bubble for a few hundred milliseconds before it disappears. The acceptance criteria do not require suppressing the running phase, and adding a "predictive hide" would require coupling UI to in-flight loop-gate state, which is out of scope here. If post-merge user reports flag the flicker, that becomes its own polish task.

No P0/P1/P2.

Approve

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces logic to hide synthetic stop tool parts in the UI while maintaining access to their metadata for diagnostics. It adds a hideSyntheticStop memoized value in message-part.tsx and updates the conditional rendering logic to suppress these parts. Corresponding unit tests were added to message-part-stale.test.ts to verify the implementation. I have no feedback to provide.

@Astro-Han

Copy link
Copy Markdown
Owner Author

GPT-X engineering final review

Result: pass. I found no P0/P1/P2 issues.

Engineering checks

  • The hide is reactive: hideSyntheticStop is a createMemo that reads through partMetadata(), so it can respond when the live tool part changes from a running state to an error state with metadata.diagnostics.loop.loopAction === "stop".
  • The declaration order is correct: partMetadata is defined before hideSyntheticStop.
  • The render condition composes with the existing question-tool suppression: <Show when={!hideQuestion() && !hideSyntheticStop()}>. This does not change the hideQuestion predicate or the question-specific error variants.
  • The change is scoped to the UI render layer and source-level UI contract tests. It does not touch processor, Export.deriveSnapshotDiagnostics, or the loop diagnostics schema.
  • The existing export tests still cover stop diagnostics audit behavior, including stop as the terminal action and lone stop parts.

Binary check

This is not a crash fix: v1 can run without it. But the redundant failed-tool bubble is directly user-visible in the stop path, while the intended user-facing output is the synthetic summary text part. Hiding the synthetic carrier part is the right lowest layer because the metadata must remain available for export diagnostics.

Notes

The brief running-state flicker before the wrapper settles the part is acceptable for this PR. Preventing that would require coupling the UI to pending loop-gate state before the metadata exists, which is a separate product/architecture decision.

@Astro-Han Astro-Han merged commit 7ac9d47 into dev May 11, 2026
22 checks passed
@Astro-Han Astro-Han deleted the fix/hide-synthetic-stop-tool branch May 11, 2026 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows enhancement New feature or request harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority task Narrow execution, audit, spike, migration, tracking, or upstream follow-up work ui Design system and user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Hide synthetic stop tool part in UI when loopAction is "stop"

1 participant