From b85deb2906a7dc9eb36b09cbb8e5912461d03159 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sat, 15 Nov 2025 14:48:56 +0100 Subject: [PATCH] Fix duplicate keys for permission cards --- .../app/src/components/agent-stream-view.tsx | 20 ++++++++++++------- plan.md | 6 +++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/app/src/components/agent-stream-view.tsx b/packages/app/src/components/agent-stream-view.tsx index b4c1b18bd..178684a46 100644 --- a/packages/app/src/components/agent-stream-view.tsx +++ b/packages/app/src/components/agent-stream-view.tsx @@ -333,13 +333,19 @@ export function AgentStreamView({ ListHeaderComponent={ pendingPermissionItems.length > 0 ? ( - {pendingPermissionItems.map((permission) => ( - - ))} + {pendingPermissionItems.map((permission, index) => { + const permissionKey = permission.request.id + ? `${permission.agentId}:${permission.request.id}` + : `${permission.agentId}:permission-${permission.request.name ?? permission.request.title ?? index}`; + + return ( + + ); + })} ) : null } diff --git a/plan.md b/plan.md index 1db1712a9..bdf52a04a 100644 --- a/plan.md +++ b/plan.md @@ -37,4 +37,8 @@ - Added `testClaudeHydratedToolBodies` to `test-idempotent-stream.ts`, which simulates Claude edit/read/command tool calls, hydrates the stream, and asserts the parsed diff/content/command output persist. Ran `npx tsx test-idempotent-stream.ts` to cover the new regression. - [x] Despite previous fixes we still see duplicate tool call pills (loading + completed/failed) across Codex and Claude, both live and hydrated streams. Track tool call IDs rigorously, dedupe pending/completed entries, and add regression tests covering real-time and hydrated flows for both providers so this never regresses again. - Reworked tool call reconciliation so completion events now resolve against the earliest matching pending entry (provider/server/tool + heuristics) instead of the most recent, eliminating duplicate pills even when call IDs arrive late. Added live and hydrated regression tests for both providers in `test-idempotent-stream.ts`, and ran `npm run typecheck --workspace=@voice-dev/app` plus `npx tsx test-idempotent-stream.ts`. -- [ ] Duplicate key warnings still appear when opening the agent stream—identify which stream items (thoughts, assistant chunks, tool calls, etc.) are emitting conflicting keys and fix the keying strategy so React no longer logs warnings. +- [x] Duplicate key warnings still appear when opening the agent stream—identify which stream items (thoughts, assistant chunks, tool calls, etc.) are emitting conflicting keys and fix the keying strategy so React no longer logs warnings. + - Hardened the assistant/thought timeline id generator so it now checks for existing ids before committing a suffix, ensuring new entries stay unique even if the stream shrinks, and added regression coverage in `test-idempotent-stream.ts` to prove assistant and reasoning ids remain unique after list pruning. Verified via `npx tsx test-idempotent-stream.ts`; note Test 1 still intentionally highlights state differences as before. + - The warning points at the permission request cards rendered in the stream header; they’re reusing the same key so start the investigation there. +- [x] Permission request cards rendered in the stream header emit duplicate key warnings because consecutive requests share the same `request.id`; derive a composite key so they stay unique per agent even when IDs collide or are missing. + - Switched the header map to key permission cards by `${agentId}:${request.id}` with a title/name/index fallback so React no longer sees duplicate keys even if providers reuse an id or omit it altogether. Ran `npm run typecheck --workspace=@voice-dev/app`.