fix: route Keil gateway prompts to Codex stdio (#471)

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Lyon
2026-05-24 22:31:41 +08:00
committed by GitHub
parent bc2e6304a3
commit 4d478a1646
2 changed files with 81 additions and 0 deletions
+14
View File
@@ -2202,6 +2202,12 @@ function detectReadOnlyRunnerIntent(message, options = {}) {
reason: "Code Agent 安全边界不读取或输出 secret、token、kubeconfig、密码、私钥或环境变量原文。"
};
}
if (isPcGatewayCodexToolRequest(text)) {
return {
kind: "none",
toolName: "codex-stdio.pc-gateway-wrapper"
};
}
const m3IoIntent = detectM3IoIntent(text);
if (m3IoIntent) {
return m3IoIntent;
@@ -2221,6 +2227,14 @@ function detectReadOnlyRunnerIntent(message, options = {}) {
return { kind: "none" };
}
function isPcGatewayCodexToolRequest(text) {
const value = String(text ?? "");
const mentionsGatewayTool = /(?:\/app\/tools\/hwlab-gateway-shell\.mjs|hwlab-gateway-shell\.mjs|hardware\.invoke\.shell|PC\s*gateway|gws_DESKTOP-[A-Z0-9-]+|cap_windows_cmd_exec|res_windows_host)/iu.test(value);
const mentionsWindowsCommand = /(?:Windows\s+cmd|cmd\s*\/c|shell\.exec|hostname|PowerShell|powershell)/iu.test(value);
const mentionsWindowsSkill = /(?:C:\\Users\\liang\\\.agents\\skills|\.agents[\\/]+skills|keil-cli\.py|\bKeil\b|MDK-ARM|\.uvprojx|F:\\Work\\constart|job-status)/iu.test(value);
return mentionsGatewayTool && (mentionsWindowsCommand || mentionsWindowsSkill);
}
function detectExternalNetworkIntent(text) {
const value = String(text ?? "").trim();
if (!value) return null;
@@ -1889,6 +1889,73 @@ test("Code Agent PC gateway prompt reaches Codex stdio instead of internal hardw
}
});
test("Code Agent Keil gateway prompt is not blocked by M3 IO intent guard", async () => {
const calls = [];
let providerCalled = false;
const fakeCodex = await createFakeCodexCommand();
const codexHome = await prepareFakeCodexHome();
const registry = createCodeAgentSessionRegistry();
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_keil_gateway_stdio",
createRpcClient: async () => createFakeAppServerClient({
calls,
responses: ["已通过 PC gateway 调用 Windows Keil skillsuccess=truereturn_code=0,生成 FREQ_Controller_FW.hex。"]
})
});
try {
const payload = await handleCodeAgentChat(
{
conversationId: "cnv_keil_gateway_stdio",
traceId: "trc_keil_gateway_stdio",
projectId: "prj_mvp_topology",
message: String.raw`请用 /app/tools/hwlab-gateway-shell.mjs 通过 PC gateway 调用 Windows cmd,进入 C:\Users\liang\.agents\skills\keil,然后运行 py -3 keil-cli.py build -p "F:\Work\constart\projects\71-00075-11\FirmWare\MDK-ARM\FREQ_Controller_FW.uvprojx" -t FREQ_Controller_FW;如果返回 job id,请用 py -3 keil-cli.py job-status <job_id> 轮询到终态。`
},
{
now: () => "2026-05-24T14:35:00.000Z",
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_SANDBOX: "danger-full-access",
HWLAB_CODE_AGENT_WORKSPACE: process.cwd(),
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://172.26.26.227:17680/v1/responses"
},
sessionRegistry: registry,
codexStdioManager: manager,
callProvider: async () => {
providerCalled = true;
throw new Error("text fallback must not be used");
},
m3IoSkillRequestJson: async () => {
throw new Error("Keil gateway prompt must not be routed to M3 IO");
}
}
);
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.responseType, undefined);
assert.notEqual(payload.capabilityLevel, HWLAB_M3_IO_CAPABILITY_LEVELS.blocked);
assert.equal(providerCalled, false);
const turn = calls.find((call) => call.method === "turn/start");
assert.ok(turn, "Codex stdio turn/start should be called");
assert.match(turn.args.prompt, /\/app\/tools\/hwlab-gateway-shell\.mjs/u);
assert.match(turn.args.prompt, /keil-cli\.py build/u);
assert.match(turn.args.prompt, /job-status/u);
assert.match(turn.args.prompt, /FREQ_Controller_FW\.uvprojx/u);
} finally {
await rm(fakeCodex.root, { recursive: true, force: true });
await rm(codexHome, { recursive: true, force: true });
}
});
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}