fix: 接入真实 Codex stdio trace

This commit is contained in:
Code Queue Review
2026-05-24 02:49:11 +00:00
parent 35bbbee951
commit e166a6ff20
12 changed files with 1791 additions and 3702 deletions
+63 -96
View File
@@ -281,22 +281,9 @@ const workbenchMarkers = Object.freeze([
]);
const requiredCodeAgentEvidenceTerms = Object.freeze([
"消息归因",
"字段缺失:证据不足",
"只是文本回答",
"当前不能执行",
"provider",
"model",
"backend",
"runner",
"workspace",
"sandbox",
"capability",
"sessionMode",
"sessionReuse",
"implementation",
"limitations",
"codexStdio",
"运行 trace",
"message-trace",
"message-trace-events",
"toolCalls",
"skills",
"runnerTrace",
@@ -304,15 +291,9 @@ const requiredCodeAgentEvidenceTerms = Object.freeze([
"trace",
"message",
"providerTrace",
"openai-responses",
"openai-responses-fallback",
"text-chat-only / 只是文本回答",
"codex-stdio",
"codex-cli",
"codex-mcp-stdio-long-lived",
"repo-owned-codex-mcp-stdio-session",
"controlled-readonly-session-registry",
"read-only-session-tools:只读长会话",
"not-codex-stdio",
"not-write-capable",
"process-local-session-registry",
@@ -320,8 +301,6 @@ const requiredCodeAgentEvidenceTerms = Object.freeze([
"untrusted_completion",
"SOURCE fixture",
"Code Agent SOURCE 回复",
"message-evidence-chip",
"message-attribution-chip",
"hwlab-skill-cli",
"hwlab-m3-io-skill-cli",
"message-m3-evidence"
@@ -635,22 +614,22 @@ function runStaticSmoke() {
addCheck(checks, blockers, "route-control-stable-dimensions", hasStableRouteControls(files), "Route controls and status tags have stable dimensions, readable wrapping, and usable labels on small screens.", {
blocker: "runtime_blocker",
evidence: ["rail-button min-width/min-height", "state-tag wrapping", "side-tab stable labels", "mobile message evidence column"]
evidence: ["rail-button min-width/min-height", "state-tag wrapping", "side-tab stable labels", "mobile trace column"]
});
addCheck(checks, blockers, "code-agent-completed-evidence-visible", hasCodeAgentCompletedEvidenceVisibility(files), "Completed full Code Agent replies expose Codex stdio provider/model/trace/conversation/session evidence and reject echo/mock/stub, OpenAI fallback, and read-only runner completions.", {
addCheck(checks, blockers, "code-agent-completed-evidence-visible", hasCodeAgentCompletedEvidenceVisibility(files), "Completed full Code Agent replies expose Codex stdio runnerTrace and reject echo/mock/stub, OpenAI fallback, and local shortcut completions.", {
blocker: "observability_blocker",
evidence: requiredCodeAgentEvidenceTerms
});
addCheck(checks, blockers, "code-agent-conversation-ux-states", hasCodeAgentConversationUxStates(files), "Code Agent thread renders trusted completed, SOURCE fixture, failed, and blocked provider states as distinct conversation replies with bounded evidence.", {
addCheck(checks, blockers, "code-agent-conversation-ux-states", hasCodeAgentConversationUxStates(files), "Code Agent thread renders trusted completed, SOURCE fixture, failed, and blocked provider states as distinct conversation replies with bounded trace.", {
blocker: "observability_blocker",
evidence: [
"DEV-LIVE 回复",
"SOURCE 回复",
"等待超时/API 错误/发送失败",
"服务受阻 or legacy BLOCKED 凭证缺口",
"message-evidence/details/chips"
"message-trace/details/events"
]
});
@@ -2347,7 +2326,7 @@ function hasStableRouteControls({ html, styles }) {
/\.(?:status-dot|state-tag|badge)[^{]*\{[^}]*max-width:\s*100%;[^}]*line-height:\s*1\.25;[^}]*white-space:\s*normal;[^}]*overflow-wrap:\s*anywhere;/su.test(styles) &&
/\.probe-card\s*\{[^}]*min-width:\s*0;/su.test(styles) &&
/\.probe-card strong\s*\{[^}]*line-height:\s*1\.2;[^}]*overflow-wrap:\s*anywhere;/su.test(styles) &&
/@media\s*\(max-width:\s*860px\)[\s\S]*?\.message-evidence\s*\{[\s\S]*?grid-column:\s*1;/u.test(styles)
/@media\s*\(max-width:\s*860px\)[\s\S]*?\.message-trace,\s*\n\s*\.message-m3-evidence\s*\{[\s\S]*?grid-column:\s*1;/u.test(styles)
);
}
@@ -2489,7 +2468,6 @@ function hasCodeAgentReadinessVisibility({ html, app, liveStatus = "" }) {
}
function hasCodeAgentCompletedEvidenceVisibility({ app, codeAgentM3Evidence }) {
const messageEvidenceBody = functionBody(app, "messageEvidenceFields");
const realEvidenceBody = functionBody(app, "hasRealCodeAgentEvidence");
const runnerEvidenceBody = functionBody(app, "isCodexRunnerCapableEvidence");
const codeAgentEvidenceSource = `${app}\n${codeAgentM3Evidence}`;
@@ -2497,34 +2475,19 @@ function hasCodeAgentCompletedEvidenceVisibility({ app, codeAgentM3Evidence }) {
requiredCodeAgentEvidenceTerms.every((term) => codeAgentEvidenceSource.includes(term)) &&
/conversationId:\s*result\.conversationId \|\| result\.sessionId \|\| state\.conversationId/u.test(app) &&
/providerTrace:\s*result\.providerTrace/u.test(app) &&
/function\s+providerTraceSummary\s*\(/u.test(app) &&
/function\s+messageAttributionPanel\s*\(/u.test(app) &&
/codeAgentAttributionFromMessage/u.test(app) &&
/attribution\.fields\.map\(\(field\) => field\.chip\)/u.test(messageEvidenceBody) &&
/recordField\("provider",\s*message\.provider\)/u.test(messageEvidenceBody) &&
/recordField\("model",\s*message\.model\)/u.test(messageEvidenceBody) &&
/recordField\("backend",\s*message\.backend\)/u.test(messageEvidenceBody) &&
/recordField\("runner",\s*message\.runner\?\.kind\)/u.test(messageEvidenceBody) &&
/recordField\("workspace",\s*message\.workspace\)/u.test(messageEvidenceBody) &&
/recordField\("sandbox",\s*message\.sandbox\)/u.test(messageEvidenceBody) &&
/recordField\("capability",\s*message\.capabilityLevel\)/u.test(messageEvidenceBody) &&
/recordField\("session",\s*sessionSummary\(message\.session\)\s*\?\?\s*message\.sessionId\)/u.test(messageEvidenceBody) &&
/recordField\("sessionMode",\s*message\.sessionMode\)/u.test(messageEvidenceBody) &&
/recordField\("sessionReuse",\s*sessionReuseSummary\(message\.sessionReuse\)\)/u.test(messageEvidenceBody) &&
/recordField\("longLivedGate",\s*longLivedSessionGateSummary\(message\.longLivedSessionGate\)\)/u.test(messageEvidenceBody) &&
/recordField\("implementation",\s*message\.implementationType\)/u.test(messageEvidenceBody) &&
/recordField\("limitations",\s*limitationsSummary\(message\.runnerLimitations\)\)/u.test(messageEvidenceBody) &&
/recordField\("codexStdio",\s*codexStdioFeasibilitySummary\(message\.codexStdioFeasibility\)\)/u.test(messageEvidenceBody) &&
/recordField\("toolCalls",\s*toolCallsSummary\(message\.toolCalls\)\)/u.test(messageEvidenceBody) &&
/recordField\("skills",\s*skillsSummary\(message\.skills\)\)/u.test(messageEvidenceBody) &&
/recordField\("runnerTrace",\s*runnerTraceSummary\(message\.runnerTrace\)\)/u.test(messageEvidenceBody) &&
/recordField\("operationId",\s*operationIdSummary\(message\)\)/u.test(messageEvidenceBody) &&
/recordField\("audit",\s*auditSummary\(message\)\)/u.test(messageEvidenceBody) &&
/recordField\("evidence",\s*evidenceSummary\(message\)\)/u.test(messageEvidenceBody) &&
/recordField\("conversation",\s*message\.conversationId\)/u.test(messageEvidenceBody) &&
/recordField\("trace",\s*message\.traceId\)/u.test(messageEvidenceBody) &&
/recordField\("message",\s*message\.messageId\)/u.test(messageEvidenceBody) &&
/providerTraceSummary\(message\.providerTrace\)/u.test(messageEvidenceBody) &&
/function\s+messageTracePanel\s*\(/u.test(app) &&
/function\s+subscribeRunnerTrace\s*\(/u.test(app) &&
/new EventSource\(`\/v1\/agent\/chat\/trace\/\$\{encodeURIComponent\(traceId\)\}\/stream`\)/u.test(app) &&
/source\.addEventListener\("runnerTrace"/u.test(app) &&
/function\s+pollRunnerTrace\s*\(/u.test(app) &&
/function\s+updateMessageTrace\s*\(/u.test(app) &&
/function\s+runnerTraceFromSnapshot\s*\(/u.test(app) &&
/function\s+runnerTraceHeadline\s*\(/u.test(app) &&
/function\s+traceEventMeta\s*\(/u.test(app) &&
!/function\s+messageAttributionPanel\s*\(/u.test(app) &&
!/function\s+messageEvidencePanel\s*\(/u.test(app) &&
!/codeAgentAttributionFromMessage/u.test(app) &&
!/codeAgentFactsFromMessage/u.test(app) &&
/extractCodeAgentM3Evidence\(result\)/u.test(app) &&
/messageM3EvidencePanel/u.test(app) &&
/m3EvidenceRows/u.test(app) &&
@@ -2540,11 +2503,9 @@ function hasCodeAgentCompletedEvidenceVisibility({ app, codeAgentM3Evidence }) {
/isTrustedCodeAgentProvider\(value\?\.provider\)/u.test(realEvidenceBody) &&
/isCodexRunnerCapableEvidence\(value\)/u.test(realEvidenceBody) &&
/CODEX_RUNNER_CAPABLE_PROVIDERS/u.test(app) &&
/CODEX_READONLY_PARTIAL_PROVIDERS/u.test(app) &&
/codex-mcp-stdio-long-lived/u.test(runnerEvidenceBody) &&
/repo-owned-codex-mcp-stdio-session/u.test(runnerEvidenceBody) &&
/long-lived-codex-stdio-session/u.test(runnerEvidenceBody) &&
/isReadOnlyRunnerPartialEvidence/u.test(app) &&
/isTextFallbackChatResult/u.test(app) &&
/value\?\.session\?\.status === "idle"/u.test(runnerEvidenceBody) &&
/value\?\.longLivedSessionGate\?\.status === "pass"/u.test(runnerEvidenceBody) &&
@@ -2614,14 +2575,13 @@ function hasCodeAgentConversationUxStates({ app, styles }) {
/function\s+isSourceFixtureChatResult\s*\(/u.test(app) &&
/function\s+isSourceFixtureCompletion\s*\(/u.test(app) &&
/function\s+isSourceFixtureCompletedChatMessage\s*\(/u.test(app) &&
/function\s+messageEvidencePanel\s*\(/u.test(app) &&
/function\s+messageAttributionPanel\s*\(/u.test(app) &&
/function\s+messageTracePanel\s*\(/u.test(app) &&
/function\s+subscribeRunnerTrace\s*\(/u.test(app) &&
/function\s+updateMessageTrace\s*\(/u.test(app) &&
/function\s+messagePendingContextPanel\s*\(/u.test(app) &&
/function\s+messageEvidenceSummary\s*\(/u.test(app) &&
/function\s+boundedEvidenceField\s*\(/u.test(app) &&
/codeAgentAttributionFromMessage/u.test(app) &&
/字段缺失:证据不足/u.test(app) &&
/当前不能执行/u.test(app) &&
!/function\s+messageEvidencePanel\s*\(/u.test(app) &&
!/function\s+messageAttributionPanel\s*\(/u.test(app) &&
!/codeAgentAttributionFromMessage/u.test(app) &&
/DEFAULT_API_TIMEOUT_MS\s*=\s*4500/u.test(app) &&
/DEFAULT_CODE_AGENT_TIMEOUT_MS\s*=\s*180000/u.test(app) &&
/timeoutMs:\s*CODE_AGENT_TIMEOUT_MS/u.test(app) &&
@@ -2640,12 +2600,12 @@ function hasCodeAgentConversationUxStates({ app, styles }) {
/message-agent/u.test(styles) &&
/message-pending-context\s*\{/u.test(styles) &&
/message-m3-evidence\s*\{/u.test(styles) &&
/message-attribution\s*\{/u.test(styles) &&
/message-attribution-chip/u.test(styles) &&
/message-m3-rows\s*\{/u.test(styles) &&
/copy-chip\s*\{/u.test(styles) &&
/message-evidence\s*\{/u.test(styles) &&
/message-evidence-chip/u.test(styles) &&
/message-trace\s*\{/u.test(styles) &&
/message-trace-events\s*\{/u.test(styles) &&
!/message-attribution\s*\{/u.test(styles) &&
!/message-evidence\s*\{/u.test(styles) &&
/width:\s*min\(100%,\s*780px\)/u.test(styles) &&
/status === "completed" \? "dev-live" : status === "failed" \|\| status === "blocked" \? "blocked" : status === "running" \? "pending" : "source"/u.test(app) &&
!/sourceKind:\s*"SOURCE"[\s\S]{0,160}status:\s*"completed"/u.test(app)
@@ -4237,29 +4197,27 @@ async function inspectJourneyUi(page) {
messageCount: document.querySelectorAll(".message-card").length,
completedMessageHasNonSensitiveMeta: Boolean(
[...document.querySelectorAll(".message-card.status-completed .message-meta")]
.some((element) => /openai-responses|codex-readonly-runner|gpt-5\.5|runner=|workspace=|toolCalls=|trc_/u.test(element.textContent ?? ""))
.some((element) => /codex-stdio|gpt-5\.5|runner=|workspace=|toolCalls=|trc_|trace\s+trc_/u.test(element.textContent ?? ""))
),
sourceMessageHasNonSensitiveMeta: Boolean(
[...document.querySelectorAll(".message-card.status-source .message-meta")]
.some((element) => /SOURCE|source-fixture|trc_/u.test(element.textContent ?? ""))
),
attributionText: [...document.querySelectorAll(".message-card.message-agent .message-attribution")]
traceText: [...document.querySelectorAll(".message-card.message-agent .message-trace")]
.map((element) => element.textContent ?? "")
.join("\n"),
attributionHasTraceId: [...document.querySelectorAll(".message-card.message-agent .message-attribution [data-field='traceId']")]
traceHasTraceId: [...document.querySelectorAll(".message-card.message-agent .message-trace")]
.some((element) => /trc_/u.test(element.textContent ?? "")),
attributionShowsToolCalls: [...document.querySelectorAll(".message-card.message-agent .message-attribution [data-field='toolCalls']")]
.some((element) => /toolCalls=/u.test(element.textContent ?? "")),
attributionMissingFieldsStructured: [...document.querySelectorAll(".message-card.message-agent .message-attribution-chip.is-missing")]
.some((element) => /字段缺失证据不足/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 ?? "")),
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-attribution")]
[...document.querySelectorAll(".message-card.message-agent .message-trace")]
.map((element) => element.textContent ?? "")
.join("\n")
),
conversationFactsVisible: /conversationFacts|fact traces|fact skills|fact tools|turns=|sessionId=|workspace=/u.test(
[
...document.querySelectorAll(".message-card.message-agent .code-agent-facts"),
document.querySelector("#code-agent-summary")
]
.map((element) => element?.textContent ?? "")
@@ -4703,9 +4661,9 @@ async function runLocalAgentFixtureSmoke({
ui.agentChatStatus === "SOURCE 回复" &&
ui.sourceMessageVisible &&
ui.sourceMessageHasNonSensitiveMeta &&
ui.attributionHasTraceId &&
ui.attributionShowsToolCalls &&
ui.attributionMissingFieldsStructured &&
ui.traceHasTraceId &&
ui.traceShowsEvents &&
ui.noMainAttributionNoise &&
ui.attributionFallbackNotRunnerControl &&
ui.conversationFactsVisible &&
mobilePending?.pass === true &&
@@ -6102,21 +6060,21 @@ async function handleLocalAgentFixtureApi({ request, response, url, options = {}
createdAt: timestamp,
updatedAt: timestamp,
traceId,
provider: "codex-readonly-runner",
model: "read-only-tools",
backend: "local-source-fixture/slow-structured-blocker",
provider: "codex-stdio",
model: "codex-stdio",
backend: "local-source-fixture/codex-stdio-slow-structured-blocker",
projectId: stringOrFallback(body?.projectId, gateSummary.topology.projectId),
workspace: "/workspace/hwlab",
sandbox: "read-only",
runner: {
kind: "hwlab-readonly-runner",
writeCapable: false,
codexStdio: false,
kind: "codex-mcp-stdio-runner",
writeCapable: true,
codexStdio: true,
longLivedSession: true,
durableSession: false
durableSession: true
},
capabilityLevel: "blocked",
sessionMode: "controlled-readonly-session-registry",
sessionMode: "codex-mcp-stdio-long-lived",
session: {
sessionId: conversationId,
conversationId,
@@ -6191,16 +6149,21 @@ async function handleLocalAgentFixtureApi({ request, response, url, options = {}
},
runnerTrace: {
traceId,
runnerKind: "hwlab-readonly-runner",
sessionMode: "controlled-readonly-session-registry",
runnerKind: "codex-mcp-stdio-runner",
sessionMode: "codex-mcp-stdio-long-lived",
status: "blocked",
events: ["tool:skills.discover:blocked"]
events: [
{ seq: 1, traceId, type: "session", stage: "created", status: "completed", label: "session:created" },
{ seq: 2, traceId, type: "prompt", stage: "sent", status: "completed", label: "prompt:sent" },
{ seq: 3, traceId, type: "error", stage: "blocked", status: "blocked", label: "codex-stdio:blocked", errorCode: "skills_unavailable", waitingFor: "codex-stdio" }
],
lastEvent: { seq: 3, traceId, type: "error", stage: "blocked", status: "blocked", label: "codex-stdio:blocked", errorCode: "skills_unavailable", waitingFor: "codex-stdio" }
},
conversationFacts: {
conversationId,
sessionId: conversationId,
sessionStatus: "idle",
sessionMode: "controlled-readonly-session-registry",
sessionMode: "codex-mcp-stdio-long-lived",
turnCount: 1,
latestTraceId: traceId,
traceIds: [traceId],
@@ -6270,7 +6233,11 @@ async function handleLocalAgentFixtureApi({ request, response, url, options = {}
runnerTrace: {
traceId,
runnerKind: "openai-responses-fallback",
events: ["fixture:text-chat-only"]
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" }
},
conversationFacts: {
conversationId,