Merge pull request #455 from pikasTech/fix/hwlab-450-trace-preview
修复 Code Agent trace 预览计数展示
This commit is contained in:
@@ -618,6 +618,11 @@ function runStaticSmoke() {
|
||||
evidence: ["DEFAULT_API_TIMEOUT_MS=4500 for light probes", `DEFAULT_CODE_AGENT_TIMEOUT_MS=${codeAgentLongTimeoutMs}`, "sendAgentMessage passes timeoutMs"]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "code-agent-trace-replay-disclosure", hasCodeAgentTraceReplayDisclosure(files), "Trace replay panels disclose tail preview counts and provide full UI/JSON/download access for long traces.", {
|
||||
blocker: "observability_blocker",
|
||||
evidence: ["显示最近 14 / 总计 N", "展开全部", "复制 JSON", "下载 trace", "internal scroll for full trace"]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "code-agent-provider-readiness-visibility", hasCodeAgentReadinessVisibility(files), "Workbench shows provider/stdio blockers without exposing credential internals and only long-lived Codex stdio replies can become full Code Agent completion.", {
|
||||
blocker: "observability_blocker",
|
||||
evidence: ["服务受阻 or legacy BLOCKED 凭证缺口", "provider_unavailable classifier", "completed -> dev-live guard", "default workspace hides credential internals"]
|
||||
@@ -2618,6 +2623,28 @@ function hasCodeAgentLongTimeoutContract(files) {
|
||||
);
|
||||
}
|
||||
|
||||
function hasCodeAgentTraceReplayDisclosure({ app, styles }) {
|
||||
const tracePanelBody = functionBody(app, "messageTracePanel");
|
||||
const traceToolbarBody = functionBody(app, "messageTraceToolbar");
|
||||
return (
|
||||
/CODE_AGENT_TRACE_PREVIEW_LIMIT\s*=\s*14/u.test(app) &&
|
||||
/function\s+messageTraceCountText\s*\(/u.test(app) &&
|
||||
/显示最近\s+\$\{CODE_AGENT_TRACE_PREVIEW_LIMIT\}\s+\/\s+总计\s+\$\{total\}/u.test(app) &&
|
||||
/function\s+renderTraceEventList\s*\(/u.test(app) &&
|
||||
/tracePreviewEvents\(events\)/u.test(tracePanelBody) &&
|
||||
/messageTraceToolbar\(message,\s*trace,\s*events,\s*list\)/u.test(tracePanelBody) &&
|
||||
/展开全部/u.test(traceToolbarBody) &&
|
||||
/复制 JSON/u.test(traceToolbarBody) &&
|
||||
/下载 trace/u.test(traceToolbarBody) &&
|
||||
/function\s+messageTraceJson\s*\(/u.test(app) &&
|
||||
/function\s+downloadTraceJson\s*\(/u.test(app) &&
|
||||
/\.message-trace-toolbar\s*\{/u.test(styles) &&
|
||||
/\.message-trace-count\s*\{/u.test(styles) &&
|
||||
/\.message-trace-action\s*\{/u.test(styles) &&
|
||||
/\.message-trace-events-full\s*\{[\s\S]*?max-height:\s*min\(360px,\s*42vh\)[\s\S]*?overflow:\s*auto/u.test(styles)
|
||||
);
|
||||
}
|
||||
|
||||
function hasCodeAgentStatusSummaryContract({ html, app, styles, codeAgentStatus }) {
|
||||
return (
|
||||
/id=["']code-agent-summary["']/u.test(html) &&
|
||||
@@ -4289,6 +4316,23 @@ async function inspectJourneyUi(page) {
|
||||
const runningActions = summarizeActions("status-running");
|
||||
const failedActions = summarizeActions("status-failed");
|
||||
const timeoutActions = summarizeActions("status-timeout");
|
||||
const tracePanels = [...document.querySelectorAll(".message-card.message-agent .message-trace")];
|
||||
const tracePanelMetrics = tracePanels.map((panel) => {
|
||||
const countText = panel.querySelector(".message-trace-count")?.textContent?.replace(/\s+/gu, " ").trim() ?? "";
|
||||
const actions = [...panel.querySelectorAll(".message-trace-action")].map((button) => button.textContent?.replace(/\s+/gu, " ").trim() ?? "");
|
||||
const events = [...panel.querySelectorAll(".message-trace-events li")].map((item) => item.textContent?.replace(/\s+/gu, " ").trim() ?? "");
|
||||
return {
|
||||
countText,
|
||||
actions,
|
||||
eventCount: events.length,
|
||||
traceMode: panel.querySelector(".message-trace-events")?.dataset.traceMode ?? "",
|
||||
tailPreviewVisible: /显示最近\s+14\s*\/\s*总计\s+(?:1[5-9]|[2-9]\d+)/u.test(countText),
|
||||
fullEntryVisible: actions.includes("展开全部"),
|
||||
copyJsonVisible: actions.includes("复制 JSON"),
|
||||
downloadTraceVisible: actions.includes("下载 trace"),
|
||||
cappedTailCount: events.length <= 14
|
||||
};
|
||||
});
|
||||
return {
|
||||
title: document.title,
|
||||
workspaceHidden: document.querySelector('[data-view="workspace"]')?.hidden ?? null,
|
||||
@@ -4331,16 +4375,24 @@ async function inspectJourneyUi(page) {
|
||||
[...document.querySelectorAll(".message-card.status-source .message-meta")]
|
||||
.some((element) => /SOURCE|source-fixture|trc_/u.test(element.textContent ?? ""))
|
||||
),
|
||||
traceText: [...document.querySelectorAll(".message-card.message-agent .message-trace")]
|
||||
traceText: tracePanels
|
||||
.map((element) => element.textContent ?? "")
|
||||
.join("\n"),
|
||||
traceHasTraceId: [...document.querySelectorAll(".message-card.message-agent .message-trace")]
|
||||
traceHasTraceId: tracePanels
|
||||
.some((element) => /trc_/u.test(element.textContent ?? "")),
|
||||
traceShowsEvents: [...document.querySelectorAll(".message-card.message-agent .message-trace-events li")]
|
||||
.some((element) => /#\d+|session|prompt|tool|assistant|timeout|blocked/u.test(element.textContent ?? "")),
|
||||
tracePanelMetrics,
|
||||
traceLongPreviewDisclosureVisible: tracePanelMetrics.some((metric) => metric.tailPreviewVisible),
|
||||
traceFullViewEntryVisible: tracePanelMetrics.some((metric) => metric.fullEntryVisible),
|
||||
traceCopyJsonVisible: tracePanelMetrics.some((metric) => metric.copyJsonVisible),
|
||||
traceDownloadVisible: tracePanelMetrics.some((metric) => metric.downloadTraceVisible),
|
||||
tracePreviewTailCapped: tracePanelMetrics
|
||||
.filter((metric) => metric.tailPreviewVisible)
|
||||
.every((metric) => metric.cappedTailCount && metric.traceMode === "tail"),
|
||||
noMainAttributionNoise: document.querySelectorAll(".message-card.message-agent .message-attribution, .message-card.message-agent .message-evidence, .message-card.message-agent .code-agent-facts").length === 0,
|
||||
attributionFallbackNotRunnerControl: !/openai-responses-fallback[\s\S]{0,80}(真实 runner|Codex stdio 长会话|workspace-write)/u.test(
|
||||
[...document.querySelectorAll(".message-card.message-agent .message-trace")]
|
||||
tracePanels
|
||||
.map((element) => element.textContent ?? "")
|
||||
.join("\n")
|
||||
),
|
||||
@@ -4831,6 +4883,11 @@ async function runLocalAgentFixtureSmoke({
|
||||
ui.sourceMessageHasNonSensitiveMeta &&
|
||||
ui.traceHasTraceId &&
|
||||
ui.traceShowsEvents &&
|
||||
ui.traceLongPreviewDisclosureVisible &&
|
||||
ui.tracePreviewTailCapped &&
|
||||
ui.traceFullViewEntryVisible &&
|
||||
ui.traceCopyJsonVisible &&
|
||||
ui.traceDownloadVisible &&
|
||||
ui.noMainAttributionNoise &&
|
||||
ui.attributionFallbackNotRunnerControl &&
|
||||
ui.conversationFactsVisible &&
|
||||
@@ -5547,6 +5604,44 @@ async function inspectQuickPromptGeometry(page, viewport) {
|
||||
}, viewport);
|
||||
}
|
||||
|
||||
function longSourceFixtureTraceEvents(traceId, count = 18) {
|
||||
const labels = [
|
||||
"source-fixture:session",
|
||||
"prompt:queued",
|
||||
"prompt:sent",
|
||||
"context:loaded",
|
||||
"session:reused",
|
||||
"assistant:started",
|
||||
"tool:skills.inspect",
|
||||
"tool:skills.inspect:completed",
|
||||
"tool:workspace.read",
|
||||
"tool:workspace.read:completed",
|
||||
"assistant:delta",
|
||||
"assistant:delta",
|
||||
"assistant:delta",
|
||||
"assistant:delta",
|
||||
"assistant:finalizing",
|
||||
"message:stored",
|
||||
"conversation:facts-updated",
|
||||
"assistant:completed"
|
||||
];
|
||||
return Array.from({ length: count }, (_, index) => {
|
||||
const seq = index + 1;
|
||||
const label = labels[index] ?? `assistant:event:${seq}`;
|
||||
const toolName = label.startsWith("tool:") ? label.split(":").slice(1).join(":") : undefined;
|
||||
return {
|
||||
seq,
|
||||
traceId,
|
||||
type: label.split(":")[0] || "event",
|
||||
stage: label.split(":")[1] || "observed",
|
||||
status: seq === count ? "completed" : "observed",
|
||||
label,
|
||||
...(toolName ? { toolName } : {}),
|
||||
elapsedMs: seq * 37
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function startStaticWebServer(options = {}) {
|
||||
const rootDir = path.resolve(options.rootDir ?? webRoot);
|
||||
const authFixtureSessions = new Set();
|
||||
@@ -6609,6 +6704,7 @@ async function handleLocalAgentFixtureApi({ request, response, url, options = {}
|
||||
items: [],
|
||||
blockers: []
|
||||
};
|
||||
const fixtureTraceEvents = longSourceFixtureTraceEvents(traceId);
|
||||
jsonResponse(response, 200, {
|
||||
conversationId,
|
||||
sessionId: conversationId,
|
||||
@@ -6637,11 +6733,8 @@ async function handleLocalAgentFixtureApi({ request, response, url, options = {}
|
||||
runnerTrace: {
|
||||
traceId,
|
||||
runnerKind: "openai-responses-fallback",
|
||||
events: [
|
||||
{ seq: 1, traceId, type: "session", stage: "fixture", status: "completed", label: "source-fixture:session" },
|
||||
{ seq: 2, traceId, type: "assistant", stage: "completed", status: "completed", label: "assistant:completed" }
|
||||
],
|
||||
lastEvent: { seq: 2, traceId, type: "assistant", stage: "completed", status: "completed", label: "assistant:completed" }
|
||||
events: fixtureTraceEvents,
|
||||
lastEvent: fixtureTraceEvents.at(-1)
|
||||
},
|
||||
conversationFacts: {
|
||||
conversationId,
|
||||
|
||||
Reference in New Issue
Block a user