344 lines
12 KiB
TypeScript
344 lines
12 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import { traceDisplayRows, traceNoiseEventCount } from "./app-trace.ts";
|
|
|
|
test("trace display rows render request, setup, command, assistant markdown, and completion path", () => {
|
|
const trace = {
|
|
traceId: "trc_trace_contract",
|
|
events: traceEvents(),
|
|
assistantStreams: [{ itemId: "assistant-final", text: "# 处理完成\n\n- trace markdown ok" }]
|
|
};
|
|
|
|
const rows = traceDisplayRows(trace, trace.events);
|
|
const text = rows.map((row) => `${row.header}\n${row.body ?? ""}`).join("\n---\n");
|
|
|
|
assert.match(text, /请求接受.*请检查 trace/u);
|
|
assert.match(text, /会话复用/u);
|
|
assert.match(text, /工具调用/u);
|
|
assert.match(text, /hostJobId=job-trace-1/u);
|
|
assert.match(text, /助手最后一条消息,轮次完成/u);
|
|
assert.match(text, /# 处理完成/u);
|
|
assert.equal(rows.some((row) => row.bodyFormat === "markdown"), true);
|
|
});
|
|
|
|
test("trace display rows render completion when no terminal assistant event exists", () => {
|
|
const events = [
|
|
event(1, "request:accepted", { promptSummary: "只跑完成事件" }),
|
|
event(2, "turn:completed", { status: "completed" })
|
|
];
|
|
|
|
const rows = traceDisplayRows({ traceId: "trc_completion", events }, events);
|
|
assert.equal(rows.some((row) => /轮次完成/u.test(row.header)), true);
|
|
});
|
|
|
|
test("trace display rows render assistant item text when stream snapshot is absent", () => {
|
|
const events = [
|
|
event(1, "request:accepted", { promptSummary: "请列出 device-pod" }),
|
|
event(2, "assistant:item_completed", {
|
|
type: "assistant_message",
|
|
status: "completed",
|
|
itemId: "msg_item_0",
|
|
message: "当前有以下 **5 个 device-pod** 可用。"
|
|
}),
|
|
commandEvent(3, "item/commandExecution:completed", {
|
|
itemId: "cmd-trace-2",
|
|
command: "grep -rn device-pod /workspace/hwlab",
|
|
status: "completed",
|
|
exitCode: 0,
|
|
stdoutSummary: "success=true"
|
|
}),
|
|
event(4, "assistant:completed", {
|
|
type: "assistant_message",
|
|
terminal: true,
|
|
status: "completed",
|
|
itemId: "assistant-final",
|
|
message: "可以继续指定要操作的 device-pod。"
|
|
})
|
|
];
|
|
|
|
const rows = traceDisplayRows({ traceId: "trc_assistant_item_text", events }, events);
|
|
const text = rows.map((row) => `${row.header}\n${row.body ?? ""}`).join("\n---\n");
|
|
|
|
assert.match(text, /🤖 助手消息(第一条)/u);
|
|
assert.match(text, /当前有以下 \*\*5 个 device-pod\*\* 可用/u);
|
|
assert.match(text, /工具调用/u);
|
|
assert.match(text, /助手最后一条消息/u);
|
|
assert.match(text, /可以继续指定要操作的 device-pod/u);
|
|
});
|
|
|
|
test("trace display rows suppress low-value AgentRun backend noise", () => {
|
|
const events = [
|
|
event(1, "agentrun:request:accepted", { message: "accepted" }),
|
|
event(2, "agentrun:run:reused"),
|
|
event(3, "agentrun:command:created"),
|
|
event(4, "agentrun:runner-job:reused"),
|
|
event(5, "agentrun:backend:command-created"),
|
|
event(6, "agentrun:backend:thread/status/changed"),
|
|
event(7, "agentrun:backend:thread/tokenUsage/updated"),
|
|
event(8, "agentrun:backend:account/rateLimits/updated"),
|
|
event(9, "agentrun:backend:codex-app-server-starting"),
|
|
event(10, "agentrun:backend:thread/goal/cleared"),
|
|
event(11, "agentrun:backend:item/agentMessage:started"),
|
|
event(12, "agentrun:backend:item/agentMessage:completed"),
|
|
commandEvent(13, "item/commandExecution:completed", {
|
|
itemId: "call_1",
|
|
command: "/bin/sh -lc 'hwpod profile list'",
|
|
status: "completed",
|
|
exitCode: 0,
|
|
durationMs: 708,
|
|
stdoutSummary: '{"ok":true,"action":"profile.list","body":{"devicePods":[{"devicePodId":"D601-F103-V2"}]}}'
|
|
}),
|
|
event(14, "agentrun:output:stdout", {
|
|
type: "output",
|
|
status: "running",
|
|
message: '{"ok":true,"action":"profile.list"}'
|
|
}),
|
|
event(15, "agentrun:assistant:message", {
|
|
type: "assistant",
|
|
status: "completed",
|
|
replyAuthority: true,
|
|
final: true,
|
|
terminal: true,
|
|
message: "当前可见 1 个 device-pod。"
|
|
}),
|
|
event(16, "agentrun:terminal:completed", { type: "result", terminal: true, status: "completed" })
|
|
];
|
|
|
|
const rows = traceDisplayRows({ traceId: "trc_agentrun_noise", events }, events);
|
|
const text = rows.map((row) => `${row.header}\n${row.body ?? ""}`).join("\n---\n");
|
|
|
|
assert.equal(traceNoiseEventCount(events), 12);
|
|
assert.equal(/agentrun:request:accepted/u.test(text), false);
|
|
assert.equal(/agentrun:run:reused/u.test(text), false);
|
|
assert.equal(/runner-job:reused/u.test(text), false);
|
|
assert.equal(/thread\/status\/changed/u.test(text), false);
|
|
assert.equal(/thread\/goal\/cleared/u.test(text), false);
|
|
assert.equal(/item\/agentMessage/u.test(text), false);
|
|
assert.equal(/terminal completed/u.test(text), false);
|
|
assert.equal(/tokenUsage/u.test(text), false);
|
|
assert.match(text, /工具调用/u);
|
|
assert.match(text, /hwpod profile list/u);
|
|
assert.match(text, /profile\.list/u);
|
|
assert.match(text, /助手最后一条消息/u);
|
|
assert.match(text, /当前可见 1 个 device-pod/u);
|
|
});
|
|
|
|
test("trace display rows collapse successful assistant-only AgentRun turns", () => {
|
|
const events = [
|
|
event(1, "agentrun:request:accepted", { message: "accepted" }),
|
|
event(2, "agentrun:run:reused"),
|
|
event(3, "agentrun:command:created"),
|
|
event(4, "agentrun:runner-job:reused"),
|
|
event(5, "agentrun:backend:codex-app-server:reused"),
|
|
event(6, "agentrun:backend:turn/start:completed"),
|
|
event(7, "agentrun:assistant:message", {
|
|
type: "assistant",
|
|
status: "completed",
|
|
terminal: true,
|
|
message: "HWLAB663_FINAL_T2_OK"
|
|
}),
|
|
event(8, "agentrun:terminal:completed", { type: "result", terminal: true, status: "completed" })
|
|
];
|
|
|
|
const rows = traceDisplayRows({ traceId: "trc_agentrun_assistant_only", events }, events);
|
|
assert.equal(rows.length, 1);
|
|
assert.equal(rows[0].tone, "ok");
|
|
assert.match(rows[0].header, /助手最后一条消息/u);
|
|
assert.match(rows[0].body ?? "", /HWLAB663_FINAL_T2_OK/u);
|
|
});
|
|
|
|
test("trace display rows keep AgentRun middle assistant message before final authority", () => {
|
|
const events = [
|
|
event(1, "agentrun:request:accepted", { message: "accepted" }),
|
|
event(2, "agentrun:assistant:message", {
|
|
type: "assistant",
|
|
status: "running",
|
|
itemId: "msg_progress",
|
|
messageIndex: 1,
|
|
messageCount: 2,
|
|
replyAuthority: false,
|
|
final: false,
|
|
message: "我先检查当前 device-pod 列表。"
|
|
}),
|
|
event(3, "agentrun:assistant:message", {
|
|
type: "assistant",
|
|
status: "completed",
|
|
itemId: "msg_final",
|
|
messageIndex: 2,
|
|
messageCount: 2,
|
|
replyAuthority: true,
|
|
final: true,
|
|
terminal: true,
|
|
message: "当前有 2 个 device-pod 可用。"
|
|
}),
|
|
event(4, "agentrun:terminal:completed", { type: "result", terminal: true, status: "completed" })
|
|
];
|
|
|
|
const rows = traceDisplayRows({ traceId: "trc_agentrun_middle_message", events }, events);
|
|
const text = rows.map((row) => `${row.header}\n${row.body ?? ""}`).join("\n---\n");
|
|
|
|
assert.equal(rows.length, 2);
|
|
assert.match(text, /助手消息(第一条)/u);
|
|
assert.match(text, /我先检查当前 device-pod 列表/u);
|
|
assert.match(text, /助手最后一条消息/u);
|
|
assert.match(text, /当前有 2 个 device-pod 可用/u);
|
|
});
|
|
|
|
test("trace display rows collapse AgentRun reused backend lifecycle noise", () => {
|
|
const events = [
|
|
event(1, "agentrun:request:accepted", { message: "accepted" }),
|
|
event(2, "agentrun:run:reused"),
|
|
event(3, "agentrun:command:created"),
|
|
event(4, "agentrun:runner-job:reused"),
|
|
event(5, "agentrun:backend:codex-app-server:reused", { message: "codex-app-server:reused" }),
|
|
event(6, "agentrun:backend:thread/resume:completed"),
|
|
event(7, "agentrun:backend:turn/start:completed"),
|
|
event(8, "agentrun:backend:backend-turn-started", { message: "backend-turn-started", waitingFor: "agentrun-backend" }),
|
|
event(9, "agentrun:backend:backend-turn-running", { message: "backend-turn-running", waitingFor: "agentrun-backend" }),
|
|
event(10, "agentrun:tool:item/started", {
|
|
type: "tool_call",
|
|
status: "running",
|
|
toolName: "userMessage",
|
|
itemId: "user_msg_noise",
|
|
outputBytes: 128,
|
|
message: "tool call"
|
|
}),
|
|
event(11, "agentrun:tool:item/completed", {
|
|
type: "tool_call",
|
|
status: "completed",
|
|
toolName: "userMessage",
|
|
itemId: "user_msg_noise",
|
|
outputBytes: 256,
|
|
message: "tool call"
|
|
}),
|
|
event(12, "agentrun:assistant:message", {
|
|
type: "assistant",
|
|
status: "completed",
|
|
replyAuthority: true,
|
|
final: true,
|
|
terminal: true,
|
|
message: "HWLAB663_REUSE_T2_OK"
|
|
}),
|
|
event(13, "agentrun:backend:backend-turn-finished", { message: "backend-turn-finished", waitingFor: "agentrun-backend" }),
|
|
event(14, "agentrun:terminal:completed", { type: "result", terminal: true, status: "completed" })
|
|
];
|
|
|
|
const rows = traceDisplayRows({ traceId: "trc_agentrun_reused_lifecycle", events }, events);
|
|
const text = rows.map((row) => `${row.header}\n${row.body ?? ""}`).join("\n---\n");
|
|
|
|
assert.equal(rows.length, 1);
|
|
assert.equal(rows[0].tone, "ok");
|
|
assert.equal(/codex-app-server:reused/u.test(text), false);
|
|
assert.equal(/backend-turn-/u.test(text), false);
|
|
assert.equal(/userMessage/u.test(text), false);
|
|
assert.match(rows[0].body ?? "", /HWLAB663_REUSE_T2_OK/u);
|
|
});
|
|
|
|
test("trace display rows render non-noise AgentRun tool item details", () => {
|
|
const events = [
|
|
event(1, "agentrun:request:accepted", { message: "accepted" }),
|
|
event(2, "agentrun:tool:item/started", {
|
|
type: "tool_call",
|
|
status: "running",
|
|
toolName: "devicePod.list",
|
|
itemId: "tool_device_pod_list",
|
|
outputBytes: 128,
|
|
message: "tool call"
|
|
}),
|
|
event(3, "agentrun:tool:item/completed", {
|
|
type: "tool_call",
|
|
status: "completed",
|
|
toolName: "devicePod.list",
|
|
itemId: "tool_device_pod_list",
|
|
outputBytes: 2048,
|
|
message: "tool call"
|
|
}),
|
|
event(4, "agentrun:tool:item/started", {
|
|
type: "tool_call",
|
|
status: "running",
|
|
toolName: "reasoning",
|
|
itemId: "rs_noise",
|
|
outputBytes: 32,
|
|
message: "tool call"
|
|
}),
|
|
event(5, "agentrun:tool:item/completed", {
|
|
type: "tool_call",
|
|
status: "completed",
|
|
toolName: "reasoning",
|
|
itemId: "rs_noise",
|
|
outputBytes: 64,
|
|
message: "tool call"
|
|
}),
|
|
event(6, "agentrun:assistant:message", {
|
|
type: "assistant",
|
|
status: "completed",
|
|
terminal: true,
|
|
message: "当前可见 2 个 device-pod。"
|
|
})
|
|
];
|
|
|
|
const rows = traceDisplayRows({ traceId: "trc_agentrun_tool_item", events }, events);
|
|
const text = rows.map((row) => `${row.header}\n${row.body ?? ""}`).join("\n---\n");
|
|
|
|
assert.equal(rows.length, 2);
|
|
assert.match(text, /工具调用:devicePod\.list/u);
|
|
assert.match(text, /toolName=devicePod\.list/u);
|
|
assert.match(text, /itemId=tool_device_pod_list/u);
|
|
assert.match(text, /outputBytes=2048/u);
|
|
assert.equal(/reasoning/u.test(text), false);
|
|
assert.match(text, /当前可见 2 个 device-pod/u);
|
|
});
|
|
|
|
function traceEvents() {
|
|
return [
|
|
event(1, "request:accepted", { promptSummary: "请检查 trace" }),
|
|
event(2, "session:reused"),
|
|
commandEvent(3, "item/commandExecution:started", {
|
|
itemId: "cmd-trace-1",
|
|
command: "bash -lc 'build start'"
|
|
}),
|
|
{
|
|
...event(4, "item/commandExecution/outputDelta", {
|
|
type: "tool_call",
|
|
status: "output_chunk",
|
|
itemId: "cmd-trace-1",
|
|
outputSummary: '{"hostJobId":"job-trace-1","success":true}'
|
|
})
|
|
},
|
|
commandEvent(5, "item/commandExecution:completed", {
|
|
itemId: "cmd-trace-1",
|
|
command: "bash -lc 'build status'",
|
|
status: "completed",
|
|
exitCode: 0,
|
|
durationMs: 1200
|
|
}),
|
|
event(6, "assistant:completed", {
|
|
type: "assistant_message",
|
|
terminal: true,
|
|
status: "completed",
|
|
itemId: "assistant-final"
|
|
})
|
|
];
|
|
}
|
|
|
|
function commandEvent(seq, label, fields) {
|
|
return event(seq, label, {
|
|
type: "tool_call",
|
|
toolName: "commandExecution",
|
|
...fields
|
|
});
|
|
}
|
|
|
|
function event(seq, label, fields = {}) {
|
|
return {
|
|
traceId: "trc_trace_contract",
|
|
seq,
|
|
label,
|
|
type: fields.type ?? "event",
|
|
status: fields.status ?? "observed",
|
|
createdAt: new Date(1779690000000 + seq * 1000).toISOString(),
|
|
...fields
|
|
};
|
|
}
|