Files
pikasTech-HWLAB/scripts/src/code-agent-response-contract.mjs
T
Lyon 29686823c5 test: add code agent browser e2e harness (#264)
Co-authored-by: Code Queue Review <code-queue-review@localhost>
2026-05-23 14:24:26 +08:00

335 lines
12 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"]);
const untrustedProviderPattern = /\b(?:echo|mock|fixture|stub|sample)\b/iu;
const blockedCodeAgentUiLabels = new Set(["发送失败", "服务受阻", "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 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
}
};
}
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
};
}
return {
status: stringOrNull(payload.status),
sourceKind: stringOrNull(payload.sourceKind),
evidenceLevel: stringOrNull(payload.evidenceLevel),
provider,
model,
backend,
traceId: observedTraceId,
hasReply: assistantReply.length > 0,
error
};
}
export function classifyCodeAgentBrowserJourney({ responseSummary, httpOk = false, httpStatus = null, ui = null } = {}) {
const providerBlock = classifyCodeAgentProviderBlock(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 (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 classifyCodeAgentBrowserFailure(error, { traceId = null } = {}) {
const message = error instanceof Error ? error.message : String(error ?? "");
const observedTraceId = traceId ?? error?.traceId ?? null;
if (timeoutPattern.test(message)) {
return {
status: "blocked",
blocker: "timeout",
category: "timeout",
chineseSummary: `超时: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
};
}
return {
status: "blocked",
blocker: "browser-runtime",
category: "browser",
chineseSummary: `浏览器故障:Workbench 浏览器链路未完成${observedTraceId ? `traceId=${observedTraceId}` : ""}。`,
reason: message || "unknown browser error"
};
}
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 (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),
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 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;
}