| import sys |
| from pathlib import Path |
|
|
| _EXAMPLES_ROOT = Path(__file__).resolve().parents[1] |
| if str(_EXAMPLES_ROOT) not in sys.path: |
| sys.path.insert(0, str(_EXAMPLES_ROOT)) |
|
|
| from _bootstrap import ensure_local_sdk_src, runtime_config |
|
|
| ensure_local_sdk_src() |
|
|
| import asyncio |
|
|
| from openai_codex import ( |
| AsyncCodex, |
| ) |
| from openai_codex.types import ( |
| ThreadTokenUsageUpdatedNotification, |
| TurnCompletedNotification, |
| ) |
|
|
|
|
| def _format_usage(usage: object) -> str: |
| last = usage.last |
| total = usage.total |
| return ( |
| "usage>\n" |
| f" last: input={last.input_tokens} output={last.output_tokens} reasoning={last.reasoning_output_tokens} total={last.total_tokens} cached={last.cached_input_tokens}\n" |
| f" total: input={total.input_tokens} output={total.output_tokens} reasoning={total.reasoning_output_tokens} total={total.total_tokens} cached={total.cached_input_tokens}" |
| ) |
|
|
|
|
| async def main() -> None: |
| print("Codex async mini CLI. Type /exit to quit.") |
|
|
| async with AsyncCodex(config=runtime_config()) as codex: |
| thread = await codex.thread_start( |
| model="gpt-5.4", config={"model_reasoning_effort": "high"} |
| ) |
| print("Thread:", thread.id) |
|
|
| while True: |
| try: |
| user_input = (await asyncio.to_thread(input, "you> ")).strip() |
| except EOFError: |
| break |
|
|
| if not user_input: |
| continue |
| if user_input in {"/exit", "/quit"}: |
| break |
|
|
| turn = await thread.turn(user_input) |
| usage = None |
| status = None |
| error = None |
|
|
| print("assistant> ", end="", flush=True) |
| async for event in turn.stream(): |
| payload = event.payload |
| if event.method == "item/agentMessage/delta": |
| delta = payload.delta |
| if delta: |
| print(delta, end="", flush=True) |
| continue |
| if isinstance(payload, ThreadTokenUsageUpdatedNotification): |
| usage = payload.token_usage |
| continue |
| if isinstance(payload, TurnCompletedNotification): |
| status = payload.turn.status |
| error = payload.turn.error |
|
|
| print() |
| if status is None: |
| raise RuntimeError("stream ended without turn/completed") |
| if usage is None: |
| raise RuntimeError("stream ended without token usage") |
|
|
| status_text = status.value |
| print(f"assistant.status> {status_text}") |
| if status_text == "failed": |
| print("assistant.error>", error) |
|
|
| print(_format_usage(usage)) |
|
|
|
|
| if __name__ == "__main__": |
| asyncio.run(main()) |
|
|