fix(web-probe): recover compact analyze turn details (#776)

* fix(web-probe): keep rounds in compact analyze output

* fix(web-probe): recover compact analyze turn details

---------

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-24 04:09:58 +08:00
committed by GitHub
parent 05495577f7
commit bd5acfae06
+43 -1
View File
@@ -8831,7 +8831,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
"exit \"$analyzer_exit\"",
].join("\n");
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, options.commandTimeoutSeconds);
const analysis = parseJsonObject(result.stdout);
const analysis = recoverWebObserveAnalyzeTurnDetails(options, spec, parseJsonObject(result.stdout));
const analysisOk = result.exitCode === 0 && analysis?.ok === true;
const analysisFailure = analysisOk
? null
@@ -8864,6 +8864,48 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
});
}
function recoverWebObserveAnalyzeTurnDetails(options: NodeWebProbeObserveOptions, spec: HwlabRuntimeLaneSpec, analysis: Record<string, unknown>): Record<string, unknown> {
const sampleMetrics = record(analysis.sampleMetrics);
const hasRounds = Array.isArray(sampleMetrics?.rounds) && sampleMetrics.rounds.length > 0;
const hasColumns = Array.isArray(sampleMetrics?.turnColumns) && sampleMetrics.turnColumns.length > 0;
if (hasRounds && hasColumns) return analysis;
const reportJsonPath = typeof analysis.reportJsonPath === "string" ? analysis.reportJsonPath : "";
if (!reportJsonPath) return analysis;
const archiveMetrics = record(record(analysis.archiveSummary)?.sampleMetrics);
const archiveHasTurnEvidence = Number(archiveMetrics?.rounds ?? 0) > 0 || Number(archiveMetrics?.turnColumns ?? 0) > 0 || Number(archiveMetrics?.turnTimingRows ?? 0) > 0;
if (!archiveHasTurnEvidence) return analysis;
const recoverScript = [
"set -eu",
`report_json=${shellQuote(reportJsonPath)}`,
"node - \"$report_json\" <<'UNIDESK_WEB_OBSERVE_RECOVER_TURN_DETAILS'",
"const fs = require('fs');",
"const reportJsonPath = process.argv[2];",
"const readJson = (path) => { try { return JSON.parse(fs.readFileSync(path, 'utf8')); } catch { return null; } };",
"const report = readJson(reportJsonPath) || {};",
"const stdoutJson = readJson(String(reportJsonPath).replace(/\\/analysis\\/report\\.json$/u, '/analysis/analyzer-stdout.json')) || {};",
"const objectOrNull = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : null;",
"const firstNonEmptyArray = (...values) => { for (const value of values) if (Array.isArray(value) && value.length > 0) return value; return []; };",
"const clip = (value, limit = 160) => value === null || value === undefined ? null : String(value).slice(0, limit);",
"const slimRound = (item) => { const v = objectOrNull(item) || {}; return { promptIndex: v.promptIndex ?? null, sampleCount: v.sampleCount ?? null, loadingSamples: v.loadingSamples ?? null, maxLoadingCount: v.maxLoadingCount ?? null, loadingOwnerCount: v.loadingOwnerCount ?? null, lastTotalElapsedSeconds: v.lastTotalElapsedSeconds ?? null, lastRecentUpdateSeconds: v.lastRecentUpdateSeconds ?? null, diagnosticSamples: v.diagnosticSamples ?? null, terminalSamples: v.terminalSamples ?? null, turnTimingTotalElapsedForwardJumpCount: v.turnTimingTotalElapsedForwardJumpCount ?? null, turnTimingTotalElapsedForwardJumpMaxSeconds: v.turnTimingTotalElapsedForwardJumpMaxSeconds ?? null, promptTextHash: clip(v.promptTextHash, 80) }; };",
"const slimTurnColumn = (item) => { const v = objectOrNull(item) || {}; return { label: clip(v.label, 24), promptIndex: v.promptIndex ?? null, lastPromptIndex: v.lastPromptIndex ?? null, traceId: clip(v.traceId, 48), firstSeq: v.firstSeq ?? null, lastSeq: v.lastSeq ?? null, source: clip(v.source, 48) }; };",
"const rounds = firstNonEmptyArray(stdoutJson.sampleMetrics?.rounds, stdoutJson.sampleMetrics?.roundItems, report.windows?.recent?.sampleMetrics?.rounds, report.sampleMetrics?.rounds).slice(-8).map(slimRound);",
"const turnColumns = firstNonEmptyArray(stdoutJson.sampleMetrics?.turnColumns, report.windows?.recent?.sampleMetrics?.turnColumns, report.sampleMetrics?.turnColumns).slice(-12).map(slimTurnColumn);",
"console.log(JSON.stringify({ ok: true, rounds, turnColumns }));",
"UNIDESK_WEB_OBSERVE_RECOVER_TURN_DETAILS",
].join("\n");
const recovered = parseJsonObject(runTransWorkspaceStdinScript(options.node, spec.workspace, recoverScript, Math.min(options.commandTimeoutSeconds, 30)).stdout);
const recoveredRounds = Array.isArray(recovered.rounds) ? recovered.rounds : [];
const recoveredColumns = Array.isArray(recovered.turnColumns) ? recovered.turnColumns : [];
if (recoveredRounds.length === 0 && recoveredColumns.length === 0) return analysis;
const nextMetrics = { ...(sampleMetrics ?? {}) };
if (!hasRounds && recoveredRounds.length > 0) {
nextMetrics.roundItems = recoveredRounds;
nextMetrics.rounds = recoveredRounds;
}
if (!hasColumns && recoveredColumns.length > 0) nextMetrics.turnColumns = recoveredColumns;
return { ...analysis, sampleMetrics: nextMetrics, recoveredTurnDetails: { rounds: recoveredRounds.length, turnColumns: recoveredColumns.length, source: "analysis-report", valuesRedacted: true } };
}
function withWebObserveAnalyzeRendered(value: Record<string, unknown>): RenderedCliResult {
return {
ok: value.ok !== false,