fix: cover code agent m3 hwlab api requests

This commit is contained in:
Code Queue Review
2026-05-23 23:50:30 +00:00
parent 034c90763c
commit c368f4d91f
3 changed files with 102 additions and 10 deletions
+8 -8
View File
@@ -2582,25 +2582,25 @@ function m3IoApiBaseUrlMissingBlocker({ route = HWLAB_M3_IO_API_ROUTE } = {}) {
function m3IoSkillReply(skillResult) {
const lines = [
`M3 IO Skill CLI result: status=${skillResult.status}; accepted=${skillResult.accepted}; route=${skillResult.route}; traceId=${skillResult.traceId}; operationId=${skillResult.operationId ?? "null"}.`
`M3 IO Skill CLI result: 已通过 Code Agent -> Skill CLI -> HWLAB API ${skillResult.route} 处理请求;status=${skillResult.status}; accepted=${skillResult.accepted}; traceId=${skillResult.traceId}; operationId=${skillResult.operationId ?? "null"}`
];
if (skillResult.audit?.summary) {
lines.push(`Audit: ${skillResult.audit.summary}.`);
lines.push(`Audit: ${skillResult.audit.summary}audit 摘要)。`);
}
if (skillResult.evidence?.summary) {
lines.push(`Evidence: ${skillResult.evidence.summary}.`);
lines.push(`Evidence: ${skillResult.evidence.summary}evidence 摘要)。`);
}
if (skillResult.blocker) {
lines.push(`Blocker: ${skillResult.blocker.code}; ${skillResult.blocker.zh ?? skillResult.blocker.message}.`);
lines.push(`Blocker: ${skillResult.blocker.code}; ${skillResult.blocker.zh ?? skillResult.blocker.message}blocker)。`);
}
if (skillResult.action === "do.write") {
lines.push(`DO1 requested value=${String(skillResult.command?.value)}; DI1 readback=${String(skillResult.result?.targetReadback?.value ?? "unknown")}.`);
lines.push(`DO1 写入请求:res_boxsimu_1:DO1=${String(skillResult.command?.value)}DI1 readbackres_boxsimu_2:DI1=${String(skillResult.result?.targetReadback?.value ?? "unknown")}`);
} else if (skillResult.action === "di.read") {
lines.push(`DI1 value=${String(skillResult.result?.value ?? "unknown")}.`);
lines.push(`DI1 读取结果:res_boxsimu_2:DI1=${String(skillResult.result?.value ?? "unknown")}`);
} else if (skillResult.readonly === true || skillResult.route === HWLAB_M3_STATUS_API_ROUTE) {
lines.push(`M3 status readback DI1=${String(skillResult.readback?.value ?? "unknown")}; readiness=${skillResult.readiness?.status ?? "unknown"}.`);
lines.push(`M3 status readbackres_boxsimu_2:DI1=${String(skillResult.readback?.value ?? "unknown")}readiness=${skillResult.readiness?.status ?? "unknown"}`);
}
lines.push(`Boundary: Code Agent -> Skill CLI -> HWLAB API ${skillResult.route}; no direct gateway/box/patch-panel call; no OpenAI fallback used. This is source/artifact control capability, not DEV-LIVE verification.`);
lines.push(`Boundary/边界:本次只走 Code Agent -> Skill CLI -> HWLAB API ${skillResult.route};没有直连 gateway/box/patch-panel,也没有使用 OpenAI fallback 冒充 toolCall。这是受控操作结果,不是 M3 DEV-LIVE 验收结论。`);
return boundToolOutput(lines.join("\n"), READONLY_TOOL_OUTPUT_LIMIT).text;
}
+7 -1
View File
@@ -2360,7 +2360,7 @@ test("cloud api /v1/agent/chat routes M3 IO through Skill CLI to /v1/m3/io only"
},
body: JSON.stringify({
conversationId: "cnv_server-test-m3-skill",
message: "通过 M3 DO1 写 false并回读 DI1"
message: "通过 HWLAB API 把 res_boxsimu_1 的 DO1 写 false然后读取 res_boxsimu_2 的 DI1"
})
});
assert.equal(response.status, 200);
@@ -2381,6 +2381,9 @@ test("cloud api /v1/agent/chat routes M3 IO through Skill CLI to /v1/m3/io only"
assert.equal(payload.providerTrace.fallbackUsed, false);
assert.equal(payload.providerTrace.method, "POST");
assert.equal(payload.providerTrace.readback.value, false);
assert.match(payload.reply.content, /HWLAB API \/v1\/m3\/io/u);
assert.match(payload.reply.content, /res_boxsimu_1:DO1=false/u);
assert.match(payload.reply.content, /res_boxsimu_2:DI1=false/u);
assert.equal(payload.runner.safety.directGatewayCallsAllowed, false);
assert.equal(payload.runner.safety.directBoxSimuCallsAllowed, false);
assert.equal(payload.runner.safety.directPatchPanelCallsAllowed, false);
@@ -2478,6 +2481,9 @@ test("cloud api /v1/agent/chat routes Codex stdio M3 request through in-process
assert.equal(payload.runnerTrace.route, "/v1/m3/io");
assert.equal(payload.providerTrace.codexStdio, true);
assert.equal(payload.providerTrace.fallbackUsed, false);
assert.match(payload.reply.content, /HWLAB API \/v1\/m3\/io/u);
assert.match(payload.reply.content, /res_boxsimu_1:DO1=true/u);
assert.match(payload.reply.content, /res_boxsimu_2:DI1=true/u);
assert.ok(payload.runner.toolPolicy.allowed.includes("POST /v1/m3/io"));
assert.deepEqual(gatewayCalls.map((call) => new URL(call.url).pathname), [
"/status",
+87 -1
View File
@@ -510,7 +510,7 @@ async function runLocalContractSmoke() {
{
conversationId: "cnv_code-agent-chat-m3-skill",
traceId: "trc_code-agent-chat-m3-skill",
message: "通过 M3 DO1 写 true并回读 DI1"
message: "通过 HWLAB API 把 res_boxsimu_1 的 DO1 写 true然后读取 res_boxsimu_2 的 DI1"
},
{
now: () => "2026-05-22T00:04:55.000Z",
@@ -583,13 +583,99 @@ async function runLocalContractSmoke() {
assert.equal(m3SkillWrite.providerTrace.method, "POST");
assert.equal(m3SkillWrite.providerTrace.readback.value, true);
assert.equal(m3SkillWrite.runner.safety.directGatewayCallsAllowed, false);
assert.match(m3SkillWrite.reply.content, /HWLAB API \/v1\/m3\/io/u);
assert.match(m3SkillWrite.reply.content, /res_boxsimu_1:DO1=true/u);
assert.match(m3SkillWrite.reply.content, /res_boxsimu_2:DI1=true/u);
assert.equal(m3SkillCalls.length, 1);
assert.equal(m3SkillCalls[0].url, "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667/v1/m3/io");
assert.equal(m3SkillCalls[0].request.body.action, "do.write");
assert.equal(m3SkillCalls[0].request.body.value, true);
assert.equal(m3SkillCalls[0].url.includes("gateway-simu"), false);
assert.equal(m3SkillCalls[0].url.includes("box-simu"), false);
assert.equal(m3SkillCalls[0].url.includes("patch-panel"), false);
logOk("M3 Skill CLI routes through HWLAB API only");
const m3SkillFalseCalls = [];
const m3SkillWriteFalse = await handleCodeAgentChat(
{
conversationId: "cnv_code-agent-chat-m3-skill-false",
traceId: "trc_code-agent-chat-m3-skill-false",
message: "通过 HWLAB API 把 res_boxsimu_1 的 DO1 写成 false,然后读取 res_boxsimu_2 的 DI1。"
},
{
now: () => "2026-05-22T00:04:56.000Z",
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: process.cwd(),
HWLAB_CODE_AGENT_HWLAB_API_BASE_URL: "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667",
OPENAI_API_KEY: "must-not-be-used"
},
callProvider: async () => {
throw new Error("OpenAI fallback must not be used for M3 IO");
},
m3IoSkillRequestJson: async (url, request) => {
m3SkillFalseCalls.push({ url, request });
return {
ok: true,
status: 200,
body: {
status: "succeeded",
accepted: true,
action: "do.write",
traceId: "trc_code-agent-chat-m3-skill-false",
operationId: "op_m3_do_write_false_smoke",
auditId: "aud_m3_do_write_false_smoke_succeeded",
evidenceId: "evd_m3_do_write_false_smoke_succeeded",
auditState: {
status: "written_non_durable"
},
evidenceState: {
status: "blocked",
sourceKind: "BLOCKED",
blocker: "runtime_durable_not_green",
writeStatus: "written_non_durable"
},
durableStatus: {
status: "degraded",
durable: false,
blocker: "runtime_durable_not_green"
},
result: {
value: false,
targetReadback: {
status: "succeeded",
value: false
}
},
controlPath: {
cloudApi: true,
gatewaySimu: true,
boxSimu: true,
patchPanel: true,
frontendBypass: false
}
}
};
}
}
);
validateCodeAgentChatSchema(m3SkillWriteFalse);
assert.equal(m3SkillWriteFalse.status, "completed");
assert.equal(m3SkillWriteFalse.provider, "hwlab-skill-cli");
assert.equal(m3SkillWriteFalse.toolCalls[0].route, "/v1/m3/io");
assert.equal(m3SkillWriteFalse.toolCalls[0].method, "POST");
assert.equal(m3SkillWriteFalse.toolCalls[0].operationId, "op_m3_do_write_false_smoke");
assert.equal(m3SkillWriteFalse.toolCalls[0].readback.value, false);
assert.equal(m3SkillWriteFalse.providerTrace.fallbackUsed, false);
assert.match(m3SkillWriteFalse.reply.content, /HWLAB API \/v1\/m3\/io/u);
assert.match(m3SkillWriteFalse.reply.content, /res_boxsimu_1:DO1=false/u);
assert.match(m3SkillWriteFalse.reply.content, /res_boxsimu_2:DI1=false/u);
assert.equal(m3SkillFalseCalls.length, 1);
assert.equal(m3SkillFalseCalls[0].url, "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667/v1/m3/io");
assert.equal(m3SkillFalseCalls[0].request.body.action, "do.write");
assert.equal(m3SkillFalseCalls[0].request.body.value, false);
logOk("M3 Skill CLI handles user-direct false request through HWLAB API only");
const directToolCallPayload = JSON.parse(JSON.stringify(m3SkillWrite));
directToolCallPayload.toolCalls[0].hwlabApi = {
route: "/v1/m3/io",