| 32 | # codex_tool accepts options as keyword arguments or a plain dict. |
| 33 | # For example: codex_tool(sandbox_mode="read-only") or codex_tool({"sandbox_mode": "read-only"}). |
| 34 | async def on_codex_stream(payload: CodexToolStreamEvent) -> None: |
| 35 | event = payload.event |
| 36 | |
| 37 | if isinstance(event, ThreadStartedEvent): |
| 38 | log(f"codex thread started: {event.thread_id}") |
| 39 | return |
| 40 | if isinstance(event, TurnStartedEvent): |
| 41 | log("codex turn started") |
| 42 | return |
| 43 | if isinstance(event, TurnCompletedEvent): |
| 44 | usage = event.usage |
| 45 | log(f"codex turn completed, usage: {usage}") |
| 46 | return |
| 47 | if isinstance(event, TurnFailedEvent): |
| 48 | error = event.error.message |
| 49 | log(f"codex turn failed: {error}") |
| 50 | return |
| 51 | if isinstance(event, ThreadErrorEvent): |
| 52 | log(f"codex stream error: {event.message}") |
| 53 | return |
| 54 | |
| 55 | if not isinstance(event, ItemStartedEvent | ItemUpdatedEvent | ItemCompletedEvent): |
| 56 | return |
| 57 | |
| 58 | item = event.item |
| 59 | |
| 60 | if isinstance(item, ReasoningItem): |
| 61 | text = item.text |
| 62 | log(f"codex reasoning ({event.type}): {text}") |
| 63 | return |
| 64 | if isinstance(item, CommandExecutionItem): |
| 65 | command = item.command |
| 66 | output = item.aggregated_output |
| 67 | output_preview = output[-200:] if isinstance(output, str) else "" |
| 68 | status = item.status |
| 69 | log(f"codex command {event.type}: {command} | status={status} | output={output_preview}") |
| 70 | return |
| 71 | if isinstance(item, McpToolCallItem): |
| 72 | server = item.server |
| 73 | tool = item.tool |
| 74 | status = item.status |
| 75 | log(f"codex mcp {event.type}: {server}.{tool} | status={status}") |
| 76 | return |
| 77 | if isinstance(item, FileChangeItem): |
| 78 | changes = item.changes |
| 79 | status = item.status |
| 80 | log(f"codex file change {event.type}: {status} | {changes}") |
| 81 | return |
| 82 | if isinstance(item, WebSearchItem): |
| 83 | log(f"codex web search {event.type}: {item.query}") |
| 84 | return |
| 85 | if isinstance(item, TodoListItem): |
| 86 | items = item.items |
| 87 | log(f"codex todo list {event.type}: {len(items)} items") |
| 88 | return |
| 89 | if isinstance(item, ErrorItem): |
| 90 | log(f"codex error {event.type}: {item.message}") |
| 91 | |