diff --git a/src/features/agent-graph/renderer/hooks/useGraphMemberLogPreviews.ts b/src/features/agent-graph/renderer/hooks/useGraphMemberLogPreviews.ts index 3ed91b86..7eddba2d 100644 --- a/src/features/agent-graph/renderer/hooks/useGraphMemberLogPreviews.ts +++ b/src/features/agent-graph/renderer/hooks/useGraphMemberLogPreviews.ts @@ -26,10 +26,18 @@ function buildRequestKey(input: { textLimit: number; forceRefresh?: boolean; }): string { - const laneEntries = Object.entries(input.laneIdsByMember) - .map(([memberName, laneId]) => [normalizeMemberName(memberName), laneId.trim()] as const) - .filter(([, laneId]) => laneId.length > 0) - .sort((left, right) => left[0].localeCompare(right[0])); + const laneEntriesByMember = new Map(); + for (const [memberName, laneId] of Object.entries(input.laneIdsByMember)) { + const normalizedMemberName = normalizeMemberName(memberName); + const trimmedLaneId = laneId.trim(); + if (!normalizedMemberName || !trimmedLaneId || laneEntriesByMember.has(normalizedMemberName)) { + continue; + } + laneEntriesByMember.set(normalizedMemberName, trimmedLaneId); + } + const laneEntries = Array.from(laneEntriesByMember.entries()).sort((left, right) => + left[0].localeCompare(right[0]) + ); return JSON.stringify([ input.teamName, input.memberNames.map(normalizeMemberName).sort((left, right) => left.localeCompare(right)), @@ -84,6 +92,23 @@ function buildMemberCacheKey(input: { ]); } +function buildLaneIdsForMembers( + memberNames: readonly string[], + laneIdsByMember: Readonly> +): Record { + const result: Record = {}; + for (const memberName of memberNames) { + const laneId = laneIdForMember(memberName, laneIdsByMember); + if (!laneId) continue; + result[memberName] = laneId; + const normalizedMemberName = normalizeMemberName(memberName); + if (normalizedMemberName && normalizedMemberName !== memberName) { + result[normalizedMemberName] = laneId; + } + } + return result; +} + export function getSafeGraphLogPreviewLaneId( member: ResolvedTeamMember | undefined ): string | undefined { @@ -226,10 +251,11 @@ export function useGraphMemberLogPreviews(input: { return; } + const requestedLaneIdsByMember = buildLaneIdsForMembers(membersToRequest, laneIdsByMember); const requestKey = buildRequestKey({ teamName: input.teamName, memberNames: membersToRequest, - laneIdsByMember, + laneIdsByMember: requestedLaneIdsByMember, maxItemsPerMember, textLimit, forceRefresh: options?.forceRefresh, @@ -247,7 +273,9 @@ export function useGraphMemberLogPreviews(input: { const requestOptions: MemberLogPreviewRequestOptions = { maxItemsPerMember, textLimit, - ...(Object.keys(laneIdsByMember).length > 0 ? { laneIdsByMember } : {}), + ...(Object.keys(requestedLaneIdsByMember).length > 0 + ? { laneIdsByMember: requestedLaneIdsByMember } + : {}), ...(options?.forceRefresh ? { forceRefresh: true } : {}), }; request = api.memberLogStream diff --git a/src/features/member-log-stream/core/domain/policies/__tests__/memberLogPreviewExtractor.test.ts b/src/features/member-log-stream/core/domain/policies/__tests__/memberLogPreviewExtractor.test.ts index e8334a6d..beba5d6a 100644 --- a/src/features/member-log-stream/core/domain/policies/__tests__/memberLogPreviewExtractor.test.ts +++ b/src/features/member-log-stream/core/domain/policies/__tests__/memberLogPreviewExtractor.test.ts @@ -1601,11 +1601,7 @@ Reply to this comment using MCP tool task_add_comment. title: 'Bash result', preview: 'Tests passed', }); - expect(result.items[1]).toMatchObject({ - kind: 'tool_use', - title: 'Bash', - preview: 'pnpm test', - }); + expect(result.items).toHaveLength(1); }); it('does not label arbitrary message fields as sent messages', () => { diff --git a/src/features/member-log-stream/core/domain/policies/memberLogPreviewExtractor.ts b/src/features/member-log-stream/core/domain/policies/memberLogPreviewExtractor.ts index 8dcdb736..df6a3a31 100644 --- a/src/features/member-log-stream/core/domain/policies/memberLogPreviewExtractor.ts +++ b/src/features/member-log-stream/core/domain/policies/memberLogPreviewExtractor.ts @@ -533,6 +533,8 @@ function buildToolUseKey(input: { function isToolUseSupersededBySuccessResult(toolName: string): boolean { const canonical = canonicalToolName(toolName); return ( + canonical === 'bash' || + canonical === 'shell' || canonical === 'sendmessage' || canonical === 'message_send' || canonical.startsWith('cross_team_') || diff --git a/src/features/member-log-stream/main/adapters/output/sources/__tests__/memberLogSources.test.ts b/src/features/member-log-stream/main/adapters/output/sources/__tests__/memberLogSources.test.ts index 6d86937e..ade8b964 100644 --- a/src/features/member-log-stream/main/adapters/output/sources/__tests__/memberLogSources.test.ts +++ b/src/features/member-log-stream/main/adapters/output/sources/__tests__/memberLogSources.test.ts @@ -189,7 +189,7 @@ describe('ClaudeMemberTranscriptPreviewSource', () => { const result = await source.loadPreview(previewInput({ textLimit: 160 })); expect(result.status).toBe('included'); - expect(result.items.map((item) => item.kind)).toEqual(['tool_result', 'tool_use']); + expect(result.items.map((item) => item.kind)).toEqual(['tool_result']); expect(result.items[0]?.preview?.length).toBeLessThanOrEqual(160); expect(parseFiles).toHaveBeenCalledWith(['/transcripts/latest.jsonl']); }); diff --git a/test/renderer/features/agent-graph/useGraphMemberLogPreviews.test.tsx b/test/renderer/features/agent-graph/useGraphMemberLogPreviews.test.tsx index 4bb05590..f7008511 100644 --- a/test/renderer/features/agent-graph/useGraphMemberLogPreviews.test.tsx +++ b/test/renderer/features/agent-graph/useGraphMemberLogPreviews.test.tsx @@ -139,7 +139,10 @@ describe('useGraphMemberLogPreviews', () => { undefined} /> );