Files
pikasTech-HWLAB/scripts/src/code-agent-response-contract.mjs
T

960 lines
40 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const trustedLiveProviders = new Set(["openai-responses", "codex-cli", "codex-readonly-runner", "codex-stdio"]);
const trustedRunnerProviders = new Set(["codex-stdio"]);
const partialRunnerProviders = new Set(["codex-readonly-runner"]);
const trustedCodexSandboxes = new Set(["workspace-write", "danger-full-access"]);
const readonlySessionCapabilityLevels = new Set(["read-only-tools", "read-only-session-tools"]);
const untrustedProviderPattern = /\b(?:echo|mock|fixture|stub|sample)\b/iu;
const blockedCodeAgentUiLabels = new Set([
"后端失败",
"服务受阻",
"等待超时",
"Provider 不可用",
"Runner 忙碌",
"Session 受阻",
"Runner 受阻",
"API 错误",
"需要配置",
"能力未开放",
"安全阻断",
"仍是 fallback",
"BLOCKED 凭证缺口"
]);
const timeoutPattern = /\b(?:timeout|timed out|abort|aborted|超时|请求超过|无新事件)\b/iu;
export function classifyCodeAgentChatReadiness(payload, { realDevLive = false, httpStatus = null } = {}) {
const providerBlock = classifyCodeAgentProviderBlock(payload, { httpStatus });
if (providerBlock.blocked) {
return {
status: "blocked",
level: providerBlock.level,
blocker: providerBlock.blocker,
devLiveReplyPass: false,
reason: providerBlock.reason,
...(providerBlock.providerStatus != null ? { providerStatus: providerBlock.providerStatus } : {})
};
}
const assistantReply = typeof payload?.reply?.content === "string" ? payload.reply.content.trim() : "";
if (payload?.status === "completed" && assistantReply) {
const evidence = inspectRealCompletionEvidence(payload);
if (!evidence.ok) {
return {
status: "blocked",
level: realDevLive ? "BLOCKED/untrusted-completion" : "SOURCE",
blocker: "untrusted-completion",
devLiveReplyPass: false,
reason: `completed response is missing real provider/model/trace/conversation evidence or looks like echo/mock/stub: ${evidence.reason}`
};
}
if (realDevLive) {
return {
status: "pass",
level: "#143 DEV-LIVE reply pass",
blocker: null,
devLiveReplyPass: true,
reason: "real DEV /v1/agent/chat completed with a non-empty assistant reply"
};
}
return {
status: "blocked",
level: "SOURCE",
blocker: "not-dev-live",
devLiveReplyPass: false,
reason: "mock, fixture, local stub, or source-only completion cannot be counted as #143 DEV-LIVE reply pass"
};
}
const suffix = httpStatus ? ` (HTTP ${httpStatus})` : "";
return {
status: "blocked",
level: "BLOCKED",
blocker: "runtime",
devLiveReplyPass: false,
reason: `Code Agent chat did not produce a completed non-empty assistant reply${suffix}`
};
}
export function classifyCodexRunnerCapability(payload, { httpStatus = null } = {}) {
const providerBlock = classifyCodeAgentProviderBlock(payload, { httpStatus });
if (providerBlock.blocked) {
return {
status: "blocked",
level: providerBlock.level,
blocker: providerBlock.blocker,
capabilityPass: false,
reason: providerBlock.reason,
...(providerBlock.providerStatus != null ? { providerStatus: providerBlock.providerStatus } : {})
};
}
const provider = stringOrNull(payload?.provider);
const runnerKind = stringOrNull(payload?.runner?.kind);
const capabilityLevel = stringOrNull(payload?.capabilityLevel);
const workspace = stringOrNull(payload?.workspace ?? payload?.runner?.workspace);
const sandbox = stringOrNull(payload?.sandbox ?? payload?.runner?.sandbox);
const toolCalls = Array.isArray(payload?.toolCalls) ? payload.toolCalls : [];
const runnerTrace = payload?.runnerTrace && typeof payload.runnerTrace === "object" ? payload.runnerTrace : null;
const skills = payload?.skills && typeof payload.skills === "object" ? payload.skills : null;
const sessionMode = stringOrNull(payload?.sessionMode ?? payload?.runner?.sessionMode ?? payload?.runner?.session);
const implementationType = stringOrNull(payload?.implementationType ?? payload?.runner?.implementationType);
const runnerLimitations = Array.isArray(payload?.runnerLimitations)
? payload.runnerLimitations.filter((item) => typeof item === "string")
: Array.isArray(payload?.runner?.runnerLimitations)
? payload.runner.runnerLimitations.filter((item) => typeof item === "string")
: [];
const sessionReuse = payload?.sessionReuse && typeof payload.sessionReuse === "object" ? payload.sessionReuse : null;
const session = payload?.session && typeof payload.session === "object" ? payload.session : null;
const longLivedSessionGate = payload?.longLivedSessionGate && typeof payload.longLivedSessionGate === "object"
? payload.longLivedSessionGate
: null;
if (provider === "openai-responses" || runnerKind === "openai-responses-fallback") {
return {
status: "blocked",
level: "BLOCKED/text-chat-only",
blocker: "openai-fallback-not-runner",
capabilityPass: false,
reason: "OpenAI Responses fallback can answer text, but it has no workspace/tools/skills runner evidence."
};
}
const missing = [];
if (payload?.status !== "completed") missing.push("completed status");
if (!trustedRunnerProviders.has(provider)) missing.push("runner provider");
if (runnerKind !== "codex-app-server-stdio-runner") missing.push("runner.kind=codex-app-server-stdio-runner");
if (capabilityLevel !== "long-lived-codex-stdio-session") missing.push("capabilityLevel=long-lived-codex-stdio-session");
if (!workspace) missing.push("workspace");
if (!trustedCodexSandboxes.has(sandbox)) missing.push("sandbox=workspace-write|danger-full-access");
if (sessionMode !== "codex-app-server-stdio-long-lived") missing.push("sessionMode=codex-app-server-stdio-long-lived");
if (implementationType !== "repo-owned-codex-app-server-stdio-session") missing.push("implementationType=repo-owned-codex-app-server-stdio-session");
if (!session) missing.push("session");
if (session && !["idle", "ready", "busy"].includes(session.status)) missing.push("session.status active/idle");
if (session && typeof session.idleTimeoutMs !== "number") missing.push("session.idleTimeoutMs");
if (session && !session.lastTraceId) missing.push("session.lastTraceId");
if (session && session.longLivedSession !== true) missing.push("session.longLivedSession=true");
if (session && session.codexStdio !== true) missing.push("session.codexStdio=true");
if (!sessionReuse) missing.push("sessionReuse");
if (toolCalls.length === 0) missing.push("toolCalls");
if (!runnerTrace) missing.push("runnerTrace");
if (!skills) missing.push("skills");
if (payload?.runner?.codexStdio !== true) missing.push("runner.codexStdio=true");
if (payload?.runner?.writeCapable !== true) missing.push("runner.writeCapable=true");
if (payload?.runner?.durableSession !== true) missing.push("runner.durableSession=true");
if (!longLivedSessionGate) missing.push("longLivedSessionGate");
if (longLivedSessionGate?.status !== "pass" || longLivedSessionGate?.pass !== true) missing.push("longLivedSessionGate=pass");
if (missing.length > 0) {
if (partialRunnerProviders.has(provider) && runnerKind === "hwlab-readonly-runner") {
return {
status: "blocked",
level: "BLOCKED/controlled-readonly-long-lived-session",
blocker: "controlled-readonly-not-long-lived",
capabilityPass: false,
reason: "controlled-readonly-session-registry exposes a reusable read-only session, but it is not Codex stdio, a write-capable sandbox, or a full Code Agent capability pass."
};
}
return {
status: "blocked",
level: "BLOCKED/runner-capability",
blocker: "runner-evidence-missing",
capabilityPass: false,
reason: `Codex runner capability evidence is incomplete: ${missing.join(", ")}`
};
}
if (toolCalls.some((tool) => tool.status !== "completed")) {
return {
status: "blocked",
level: "BLOCKED/tool",
blocker: "tool-unavailable",
capabilityPass: false,
reason: "At least one runner tool call is not completed."
};
}
return {
status: "pass",
level: "#275 long-lived Codex stdio session skeleton pass",
blocker: null,
capabilityPass: true,
longLivedSession: true,
reason: "completed repo-owned Codex stdio response includes reusable session, write-capable sandbox, toolCalls, skills, runnerTrace, and a passed long-lived session gate"
};
}
export function classifyCodeAgentProviderBlock(payload, { httpStatus = null } = {}) {
const payloadStatus = stringOrNull(payload?.status);
const errorCode = stringOrNull(payload?.error?.code);
const availabilityStatus = stringOrNull(payload?.availability?.status);
const missingEnv = Array.isArray(payload?.error?.missingEnv)
? payload.error.missingEnv.filter((item) => typeof item === "string")
: [];
const providerStatus = numericStatus(payload?.error?.providerStatus);
const responseStatus = numericStatus(httpStatus);
const providerHttpBlocked = isHttpNon2xxStatus(providerStatus);
const responseHttpBlocked = isHttpNon2xxStatus(responseStatus);
const httpBlocked = providerHttpBlocked || responseHttpBlocked;
const blockingHttpStatus = providerHttpBlocked ? providerStatus : responseHttpBlocked ? responseStatus : providerStatus ?? responseStatus;
const providerUnavailable =
errorCode === "provider_unavailable" ||
availabilityStatus === "blocked" ||
payloadStatus === "blocked" ||
httpBlocked;
if (!providerUnavailable) {
return { blocked: false };
}
if (httpBlocked) {
return {
blocked: true,
level: "BLOCKED/provider",
blocker: "provider-upstream",
providerStatus: blockingHttpStatus,
missingEnv,
reason: `Code Agent HTTP non-2xx status ${blockingHttpStatus} means the upstream response is blocked, not completed`
};
}
if (missingEnv.includes("OPENAI_API_KEY")) {
return {
blocked: true,
level: "BLOCKED/credential",
blocker: "credential",
providerStatus: blockingHttpStatus,
missingEnv,
reason: "provider_unavailable with missing OPENAI_API_KEY means the provider credential contract is incomplete"
};
}
if (missingEnv.includes("HWLAB_CODE_AGENT_OPENAI_BASE_URL")) {
return {
blocked: true,
level: "BLOCKED/provider-config",
blocker: "provider-config",
providerStatus: blockingHttpStatus,
missingEnv,
reason: "provider_unavailable with missing HWLAB_CODE_AGENT_OPENAI_BASE_URL means the provider egress/base-url contract is incomplete"
};
}
return {
blocked: true,
level: "BLOCKED/provider",
blocker: "provider-unavailable",
providerStatus: blockingHttpStatus,
missingEnv,
reason: "provider_unavailable or availability.status=blocked means the provider path is blocked, not completed"
};
}
export function summarizeCodeAgentPayload(payload, { httpStatus = null, traceId = null } = {}) {
const providerBlock = classifyCodeAgentProviderBlock(payload, { httpStatus });
const hasObjectPayload = payload && typeof payload === "object" && !Array.isArray(payload);
if (!hasObjectPayload) {
if (!providerBlock.blocked) return null;
return {
status: "failed",
sourceKind: null,
evidenceLevel: null,
provider: "unknown",
model: "unknown",
backend: "unknown",
traceId: traceId || "unknown",
hasReply: false,
error: {
code: "provider_unavailable",
missingEnv: [],
missingCommands: [],
providerStatus: providerBlock.providerStatus
},
runner: null,
workspace: null,
sandbox: null,
capabilityLevel: null,
toolCalls: [],
skills: null,
runnerTrace: null,
sessionMode: null,
sessionLifecycleStatus: null,
sessionSummary: null,
sessionReuse: null,
session: null,
implementationType: null,
runnerLimitations: [],
codexStdioFeasibility: null,
longLivedSessionGate: null,
conversationFacts: null
};
}
const error = normalizeCodeAgentError(payload.error);
const assistantReply = typeof payload.reply?.content === "string" ? payload.reply.content.trim() : "";
const provider = stringOrNull(payload.provider) ?? (providerBlock.blocked ? "unknown" : null);
const model = stringOrNull(payload.model) ?? (providerBlock.blocked ? "unknown" : null);
const backend = stringOrNull(payload.backend) ?? (providerBlock.blocked ? "unknown" : null);
const observedTraceId = stringOrNull(payload.traceId) ?? traceId ?? (providerBlock.blocked ? "unknown" : null);
if (providerBlock.blocked) {
const blockedError = error
? {
...error,
code: error.code ?? "provider_unavailable",
providerStatus: error.providerStatus ?? providerBlock.providerStatus
}
: {
code: "provider_unavailable",
missingEnv: providerBlock.missingEnv ?? [],
missingCommands: [],
providerStatus: providerBlock.providerStatus
};
return {
status: "failed",
sourceKind: stringOrNull(payload.sourceKind),
evidenceLevel: stringOrNull(payload.evidenceLevel),
provider,
model,
backend,
traceId: observedTraceId,
hasReply: false,
error: blockedError,
blocker: summarizeBlocker(payload.blocker ?? payload.error?.blocker),
runner: summarizeRunner(payload),
workspace: stringOrNull(payload.workspace),
sandbox: stringOrNull(payload.sandbox),
capabilityLevel: stringOrNull(payload.capabilityLevel),
toolCalls: summarizeToolCalls(payload.toolCalls),
skills: summarizeSkills(payload.skills),
runnerTrace: summarizeRunnerTrace(payload.runnerTrace),
sessionMode: stringOrNull(payload.sessionMode),
sessionLifecycleStatus: stringOrNull(payload.sessionLifecycleStatus ?? payload.sessionSummary?.status ?? payload.session?.lifecycleStatus),
sessionSummary: summarizeSessionLifecycle(payload.sessionSummary ?? payload.sessionLifecycle),
sessionReuse: summarizeSessionReuse(payload.sessionReuse),
session: summarizeSession(payload.session),
implementationType: stringOrNull(payload.implementationType),
runnerLimitations: summarizeStringList(payload.runnerLimitations),
codexStdioFeasibility: summarizeCodexStdioFeasibility(payload.codexStdioFeasibility),
longLivedSessionGate: summarizeLongLivedSessionGate(payload.longLivedSessionGate),
conversationFacts: summarizeConversationFacts(payload.conversationFacts)
};
}
return {
status: stringOrNull(payload.status),
sourceKind: stringOrNull(payload.sourceKind),
evidenceLevel: stringOrNull(payload.evidenceLevel),
provider,
model,
backend,
traceId: observedTraceId,
hasReply: assistantReply.length > 0,
error,
blocker: summarizeBlocker(payload.blocker ?? payload.error?.blocker),
runner: summarizeRunner(payload),
workspace: stringOrNull(payload.workspace),
sandbox: stringOrNull(payload.sandbox),
capabilityLevel: stringOrNull(payload.capabilityLevel),
toolCalls: summarizeToolCalls(payload.toolCalls),
skills: summarizeSkills(payload.skills),
runnerTrace: summarizeRunnerTrace(payload.runnerTrace),
sessionMode: stringOrNull(payload.sessionMode),
sessionLifecycleStatus: stringOrNull(payload.sessionLifecycleStatus ?? payload.sessionSummary?.status ?? payload.session?.lifecycleStatus),
sessionSummary: summarizeSessionLifecycle(payload.sessionSummary ?? payload.sessionLifecycle),
sessionReuse: summarizeSessionReuse(payload.sessionReuse),
session: summarizeSession(payload.session),
implementationType: stringOrNull(payload.implementationType),
runnerLimitations: summarizeStringList(payload.runnerLimitations),
codexStdioFeasibility: summarizeCodexStdioFeasibility(payload.codexStdioFeasibility),
longLivedSessionGate: summarizeLongLivedSessionGate(payload.longLivedSessionGate),
conversationFacts: summarizeConversationFacts(payload.conversationFacts)
};
}
export function classifyCodeAgentBrowserJourney({ responseSummary, httpOk = false, httpStatus = null, ui = null } = {}) {
const providerBlock = classifyCodeAgentProviderBlock(responseSummary, { httpStatus });
const runtimeBlock = classifyCodeAgentRuntimeBlock(responseSummary, { httpStatus });
const uiCompleted = ui?.agentChatStatus === "DEV-LIVE 回复" || ui?.agentChatStatus === "已回复" || ui?.completedMessageVisible === true;
const uiFailed = ui?.failedMessageVisible === true || blockedCodeAgentUiLabels.has(ui?.agentChatStatus);
const evidence = inspectSanitizedCompletionEvidence(responseSummary);
const backendCompleted =
httpOk &&
responseSummary?.status === "completed" &&
responseSummary?.hasReply === true &&
responseSummary.error === null &&
evidence.ok;
if (backendCompleted && uiCompleted && !uiFailed) {
return {
status: "pass",
blocker: null,
reason: "completed Code Agent payload over HTTP 2xx with real provider/backend/model/trace/reply evidence and completed UI state"
};
}
if (runtimeBlock.blocked) {
return runtimeBlock;
}
if (providerBlock.blocked) {
return {
status: "blocked",
blocker: providerBlock.blocker,
reason: providerBlock.reason,
...(providerBlock.providerStatus != null ? { providerStatus: providerBlock.providerStatus } : {})
};
}
if (responseSummary?.status === "completed") {
return {
status: "blocked",
blocker: "untrusted-completion",
reason: `Code Agent completed-looking payload was not paired with HTTP success, completed UI, and real provider evidence: ${evidence.reason}`
};
}
return {
status: "blocked",
blocker: "runtime",
reason: "Code Agent browser journey did not produce a completed non-error response"
};
}
export function classifyCodeAgentRuntimeBlock(payload, { httpStatus = null } = {}) {
const errorCode = stringOrNull(payload?.error?.code);
const blockerCode = stringOrNull(payload?.blocker?.code ?? payload?.error?.blocker?.code);
const layer = stringOrNull(payload?.error?.layer ?? payload?.blocker?.layer ?? payload?.error?.blocker?.layer);
const category = stringOrNull(payload?.error?.category ?? payload?.blocker?.category ?? payload?.error?.blocker?.category);
const payloadStatus = stringOrNull(payload?.status);
if (["skill_cli_api_base_missing"].includes(errorCode ?? blockerCode)) {
return {
blocked: true,
status: "blocked",
blocker: "needs-config",
category: "needs_config",
layer,
reason: "M3 Skill CLI is missing a safe HWLAB API base URL contract; do not show generic send failure."
};
}
if (["hwlab_api_unavailable"].includes(errorCode ?? blockerCode)) {
return {
blocked: true,
status: "blocked",
blocker: "retryable",
category: "retryable",
layer,
reason: "HWLAB API is unavailable; the UI should show retryable blocker semantics."
};
}
if (["text_chat_only_fallback"].includes(errorCode ?? blockerCode) || category === "fallback") {
return {
blocked: true,
status: "blocked",
blocker: "text-chat-only-fallback",
category: "fallback",
layer,
reason: "Code Agent response is still text chat fallback and does not satisfy runner/session/tool control."
};
}
if (["m3_readiness_blocked"].includes(errorCode ?? blockerCode) || layer === "m3-readiness") {
return {
blocked: true,
status: "blocked",
blocker: "capability-unavailable",
category: category ?? "capability_unavailable",
layer,
reason: "M3 readiness is blocked; the UI must not treat this as generic send failure or completed control."
};
}
if (errorCode === "session_busy") {
return {
blocked: true,
status: "blocked",
blocker: "runner-busy",
category: "runner_busy",
reason: "Code Agent read-only runner session is already busy; the UI must keep the input retryable."
};
}
if (["session_expired", "session_reuse_conflict", "session_failed", "session_interrupted", "session_canceled", "session_timeout", "session_error"].includes(errorCode)) {
return {
blocked: true,
status: "blocked",
blocker: "session-blocked",
category: "session_blocked",
reason: `Code Agent session is blocked by ${errorCode}; fallback must not be reported as a Codex session.`
};
}
if ([
"runner_unavailable",
"tool_unavailable",
"skills_unavailable",
"security_blocked",
"codex_stdio_blocked",
"codex_stdio_failed",
"codex_stdio_protocol_blocked",
"codex_stdio_empty_response",
"codex_stdio_command_probe_failed",
"external_network_blocked",
"network_tool_unavailable",
"network_timeout"
].includes(errorCode)) {
return {
blocked: true,
status: "blocked",
blocker: "runner-blocked",
category: "runner_blocked",
reason: `Code Agent read-only runner returned ${errorCode}; this is blocked runner evidence, not a completed fallback.`
};
}
if (["invalid_params", "parse_error", "request_failed", "cloud_api_proxy_failed", "upstream_unavailable"].includes(errorCode)) {
return {
blocked: true,
status: "blocked",
blocker: "api-error",
category: "api_error",
reason: `Code Agent API returned ${errorCode}; the request is retryable and must remain distinguishable from provider failure.`
};
}
if (payloadStatus === "failed" && errorCode && errorCode !== "provider_unavailable") {
return {
blocked: true,
status: "blocked",
blocker: "api-error",
category: "api_error",
reason: `Code Agent returned failed status with ${errorCode}.`
};
}
return { blocked: false };
}
export function classifyCodeAgentBrowserFailure(error, { traceId = null } = {}) {
const message = error instanceof Error ? error.message : String(error ?? "");
const observedTraceId = traceId ?? error?.traceId ?? null;
if (error?.userMessage) {
return {
status: "blocked",
blocker: blockerForStructuredCategory(error.category, error.code),
category: error.category ?? "runner_blocked",
chineseSummary: `${error.userMessage}${observedTraceId ? `traceId=${observedTraceId}` : ""}`,
reason: message
};
}
if (timeoutPattern.test(message)) {
return {
status: "blocked",
blocker: "timeout",
category: "timeout",
chineseSummary: `超时:Code Agent 在配置的活动时间边界内没有新事件${observedTraceId ? `traceId=${observedTraceId}` : ""}。`,
reason: message
};
}
if (/session[_ -]?busy|runner busy|already busy/iu.test(message)) {
return {
status: "blocked",
blocker: "runner-busy",
category: "runner_busy",
chineseSummary: `Runner 忙碌:Code Agent 正在处理上一轮请求,可稍后重试${observedTraceId ? `traceId=${observedTraceId}` : ""}。`,
reason: message
};
}
if (/session[_ -]?(expired|blocked|reuse_conflict)|conversation.*session/iu.test(message)) {
return {
status: "blocked",
blocker: "session-blocked",
category: "session_blocked",
chineseSummary: `Session 受阻:Code Agent 会话无法复用或已过期${observedTraceId ? `traceId=${observedTraceId}` : ""}。`,
reason: message
};
}
if (/provider|upstream|openai|codex|502|503|504|429|provider_unavailable/iu.test(message)) {
return {
status: "blocked",
blocker: "provider-upstream",
category: "provider",
chineseSummary: `Provider 故障:Code Agent 上游或后端返回失败${observedTraceId ? `traceId=${observedTraceId}` : ""}。`,
reason: message
};
}
if (/api|http \d{3}|invalid_params|parse_error|request_failed|cloud_api_proxy_failed/iu.test(message)) {
return {
status: "blocked",
blocker: "api-error",
category: "api_error",
chineseSummary: `API 错误:Code Agent 接口返回失败,输入应保留可重试${observedTraceId ? `traceId=${observedTraceId}` : ""}。`,
reason: message
};
}
return {
status: "blocked",
blocker: "browser-runtime",
category: "browser",
chineseSummary: `浏览器故障:Workbench 浏览器链路未完成${observedTraceId ? `traceId=${observedTraceId}` : ""}。`,
reason: message || "unknown browser error"
};
}
function blockerForStructuredCategory(category, code) {
if (category === "needs_config") return "needs-config";
if (category === "security_blocked" || code === "security_blocked") return "security-blocked";
if (category === "fallback" || code === "text_chat_only_fallback") return "text-chat-only-fallback";
if (category === "capability_unavailable") return "capability-unavailable";
if (category === "retryable") return "retryable";
if (category === "runner_busy") return "runner-busy";
if (category === "session_blocked") return "session-blocked";
if (category === "timeout") return "timeout";
return "runtime";
}
export function inspectRealCompletionEvidence(payload) {
const provider = String(payload?.provider ?? "").trim().toLowerCase();
const backend = String(payload?.backend ?? "").trim().toLowerCase();
const missing = [];
if (!payload?.conversationId && !payload?.sessionId) missing.push("conversationId");
if (!payload?.traceId) missing.push("traceId");
if (!payload?.messageId) missing.push("messageId");
if (!payload?.provider) missing.push("provider");
if (!payload?.model) missing.push("model");
if (!payload?.backend) missing.push("backend");
if (missing.length > 0) {
return { ok: false, reason: `missing ${missing.join(",")}` };
}
if (!trustedLiveProviders.has(provider)) {
return { ok: false, reason: `provider ${payload.provider} is not an accepted real provider` };
}
if (provider === "openai-responses" && payload?.capabilityLevel && payload.capabilityLevel !== "text-chat-only") {
return { ok: false, reason: "openai-responses cannot claim runner capabilityLevel" };
}
if (provider === "codex-readonly-runner" && payload?.longLivedSessionGate?.status === "pass") {
return { ok: false, reason: "read-only runner cannot claim long-lived session gate pass" };
}
if (provider === "codex-readonly-runner") {
return { ok: false, reason: "controlled read-only runner is partial capability only and cannot be reported as full Code Agent completion" };
}
if (provider === "openai-responses" && payload?.longLivedSessionGate?.status !== "pass") {
return { ok: false, reason: "OpenAI Responses fallback is text-chat-only and cannot be reported as full Code Agent completion" };
}
if (provider === "codex-stdio" && payload?.longLivedSessionGate?.status !== "pass") {
return { ok: false, reason: "codex-stdio completion is missing long-lived session gate pass" };
}
if (untrustedProviderPattern.test(`${provider} ${backend}`)) {
return { ok: false, reason: `provider/backend looks non-real: ${payload.provider}/${payload.backend}` };
}
return { ok: true, reason: "provider/model/trace/conversation evidence present" };
}
export function normalizeCodeAgentError(error) {
if (!error || typeof error !== "object") return null;
return {
code: stringOrNull(error.code),
layer: stringOrNull(error.layer),
category: stringOrNull(error.category),
retryable: error.retryable === true,
userMessage: stringOrNull(error.userMessage),
traceId: stringOrNull(error.traceId),
route: stringOrNull(error.route),
toolName: stringOrNull(error.toolName),
blocker: summarizeBlocker(error.blocker),
missingConfig: Array.isArray(error.missingConfig) ? error.missingConfig.filter((item) => typeof item === "string") : [],
missingEnv: Array.isArray(error.missingEnv) ? error.missingEnv.filter((item) => typeof item === "string") : [],
missingCommands: Array.isArray(error.missingCommands) ? error.missingCommands.filter((item) => typeof item === "string") : [],
providerStatus: numericStatus(error.providerStatus)
};
}
export function isHttpNon2xxStatus(value) {
const status = numericStatus(value);
return status !== null && (status < 200 || status > 299);
}
function inspectSanitizedCompletionEvidence(summary) {
const provider = String(summary?.provider ?? "").trim().toLowerCase();
const backend = String(summary?.backend ?? "").trim().toLowerCase();
const missing = [];
if (!summary?.provider) missing.push("provider");
if (!summary?.model) missing.push("model");
if (!summary?.backend) missing.push("backend");
if (!summary?.traceId) missing.push("traceId");
if (summary?.hasReply !== true) missing.push("reply");
if (missing.length > 0) {
return { ok: false, reason: `missing ${missing.join(",")}` };
}
if (!trustedLiveProviders.has(provider)) {
return { ok: false, reason: `provider ${summary.provider} is not an accepted real provider` };
}
if (untrustedProviderPattern.test(`${provider} ${backend}`)) {
return { ok: false, reason: `provider/backend looks non-real: ${summary.provider}/${summary.backend}` };
}
return { ok: true, reason: "real provider/backend/model/trace/reply evidence present" };
}
function summarizeRunner(payload) {
if (!payload?.runner || typeof payload.runner !== "object") return null;
return {
kind: stringOrNull(payload.runner.kind),
backend: stringOrNull(payload.runner.backend),
workspace: stringOrNull(payload.runner.workspace),
sandbox: stringOrNull(payload.runner.sandbox),
session: stringOrNull(payload.runner.session),
sessionMode: stringOrNull(payload.runner.sessionMode),
sessionId: stringOrNull(payload.runner.sessionId),
implementationType: stringOrNull(payload.runner.implementationType),
codexStdio: payload.runner.codexStdio === true,
writeCapable: payload.runner.writeCapable === true,
durableSession: payload.runner.durableSession === true,
longLivedSession: payload.runner.longLivedSession === true,
readOnly: payload.runner.readOnly === true,
capabilityLevel: stringOrNull(payload.runner.capabilityLevel),
runnerLimitations: summarizeStringList(payload.runner.runnerLimitations)
};
}
function summarizeToolCalls(value) {
if (!Array.isArray(value)) return [];
return value.map((tool) => ({
name: stringOrNull(tool?.name),
type: stringOrNull(tool?.type),
status: stringOrNull(tool?.status),
route: stringOrNull(tool?.route),
capabilityLevel: stringOrNull(tool?.capabilityLevel),
blocker: summarizeBlocker(tool?.blocker),
exitCode: numericStatus(tool?.exitCode),
outputTruncated: tool?.outputTruncated === true
}));
}
function summarizeSkills(value) {
if (!value || typeof value !== "object") return null;
return {
status: stringOrNull(value.status),
count: typeof value.count === "number" ? value.count : Array.isArray(value.items) ? value.items.length : null,
totalCount: typeof value.totalCount === "number" ? value.totalCount : null,
blockers: Array.isArray(value.blockers)
? value.blockers.map((blocker) => ({
code: stringOrNull(blocker.code),
sourceIssue: stringOrNull(blocker.sourceIssue)
}))
: []
};
}
function summarizeRunnerTrace(value) {
if (!value || typeof value !== "object") return null;
return {
runnerKind: stringOrNull(value.runnerKind),
route: stringOrNull(value.route),
capabilityLevel: stringOrNull(value.capabilityLevel),
blocker: summarizeBlocker(value.blocker),
sandbox: stringOrNull(value.sandbox),
sessionMode: stringOrNull(value.sessionMode),
sessionStatus: stringOrNull(value.sessionStatus),
sessionLifecycleStatus: stringOrNull(value.sessionLifecycleStatus),
implementationType: stringOrNull(value.implementationType),
sessionReused: value.sessionReused === true,
turn: typeof value.turn === "number" ? value.turn : null,
outputTruncated: value.outputTruncated === true,
valuesPrinted: value.valuesPrinted === true
};
}
function summarizeBlocker(value) {
if (!value || typeof value !== "object") return null;
return {
code: stringOrNull(value.code),
layer: stringOrNull(value.layer),
category: stringOrNull(value.category),
retryable: value.retryable === true,
userMessage: stringOrNull(value.userMessage),
route: stringOrNull(value.route),
toolName: stringOrNull(value.toolName)
};
}
function summarizeSessionReuse(value) {
if (!value || typeof value !== "object") return null;
return {
conversationId: stringOrNull(value.conversationId),
sessionId: stringOrNull(value.sessionId),
mapped: value.mapped === true,
reused: value.reused === true,
turn: typeof value.turn === "number" ? value.turn : null,
previousTurns: typeof value.previousTurns === "number" ? value.previousTurns : null,
workspace: stringOrNull(value.workspace),
status: stringOrNull(value.status),
idleTimeoutMs: typeof value.idleTimeoutMs === "number" ? value.idleTimeoutMs : null,
lastTraceId: stringOrNull(value.lastTraceId)
};
}
function summarizeSession(value) {
if (!value || typeof value !== "object") return null;
return {
sessionId: stringOrNull(value.sessionId),
conversationId: stringOrNull(value.conversationId),
status: stringOrNull(value.status),
lifecycleStatus: stringOrNull(value.lifecycleStatus ?? value.lifecycle?.status),
workspace: stringOrNull(value.workspace),
sandbox: stringOrNull(value.sandbox),
runnerKind: stringOrNull(value.runnerKind),
capabilityLevel: stringOrNull(value.capabilityLevel),
implementationType: stringOrNull(value.implementationType),
createdAt: stringOrNull(value.createdAt),
updatedAt: stringOrNull(value.updatedAt),
idleTimeoutMs: typeof value.idleTimeoutMs === "number" ? value.idleTimeoutMs : null,
lastTraceId: stringOrNull(value.lastTraceId),
turn: typeof value.turn === "number" ? value.turn : null,
longLivedSession: value.longLivedSession === true,
codexStdio: value.codexStdio === true,
writeCapable: value.writeCapable === true,
secretMaterialStored: value.secretMaterialStored === true
};
}
function summarizeConversationFacts(value) {
if (!value || typeof value !== "object") return null;
return {
conversationId: stringOrNull(value.conversationId),
sessionId: stringOrNull(value.sessionId),
sessionStatus: stringOrNull(value.sessionStatus),
sessionLifecycleStatus: stringOrNull(value.sessionLifecycleStatus),
sessionMode: stringOrNull(value.sessionMode),
capabilityLevel: stringOrNull(value.capabilityLevel),
runnerKind: stringOrNull(value.runnerKind),
workspace: stringOrNull(value.workspace),
sandbox: stringOrNull(value.sandbox),
turnCount: typeof value.turnCount === "number" ? value.turnCount : null,
latestTraceId: stringOrNull(value.latestTraceId),
traceIds: Array.isArray(value.traceIds) ? value.traceIds.map(stringOrNull).filter(Boolean).slice(-6) : [],
latestSkills: value.latestSkills && typeof value.latestSkills === "object"
? {
status: stringOrNull(value.latestSkills.status),
count: typeof value.latestSkills.count === "number" ? value.latestSkills.count : null,
totalCount: typeof value.latestSkills.totalCount === "number" ? value.latestSkills.totalCount : null,
names: Array.isArray(value.latestSkills.names) ? value.latestSkills.names.map(stringOrNull).filter(Boolean).slice(0, 8) : []
}
: null,
recentToolCalls: Array.isArray(value.recentToolCalls)
? value.recentToolCalls.map((tool) => ({
name: stringOrNull(tool?.name),
status: stringOrNull(tool?.status)
})).filter((tool) => tool.name || tool.status).slice(-8)
: [],
valuesRedacted: value.valuesRedacted === true,
secretMaterialStored: value.secretMaterialStored === true
};
}
function summarizeSessionLifecycle(value) {
if (!value || typeof value !== "object") return null;
return {
status: stringOrNull(value.status),
rawStatus: stringOrNull(value.rawStatus),
label: stringOrNull(value.label),
action: stringOrNull(value.action),
reusable: value.reusable === true,
reused: typeof value.reused === "boolean" ? value.reused : null,
newSession: value.newSession === true,
busy: value.busy === true,
requiresNewSession: value.requiresNewSession === true,
degraded: value.degraded === true,
fallback: value.fallback === true,
unsupported: value.unsupported === true,
reasonCode: stringOrNull(value.reasonCode),
userMessage: stringOrNull(value.userMessage)
};
}
function summarizeCodexStdioFeasibility(value) {
if (!value || typeof value !== "object") return null;
return {
status: stringOrNull(value.status),
canStartLongLivedCodexStdio: value.canStartLongLivedCodexStdio === true,
currentImplementation: stringOrNull(value.currentImplementation),
implementationRequired: stringOrNull(value.implementationRequired),
binaryOnPath: value.binaryOnPath === true,
binary: value.binary && typeof value.binary === "object"
? {
status: stringOrNull(value.binary.status),
present: value.binary.present === true,
command: stringOrNull(value.binary.command),
version: stringOrNull(value.binary.version),
versionDetected: value.binary.versionDetected === true
}
: null,
runtimeContract: value.runtimeContract && typeof value.runtimeContract === "object"
? {
status: stringOrNull(value.runtimeContract.status),
ready: value.runtimeContract.ready === true,
binaryStatus: stringOrNull(value.runtimeContract.binary?.status),
stdioProtocolStatus: stringOrNull(value.runtimeContract.stdioProtocol?.status),
lifecycleStatus: stringOrNull(value.runtimeContract.lifecycleSupervisor?.status),
workspaceStatus: stringOrNull(value.runtimeContract.workspaceMount?.status),
tokenBoundaryStatus: stringOrNull(value.runtimeContract.tokenBoundary?.status),
cancelReapTraceStatus: stringOrNull(value.runtimeContract.cancelReapTraceReadiness?.status)
}
: null,
workspace: stringOrNull(value.workspace),
sandbox: stringOrNull(value.sandbox),
ready: value.ready === true,
sessionLifecycle: value.sessionLifecycle && typeof value.sessionLifecycle === "object"
? {
create: value.sessionLifecycle.create === true,
reuse: value.sessionLifecycle.reuse === true,
cancel: value.sessionLifecycle.cancel === true,
reap: value.sessionLifecycle.reap === true,
idleTimeout: value.sessionLifecycle.idleTimeout === true,
traceCapture: value.sessionLifecycle.traceCapture === true,
idleTimeoutMs: typeof value.sessionLifecycle.idleTimeoutMs === "number" ? value.sessionLifecycle.idleTimeoutMs : null
}
: null,
blockers: Array.isArray(value.blockers)
? value.blockers.map((blocker) => ({
code: stringOrNull(blocker.code),
sourceIssue: stringOrNull(blocker.sourceIssue)
}))
: []
};
}
function summarizeLongLivedSessionGate(value) {
if (!value || typeof value !== "object") return null;
return {
status: stringOrNull(value.status),
pass: value.pass === true,
requiredCapability: stringOrNull(value.requiredCapability),
currentCapability: stringOrNull(value.currentCapability),
sessionId: stringOrNull(value.sessionId),
sessionStatus: stringOrNull(value.sessionStatus),
runnerKind: stringOrNull(value.runnerKind),
provider: stringOrNull(value.provider),
blockers: Array.isArray(value.blockers)
? value.blockers.map((blocker) => ({
code: stringOrNull(blocker.code),
sourceIssue: stringOrNull(blocker.sourceIssue)
}))
: []
};
}
function summarizeStringList(value) {
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
}
function stringOrNull(value) {
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
}
function numericStatus(value) {
if (typeof value !== "number" || !Number.isInteger(value)) return null;
return value;
}