fix: rebuild codex client on provider profile switch
This commit is contained in:
@@ -804,6 +804,66 @@ test("Code Agent PC gateway prompt reaches Codex stdio instead of internal hardw
|
||||
}
|
||||
});
|
||||
|
||||
test("Codex stdio manager rebuilds app-server client when provider profile config changes", async () => {
|
||||
const calls = [];
|
||||
const createdModels = [];
|
||||
const closedModels = [];
|
||||
const fakeCodex = await createFakeCodexCommand();
|
||||
const codexHome = await prepareFakeCodexHome();
|
||||
const baseEnv = {
|
||||
PATH: process.env.PATH,
|
||||
OPENAI_API_KEY: "test-openai-key-material",
|
||||
CODEX_HOME: codexHome,
|
||||
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
|
||||
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()
|
||||
};
|
||||
const manager = createCodexStdioSessionManager({
|
||||
idFactory: () => `ses_profile_${createdModels.length + 1}`,
|
||||
createRpcClient: async ({ env }) => {
|
||||
const model = env.HWLAB_CODE_AGENT_MODEL;
|
||||
createdModels.push(model);
|
||||
const client = createFakeAppServerClient({ calls, responses: [`reply from ${model}`] });
|
||||
client.close = () => closedModels.push(model);
|
||||
return client;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await manager.chat({
|
||||
conversationId: "cnv_profile_deepseek",
|
||||
traceId: "trc_profile_deepseek",
|
||||
message: "first",
|
||||
env: {
|
||||
...baseEnv,
|
||||
HWLAB_CODE_AGENT_MODEL: "deepseek-chat",
|
||||
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://hwlab-deepseek-proxy.hwlab-dev.svc.cluster.local:4000/v1/responses"
|
||||
}
|
||||
});
|
||||
await manager.chat({
|
||||
conversationId: "cnv_profile_codex",
|
||||
traceId: "trc_profile_codex",
|
||||
message: "second",
|
||||
env: {
|
||||
...baseEnv,
|
||||
HWLAB_CODE_AGENT_MODEL: "gpt-5.5",
|
||||
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://172.26.26.227:17680/v1/responses"
|
||||
}
|
||||
});
|
||||
|
||||
assert.deepEqual(createdModels, ["deepseek-chat", "gpt-5.5"]);
|
||||
assert.deepEqual(closedModels, ["deepseek-chat"]);
|
||||
assert.equal(calls.filter((call) => call.method === "initialize").length, 2);
|
||||
assert.deepEqual(calls.filter((call) => call.method === "turn/start").map((call) => call.args.model), ["deepseek-chat", "gpt-5.5"]);
|
||||
} finally {
|
||||
await rm(fakeCodex.root, { recursive: true, force: true });
|
||||
await rm(codexHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("Code Agent Keil gateway prompt is not blocked by M3 IO intent guard", async () => {
|
||||
const calls = [];
|
||||
let providerCalled = false;
|
||||
|
||||
@@ -112,6 +112,7 @@ export function createCodexStdioSessionManager(options = {}) {
|
||||
const sessions = new Map();
|
||||
const conversations = new Map();
|
||||
let rpcClient = options.rpcClient ?? null;
|
||||
let rpcClientSignature = options.rpcClient ? "injected" : null;
|
||||
let rpcStartedAt = null;
|
||||
let rpcInitialized = false;
|
||||
let protocolProbe = null;
|
||||
@@ -964,18 +965,30 @@ export function createCodexStdioSessionManager(options = {}) {
|
||||
}
|
||||
|
||||
async function ensureRpcClient({ env, availability, timeoutMs } = {}) {
|
||||
if (rpcClient && typeof rpcClient.startTurn === "function") return rpcClient;
|
||||
const args = codexAppServerArgs(env);
|
||||
const childEnv = childProcessEnv(env);
|
||||
const nextSignature = rpcClientConfigSignature({ availability, args, childEnv });
|
||||
if (rpcClient && typeof rpcClient.startTurn === "function" && rpcClientSignature === nextSignature) return rpcClient;
|
||||
if (rpcClient && rpcClientSignature !== nextSignature && typeof rpcClient.close === "function") {
|
||||
rpcClient.close();
|
||||
}
|
||||
if (rpcClientSignature !== nextSignature) {
|
||||
rpcClient = null;
|
||||
rpcInitialized = false;
|
||||
rpcClientSignature = null;
|
||||
}
|
||||
rpcClient = options.createRpcClient
|
||||
? await options.createRpcClient({ env, availability })
|
||||
: createCodexAppServerJsonLineClient({
|
||||
command: availability.command,
|
||||
args: codexAppServerArgs(env),
|
||||
env: childProcessEnv(env),
|
||||
args,
|
||||
env: childEnv,
|
||||
cwd: availability.workspace
|
||||
});
|
||||
if (typeof rpcClient.initialize === "function") {
|
||||
await rpcClient.initialize(effectiveTimeout(timeoutMs));
|
||||
}
|
||||
rpcClientSignature = nextSignature;
|
||||
rpcInitialized = true;
|
||||
rpcStartedAt = timestampFor(nowDefault);
|
||||
return rpcClient;
|
||||
@@ -3550,6 +3563,15 @@ function codexProviderNoProxyEntries(env = process.env) {
|
||||
}
|
||||
}
|
||||
|
||||
function rpcClientConfigSignature({ availability, args = [], childEnv = {} } = {}) {
|
||||
return JSON.stringify({
|
||||
command: availability?.command ?? null,
|
||||
workspace: availability?.workspace ?? null,
|
||||
codexHome: childEnv.CODEX_HOME ?? null,
|
||||
args
|
||||
});
|
||||
}
|
||||
|
||||
function mergeNoProxy(...parts) {
|
||||
const entries = [];
|
||||
const seen = new Set();
|
||||
|
||||
Reference in New Issue
Block a user