Merge pull request #338 from ComposioHQ/session/ao-3
fix: suppress codex update prompt in non-interactive agent sessions
This commit is contained in:
commit
767495ff84
|
|
@ -0,0 +1,45 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import type { AgentLaunchConfig } from "@composio/ao-core";
|
||||
import codexPlugin from "@composio/ao-plugin-agent-codex";
|
||||
|
||||
function makeLaunchConfig(overrides: Partial<AgentLaunchConfig> = {}): AgentLaunchConfig {
|
||||
return {
|
||||
sessionId: "sess-int-1",
|
||||
projectConfig: {
|
||||
name: "my-project",
|
||||
repo: "owner/repo",
|
||||
path: "/workspace/repo",
|
||||
defaultBranch: "main",
|
||||
sessionPrefix: "my",
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("agent-codex launch/env wiring (integration)", () => {
|
||||
const agent = codexPlugin.create();
|
||||
|
||||
it("includes check_for_update_on_startup=false in launch command", () => {
|
||||
const cmd = agent.getLaunchCommand(makeLaunchConfig());
|
||||
expect(cmd).toContain("-c check_for_update_on_startup=false");
|
||||
});
|
||||
|
||||
it("preserves update-check override alongside other flags", () => {
|
||||
const cmd = agent.getLaunchCommand(
|
||||
makeLaunchConfig({
|
||||
permissions: "default",
|
||||
model: "o3-mini",
|
||||
prompt: "Do the thing",
|
||||
}),
|
||||
);
|
||||
expect(cmd).toContain("-c check_for_update_on_startup=false");
|
||||
expect(cmd).not.toContain("--ask-for-approval");
|
||||
expect(cmd).toContain("--model 'o3-mini'");
|
||||
expect(cmd).toContain("-c model_reasoning_effort=high");
|
||||
});
|
||||
|
||||
it("sets CODEX_DISABLE_UPDATE_CHECK=1 in environment", () => {
|
||||
const env = agent.getEnvironment(makeLaunchConfig());
|
||||
expect(env["CODEX_DISABLE_UPDATE_CHECK"]).toBe("1");
|
||||
});
|
||||
});
|
||||
|
|
@ -210,7 +210,7 @@ describe("getLaunchCommand", () => {
|
|||
const agent = create();
|
||||
|
||||
it("generates base command", () => {
|
||||
expect(agent.getLaunchCommand(makeLaunchConfig())).toBe("'codex'");
|
||||
expect(agent.getLaunchCommand(makeLaunchConfig())).toBe("'codex' -c check_for_update_on_startup=false");
|
||||
});
|
||||
|
||||
it("includes bypass flag when permissions=permissionless", () => {
|
||||
|
|
@ -258,7 +258,7 @@ describe("getLaunchCommand", () => {
|
|||
const cmd = agent.getLaunchCommand(
|
||||
makeLaunchConfig({ permissions: "permissionless", model: "o3", prompt: "Go" }),
|
||||
);
|
||||
expect(cmd).toBe("'codex' --dangerously-bypass-approvals-and-sandbox --model 'o3' -c model_reasoning_effort=high -- 'Go'");
|
||||
expect(cmd).toBe("'codex' -c check_for_update_on_startup=false --dangerously-bypass-approvals-and-sandbox --model 'o3' -c model_reasoning_effort=high -- 'Go'");
|
||||
});
|
||||
|
||||
it("escapes single quotes in prompt (POSIX shell escaping)", () => {
|
||||
|
|
@ -297,10 +297,15 @@ describe("getLaunchCommand", () => {
|
|||
expect(cmd).not.toContain("--dangerously-bypass-approvals-and-sandbox");
|
||||
expect(cmd).not.toContain("--ask-for-approval");
|
||||
expect(cmd).not.toContain("--model");
|
||||
expect(cmd).not.toContain("-c");
|
||||
expect(cmd).toContain("-c check_for_update_on_startup=false");
|
||||
expect(cmd).not.toContain("model_reasoning_effort");
|
||||
});
|
||||
|
||||
it("always includes -c check_for_update_on_startup=false", () => {
|
||||
const cmd = agent.getLaunchCommand(makeLaunchConfig({ model: "gpt-4o", prompt: "Fix it" }));
|
||||
expect(cmd).toContain("-c check_for_update_on_startup=false");
|
||||
});
|
||||
|
||||
// -- Reasoning effort tests --
|
||||
describe("reasoning effort", () => {
|
||||
it("adds model_reasoning_effort=high for o3 model", () => {
|
||||
|
|
@ -377,6 +382,11 @@ describe("getEnvironment", () => {
|
|||
expect(env["PATH"]?.startsWith("/mock/home/.ao/bin:")).toBe(true);
|
||||
});
|
||||
|
||||
it("sets CODEX_DISABLE_UPDATE_CHECK=1 to suppress interactive update prompts", () => {
|
||||
const env = agent.getEnvironment(makeLaunchConfig());
|
||||
expect(env["CODEX_DISABLE_UPDATE_CHECK"]).toBe("1");
|
||||
});
|
||||
|
||||
it("falls back to /usr/bin:/bin when process.env.PATH is undefined", () => {
|
||||
const originalPath = process.env["PATH"];
|
||||
delete process.env["PATH"];
|
||||
|
|
@ -965,6 +975,7 @@ describe("getRestoreCommand", () => {
|
|||
|
||||
expect(cmd).not.toBeNull();
|
||||
expect(cmd).toContain("'codex' resume");
|
||||
expect(cmd).toContain("-c check_for_update_on_startup=false");
|
||||
expect(cmd).toContain("thread-abc-123");
|
||||
});
|
||||
|
||||
|
|
@ -1236,13 +1247,13 @@ describe("postLaunchSetup", () => {
|
|||
mockReadFile.mockRejectedValue(new Error("ENOENT"));
|
||||
|
||||
// Before postLaunchSetup, binary is "codex"
|
||||
expect(agent.getLaunchCommand(makeLaunchConfig())).toBe("'codex'");
|
||||
expect(agent.getLaunchCommand(makeLaunchConfig())).toBe("'codex' -c check_for_update_on_startup=false");
|
||||
|
||||
// After postLaunchSetup resolves the binary
|
||||
await agent.postLaunchSetup!(makeSession({ workspacePath: "/workspace/test" }));
|
||||
|
||||
// Now getLaunchCommand should use the resolved binary
|
||||
expect(agent.getLaunchCommand(makeLaunchConfig())).toBe("'/opt/bin/codex'");
|
||||
expect(agent.getLaunchCommand(makeLaunchConfig())).toBe("'/opt/bin/codex' -c check_for_update_on_startup=false");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -548,6 +548,11 @@ function appendModelFlags(parts: string[], model: string | undefined): void {
|
|||
}
|
||||
}
|
||||
|
||||
/** Disable Codex startup update checks/prompts in non-interactive sessions */
|
||||
function appendNoUpdateCheckFlag(parts: string[]): void {
|
||||
parts.push("-c", "check_for_update_on_startup=false");
|
||||
}
|
||||
|
||||
/** TTL for session file path cache (ms). Prevents redundant filesystem scans
|
||||
* when getActivityState and getSessionInfo are called in the same refresh cycle. */
|
||||
const SESSION_FILE_CACHE_TTL_MS = 30_000;
|
||||
|
|
@ -580,6 +585,7 @@ function createCodexAgent(): Agent {
|
|||
getLaunchCommand(config: AgentLaunchConfig): string {
|
||||
const binary = resolvedBinary ?? "codex";
|
||||
const parts: string[] = [shellEscape(binary)];
|
||||
appendNoUpdateCheckFlag(parts);
|
||||
|
||||
appendApprovalFlags(parts, config.permissions);
|
||||
appendModelFlags(parts, config.model);
|
||||
|
|
@ -613,6 +619,8 @@ function createCodexAgent(): Agent {
|
|||
// The wrappers strip this directory from PATH before calling the real
|
||||
// binary, so there's no infinite recursion.
|
||||
env["PATH"] = `${AO_BIN_DIR}:${process.env["PATH"] ?? "/usr/bin:/bin"}`;
|
||||
// Disable Codex's version check/update prompt for non-interactive AO sessions.
|
||||
env["CODEX_DISABLE_UPDATE_CHECK"] = "1";
|
||||
|
||||
return env;
|
||||
},
|
||||
|
|
@ -769,6 +777,7 @@ function createCodexAgent(): Agent {
|
|||
// Flags are placed before the positional threadId for CLI parser compatibility.
|
||||
const binary = resolvedBinary ?? "codex";
|
||||
const parts: string[] = [shellEscape(binary), "resume"];
|
||||
appendNoUpdateCheckFlag(parts);
|
||||
|
||||
appendApprovalFlags(parts, project.agentConfig?.permissions);
|
||||
const effectiveModel = (project.agentConfig?.model ?? data.model) as string | undefined;
|
||||
|
|
|
|||
Loading…
Reference in New Issue