Skip to content

fix(group-chat): add participant remove button and allow agentId updates#718

Merged
pedramamini merged 2 commits intomainfrom
fix/717-group-chat-stale-provider-no-remove
Apr 4, 2026
Merged

fix(group-chat): add participant remove button and allow agentId updates#718
pedramamini merged 2 commits intomainfrom
fix/717-group-chat-stale-provider-no-remove

Conversation

@pedramamini
Copy link
Copy Markdown
Collaborator

@pedramamini pedramamini commented Apr 3, 2026

Summary

  • Add Remove button (with confirmation) to ParticipantCard so users can remove stale participants from group chats
  • Wire up onRemove callback through GroupChatRightPanel and GroupChatParticipants to the existing removeParticipant IPC handler (backend was already implemented, UI was missing)
  • Add agentId to ParticipantUpdate type enabling programmatic updates to a participant's agent type when provider changes

Root Cause

When a user switches an agent's provider (e.g., Codex → Claude) after adding it to a group chat, the participant's agentId is snapshotted at creation time in metadata.json and never updated. The stale reference causes the right panel to display the old provider, and since there was no UI to remove participants, users were stuck with no way to fix the group chat.

Workaround (pre-fix)

Create a new group chat — it picks up the updated provider automatically.

Closes #717

Test plan

  • Create a group chat with a Codex participant
  • Switch the agent's provider to Claude Code in agent settings
  • Return to the group chat — verify the Remove button appears on participant cards
  • Click Remove → verify confirmation prompt appears (Confirm/Cancel)
  • Confirm removal → verify participant is removed from the group chat
  • Re-add the agent — verify it now uses the updated provider
  • Verify the moderator card does NOT show a Remove button (moderators cannot be removed)

Summary by CodeRabbit

  • New Features
    • Remove participants directly from the group chat participant list.
    • Two-step confirmation flow (Confirm/Cancel) to prevent accidental removals.
    • Visual feedback while removal is in progress ("Removing..." indicator) and disabled controls during the operation.
    • Remove action available on non-moderator participant entries in the Participants tab.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 3, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9010187e-0409-46f0-a380-1025e53a7007

📥 Commits

Reviewing files that changed from the base of the PR and between b1c325c and b5e8d9a.

📒 Files selected for processing (3)
  • src/renderer/components/GroupChatParticipants.tsx
  • src/renderer/components/GroupChatRightPanel.tsx
  • src/renderer/components/ParticipantCard.tsx

📝 Walkthrough

Walkthrough

Added participant removal UI and callbacks: ParticipantCard gains an optional onRemove prop and confirmation UI; GroupChatParticipants and GroupChatRightPanel each pass a memoized handleRemoveParticipant that calls window.maestro.groupChat.removeParticipant(groupChatId, participantName).

Changes

Cohort / File(s) Summary
Group Chat Removal Handlers
src/renderer/components/GroupChatParticipants.tsx, src/renderer/components/GroupChatRightPanel.tsx
Each file adds a memoized handleRemoveParticipant(participantName) that invokes window.maestro.groupChat.removeParticipant(groupChatId, participantName) and passes it as onRemove to ParticipantCard.
Participant Card UI & State
src/renderer/components/ParticipantCard.tsx
Adds optional onRemove?: (participantName: string) => void prop, isRemoving and confirmRemove state, async handleRemove calling onRemove, two-step confirm/cancel UI, "Removing..." indicator, and imports UserMinus icon.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ParticipantCard
    participant GroupChatPanel
    participant MaestroAPI as window.maestro.groupChat

    User->>ParticipantCard: Click "Remove"
    ParticipantCard->>ParticipantCard: Show confirm/cancel
    User->>ParticipantCard: Click "Confirm"
    ParticipantCard->>ParticipantCard: set isRemoving = true
    ParticipantCard->>GroupChatPanel: onRemove(participantName)
    GroupChatPanel->>MaestroAPI: removeParticipant(groupChatId, participantName)
    MaestroAPI-->>GroupChatPanel: Success/Failure
    GroupChatPanel-->>ParticipantCard: resolve/reject
    ParticipantCard->>ParticipantCard: clear isRemoving & confirmRemove
    ParticipantCard->>User: Update UI (removed or reset)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit nudges the code today,
