mirror of
https://github.com/openai/codex.git
synced 2026-04-24 22:54:54 +00:00
feat: make it possible to specify --config flags in the SDK (#10003)
Updates the `CodexOptions` passed to the `Codex()` constructor in the
SDK to support a `config` property that is a map of configuration data
that will be transformed into `--config` flags passed to the invocation
of `codex`.
Therefore, something like this:
```typescript
const codex = new Codex({
config: {
show_raw_agent_reasoning: true,
sandbox_workspace_write: { network_access: true },
},
});
```
would result in the following args being added to the invocation of
`codex`:
```shell
--config show_raw_agent_reasoning=true --config sandbox_workspace_write.network_access=true
```
This commit is contained in:
@@ -410,6 +410,86 @@ describe("Codex", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("passes CodexOptions config overrides as TOML --config flags", async () => {
|
||||
const { url, close } = await startResponsesTestProxy({
|
||||
statusCode: 200,
|
||||
responseBodies: [
|
||||
sse(
|
||||
responseStarted("response_1"),
|
||||
assistantMessage("Config overrides applied", "item_1"),
|
||||
responseCompleted("response_1"),
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
const { args: spawnArgs, restore } = codexExecSpy();
|
||||
|
||||
try {
|
||||
const client = new Codex({
|
||||
codexPathOverride: codexExecPath,
|
||||
baseUrl: url,
|
||||
apiKey: "test",
|
||||
config: {
|
||||
approval_policy: "never",
|
||||
sandbox_workspace_write: { network_access: true },
|
||||
retry_budget: 3,
|
||||
tool_rules: { allow: ["git status", "git diff"] },
|
||||
},
|
||||
});
|
||||
|
||||
const thread = client.startThread();
|
||||
await thread.run("apply config overrides");
|
||||
|
||||
const commandArgs = spawnArgs[0];
|
||||
expect(commandArgs).toBeDefined();
|
||||
expectPair(commandArgs, ["--config", 'approval_policy="never"']);
|
||||
expectPair(commandArgs, ["--config", "sandbox_workspace_write.network_access=true"]);
|
||||
expectPair(commandArgs, ["--config", "retry_budget=3"]);
|
||||
expectPair(commandArgs, ["--config", 'tool_rules.allow=["git status", "git diff"]']);
|
||||
} finally {
|
||||
restore();
|
||||
await close();
|
||||
}
|
||||
});
|
||||
|
||||
it("lets thread options override CodexOptions config overrides", async () => {
|
||||
const { url, close } = await startResponsesTestProxy({
|
||||
statusCode: 200,
|
||||
responseBodies: [
|
||||
sse(
|
||||
responseStarted("response_1"),
|
||||
assistantMessage("Thread overrides applied", "item_1"),
|
||||
responseCompleted("response_1"),
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
const { args: spawnArgs, restore } = codexExecSpy();
|
||||
|
||||
try {
|
||||
const client = new Codex({
|
||||
codexPathOverride: codexExecPath,
|
||||
baseUrl: url,
|
||||
apiKey: "test",
|
||||
config: { approval_policy: "never" },
|
||||
});
|
||||
|
||||
const thread = client.startThread({ approvalPolicy: "on-request" });
|
||||
await thread.run("override approval policy");
|
||||
|
||||
const commandArgs = spawnArgs[0];
|
||||
const approvalPolicyOverrides = collectConfigValues(commandArgs, "approval_policy");
|
||||
expect(approvalPolicyOverrides).toEqual([
|
||||
'approval_policy="never"',
|
||||
'approval_policy="on-request"',
|
||||
]);
|
||||
expect(approvalPolicyOverrides.at(-1)).toBe('approval_policy="on-request"');
|
||||
} finally {
|
||||
restore();
|
||||
await close();
|
||||
}
|
||||
});
|
||||
|
||||
it("allows overriding the env passed to the Codex CLI", async () => {
|
||||
const { url, close } = await startResponsesTestProxy({
|
||||
statusCode: 200,
|
||||
@@ -737,13 +817,37 @@ describe("Codex", () => {
|
||||
}
|
||||
}, 10000); // TODO(pakrym): remove timeout
|
||||
});
|
||||
|
||||
/**
|
||||
* Given a list of args to `codex` and a `key`, collects all `--config`
|
||||
* overrides for that key.
|
||||
*/
|
||||
function collectConfigValues(args: string[] | undefined, key: string): string[] {
|
||||
if (!args) {
|
||||
throw new Error("args is undefined");
|
||||
}
|
||||
|
||||
const values: string[] = [];
|
||||
for (let i = 0; i < args.length; i += 1) {
|
||||
if (args[i] !== "--config") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const override = args[i + 1];
|
||||
if (override?.startsWith(`${key}=`)) {
|
||||
values.push(override);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
function expectPair(args: string[] | undefined, pair: [string, string]) {
|
||||
if (!args) {
|
||||
throw new Error("Args is undefined");
|
||||
throw new Error("args is undefined");
|
||||
}
|
||||
const index = args.indexOf(pair[0]);
|
||||
const index = args.findIndex((arg, i) => arg === pair[0] && args[i + 1] === pair[1]);
|
||||
if (index === -1) {
|
||||
throw new Error(`Pair ${pair[0]} not found in args`);
|
||||
throw new Error(`Pair ${pair[0]} ${pair[1]} not found in args`);
|
||||
}
|
||||
expect(args[index + 1]).toBe(pair[1]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user