fix: refresh full trace aggregates in caserun

This commit is contained in:
Codex Agent
2026-06-08 13:14:53 +08:00
parent 19161b5f82
commit 435ce50f11
2 changed files with 67 additions and 3 deletions
@@ -24,6 +24,7 @@ rmSync(checkoutDir, { recursive: true, force: true });
run("git", ["clone", "--no-checkout", "--single-branch", "--branch", bootRef, readUrl, checkoutDir], "/");
run("git", ["checkout", "--detach", bootCommit], checkoutDir);
linkNodeModules();
ensureRuntimeDependencies();
installHwpodAliases();
const scriptPath = path.join(checkoutDir, bootSh);
@@ -49,6 +50,30 @@ function linkNodeModules(): void {
symlinkSync(runtimeNodeModules, target, "dir");
}
function ensureRuntimeDependencies(): void {
const packageJson = path.join(checkoutDir, "package.json");
if (!existsSync(packageJson)) return;
if (canResolvePackage("yaml")) {
process.stdout.write(`${JSON.stringify({ event: "hwlab-env-reuse-dependencies", status: "cached", package: "yaml" })}\n`);
return;
}
const npmCommand = process.env.HWLAB_NPM_COMMAND || "npm";
process.stdout.write(`${JSON.stringify({ event: "hwlab-env-reuse-dependencies", status: "installing", package: "yaml", manager: npmCommand })}\n`);
run(npmCommand, ["install", "--omit=dev", "--include=optional", "--ignore-scripts", "--prefer-offline"], checkoutDir);
if (!canResolvePackage("yaml")) fail("runtime dependency install completed but package yaml is still unavailable");
process.stdout.write(`${JSON.stringify({ event: "hwlab-env-reuse-dependencies", status: "installed", package: "yaml", manager: npmCommand })}\n`);
}
function canResolvePackage(packageName: string): boolean {
const result = spawnSync(process.execPath, ["-e", `require.resolve(${JSON.stringify(packageName)})`], {
cwd: checkoutDir,
env: process.env,
stdio: "ignore"
});
return !result.error && !result.signal && result.status === 0;
}
function installHwpodAliases(): void {
installHwpodAlias("hwpod", "tools/hwpod-cli.ts");
installHwpodAlias("hwpod-ctl", "tools/hwpod-ctl.ts");
+42 -3
View File
@@ -1799,7 +1799,7 @@ async function writeCaseAggregateFromRegistry(context: CaseContext, caseRepo: st
if (!evidence && !run && !manifest) throw cliError("case_registry_run_not_found", "case registry run artifacts were not found", { caseRepoRunDir, caseId, runId });
const outputRel = aggregateOutputRel(context);
const outputPath = path.join(caseRepoRunDir, outputRel);
const markdown = await renderCaseAggregateMarkdown({ caseRepoRunDir, caseId, runId, evidence, run, manifest });
const markdown = await renderCaseAggregateMarkdown(context, { caseRepoRunDir, caseId, runId, evidence, run, manifest });
await mkdir(path.dirname(outputPath), { recursive: true });
await writeFile(outputPath, markdown, "utf8");
const file = await registryAggregateFileRecord(outputPath);
@@ -1829,16 +1829,16 @@ function aggregateOutputRel(context: CaseContext) {
return rel;
}
async function renderCaseAggregateMarkdown(input: { caseRepoRunDir: string; caseId: string; runId: string; evidence: any; run: any; manifest: any }) {
async function renderCaseAggregateMarkdown(context: CaseContext, input: { caseRepoRunDir: string; caseId: string; runId: string; evidence: any; run: any; manifest: any }) {
const prompt = await readTextIfExists(path.join(input.caseRepoRunDir, "agent-prompt.md"));
const finalResponse = await readTextIfExists(path.join(input.caseRepoRunDir, "final-response.md"));
const diffPatch = await readTextIfExists(path.join(input.caseRepoRunDir, "agent-diff.patch"));
const traceMarkdown = await readTextIfExists(path.join(input.caseRepoRunDir, "agent-trace.md"));
const specText = await readTextIfExists(path.join(input.caseRepoRunDir, ".hwlab", "hwpod-spec.yaml"));
const messages = await readJsonIfExists(path.join(input.caseRepoRunDir, "agent-messages.json"));
const evidence = input.evidence ?? {};
const run = input.run ?? {};
const manifest = input.manifest ?? {};
const archivedMessages = await readJsonIfExists(path.join(input.caseRepoRunDir, "agent-messages.json"));
const traceLookup = manifest.traceLookup ?? evidence.traceLookup ?? run.agent?.traceLookup;
const commands = traceLookup?.commands ?? {};
const agent = manifest.agent ?? manifest.trace ?? evidence.agent ?? run.agent ?? {};
@@ -1847,6 +1847,7 @@ async function renderCaseAggregateMarkdown(input: { caseRepoRunDir: string; case
const diff = manifest.diff ?? evidence.agentDiff ?? run.agentDiff ?? {};
const keilJob = manifest.keilJob ?? evidence.keilJob ?? null;
const agentStage = manifest.agentStage ?? agentStageSummary(evidence);
const messages = await aggregateMessagesWithFreshFullTrace(context, { archivedMessages, traceLookup, traceId: agent.traceId ?? trace.traceId ?? traceLookup?.traceId, run, evidence, manifest });
const traceBody = aggregateTraceBody(messages, traceMarkdown);
return `${[
`# HWPOD CaseRun Aggregate: ${input.caseId}`,
@@ -1952,6 +1953,44 @@ function aggregateTraceBody(messages: any, traceMarkdown: string) {
return `_No readable trace artifact was found._`;
}
async function aggregateMessagesWithFreshFullTrace(context: CaseContext, input: { archivedMessages: any; traceLookup: any; traceId: unknown; run: any; evidence: any; manifest: any }) {
const archivedMessages = input.archivedMessages;
const traceId = text(input.traceId ?? input.traceLookup?.traceId ?? input.run?.agent?.traceId ?? input.evidence?.agent?.traceId ?? input.manifest?.agent?.traceId);
const baseUrl = text(input.traceLookup?.baseUrl ?? input.run?.agent?.baseUrl ?? input.evidence?.agent?.baseUrl);
const apiKey = text(context.env.HWLAB_API_KEY ?? process.env.HWLAB_API_KEY);
if (!traceId || !baseUrl || !apiKey.startsWith(HWLAB_API_KEY_PREFIX)) return archivedMessages;
const command = [process.execPath, path.join(context.cwd, "tools/hwlab-cli/bin/hwlab-cli.mjs"), "client", "agent", "trace", traceId, "--render", "web", "--full"];
const result = await (context.runProcess ?? runProcess)(command, context.cwd, { ...process.env, ...context.env, HWLAB_RUNTIME_WEB_URL: baseUrl });
if (result.exitCode !== 0) return archivedMessages;
const parsed = parseJsonMaybe(result.stdout);
const rendered = freshRenderedTraceBody(parsed);
const rows = arrayOfObjects(rendered?.rows);
if (rows.length === 0) return archivedMessages;
return clean({
...(archivedMessages && typeof archivedMessages === "object" ? archivedMessages : {}),
renderer: rendered.renderer ?? archivedMessages?.renderer ?? CASE_TRACE_RENDERER,
traceSource: rendered.source ?? archivedMessages?.traceSource,
traceLookup: archivedMessages?.traceLookup ?? input.traceLookup,
traceId: rendered.traceId ?? traceId,
status: rendered.traceStatus ?? rendered.status ?? archivedMessages?.status,
sourceEventCount: rendered.sourceEventCount ?? archivedMessages?.sourceEventCount,
renderedRowCount: rendered.renderedRowCount ?? rows.length,
returnedRowCount: rendered.returnedRowCount ?? rows.length,
noiseEventCount: rendered.noiseEventCount ?? archivedMessages?.noiseEventCount,
finalResponse: rendered.finalResponse ?? archivedMessages?.finalResponse,
rows
});
}
function freshRenderedTraceBody(parsed: any) {
if (!parsed || typeof parsed !== "object") return null;
const body = parsed.body && typeof parsed.body === "object" ? parsed.body : null;
if (Array.isArray(body?.rows)) return body;
const data = parsed.data && typeof parsed.data === "object" ? parsed.data : null;
if (Array.isArray(data?.rows)) return data;
return Array.isArray(parsed.rows) ? parsed : null;
}
function traceEventRowFromAggregate(row: Record<string, unknown>): TraceEventRow {
const bodyFormat = text(row.bodyFormat);
return {