fix: 接入真实 Codex stdio trace
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user