fix(logs): refine graph preview readability
This commit is contained in:
parent
e777610baa
commit
7c39fbd8e7
3 changed files with 280 additions and 102 deletions
|
|
@ -28,8 +28,8 @@ import type {
|
|||
const LOG_PREVIEW_FALLBACK_WIDTH = 260;
|
||||
const LOG_PREVIEW_FALLBACK_HEIGHT = 292;
|
||||
const NEW_LOG_HIGHLIGHT_MS = 1_000;
|
||||
const COMPACT_ROW_TEXT_LIMIT = 92;
|
||||
const COMPACT_ROW_MIN_PREVIEW_LIMIT = 48;
|
||||
const COMPACT_ROW_TEXT_LIMIT = 76;
|
||||
const COMPACT_ROW_MIN_PREVIEW_LIMIT = 40;
|
||||
|
||||
interface StableRectLike {
|
||||
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-white/10 bg-[rgba(8,14,28,0.52)] hover:border-white/20 hover:bg-[rgba(12,20,40,0.78)]';
|
||||
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 inline-flex size-5 shrink-0 items-center justify-center rounded bg-white/5';
|
||||
const headerClassName = 'inline-flex h-5 items-center align-top';
|
||||
? '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 mt-px inline-flex size-5 shrink-0 items-center justify-center rounded bg-white/5';
|
||||
const headerClassName = 'inline align-baseline';
|
||||
const titleClassName = isError
|
||||
? '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-rose-100'
|
||||
: 'align-baseline text-[11px] font-medium leading-[18px] text-slate-200';
|
||||
const timeClassName = isError
|
||||
? 'ml-1 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-rose-300/70'
|
||||
: 'ml-1 align-baseline text-[9px] font-normal leading-[18px] text-slate-500';
|
||||
const previewClassName = isError
|
||||
? 'ml-1 break-words align-top 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-rose-100/85'
|
||||
: 'ml-1 break-words align-baseline text-[10px] leading-[18px] text-slate-300/85';
|
||||
|
||||
return (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -39,7 +39,12 @@ describe('memberLogPreviewExtractor', () => {
|
|||
message({
|
||||
uuid: 'new',
|
||||
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',
|
||||
});
|
||||
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', () => {
|
||||
|
|
@ -276,7 +315,7 @@ Reply to this comment using MCP tool task_add_comment.
|
|||
expect(result.items[0]).toMatchObject({
|
||||
kind: 'tool_result',
|
||||
title: 'Message sent',
|
||||
preview: 'Message sent to team-lead - #abc done',
|
||||
preview: 'to team-lead - #abc done',
|
||||
});
|
||||
expect(result.items).toHaveLength(1);
|
||||
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('[{');
|
||||
});
|
||||
|
||||
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', () => {
|
||||
const result = extractMemberLogPreviewItems({
|
||||
provider: 'claude_transcript',
|
||||
|
|
@ -1258,6 +1338,84 @@ Reply to this comment using MCP tool task_add_comment.
|
|||
});
|
||||
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({
|
||||
provider: 'opencode_runtime',
|
||||
maxItems: 3,
|
||||
|
|
@ -1321,7 +1479,7 @@ Reply to this comment using MCP tool task_add_comment.
|
|||
{
|
||||
toolName: 'agent-teams_cross_team_list_targets',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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', () => {
|
||||
const result = extractMemberLogPreviewItems({
|
||||
provider: 'claude_transcript',
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ function parseJsonLikeString(value: string): unknown {
|
|||
}
|
||||
|
||||
function truncatePreview(value: string, limit: number): { preview: string; truncated: boolean } {
|
||||
const compact = compactWhitespace(value);
|
||||
const compact = compactWhitespace(removeHiddenInstructionBlocks(value));
|
||||
if (compact.length <= limit) {
|
||||
return { preview: compact, truncated: false };
|
||||
}
|
||||
|
|
@ -388,7 +388,7 @@ function formatRuntimeErrorText(
|
|||
value: string,
|
||||
limit: number
|
||||
): (ValuePreview & { title: string }) | null {
|
||||
const compact = compactWhitespace(value);
|
||||
const compact = compactWhitespace(removeHiddenInstructionBlocks(value));
|
||||
if (!compact) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -642,7 +642,11 @@ function countArrayField(payload: Record<string, unknown>, keys: readonly string
|
|||
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 taskSummary = shortTaskSummary(task);
|
||||
if (taskRef && taskSummary) return `${taskRef}: ${taskSummary}`;
|
||||
|
|
@ -659,20 +663,17 @@ function formatTaskCollectionArrayPayload(
|
|||
return null;
|
||||
}
|
||||
|
||||
const tasks = items
|
||||
.map((item) => asRecord(item))
|
||||
.filter((item): item is Record<string, unknown> => Boolean(item));
|
||||
if (tasks.length === 0) {
|
||||
if (items.length === 0) {
|
||||
return {
|
||||
title: canonical === 'task_briefing' ? 'Task briefing' : 'Task list',
|
||||
text: '0 tasks',
|
||||
};
|
||||
}
|
||||
|
||||
const taskSummaries = tasks.slice(0, 3).map(formatTaskCollectionItem).filter(Boolean);
|
||||
const remainingTaskCount = Math.max(0, tasks.length - taskSummaries.length);
|
||||
const taskSummaries = items.slice(0, 3).map(formatTaskCollectionItem).filter(Boolean);
|
||||
const remainingTaskCount = Math.max(0, items.length - taskSummaries.length);
|
||||
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 {
|
||||
title: canonical === 'task_briefing' ? 'Task briefing' : 'Task list',
|
||||
text:
|
||||
|
|
@ -713,32 +714,7 @@ function formatProcessCollectionPayload(
|
|||
(Array.isArray(payload.processes) ? payload.processes : null) ??
|
||||
(Array.isArray(payload.items) ? payload.items : null);
|
||||
if (rawProcesses) {
|
||||
const processes = 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,
|
||||
};
|
||||
return formatProcessCollectionArrayPayload(rawProcesses);
|
||||
}
|
||||
|
||||
const processCount = countArrayField(payload, ['processes', 'items']);
|
||||
|
|
@ -749,12 +725,11 @@ function formatProcessCollectionPayload(
|
|||
}
|
||||
|
||||
function formatProcessCollectionArrayPayload(items: readonly unknown[]): KnownPayloadPreview {
|
||||
const processes = items
|
||||
.map((item) => asRecord(item))
|
||||
.filter((item): item is Record<string, unknown> => Boolean(item));
|
||||
const processSummaries = processes
|
||||
const processSummaries = items
|
||||
.slice(0, 3)
|
||||
.map((process) => {
|
||||
.map((item) => {
|
||||
const process = asRecord(item);
|
||||
if (!process) return stringifyPrimitive(item);
|
||||
const label =
|
||||
stringField(process, 'label') ??
|
||||
stringField(process, 'name') ??
|
||||
|
|
@ -764,10 +739,10 @@ function formatProcessCollectionArrayPayload(items: readonly unknown[]): KnownPa
|
|||
if (label && status) return `${label} ${status}`;
|
||||
return label || status;
|
||||
})
|
||||
.filter(Boolean);
|
||||
const remainingCount = Math.max(0, processes.length - processSummaries.length);
|
||||
.filter((summary): summary is string => Boolean(summary));
|
||||
const remainingCount = Math.max(0, items.length - processSummaries.length);
|
||||
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 {
|
||||
title: 'Process list',
|
||||
text:
|
||||
|
|
@ -787,14 +762,14 @@ function processLabelFromPayload(
|
|||
stringField(payload, 'label'),
|
||||
stringField(payload, 'name'),
|
||||
stringField(payload, 'command'),
|
||||
stringField(payload, 'processId'),
|
||||
stringField(payload, 'id'),
|
||||
stringifyPrimitive(payload.pid),
|
||||
stringField(process, 'label'),
|
||||
stringField(process, 'name'),
|
||||
stringField(process, 'command'),
|
||||
stringField(payload, 'processId'),
|
||||
stringField(payload, 'id'),
|
||||
stringField(process, 'processId'),
|
||||
stringField(process, 'id'),
|
||||
stringifyPrimitive(payload.pid),
|
||||
stringifyPrimitive(process?.pid),
|
||||
stringField(fallbackInput ?? undefined, 'label'),
|
||||
stringField(fallbackInput ?? undefined, 'name'),
|
||||
|
|
@ -882,29 +857,28 @@ function formatCrossTeamCollectionArrayPayload(
|
|||
: null;
|
||||
if (!title) return null;
|
||||
|
||||
const records = items
|
||||
.map((item) => asRecord(item))
|
||||
.filter((item): item is Record<string, unknown> => Boolean(item));
|
||||
const summaries = records
|
||||
const summaries = items
|
||||
.slice(0, 3)
|
||||
.map((item) =>
|
||||
canonical === 'cross_team_list_targets'
|
||||
? formatCrossTeamTargetItem(item)
|
||||
: formatCrossTeamOutboxItem(item)
|
||||
)
|
||||
.filter(Boolean);
|
||||
const remainingCount = Math.max(0, records.length - summaries.length);
|
||||
.map((item) => {
|
||||
const record = asRecord(item);
|
||||
if (!record) return stringifyPrimitive(item);
|
||||
return canonical === 'cross_team_list_targets'
|
||||
? formatCrossTeamTargetItem(record)
|
||||
: formatCrossTeamOutboxItem(record);
|
||||
})
|
||||
.filter((summary): summary is string => Boolean(summary));
|
||||
const remainingCount = Math.max(0, items.length - summaries.length);
|
||||
const moreText = remainingCount > 0 ? `; +${remainingCount} more` : '';
|
||||
|
||||
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 {
|
||||
title,
|
||||
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 {
|
||||
title,
|
||||
text: summaries.length > 0 ? `${countText} - ${summaries.join('; ')}${moreText}` : countText,
|
||||
|
|
@ -1240,6 +1214,12 @@ function formatErrorPayload(payload: Record<string, unknown>): KnownPayloadPrevi
|
|||
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 {
|
||||
const routing = asRecord(payload.routing) ?? undefined;
|
||||
const messageRecord = asRecord(payload.message) ?? undefined;
|
||||
|
|
@ -1251,13 +1231,16 @@ function formatMessageSendPayload(payload: Record<string, unknown>): string | nu
|
|||
stringField(messageRecord, 'content') ??
|
||||
stringField(routing, 'content');
|
||||
|
||||
if (deliveryMessage && summary) return `${deliveryMessage} - ${summary}`;
|
||||
if (summary && target) return `Message sent to ${target} - ${summary}`;
|
||||
if (deliveryMessage && summary) {
|
||||
const deliveryTarget = stripMessageSentPrefix(deliveryMessage);
|
||||
return deliveryTarget ? `${deliveryTarget} - ${summary}` : summary;
|
||||
}
|
||||
if (summary && target) return `to ${target} - ${summary}`;
|
||||
if (summary) return summary;
|
||||
if (deliveryMessage) return deliveryMessage;
|
||||
if (messageText && target) return `Message sent to ${target} - ${messageText}`;
|
||||
if (deliveryMessage) return stripMessageSentPrefix(deliveryMessage) ?? deliveryMessage;
|
||||
if (messageText && target) return `to ${target} - ${messageText}`;
|
||||
if (messageText) return messageText;
|
||||
if (target) return `Message sent to ${target}`;
|
||||
if (target) return `to ${target}`;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -1284,8 +1267,8 @@ function formatMessageSendResultFromInput(payload: Record<string, unknown>): str
|
|||
stringField(payload, 'text') ??
|
||||
stringField(payload, 'message') ??
|
||||
stringField(payload, 'content');
|
||||
if (target && summary) return `Message sent to ${target} - ${summary}`;
|
||||
if (target) return `Message sent to ${target}`;
|
||||
if (target && summary) return `to ${target} - ${summary}`;
|
||||
if (target) return `to ${target}`;
|
||||
if (summary) return summary;
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1399,7 +1382,7 @@ function formatPlainToolResultStatus(
|
|||
}
|
||||
|
||||
function formatPlainToolErrorText(value: string, limit: number): ValuePreview | null {
|
||||
const compact = compactWhitespace(value);
|
||||
const compact = compactWhitespace(removeHiddenInstructionBlocks(value));
|
||||
if (!compact) {
|
||||
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)) {
|
||||
input.message.content.forEach((block, index) => {
|
||||
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;
|
||||
}
|
||||
|
|
@ -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) =>
|
||||
addResult(
|
||||
{
|
||||
|
|
@ -2125,19 +2121,6 @@ function collectToolResultCandidates(input: {
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue