fix: 精简工具调用摘要状态展示
This commit is contained in:
@@ -779,8 +779,8 @@ test("case aggregate writes one registry markdown entry without grading or broad
|
||||
renderedRowCount: 4,
|
||||
rows: [
|
||||
{ rowId: "row-1", seq: 1, header: "请求接受", body: "CaseRun started" },
|
||||
{ rowId: "row-2", seq: 2, header: "ok commandExecution", body: "hwpod build --spec .hwlab/hwpod-spec.yaml\nexitCode=0" },
|
||||
{ rowId: "row-3", seq: 3, header: "ok commandExecution", body: `${longTraceCommand} stdout: first line\nsecond line exitCode=0` },
|
||||
{ rowId: "tool:hwpod-build", seq: 2, tone: "ok", header: "00:00:02 hwpod duration=00:00:01 exit=0", body: "hwpod build --spec .hwlab/hwpod-spec.yaml\nexitCode=0" },
|
||||
{ rowId: "tool:hwpod-cat", seq: 3, tone: "ok", header: "00:00:03 hwpod duration=00:00:01 exit=0", body: `${longTraceCommand} stdout: first line\nsecond line exitCode=0` },
|
||||
{ rowId: "row-4", seq: 4, header: "助手最终消息", terminal: true, bodyFormat: "markdown", body: "Build completed" }
|
||||
]
|
||||
});
|
||||
@@ -834,12 +834,12 @@ test("case aggregate writes one registry markdown entry without grading or broad
|
||||
assert.match(aggregate, /## 低噪声 Trace/u);
|
||||
assert.doesNotMatch(aggregate, /• 2\. ok commandExecution/u);
|
||||
assert.match(aggregate, /\*\*CaseRun started\*\*/u);
|
||||
assert.match(aggregate, /- <details>\n <summary>已运行 hwpod build --spec \.hwlab\/hwpod-spec\.yaml<\/summary>/u);
|
||||
assert.match(aggregate, /- <details>\n <summary aria-label="工具调用成功:[^"]+" title="工具调用成功:[^"]+"><code>00:00:02 hwpod duration=00:00:01 exit=0<\/code> hwpod build --spec \.hwlab\/hwpod-spec\.yaml<\/summary>/u);
|
||||
assert.match(aggregate, / ```text\n hwpod build --spec \.hwlab\/hwpod-spec\.yaml\n exitCode=0[\s\S]* <\/details>/u);
|
||||
assert.match(aggregate, /<summary>已运行 hwpod workspace cat projects\/01_baseline\/Middlewares\/Arm-2D\/Library\/include\/arm_2d_type\.\.\.<\/summary>/u);
|
||||
assert.match(aggregate, /<summary aria-label="工具调用成功:[^"]+" title="工具调用成功:[^"]+"><code>00:00:03 hwpod duration=00:00:01 exit=0<\/code> hwpod workspace cat projects\/01_baseline\/Middlewares\/Arm-2D\/Library\/include\/arm_2d_type/u);
|
||||
assert.match(aggregate, / ```text\n hwpod workspace cat [^\n]+\n stdout:\n first line\n second line\n exitCode=0[\s\S]* <\/details>\n\n\*\*Build completed\*\*\n\n## Final Response/u);
|
||||
for (const [, summary] of aggregate.matchAll(/<summary>([\s\S]*?)<\/summary>/gu)) assert.doesNotMatch(summary, /\n|stdout:|stderr:|exitCode=|grep -A 20/u);
|
||||
assert.doesNotMatch(aggregate, /<summary>.*助手最终消息/u);
|
||||
for (const [, summary] of aggregate.matchAll(/<summary[^>]*>([\s\S]*?)<\/summary>/gu)) assert.doesNotMatch(summary, /\n|stdout:|stderr:|exitCode=|grep -A 20/u);
|
||||
assert.doesNotMatch(aggregate, /<summary[^>]*>.*助手最终消息/u);
|
||||
assert.match(aggregate, /## Final Response/u);
|
||||
assert.match(aggregate, /## 最后 Diff/u);
|
||||
assert.match(aggregate, /Implement ARM-2D integration/u);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { test } from "bun:test";
|
||||
|
||||
import { queryKafkaEventStream } from "../../internal/cloud/kafka-event-bridge.ts";
|
||||
import { mapAgentRunRecordsToHwlabDebugEvents, renderKafkaCliText, runKafkaCli } from "../src/hwlab-cli/kafka-regenerate.ts";
|
||||
import { traceDisplayRows } from "../src/hwlab-cli/trace-renderer.ts";
|
||||
import { renderTraceRowsMarkdown, traceDisplayRows, traceToolSummary } from "../src/hwlab-cli/trace-renderer.ts";
|
||||
|
||||
const SESSION_ID = "ses_agentrun_5ec4e141_6abc_466d_9afe_049f7c0ac105";
|
||||
const HWLAB_SESSION_ID = "ses_5ec4e141-6abc-466d-9afe-049f7c0ac105";
|
||||
@@ -86,7 +86,10 @@ test("offline HWLAB JSONL uses the shared Web pipeline and renders final respons
|
||||
assert.equal(result.payload.validation.allMatchedEventsApplied, true);
|
||||
assert.equal(result.payload.validation.finalResponseOutsideTrace, true);
|
||||
const toolRow = result.payload.render.rows.find((row: any) => row.rowId.startsWith("tool:"));
|
||||
assert.match(toolRow.header, /ok rg duration=00:00:01 exit=0/u);
|
||||
assert.match(toolRow.header, /^\d{2}:\d{2}:\d{2} rg duration=00:00:01 exit=0$/u);
|
||||
assert.doesNotMatch(toolRow.header, /\b(?:ok|fail|run|running)\b|total=/u);
|
||||
assert.equal(toolRow.toolState, "success");
|
||||
assert.equal(toolRow.statusLabel, "工具调用成功");
|
||||
assert.match(toolRow.preview, /rg -n target src/u);
|
||||
assert.match(toolRow.preview, /src\/main\.ts:42:target/u);
|
||||
const markdown = await readFile(outputFile, "utf8");
|
||||
@@ -96,6 +99,8 @@ test("offline HWLAB JSONL uses the shared Web pipeline and renders final respons
|
||||
assert.match(markdown, /target trace: trc_render_trace_target/u);
|
||||
assert.match(markdown, /## 运行记录/u);
|
||||
assert.match(markdown, /## 最终回复/u);
|
||||
assert.match(markdown, /<summary aria-label="工具调用成功:[^"]+" title="工具调用成功:[^"]+"><code>\d{2}:\d{2}:\d{2} rg duration=00:00:01 exit=0<\/code> [\s\S]*rg -n target src[\s\S]*src\/main\.ts:42:target<\/summary>/u);
|
||||
assert.doesNotMatch(markdown, /total=|总耗时/u);
|
||||
assert.equal(result.markdownOutput?.trim(), markdown.trim());
|
||||
});
|
||||
|
||||
@@ -162,6 +167,78 @@ test("shared row model removes late assistant progress after the same item compl
|
||||
assert.equal((result.markdownOutput?.match(new RegExp(duplicateText.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"), "gu")) ?? []).length, 1);
|
||||
});
|
||||
|
||||
test("shared tool summary model keeps status semantic and visible content status-free", () => {
|
||||
const rows = traceDisplayRows({ eventSource: "hwlab-kafka-sse" }, [
|
||||
{
|
||||
sourceSeq: 1,
|
||||
sourceEventId: "evt_tool_running",
|
||||
type: "tool_call",
|
||||
status: "running",
|
||||
label: "agentrun:tool:commandExecution:started",
|
||||
toolName: "commandExecution",
|
||||
itemId: "tool_running",
|
||||
command: "bun test active-fixture",
|
||||
createdAt: "2026-07-10T11:00:01.000Z"
|
||||
},
|
||||
{
|
||||
sourceSeq: 2,
|
||||
sourceEventId: "evt_tool_success",
|
||||
type: "tool_call",
|
||||
status: "completed",
|
||||
label: "agentrun:tool:commandExecution:completed",
|
||||
toolName: "commandExecution",
|
||||
itemId: "tool_success",
|
||||
command: "rg -n success src",
|
||||
durationMs: 1234,
|
||||
exitCode: 0,
|
||||
stdoutSummary: "src/main.ts:1:success",
|
||||
createdAt: "2026-07-10T11:00:02.000Z"
|
||||
},
|
||||
{
|
||||
sourceSeq: 3,
|
||||
sourceEventId: "evt_tool_failure",
|
||||
type: "tool_call",
|
||||
status: "completed",
|
||||
label: "agentrun:tool:commandExecution:completed",
|
||||
toolName: "commandExecution",
|
||||
itemId: "tool_failure",
|
||||
command: "bun test failure-fixture",
|
||||
durationMs: 2345,
|
||||
exitCode: 1,
|
||||
stderrSummary: "failure output",
|
||||
createdAt: "2026-07-10T11:00:03.000Z"
|
||||
},
|
||||
{
|
||||
sourceSeq: 4,
|
||||
sourceEventId: "evt_tool_output_chunk",
|
||||
type: "tool_call",
|
||||
status: "output_chunk",
|
||||
label: "item/commandExecution/outputDelta",
|
||||
outputSummary: "streamed output",
|
||||
createdAt: "2026-07-10T11:00:04.000Z"
|
||||
}
|
||||
]).filter((row) => row.rowId.startsWith("tool:"));
|
||||
|
||||
assert.deepEqual(rows.map((row) => row.toolState), ["running", "success", "failure", "running"]);
|
||||
assert.deepEqual(rows.map((row) => row.tone), ["warn", "ok", "blocked", "warn"]);
|
||||
assert.deepEqual(rows.map((row) => row.statusLabel), ["工具调用中", "工具调用成功", "工具调用失败", "工具调用中"]);
|
||||
assert.ok(rows.every((row) => !/\b(?:ok|fail|run|running)\b|total=/u.test(row.header)));
|
||||
assert.match(rows[1]!.header, /rg duration=00:00:01 exit=0$/u);
|
||||
assert.match(rows[2]!.header, /bun duration=00:00:02 exit=1$/u);
|
||||
assert.doesNotMatch(rows[3]!.header, /commandExecution|outputDelta/u);
|
||||
|
||||
const markdown = renderTraceRowsMarkdown(rows);
|
||||
const visibleSummaries = [...markdown.matchAll(/<summary[^>]*>([\s\S]*?)<\/summary>/gu)].map((match) => match[1]);
|
||||
assert.equal(visibleSummaries.length, 4);
|
||||
for (const [index, summary] of visibleSummaries.entries()) {
|
||||
assert.equal(summary, `<code>${rows[index]!.header}</code> ${traceToolSummary(rows[index]!)}`);
|
||||
assert.doesNotMatch(summary, /\b(?:ok|fail|run|running)\b|total=/u);
|
||||
}
|
||||
assert.match(markdown, /aria-label="工具调用中:/u);
|
||||
assert.match(markdown, /aria-label="工具调用成功:/u);
|
||||
assert.match(markdown, /aria-label="工具调用失败:/u);
|
||||
});
|
||||
|
||||
test("outer final response stays out of the Trace fallback when no completion event exists", () => {
|
||||
const finalText = "Hi. What do you want to work on?";
|
||||
const rows = traceDisplayRows({ eventSource: "hwlab-kafka-sse" }, [
|
||||
|
||||
Reference in New Issue
Block a user