fix: avoid protocol-only tool trace summaries

This commit is contained in:
lyon
2026-06-16 01:00:54 +08:00
parent 8f4fb1bceb
commit 7fcc83e692
2 changed files with 89 additions and 6 deletions
+48 -5
View File
@@ -1695,15 +1695,26 @@ function mapAgentRunEvent(event, mapping = {}) {
if (event.type === "tool_call") {
const commandExecution = agentRunCommandExecutionEvent(base, payload);
if (commandExecution) return commandExecution;
const toolName = firstNonEmpty(payload.toolName, payload.name, payload.item?.type, payload.type, payload.method, "call");
const command = firstNonEmpty(payload.command, payload.commandLine, payload.item?.command, payload.item?.commandLine);
const output = firstNonEmpty(payload.outputSummary, payload.stdoutSummary, payload.summary?.text, payload.itemPreview);
const preview = agentRunToolCallPreviewSummary(payload);
const toolName = firstNonEmpty(
payload.toolName,
payload.name,
payload.item?.type,
payload.type,
preview.toolName,
preview.name,
preview.type,
isProtocolToolLifecycleMethod(payload.method) ? null : payload.method,
"tool call"
);
const command = firstNonEmpty(payload.command, payload.commandLine, payload.item?.command, payload.item?.commandLine, preview.command, preview.commandLine);
const output = firstNonEmpty(payload.outputSummary, payload.stdoutSummary, preview.outputSummary, preview.stdoutSummary, payload.summary?.text, payload.itemPreview);
return {
...base,
type: "tool_call",
status: String(payload.status ?? (payload.method === "item/completed" ? "completed" : "running")),
status: String(payload.status ?? preview.status ?? (payload.method === "item/completed" ? "completed" : "running")),
label: `agentrun:tool:${String(toolName)}`,
itemId: payload.item?.id ?? payload.itemId ?? null,
itemId: payload.item?.id ?? payload.itemId ?? preview.itemId ?? null,
toolName,
command,
exitCode: Number.isInteger(payload.item?.exitCode) ? payload.item.exitCode : Number.isInteger(payload.exitCode) ? payload.exitCode : undefined,
@@ -1732,6 +1743,38 @@ function mapAgentRunEvent(event, mapping = {}) {
return { ...base, type: "backend", status: "running", label: `agentrun:event:${String(event.type ?? "unknown")}`, message: textPayload(payload, "AgentRun event") };
}
function isProtocolToolLifecycleMethod(value) {
return /^item\/(started|completed)$/u.test(String(value ?? ""));
}
function agentRunToolCallPreviewSummary(payload = {}) {
const text = firstNonEmpty(payload.itemPreview, payload.summary?.text);
return {
itemId: jsonPreviewStringField(text, "itemId"),
type: jsonPreviewStringField(text, "type"),
toolName: jsonPreviewStringField(text, "toolName"),
name: jsonPreviewStringField(text, "name"),
status: jsonPreviewStringField(text, "status"),
command: jsonPreviewStringField(text, "command"),
commandLine: jsonPreviewStringField(text, "commandLine"),
outputSummary: jsonPreviewStringField(text, "outputSummary"),
stdoutSummary: jsonPreviewStringField(text, "stdoutSummary")
};
}
function jsonPreviewStringField(text, key) {
const body = String(text ?? "");
if (!body || !/^[A-Za-z][A-Za-z0-9_]*$/u.test(key)) return null;
const match = body.match(new RegExp(`"${key}"\\s*:\\s*"((?:\\\\.|[^"\\\\])*)"`, "u"));
if (!match) return null;
try {
const parsed = JSON.parse(`"${match[1]}"`);
return typeof parsed === "string" && parsed.trim() ? parsed.trim() : null;
} catch {
return match[1]?.trim() || null;
}
}
function agentRunBackendStatusDetails(phase, payload = {}) {
if (phase === "initial-prompt-assembly") {
return compactObject({
+41 -1
View File
@@ -126,7 +126,7 @@ interface AssistantSnapshotDecision {
function traceToolCallRow(trace: Record<string, unknown>, event: TraceEvent): TraceEventRow {
const command = cleanShellCommand(event.command);
const status = traceStatusToken(event);
const toolName = nonEmptyString(event.toolName) ?? readableTraceLabel(event).replace(/^item\//u, "");
const toolName = traceToolName(event, command);
const body = traceToolCallBody(event, command);
return {
rowId: `tool:${event.itemId ?? event.seq ?? `${event.label ?? event.type ?? "tool"}:${event.createdAt ?? "unknown"}`}`,
@@ -139,6 +139,46 @@ function traceToolCallRow(trace: Record<string, unknown>, event: TraceEvent): Tr
};
}
function traceToolName(event: TraceEvent, command: string | null): string {
const direct = nonEmptyString(event.toolName);
if (direct && !isProtocolToolLifecycleName(direct)) return direct;
const label = readableTraceLabel(event).replace(/^agentrun:tool:/u, "").replace(/^tool:/u, "").replace(/^item\//u, "");
if (label && !isProtocolToolLifecycleName(label)) return label;
const commandName = traceToolNameFromCommand(command);
if (commandName) return commandName;
const previewName = traceToolNameFromPreview(event);
if (previewName) return previewName;
return "tool call";
}
function isProtocolToolLifecycleName(value: unknown): boolean {
return /^(?:item\/)?(?:started|completed)$/iu.test(String(value ?? "").trim()) || /^item\/(?:started|completed)$/iu.test(String(value ?? "").trim());
}
function traceToolNameFromCommand(command: string | null): string | null {
const text = cleanTraceText(command);
const match = text.match(/^([A-Za-z][A-Za-z0-9_.:-]{1,80})(?:\s|$)/u);
return match?.[1] ?? null;
}
function traceToolNameFromPreview(event: TraceEvent): string | null {
const preview = traceEventText(event, ["output", "outputText", "outputSummary", "stdoutSummary", "message"]);
return jsonPreviewStringField(preview, "toolName") ?? jsonPreviewStringField(preview, "type") ?? jsonPreviewStringField(preview, "name");
}
function jsonPreviewStringField(text: string | null, key: string): string | null {
const body = String(text ?? "");
if (!body || !/^[A-Za-z][A-Za-z0-9_]*$/u.test(key)) return null;
const match = body.match(new RegExp(`"${key}"\\s*:\\s*"((?:\\\\.|[^"\\\\])*)"`, "u"));
if (!match) return null;
try {
const parsed = JSON.parse(`"${match[1]}"`);
return typeof parsed === "string" && parsed.trim() ? parsed.trim() : null;
} catch {
return match[1]?.trim() || null;
}
}
function traceToolCallBody(event: TraceEvent, command: string | null): string | null {
const lines = [
command,