fix: avoid protocol-only tool trace summaries
This commit is contained in:
@@ -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({
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user