fix(logs): scope graph preview lane requests

This commit is contained in:
777genius 2026-05-07 20:14:59 +03:00
parent 7c39fbd8e7
commit 0f9f79da66
5 changed files with 42 additions and 13 deletions

View file

@ -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<string, string>();
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<string, string>>
): Record<string, string> {
const result: Record<string, string> = {};
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

View file

@ -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', () => {

View file

@ -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_') ||

View file

@ -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']);
});

View file

@ -139,7 +139,10 @@ describe('useGraphMemberLogPreviews', () => {
<HookProbe
teamName="alpha-team"
memberNames={['alice', 'alice']}
laneIdsByMember={{ alice: 'secondary:opencode:alice' }}
laneIdsByMember={{
alice: 'secondary:opencode:alice',
bob: 'secondary:opencode:bob',
}}
onState={() => undefined}
/>
);