A gentle click, then "Confirm" — away!
Cards hop out with a tiny sigh,
No frozen panels watching by.
Soft thumps of keys, the group trims neat 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title mentions 'participant remove button' and 'agentId updates', both of which are core components of the changeset across multiple files.
Linked Issues check ✅ Passed The PR implements the primary coding objectives from #717: adds Remove button UI to ParticipantCard, wires onRemove callback through the component hierarchy, integrates with backend removeParticipant handler, and adds agentId to ParticipantUpdate type.
Out of Scope Changes check ✅ Passed All changes are directly scoped to addressing #717: ParticipantCard UI enhancements for removal, callback wiring in GroupChatRightPanel and GroupChatParticipants, and agentId type addition. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/717-group-chat-stale-provider-no-remove

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 3, 2026

Greptile Summary

This PR wires up a missing "Remove participant" UI for group chats — a two-step confirmation button on ParticipantCard — and exposes agentId in ParticipantUpdate to allow programmatic agent-type corrections. The backend removeParticipant handler was already implemented; only the renderer plumbing was missing.

  • P1 — Silent failure on remove: Both handleRemoveParticipant callbacks (in GroupChatParticipants.tsx and GroupChatRightPanel.tsx) catch all errors and only console.error them, violating the CLAUDE.md error-handling contract. If the IPC call fails, onRemove resolves successfully, ParticipantCard resets its UI state (confirm dialog closes, spinner stops), and the participant card reappears — leaving the user with no indication that anything went wrong, and no signal to Sentry.

Confidence Score: 4/5

Safe to merge after fixing silent error swallowing in both remove-participant handlers.

One P1 finding: errors from the IPC call are swallowed before reaching ParticipantCard, so failures are invisible to both the user and Sentry. The rest of the change — type extension, confirmation UI, moderator exclusion — is correct and low-risk.

src/renderer/components/GroupChatParticipants.tsx and src/renderer/components/GroupChatRightPanel.tsx — identical handleRemoveParticipant handlers both need error re-throwing.

Important Files Changed

Filename Overview
src/main/group-chat/group-chat-storage.ts Adds agentId to ParticipantUpdate — purely additive type change, no functional risk.
src/renderer/components/GroupChatParticipants.tsx Wires handleRemoveParticipant to ParticipantCard.onRemove; handler silently swallows errors, violating CLAUDE.md and leaving users with no feedback on failure.
src/renderer/components/GroupChatRightPanel.tsx Identical handleRemoveParticipant added with same silent-swallow error pattern; moderator card correctly omits onRemove.
src/renderer/components/ParticipantCard.tsx Adds Remove button with two-step confirmation flow (Remove → Confirm/Cancel) and in-progress state; moderator protection is correctly handled by omitting onRemove at the call site.

Sequence Diagram

sequenceDiagram
    actor User
    participant PC as ParticipantCard
    participant GCP as GroupChatParticipants / GroupChatRightPanel
    participant IPC as window.maestro.groupChat
    participant BE as group-chat-storage (main)

    User->>PC: Click "Remove"
    PC->>PC: setConfirmRemove(true)
    User->>PC: Click "Confirm"
    PC->>PC: setIsRemoving(true)
    PC->>GCP: onRemove(participantName)
    GCP->>IPC: removeParticipant(groupChatId, participantName)
    IPC->>BE: removeParticipant()
    alt Success
        BE-->>IPC: resolved
        IPC-->>GCP: resolved
        GCP-->>PC: resolved (onRemove returns)
        PC->>PC: finally: setIsRemoving(false), setConfirmRemove(false)
        Note over PC: Component unmounts (participant removed from state)
    else Failure
        BE-->>IPC: throws
        IPC-->>GCP: throws
        GCP->>GCP: catch: console.error only
        GCP-->>PC: resolved (error swallowed!)
        PC->>PC: finally: setIsRemoving(false), setConfirmRemove(false)
        Note over PC: Remove button reappears — no user feedback
    end
Loading

Reviews (1): Last reviewed commit: "fix(group-chat): add participant remove ..." | Re-trigger Greptile

