mirror of
https://github.com/openai/codex.git
synced 2026-08-23 13:09:46 +00:00
Allow exec callers to classify new threads (#40161)
## What changed - Add a global `codex exec --thread-source <SOURCE>` option and propagate it to newly created and forked threads. - Default the source to `user` when the option is omitted. - Expose the classification as `threadSource` in the TypeScript SDK. It applies when a thread is first created and does not override the source when resuming an existing thread. ## Testing - Cover CLI parsing and persisted metadata for new, resumed, and forked threads. - Verify that the TypeScript SDK forwards `threadSource` only for new threads. GitOrigin-RevId: 67a55a2b1f91b3a88f946c2af1c2a0989abb3130
This commit is contained in:
@@ -13,6 +13,8 @@ export type CodexExecArgs = {
|
||||
baseUrl?: string;
|
||||
apiKey?: string;
|
||||
threadId?: string | null;
|
||||
// --thread-source; only applies when creating a new thread
|
||||
threadSource?: string;
|
||||
images?: string[];
|
||||
// --model
|
||||
model?: string;
|
||||
@@ -112,6 +114,10 @@ export class CodexExec {
|
||||
commandArgs.push("--model", args.model);
|
||||
}
|
||||
|
||||
if (args.threadSource !== undefined && !args.threadId) {
|
||||
commandArgs.push("--thread-source", args.threadSource);
|
||||
}
|
||||
|
||||
if (args.sandboxMode) {
|
||||
commandArgs.push("--sandbox", args.sandboxMode);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ export class Thread {
|
||||
threadId: this._id,
|
||||
images,
|
||||
model: options?.model,
|
||||
threadSource: options?.threadSource,
|
||||
sandboxMode: options?.sandboxMode,
|
||||
workingDirectory: options?.workingDirectory,
|
||||
skipGitRepoCheck: options?.skipGitRepoCheck,
|
||||
|
||||
@@ -15,6 +15,8 @@ export type WebSearchMode = "disabled" | "cached" | "live";
|
||||
|
||||
export type ThreadOptions = {
|
||||
model?: string;
|
||||
/** Source classification applied when this thread is first created. */
|
||||
threadSource?: string;
|
||||
sandboxMode?: SandboxMode;
|
||||
workingDirectory?: string;
|
||||
skipGitRepoCheck?: boolean;
|
||||
|
||||
@@ -185,6 +185,31 @@ describe("CodexExec", () => {
|
||||
},
|
||||
);
|
||||
|
||||
it("passes the thread source when starting a new thread", async () => {
|
||||
const { CodexExec } = await import("../src/exec");
|
||||
spawnMock.mockClear();
|
||||
const child = new FakeChildProcess();
|
||||
spawnMock.mockReturnValue(child as unknown as child_process.ChildProcess);
|
||||
|
||||
setImmediate(() => {
|
||||
child.stdout.end();
|
||||
child.stderr.end();
|
||||
child.emit("exit", 0, null);
|
||||
});
|
||||
|
||||
const exec = new CodexExec("codex");
|
||||
for await (const _ of exec.run({ input: "hi", threadSource: "automated_review" })) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
expect(spawnMock.mock.calls[0]?.[1]).toEqual([
|
||||
"exec",
|
||||
"--experimental-json",
|
||||
"--thread-source",
|
||||
"automated_review",
|
||||
]);
|
||||
});
|
||||
|
||||
it("lets SDK-managed and thread settings override raw configuration when resuming", async () => {
|
||||
const { CodexExec } = await import("../src/exec");
|
||||
spawnMock.mockClear();
|
||||
@@ -205,6 +230,7 @@ describe("CodexExec", () => {
|
||||
for await (const _ of exec.run({
|
||||
input: "resume with overrides",
|
||||
threadId: "thread-id",
|
||||
threadSource: "should_not_override",
|
||||
baseUrl: "https://managed.example.test",
|
||||
approvalPolicy: "on-request",
|
||||
networkAccessEnabled: false,
|
||||
|
||||
@@ -202,6 +202,7 @@ describe("Codex", () => {
|
||||
try {
|
||||
const thread = client.startThread({
|
||||
model: "gpt-test-1",
|
||||
threadSource: "automated_review",
|
||||
sandboxMode: "workspace-write",
|
||||
});
|
||||
await thread.run("apply options");
|
||||
@@ -216,6 +217,11 @@ describe("Codex", () => {
|
||||
|
||||
expectPair(commandArgs, ["--sandbox", "workspace-write"]);
|
||||
expectPair(commandArgs, ["--model", "gpt-test-1"]);
|
||||
expectPair(commandArgs, ["--thread-source", "automated_review"]);
|
||||
const metadata = JSON.parse(payload!.headers["x-codex-turn-metadata"] as string) as {
|
||||
thread_source?: string;
|
||||
};
|
||||
expect(metadata.thread_source).toBe("automated_review");
|
||||
} finally {
|
||||
cleanup();
|
||||
restore();
|
||||
|
||||
Reference in New Issue
Block a user