fix: block code agent non-2xx readiness
This commit is contained in:
@@ -7,6 +7,12 @@ import { fileURLToPath } from "node:url";
|
||||
|
||||
import { gateSummary } from "../../web/hwlab-cloud-web/gate-summary.mjs";
|
||||
import { runtime } from "../../web/hwlab-cloud-web/runtime.mjs";
|
||||
import {
|
||||
classifyCodeAgentBrowserJourney,
|
||||
summarizeCodeAgentPayload
|
||||
} from "./code-agent-response-contract.mjs";
|
||||
|
||||
export { classifyCodeAgentBrowserJourney };
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const webRoot = path.join(repoRoot, "web/hwlab-cloud-web");
|
||||
@@ -510,7 +516,7 @@ async function runLiveSmoke(args) {
|
||||
hardwareWriteApis: false,
|
||||
sourceIsDevLive: false,
|
||||
liveMode: "browser-user-journey-with-code-agent-post",
|
||||
retainedApiFields: ["status", "provider", "model", "backend", "traceId", "hasReply", "error.code", "error.missingEnv"],
|
||||
retainedApiFields: ["status", "provider", "model", "backend", "traceId", "hasReply", "error.code", "error.missingEnv", "error.providerStatus"],
|
||||
statement: "Live smoke opens the deployed workbench and sends one controlled Code Agent message; it does not call hardware write APIs and must not be used to infer M3 DEV-LIVE hardware-loop acceptance."
|
||||
}
|
||||
});
|
||||
@@ -1667,7 +1673,7 @@ async function inspectLiveUserJourney(url) {
|
||||
method: response.request().method(),
|
||||
status: response.status(),
|
||||
urlPath: new URL(response.url()).pathname,
|
||||
body: sanitizeAgentChatBody(body)
|
||||
body: sanitizeAgentChatBody(body, { httpStatus: response.status() })
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1698,28 +1704,30 @@ async function inspectLiveUserJourney(url) {
|
||||
}
|
||||
await page.waitForTimeout(500);
|
||||
const ui = await inspectJourneyUi(page);
|
||||
const responseSummary = sanitizeAgentChatBody(responseBody);
|
||||
const backendCompleted =
|
||||
response.ok() &&
|
||||
responseSummary?.status === "completed" &&
|
||||
Boolean(responseSummary.provider) &&
|
||||
Boolean(responseSummary.model) &&
|
||||
Boolean(responseSummary.traceId);
|
||||
const uiCompleted = ui.agentChatStatus === "DEV-LIVE 回复" || ui.completedMessageVisible;
|
||||
const pass = backendCompleted && uiCompleted && !ui.failedMessageVisible;
|
||||
const responseSummary = sanitizeAgentChatBody(responseBody, { httpStatus: response.status() });
|
||||
const classification = classifyCodeAgentBrowserJourney({
|
||||
responseSummary,
|
||||
httpOk: response.ok(),
|
||||
httpStatus: response.status(),
|
||||
ui
|
||||
});
|
||||
const pass = classification.status === "pass";
|
||||
|
||||
return {
|
||||
status: pass ? "pass" : "blocked",
|
||||
summary: pass
|
||||
? "Deployed browser journey opened the workbench, sent a Code Agent message, and observed a completed UI response."
|
||||
: "Deployed browser journey did not observe a completed non-error Code Agent response.",
|
||||
: classification.blocker === "provider-upstream" || classification.blocker === "provider-unavailable"
|
||||
? "Deployed browser journey reached Code Agent, but the provider returned a blocked/unavailable state instead of a completed reply."
|
||||
: "Deployed browser journey did not observe a completed non-error Code Agent response.",
|
||||
evidence: [
|
||||
`POST /v1/agent/chat HTTP ${response.status()}`,
|
||||
`status=${responseSummary?.status ?? "unknown"}`,
|
||||
`provider=${responseSummary?.provider ?? "unknown"}`,
|
||||
`model=${responseSummary?.model ?? "unknown"}`,
|
||||
`traceId=${responseSummary?.traceId ?? "unknown"}`,
|
||||
`uiStatus=${ui.agentChatStatus ?? "unknown"}`
|
||||
`uiStatus=${ui.agentChatStatus ?? "unknown"}`,
|
||||
`blocker=${classification.blocker ?? "none"}`
|
||||
],
|
||||
observations: {
|
||||
controls,
|
||||
@@ -1729,6 +1737,7 @@ async function inspectLiveUserJourney(url) {
|
||||
urlPath: new URL(response.url()).pathname
|
||||
},
|
||||
response: responseSummary,
|
||||
classification,
|
||||
ui,
|
||||
networkEvents: agentResponses
|
||||
}
|
||||
@@ -1811,24 +1820,8 @@ async function inspectDefaultApiStatus(page) {
|
||||
});
|
||||
}
|
||||
|
||||
function sanitizeAgentChatBody(body) {
|
||||
if (!body || typeof body !== "object") return null;
|
||||
return {
|
||||
status: typeof body.status === "string" ? body.status : null,
|
||||
sourceKind: typeof body.sourceKind === "string" ? body.sourceKind : null,
|
||||
evidenceLevel: typeof body.evidenceLevel === "string" ? body.evidenceLevel : null,
|
||||
provider: typeof body.provider === "string" ? body.provider : null,
|
||||
model: typeof body.model === "string" ? body.model : null,
|
||||
backend: typeof body.backend === "string" ? body.backend : null,
|
||||
traceId: typeof body.traceId === "string" ? body.traceId : null,
|
||||
hasReply: Boolean(body.reply?.content),
|
||||
error: body.error && typeof body.error === "object"
|
||||
? {
|
||||
code: typeof body.error.code === "string" ? body.error.code : null,
|
||||
missingEnv: Array.isArray(body.error.missingEnv) ? body.error.missingEnv.filter((item) => typeof item === "string") : []
|
||||
}
|
||||
: null
|
||||
};
|
||||
export function sanitizeAgentChatBody(body, options = {}) {
|
||||
return summarizeCodeAgentPayload(body, options);
|
||||
}
|
||||
|
||||
export async function runDevCloudWorkbenchLocalAgentFixtureSmoke() {
|
||||
@@ -1867,7 +1860,7 @@ export async function runDevCloudWorkbenchLocalAgentFixtureSmoke() {
|
||||
method: response.request().method(),
|
||||
status: response.status(),
|
||||
urlPath: new URL(response.url()).pathname,
|
||||
body: sanitizeAgentChatBody(body)
|
||||
body: sanitizeAgentChatBody(body, { httpStatus: response.status() })
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1894,7 +1887,7 @@ export async function runDevCloudWorkbenchLocalAgentFixtureSmoke() {
|
||||
{ timeout: 8000 }
|
||||
);
|
||||
const ui = await inspectJourneyUi(page);
|
||||
const responseSummary = sanitizeAgentChatBody(responseBody);
|
||||
const responseSummary = sanitizeAgentChatBody(responseBody, { httpStatus: response.status() });
|
||||
const pass =
|
||||
response.ok() &&
|
||||
responseSummary?.status === "completed" &&
|
||||
|
||||
Reference in New Issue
Block a user