Comment on lines +106 to +114
const handleRemoveParticipant = useCallback(
async (participantName: string) => {
try {
await window.maestro.groupChat.removeParticipant(groupChatId, participantName);
} catch (error) {
console.error(`Failed to remove participant ${participantName}:`, error);
}
},
[groupChatId]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Silent failure on remove — no user feedback and Sentry bypass

handleRemoveParticipant catches and swallows all errors, so if the IPC call fails the onRemove callback never rejects. ParticipantCard's handleRemove then completes normally, resets isRemoving and confirmRemove, and the Remove button reappears — but the user receives no indication that the operation failed. This also prevents Sentry from capturing unexpected backend failures (CLAUDE.md explicitly flags this pattern as "WRONG"). The same issue exists in GroupChatRightPanel.tsx at the equivalent handler.

The fix is to let unexpected errors re-throw (Sentry captures them automatically) and have ParticipantCard surface a failure state — or at minimum have onRemove not catch the error so the finally in handleRemove can be paired with a caught error that shows a toast/message.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/renderer/components/GroupChatRightPanel.tsx (1)

192-202: Consider extracting shared participant action handlers.

Both GroupChatRightPanel.tsx and GroupChatParticipants.tsx now contain identical handleRemoveParticipant and handleContextReset implementations. These could be extracted into a shared hook (e.g., useParticipantActions(groupChatId)) to reduce duplication.

This is existing technical debt that predates this PR, so deferring is reasonable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/GroupChatRightPanel.tsx` around lines 192 - 202, Both
components duplicate participant action handlers; extract them into a shared
hook named useParticipantActions(groupChatId) that returns
handleRemoveParticipant and handleContextReset so the logic is centralized. Move
the try/catch logic that calls
window.maestro.groupChat.removeParticipant(groupChatId, participantName) into
the hook and implement handleContextReset there as well; then replace the inline
handleRemoveParticipant and handleContextReset in GroupChatRightPanel and
GroupChatParticipants with the hook's returned functions to remove duplication
and keep behavior identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/renderer/components/GroupChatRightPanel.tsx`:
- Around line 192-202: Both components duplicate participant action handlers;
extract them into a shared hook named useParticipantActions(groupChatId) that
returns handleRemoveParticipant and handleContextReset so the logic is
centralized. Move the try/catch logic that calls
window.maestro.groupChat.removeParticipant(groupChatId, participantName) into
the hook and implement handleContextReset there as well; then replace the inline
handleRemoveParticipant and handleContextReset in GroupChatRightPanel and
GroupChatParticipants with the hook's returned functions to remove duplication
and keep behavior identical.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ffd54000-f4b2-4cd4-8c29-098614155044

📥 Commits

Reviewing files that changed from the base of the PR and between 626cd6f and 776ec43.

📒 Files selected for processing (4)
  • src/main/group-chat/group-chat-storage.ts
  • src/renderer/components/GroupChatParticipants.tsx
  • src/renderer/components/GroupChatRightPanel.tsx
  • src/renderer/components/ParticipantCard.tsx

@pedramamini
Copy link
Copy Markdown
Collaborator Author

Thanks for the contribution, @pedramamini! Clean fix — the two-step confirm UX on the Remove button is a nice touch, and wiring up the already-implemented backend was the right call.

One thing to address before merge:

Greptile flagged (and I agree) that the handleRemoveParticipant handlers in both GroupChatParticipants.tsx and GroupChatRightPanel.tsx silently swallow errors:

try {
    await window.maestro.groupChat.removeParticipant(groupChatId, participantName);
} catch (error) {
    console.error(`Failed to remove participant ${participantName}:`, error);
}

Per our error handling guidelines in CLAUDE.md, unexpected errors should bubble up so Sentry can capture them. The user also gets zero feedback that the remove failed — the button just reappears silently. Please either:

  1. Remove the try/catch and let errors propagate (Sentry picks them up automatically, and ParticipantCard's finally block still runs), or
  2. Re-throw after logging so the card can show a failure state.

Everything else looks good. The agentId addition to ParticipantUpdate and the ParticipantCard UI changes are solid. CI failures are pre-existing and unrelated to this PR.

…tes (#717)

When a user switches an agent's provider after adding it to a group chat,
the participant becomes stale (old agentId) and cannot be removed because
no remove UI existed despite the backend API being fully implemented.

- Add Remove button with confirmation to ParticipantCard component
- Wire up onRemove callback in GroupChatRightPanel and GroupChatParticipants
- Add agentId to ParticipantUpdate type so stale participants can be updated

Closes #717
…d from ParticipantUpdate

- Remove try/catch in handleRemoveParticipant callbacks so failures
  reach Sentry instead of being silently swallowed via console.error
- Remove unused 'agentId' from ParticipantUpdate type (no code path
  uses it to update stale agent IDs)
@pedramamini pedramamini force-pushed the fix/717-group-chat-stale-provider-no-remove branch from b1c325c to b5e8d9a Compare April 4, 2026 23:36
@pedramamini pedramamini merged commit 48651b6 into main Apr 4, 2026
3 of 4 checks passed
@pedramamini pedramamini deleted the fix/717-group-chat-stale-provider-no-remove branch April 4, 2026 23:36
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.

Bug: Provider switch breaks existing group chat: panel controls frozen, ag...

1 participant