fix(logs): refine graph preview readability

This commit is contained in:
777genius 2026-05-07 19:54:31 +03:00
parent e777610baa
commit 7c39fbd8e7
3 changed files with 280 additions and 102 deletions

View file

@ -28,8 +28,8 @@ import type {
const LOG_PREVIEW_FALLBACK_WIDTH = 260; const LOG_PREVIEW_FALLBACK_WIDTH = 260;
const LOG_PREVIEW_FALLBACK_HEIGHT = 292; const LOG_PREVIEW_FALLBACK_HEIGHT = 292;
const NEW_LOG_HIGHLIGHT_MS = 1_000; const NEW_LOG_HIGHLIGHT_MS = 1_000;
const COMPACT_ROW_TEXT_LIMIT = 92; const COMPACT_ROW_TEXT_LIMIT = 76;
const COMPACT_ROW_MIN_PREVIEW_LIMIT = 48; const COMPACT_ROW_MIN_PREVIEW_LIMIT = 40;
interface StableRectLike { interface StableRectLike {
left: number; left: number;
@ -434,18 +434,18 @@ export const GraphMemberLogPreviewHud = ({
? 'border-rose-400/35 bg-rose-950/20 hover:border-rose-300/50 hover:bg-rose-950/30' ? 'border-rose-400/35 bg-rose-950/20 hover:border-rose-300/50 hover:bg-rose-950/30'
: 'border-white/10 bg-[rgba(8,14,28,0.52)] hover:border-white/20 hover:bg-[rgba(12,20,40,0.78)]'; : 'border-white/10 bg-[rgba(8,14,28,0.52)] hover:border-white/20 hover:bg-[rgba(12,20,40,0.78)]';
const iconClassName = isError const iconClassName = isError
? 'float-left mr-2 inline-flex size-5 shrink-0 items-center justify-center rounded bg-rose-500/10' ? 'float-left mr-2 mt-px inline-flex size-5 shrink-0 items-center justify-center rounded bg-rose-500/10'
: 'float-left mr-2 inline-flex size-5 shrink-0 items-center justify-center rounded bg-white/5'; : 'float-left mr-2 mt-px inline-flex size-5 shrink-0 items-center justify-center rounded bg-white/5';
const headerClassName = 'inline-flex h-5 items-center align-top'; const headerClassName = 'inline align-baseline';
const titleClassName = isError const titleClassName = isError
? 'text-[11px] font-medium leading-[18px] text-rose-100' ? 'align-baseline text-[11px] font-medium leading-[18px] text-rose-100'
: 'text-[11px] font-medium leading-[18px] text-slate-200'; : 'align-baseline text-[11px] font-medium leading-[18px] text-slate-200';
const timeClassName = isError const timeClassName = isError
? 'ml-1 text-[9px] font-normal leading-[18px] text-rose-300/70' ? 'ml-1 align-baseline text-[9px] font-normal leading-[18px] text-rose-300/70'
: 'ml-1 text-[9px] font-normal leading-[18px] text-slate-500'; : 'ml-1 align-baseline text-[9px] font-normal leading-[18px] text-slate-500';
const previewClassName = isError const previewClassName = isError
? 'ml-1 break-words align-top text-[10px] leading-[18px] text-rose-100/85' ? 'ml-1 break-words align-baseline text-[10px] leading-[18px] text-rose-100/85'
: 'ml-1 break-words align-top text-[10px] leading-[18px] text-slate-300/85'; : 'ml-1 break-words align-baseline text-[10px] leading-[18px] text-slate-300/85';
return ( return (
<button <button

View file

@ -39,7 +39,12 @@ describe('memberLogPreviewExtractor', () => {
message({ message({
uuid: 'new', uuid: 'new',
timestamp: '2026-04-01T10:01:00.000Z', timestamp: '2026-04-01T10:01:00.000Z',
content: [{ type: 'text', text: '<system-reminder>latest answer</system-reminder>' }], content: [
{
type: 'text',
text: 'latest answer <system-reminder>hidden reminder text</system-reminder>',
},
],
}), }),
], ],
}); });
@ -51,6 +56,40 @@ describe('memberLogPreviewExtractor', () => {
preview: 'latest answer', preview: 'latest answer',
}); });
expect(result.items[1]?.preview).toBe('older answer'); expect(result.items[1]?.preview).toBe('older answer');
expect(JSON.stringify(result.items)).not.toContain('hidden reminder text');
});
it('removes agent-only blocks from generic assistant text previews', () => {
const result = extractMemberLogPreviewItems({
provider: 'opencode_runtime',
maxItems: 3,
textLimit: 160,
messages: [
message({
uuid: 'assistant-hidden-block',
timestamp: '2026-04-01T10:00:00.000Z',
content: [
{
type: 'text',
text: `Visible user-facing update.
<info_for_agent>
API Error: 500 hidden MCP protocol instructions.
</info_for_agent>`,
},
],
}),
],
});
expect(result.items[0]).toMatchObject({
kind: 'text',
title: 'Assistant',
preview: 'Visible user-facing update.',
tone: 'neutral',
});
expect(JSON.stringify(result.items)).not.toContain('Hidden MCP protocol');
expect(JSON.stringify(result.items)).not.toContain('API Error: 500');
}); });
it('marks assistant runtime error text as error tone without flagging normal text', () => { it('marks assistant runtime error text as error tone without flagging normal text', () => {
@ -276,7 +315,7 @@ Reply to this comment using MCP tool task_add_comment.
expect(result.items[0]).toMatchObject({ expect(result.items[0]).toMatchObject({
kind: 'tool_result', kind: 'tool_result',
title: 'Message sent', title: 'Message sent',
preview: 'Message sent to team-lead - #abc done', preview: 'to team-lead - #abc done',
}); });
expect(result.items).toHaveLength(1); expect(result.items).toHaveLength(1);
expect(JSON.stringify(result.items)).not.toContain('deliveredToInbox'); expect(JSON.stringify(result.items)).not.toContain('deliveredToInbox');
@ -856,6 +895,47 @@ Reply to this comment using MCP tool task_add_comment.
expect(result.items[0]?.preview).not.toContain('[{'); expect(result.items[0]?.preview).not.toContain('[{');
}); });
it('formats primitive task list arrays as task refs instead of empty lists', () => {
const result = extractMemberLogPreviewItems({
provider: 'claude_transcript',
maxItems: 3,
textLimit: 160,
messages: [
message({
uuid: 'primitive-list-call',
timestamp: '2026-04-01T10:00:00.000Z',
content: [
{
type: 'tool_use',
id: 'tool-primitive-list',
name: 'mcp__agent-teams__task_list',
input: { teamName: 'demo' },
},
],
}),
message({
uuid: 'primitive-list-result',
type: 'user',
role: 'user',
timestamp: '2026-04-01T10:01:00.000Z',
content: [
{
type: 'tool_result',
tool_use_id: 'tool-primitive-list',
content: JSON.stringify(['abc12345', 'def67890']),
},
],
}),
],
});
expect(result.items[0]).toMatchObject({
kind: 'tool_result',
title: 'Task list',
preview: '2 tasks - #abc12345; #def67890',
});
});
it('formats sourceToolUseID result wrappers with text-block content arrays', () => { it('formats sourceToolUseID result wrappers with text-block content arrays', () => {
const result = extractMemberLogPreviewItems({ const result = extractMemberLogPreviewItems({
provider: 'claude_transcript', provider: 'claude_transcript',
@ -1258,6 +1338,84 @@ Reply to this comment using MCP tool task_add_comment.
}); });
expect(processResult.items[0]?.preview).not.toContain('[{'); expect(processResult.items[0]?.preview).not.toContain('[{');
const primitiveProcessResult = extractMemberLogPreviewItems({
provider: 'opencode_runtime',
maxItems: 3,
textLimit: 160,
messages: [
message({
uuid: 'primitive-process-call',
timestamp: '2026-04-01T10:00:00.000Z',
content: [
{
type: 'tool_use',
id: 'tool-primitive-process-list',
name: 'agent-teams_process_list',
input: { teamName: 'relay-works-10' },
},
],
}),
message({
uuid: 'primitive-process-result',
type: 'user',
role: 'user',
timestamp: '2026-04-01T10:01:00.000Z',
content: [
{
type: 'tool_result',
tool_use_id: 'tool-primitive-process-list',
content: ['vite dev', 'pnpm test'],
},
],
}),
],
});
expect(primitiveProcessResult.items[0]).toMatchObject({
kind: 'tool_result',
title: 'Process list',
preview: '2 processes - vite dev; pnpm test',
});
const wrappedPrimitiveProcessResult = extractMemberLogPreviewItems({
provider: 'opencode_runtime',
maxItems: 3,
textLimit: 160,
messages: [
message({
uuid: 'wrapped-primitive-process-call',
timestamp: '2026-04-01T10:00:00.000Z',
content: [
{
type: 'tool_use',
id: 'tool-wrapped-primitive-process-list',
name: 'agent-teams_process_list',
input: { teamName: 'relay-works-10' },
},
],
}),
message({
uuid: 'wrapped-primitive-process-result',
type: 'user',
role: 'user',
timestamp: '2026-04-01T10:01:00.000Z',
content: [
{
type: 'tool_result',
tool_use_id: 'tool-wrapped-primitive-process-list',
content: { processes: ['vite dev', 'pnpm test'] },
},
],
}),
],
});
expect(wrappedPrimitiveProcessResult.items[0]).toMatchObject({
kind: 'tool_result',
title: 'Process list',
preview: '2 processes - vite dev; pnpm test',
});
const taskUpdateResult = extractMemberLogPreviewItems({ const taskUpdateResult = extractMemberLogPreviewItems({
provider: 'opencode_runtime', provider: 'opencode_runtime',
maxItems: 3, maxItems: 3,
@ -1321,7 +1479,7 @@ Reply to this comment using MCP tool task_add_comment.
{ {
toolName: 'agent-teams_cross_team_list_targets', toolName: 'agent-teams_cross_team_list_targets',
input: { teamName: 'relay-works-10' }, input: { teamName: 'relay-works-10' },
result: JSON.stringify([{ teamName: 'qa-team' }, { name: 'design-team' }]), result: JSON.stringify(['qa-team', 'design-team']),
expectedTitle: 'Cross-team targets', expectedTitle: 'Cross-team targets',
expectedPreview: '2 teams - qa-team; design-team', expectedPreview: '2 teams - qa-team; design-team',
}, },
@ -1337,7 +1495,7 @@ Reply to this comment using MCP tool task_add_comment.
{ {
toolName: 'agent-teams_process_register', toolName: 'agent-teams_process_register',
input: { label: 'vite dev', command: 'pnpm dev' }, input: { label: 'vite dev', command: 'pnpm dev' },
result: { process: { label: 'vite dev', status: 'running' } }, result: { pid: 123, process: { label: 'vite dev', status: 'running' } },
expectedTitle: 'Process registered', expectedTitle: 'Process registered',
expectedPreview: 'Registered vite dev running', expectedPreview: 'Registered vite dev running',
}, },
@ -1549,6 +1707,43 @@ Reply to this comment using MCP tool task_add_comment.
}); });
}); });
it('uses content block order before mirrored toolCalls for same-message readability', () => {
const result = extractMemberLogPreviewItems({
provider: 'claude_transcript',
maxItems: 3,
textLimit: 120,
messages: [
message({
uuid: 'mirrored-tool-call',
timestamp: '2026-04-01T10:01:00.000Z',
content: [
{ type: 'text', text: 'I will inspect the files first.' },
{
type: 'tool_use',
id: 'tool-read',
name: 'Read',
input: { file_path: 'src/app.ts' },
},
],
toolCalls: [
{
id: 'tool-read',
name: 'Read',
input: { file_path: 'src/app.ts' },
isTask: false,
},
],
}),
],
});
expect(result.items.map((item) => item.title)).toEqual(['Assistant', 'Read']);
expect(result.items[0]).toMatchObject({
kind: 'text',
preview: 'I will inspect the files first.',
});
});
it('caps preview items at three and reports overflow', () => { it('caps preview items at three and reports overflow', () => {
const result = extractMemberLogPreviewItems({ const result = extractMemberLogPreviewItems({
provider: 'claude_transcript', provider: 'claude_transcript',

View file

@ -192,7 +192,7 @@ function parseJsonLikeString(value: string): unknown {
} }
function truncatePreview(value: string, limit: number): { preview: string; truncated: boolean } { function truncatePreview(value: string, limit: number): { preview: string; truncated: boolean } {
const compact = compactWhitespace(value); const compact = compactWhitespace(removeHiddenInstructionBlocks(value));
if (compact.length <= limit) { if (compact.length <= limit) {
return { preview: compact, truncated: false }; return { preview: compact, truncated: false };
} }
@ -388,7 +388,7 @@ function formatRuntimeErrorText(
value: string, value: string,
limit: number limit: number
): (ValuePreview & { title: string }) | null { ): (ValuePreview & { title: string }) | null {
const compact = compactWhitespace(value); const compact = compactWhitespace(removeHiddenInstructionBlocks(value));
if (!compact) { if (!compact) {
return null; return null;
} }
@ -642,7 +642,11 @@ function countArrayField(payload: Record<string, unknown>, keys: readonly string
return null; return null;
} }
function formatTaskCollectionItem(task: Record<string, unknown>): string | null { function formatTaskCollectionItem(item: unknown): string | null {
const task = asRecord(item);
if (!task) {
return formatTaskRef(stringifyPrimitive(item));
}
const taskRef = taskRefFromPayload(task); const taskRef = taskRefFromPayload(task);
const taskSummary = shortTaskSummary(task); const taskSummary = shortTaskSummary(task);
if (taskRef && taskSummary) return `${taskRef}: ${taskSummary}`; if (taskRef && taskSummary) return `${taskRef}: ${taskSummary}`;
@ -659,20 +663,17 @@ function formatTaskCollectionArrayPayload(
return null; return null;
} }
const tasks = items if (items.length === 0) {
.map((item) => asRecord(item))
.filter((item): item is Record<string, unknown> => Boolean(item));
if (tasks.length === 0) {
return { return {
title: canonical === 'task_briefing' ? 'Task briefing' : 'Task list', title: canonical === 'task_briefing' ? 'Task briefing' : 'Task list',
text: '0 tasks', text: '0 tasks',
}; };
} }
const taskSummaries = tasks.slice(0, 3).map(formatTaskCollectionItem).filter(Boolean); const taskSummaries = items.slice(0, 3).map(formatTaskCollectionItem).filter(Boolean);
const remainingTaskCount = Math.max(0, tasks.length - taskSummaries.length); const remainingTaskCount = Math.max(0, items.length - taskSummaries.length);
const moreText = remainingTaskCount > 0 ? `; +${remainingTaskCount} more` : ''; const moreText = remainingTaskCount > 0 ? `; +${remainingTaskCount} more` : '';
const countText = `${tasks.length} ${tasks.length === 1 ? 'task' : 'tasks'}`; const countText = `${items.length} ${items.length === 1 ? 'task' : 'tasks'}`;
return { return {
title: canonical === 'task_briefing' ? 'Task briefing' : 'Task list', title: canonical === 'task_briefing' ? 'Task briefing' : 'Task list',
text: text:
@ -713,32 +714,7 @@ function formatProcessCollectionPayload(
(Array.isArray(payload.processes) ? payload.processes : null) ?? (Array.isArray(payload.processes) ? payload.processes : null) ??
(Array.isArray(payload.items) ? payload.items : null); (Array.isArray(payload.items) ? payload.items : null);
if (rawProcesses) { if (rawProcesses) {
const processes = rawProcesses return formatProcessCollectionArrayPayload(rawProcesses);
.map((item) => asRecord(item))
.filter((item): item is Record<string, unknown> => Boolean(item));
const processSummaries = processes
.slice(0, 3)
.map((process) => {
const label =
stringField(process, 'label') ??
stringField(process, 'name') ??
stringField(process, 'command') ??
stringField(process, 'pid');
const status = stringField(process, 'status');
if (label && status) return `${label} ${status}`;
return label ?? status;
})
.filter(Boolean);
const remainingCount = Math.max(0, processes.length - processSummaries.length);
const moreText = remainingCount > 0 ? `; +${remainingCount} more` : '';
const countText = `${processes.length} ${processes.length === 1 ? 'process' : 'processes'}`;
return {
title: 'Process list',
text:
processSummaries.length > 0
? `${countText} - ${processSummaries.join('; ')}${moreText}`
: countText,
};
} }
const processCount = countArrayField(payload, ['processes', 'items']); const processCount = countArrayField(payload, ['processes', 'items']);
@ -749,12 +725,11 @@ function formatProcessCollectionPayload(
} }
function formatProcessCollectionArrayPayload(items: readonly unknown[]): KnownPayloadPreview { function formatProcessCollectionArrayPayload(items: readonly unknown[]): KnownPayloadPreview {
const processes = items const processSummaries = items
.map((item) => asRecord(item))
.filter((item): item is Record<string, unknown> => Boolean(item));
const processSummaries = processes
.slice(0, 3) .slice(0, 3)
.map((process) => { .map((item) => {
const process = asRecord(item);
if (!process) return stringifyPrimitive(item);
const label = const label =
stringField(process, 'label') ?? stringField(process, 'label') ??
stringField(process, 'name') ?? stringField(process, 'name') ??
@ -764,10 +739,10 @@ function formatProcessCollectionArrayPayload(items: readonly unknown[]): KnownPa
if (label && status) return `${label} ${status}`; if (label && status) return `${label} ${status}`;
return label || status; return label || status;
}) })
.filter(Boolean); .filter((summary): summary is string => Boolean(summary));
const remainingCount = Math.max(0, processes.length - processSummaries.length); const remainingCount = Math.max(0, items.length - processSummaries.length);
const moreText = remainingCount > 0 ? `; +${remainingCount} more` : ''; const moreText = remainingCount > 0 ? `; +${remainingCount} more` : '';
const countText = `${processes.length} ${processes.length === 1 ? 'process' : 'processes'}`; const countText = `${items.length} ${items.length === 1 ? 'process' : 'processes'}`;
return { return {
title: 'Process list', title: 'Process list',
text: text:
@ -787,14 +762,14 @@ function processLabelFromPayload(
stringField(payload, 'label'), stringField(payload, 'label'),
stringField(payload, 'name'), stringField(payload, 'name'),
stringField(payload, 'command'), stringField(payload, 'command'),
stringField(payload, 'processId'),
stringField(payload, 'id'),
stringifyPrimitive(payload.pid),
stringField(process, 'label'), stringField(process, 'label'),
stringField(process, 'name'), stringField(process, 'name'),
stringField(process, 'command'), stringField(process, 'command'),
stringField(payload, 'processId'),
stringField(payload, 'id'),
stringField(process, 'processId'), stringField(process, 'processId'),
stringField(process, 'id'), stringField(process, 'id'),
stringifyPrimitive(payload.pid),
stringifyPrimitive(process?.pid), stringifyPrimitive(process?.pid),
stringField(fallbackInput ?? undefined, 'label'), stringField(fallbackInput ?? undefined, 'label'),
stringField(fallbackInput ?? undefined, 'name'), stringField(fallbackInput ?? undefined, 'name'),
@ -882,29 +857,28 @@ function formatCrossTeamCollectionArrayPayload(
: null; : null;
if (!title) return null; if (!title) return null;
const records = items const summaries = items
.map((item) => asRecord(item))
.filter((item): item is Record<string, unknown> => Boolean(item));
const summaries = records
.slice(0, 3) .slice(0, 3)
.map((item) => .map((item) => {
canonical === 'cross_team_list_targets' const record = asRecord(item);
? formatCrossTeamTargetItem(item) if (!record) return stringifyPrimitive(item);
: formatCrossTeamOutboxItem(item) return canonical === 'cross_team_list_targets'
) ? formatCrossTeamTargetItem(record)
.filter(Boolean); : formatCrossTeamOutboxItem(record);
const remainingCount = Math.max(0, records.length - summaries.length); })
.filter((summary): summary is string => Boolean(summary));
const remainingCount = Math.max(0, items.length - summaries.length);
const moreText = remainingCount > 0 ? `; +${remainingCount} more` : ''; const moreText = remainingCount > 0 ? `; +${remainingCount} more` : '';
if (canonical === 'cross_team_list_targets') { if (canonical === 'cross_team_list_targets') {
const countText = `${records.length} ${records.length === 1 ? 'team' : 'teams'}`; const countText = `${items.length} ${items.length === 1 ? 'team' : 'teams'}`;
return { return {
title, title,
text: summaries.length > 0 ? `${countText} - ${summaries.join('; ')}${moreText}` : countText, text: summaries.length > 0 ? `${countText} - ${summaries.join('; ')}${moreText}` : countText,
}; };
} }
const countText = `${records.length} ${records.length === 1 ? 'message' : 'messages'}`; const countText = `${items.length} ${items.length === 1 ? 'message' : 'messages'}`;
return { return {
title, title,
text: summaries.length > 0 ? `${countText} - ${summaries.join('; ')}${moreText}` : countText, text: summaries.length > 0 ? `${countText} - ${summaries.join('; ')}${moreText}` : countText,
@ -1240,6 +1214,12 @@ function formatErrorPayload(payload: Record<string, unknown>): KnownPayloadPrevi
return null; return null;
} }
function stripMessageSentPrefix(value: string): string | null {
const compact = compactWhitespace(value);
const stripped = compact.replace(/^message sent\b/i, '').trim();
return stripped.length > 0 ? stripped : null;
}
function formatMessageSendPayload(payload: Record<string, unknown>): string | null { function formatMessageSendPayload(payload: Record<string, unknown>): string | null {
const routing = asRecord(payload.routing) ?? undefined; const routing = asRecord(payload.routing) ?? undefined;
const messageRecord = asRecord(payload.message) ?? undefined; const messageRecord = asRecord(payload.message) ?? undefined;
@ -1251,13 +1231,16 @@ function formatMessageSendPayload(payload: Record<string, unknown>): string | nu
stringField(messageRecord, 'content') ?? stringField(messageRecord, 'content') ??
stringField(routing, 'content'); stringField(routing, 'content');
if (deliveryMessage && summary) return `${deliveryMessage} - ${summary}`; if (deliveryMessage && summary) {
if (summary && target) return `Message sent to ${target} - ${summary}`; const deliveryTarget = stripMessageSentPrefix(deliveryMessage);
return deliveryTarget ? `${deliveryTarget} - ${summary}` : summary;
}
if (summary && target) return `to ${target} - ${summary}`;
if (summary) return summary; if (summary) return summary;
if (deliveryMessage) return deliveryMessage; if (deliveryMessage) return stripMessageSentPrefix(deliveryMessage) ?? deliveryMessage;
if (messageText && target) return `Message sent to ${target} - ${messageText}`; if (messageText && target) return `to ${target} - ${messageText}`;
if (messageText) return messageText; if (messageText) return messageText;
if (target) return `Message sent to ${target}`; if (target) return `to ${target}`;
return null; return null;
} }
@ -1284,8 +1267,8 @@ function formatMessageSendResultFromInput(payload: Record<string, unknown>): str
stringField(payload, 'text') ?? stringField(payload, 'text') ??
stringField(payload, 'message') ?? stringField(payload, 'message') ??
stringField(payload, 'content'); stringField(payload, 'content');
if (target && summary) return `Message sent to ${target} - ${summary}`; if (target && summary) return `to ${target} - ${summary}`;
if (target) return `Message sent to ${target}`; if (target) return `to ${target}`;
if (summary) return summary; if (summary) return summary;
return null; return null;
} }
@ -1399,7 +1382,7 @@ function formatPlainToolResultStatus(
} }
function formatPlainToolErrorText(value: string, limit: number): ValuePreview | null { function formatPlainToolErrorText(value: string, limit: number): ValuePreview | null {
const compact = compactWhitespace(value); const compact = compactWhitespace(removeHiddenInstructionBlocks(value));
if (!compact) { if (!compact) {
return null; return null;
} }
@ -2023,12 +2006,6 @@ function collectToolUseCandidates(input: {
); );
}; };
input.message.toolCalls?.forEach((toolCall, index) => {
const normalized = normalizeToolCall(toolCall);
if (normalized) {
addTool(normalized, 100 + index);
}
});
if (Array.isArray(input.message.content)) { if (Array.isArray(input.message.content)) {
input.message.content.forEach((block, index) => { input.message.content.forEach((block, index) => {
if (!isToolUseBlock(block)) return; if (!isToolUseBlock(block)) return;
@ -2042,6 +2019,12 @@ function collectToolUseCandidates(input: {
); );
}); });
} }
input.message.toolCalls?.forEach((toolCall, index) => {
const normalized = normalizeToolCall(toolCall);
if (normalized) {
addTool(normalized, 100 + index);
}
});
return candidates; return candidates;
} }
@ -2105,6 +2088,19 @@ function collectToolResultCandidates(input: {
); );
}; };
if (Array.isArray(input.message.content)) {
input.message.content.forEach((block, index) => {
if (!isToolResultBlock(block)) return;
addResult(
{
toolUseId: block.tool_use_id,
content: block.content,
isError: block.is_error === true,
},
index
);
});
}
input.message.toolResults?.forEach((result, index) => input.message.toolResults?.forEach((result, index) =>
addResult( addResult(
{ {
@ -2125,19 +2121,6 @@ function collectToolResultCandidates(input: {
240 240
); );
} }
if (Array.isArray(input.message.content)) {
input.message.content.forEach((block, index) => {
if (!isToolResultBlock(block)) return;
addResult(
{
toolUseId: block.tool_use_id,
content: block.content,
isError: block.is_error === true,
},
index
);
});
}
return candidates; return candidates;
} }