import asyncio from datetime import datetime from agents import Agent, Runner, gen_trace_id, trace # This tool is still in experimental phase and the details could be changed until being GAed. from agents.extensions.experimental.codex import ( CodexToolStreamEvent, CommandExecutionItem, ErrorItem, FileChangeItem, ItemCompletedEvent, ItemStartedEvent, ItemUpdatedEvent, McpToolCallItem, ReasoningItem, ThreadErrorEvent, ThreadOptions, ThreadStartedEvent, TodoListItem, TurnCompletedEvent, TurnFailedEvent, TurnOptions, TurnStartedEvent, WebSearchItem, codex_tool, ) # This example runs the Codex CLI via the Codex tool wrapper. # You can configure the CLI path with CODEX_PATH or CodexOptions(codex_path_override="..."). # codex_tool accepts options as keyword arguments or a plain dict. # For example: codex_tool(sandbox_mode="read-only") or codex_tool({"sandbox_mode": "read-only"}). async def on_codex_stream(payload: CodexToolStreamEvent) -> None: event = payload.event if isinstance(event, ThreadStartedEvent): log(f"codex thread started: {event.thread_id}") return if isinstance(event, TurnStartedEvent): log("codex turn started") return if isinstance(event, TurnCompletedEvent): usage = event.usage log(f"codex turn completed, usage: {usage}") return if isinstance(event, TurnFailedEvent): error = event.error.message log(f"codex turn failed: {error}") return if isinstance(event, ThreadErrorEvent): log(f"codex stream error: {event.message}") return if not isinstance(event, ItemStartedEvent | ItemUpdatedEvent | ItemCompletedEvent): return item = event.item if isinstance(item, ReasoningItem): text = item.text log(f"codex reasoning ({event.type}): {text}") return if isinstance(item, CommandExecutionItem): command = item.command output = item.aggregated_output output_preview = output[-200:] if isinstance(output, str) else "" status = item.status log(f"codex command {event.type}: {command} | status={status} | output={output_preview}") return if isinstance(item, McpToolCallItem): server = item.server tool = item.tool status = item.status log(f"codex mcp {event.type}: {server}.{tool} | status={status}") return if isinstance(item, FileChangeItem): changes = item.changes status = item.status log(f"codex file change {event.type}: {status} | {changes}") return if isinstance(item, WebSearchItem): log(f"codex web search {event.type}: {item.query}") return if isinstance(item, TodoListItem): items = item.items log(f"codex todo list {event.type}: {len(items)} items") return if isinstance(item, ErrorItem): log(f"codex error {event.type}: {item.message}") def _timestamp() -> str: return datetime.now().strftime("%Y-%m-%d %H:%M:%S") def log(message: str) -> None: timestamp = _timestamp() lines = str(message).splitlines() or [""] for line in lines: print(f"{timestamp} {line}") async def main() -> None: agent = Agent( name="Codex Agent", instructions=( "Use the codex tool to inspect the workspace in read-only mode and answer the question. " "When skill names, which usually starts with `$`, are mentioned, " "you must rely on the codex tool to use the skill and answer the question.\n\n" "When you send the final answer, you must include the following info at the end:\n\n" "Run `codex resume ` to continue the codex session." ), tools=[ # Run local Codex CLI as a sub process codex_tool( sandbox_mode="read-only", default_thread_options=ThreadOptions( # You can pass a Codex instance to customize CLI details # codex=Codex(executable_path="/path/to/codex", base_url="..."), model="gpt-5.5", model_reasoning_effort="low", network_access_enabled=True, web_search_enabled=False, approval_policy="never", # We'll update this example once the HITL is implemented ), default_turn_options=TurnOptions( # Abort Codex CLI if no events arrive within this many seconds. idle_timeout_seconds=60, ), on_stream=on_codex_stream, ) ], ) trace_id = gen_trace_id() log(f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}") with trace("Codex tool example", trace_id=trace_id): log("Using the Codex tool to inspect pyproject.toml and summarize Python requirements...") result = await Runner.run( agent, ( "Inspect pyproject.toml in this repository and summarize the supported Python " "version plus the main local test command. Do not modify any files." ), ) log(result.final_output) # Use local inspection in read-only mode. log( "Using the Codex tool to inspect AGENTS.md and summarize the local verification workflow..." ) result = await Runner.run( agent, ( "Inspect AGENTS.md and summarize the mandatory local verification commands for this " "repository. Do not modify any files or suggest code changes." ), ) log(result.final_output) # (A read-only summary of the local verification workflow will be displayed.) if __name__ == "__main__": asyncio.run(main())