Skip to content

Commit 40ac5e7

Browse files
committed
Stream Codex agent events to stdout for visibility
1 parent cf3b482 commit 40ac5e7

1 file changed

Lines changed: 38 additions & 14 deletions

File tree

codegen-llm/src/codegen.ts

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Codex } from "@openai/codex-sdk";
1+
import { Codex, type ThreadEvent } from "@openai/codex-sdk";
22
import { execSync } from "node:child_process";
33
import * as fs from "node:fs";
44
import * as os from "node:os";
@@ -77,20 +77,10 @@ export async function runCodegen(opts: CodegenOptions): Promise<void> {
7777
log(opts, `Prompt length: ${prompt.length} chars`);
7878
}
7979

80-
const turn = await thread.run(prompt);
80+
const { events } = await thread.runStreamed(prompt);
8181

82-
if (opts.verbose && turn.finalResponse) {
83-
log(
84-
opts,
85-
`Agent response (truncated): ${turn.finalResponse.slice(0, 500)}`,
86-
);
87-
}
88-
89-
if (turn.usage) {
90-
log(
91-
opts,
92-
`Token usage -- input: ${turn.usage.input_tokens}, output: ${turn.usage.output_tokens}`,
93-
);
82+
for await (const event of events) {
83+
printEvent(event, opts);
9484
}
9585

9686
// Run verification ourselves to confirm state.
@@ -269,3 +259,37 @@ function log(opts: CodegenOptions, msg: string): void {
269259
console.log(msg);
270260
}
271261
}
262+
263+
function printEvent(event: ThreadEvent, opts: CodegenOptions): void {
264+
switch (event.type) {
265+
case "item.completed": {
266+
const item = event.item;
267+
if (item.type === "agent_message") {
268+
console.log(`\n[agent] ${item.text}\n`);
269+
} else if (item.type === "command_execution") {
270+
const cmd = "command" in item ? String(item.command) : "";
271+
const exit = "exit_code" in item ? item.exit_code : undefined;
272+
console.log(`[exec] ${cmd} (exit ${exit ?? "?"})`);
273+
} else if (item.type === "file_change") {
274+
const file = "path" in item ? String(item.path) : "";
275+
console.log(`[file] ${file}`);
276+
} else if (item.type === "reasoning" && opts.verbose) {
277+
const text = "text" in item ? String(item.text) : "";
278+
console.log(`[think] ${text.slice(0, 200)}`);
279+
}
280+
break;
281+
}
282+
case "turn.completed":
283+
if (event.usage) {
284+
console.log(
285+
`[usage] input: ${event.usage.input_tokens}, output: ${event.usage.output_tokens}`,
286+
);
287+
}
288+
break;
289+
case "turn.failed":
290+
console.error(`[error] ${event.error.message}`);
291+
break;
292+
default:
293+
break;
294+
}
295+
}

0 commit comments

Comments
 (0)