use codex_cli_sdk::config::TurnOptions;
use codex_cli_sdk::{Codex, CodexConfig, ThreadEvent, ThreadItem, ThreadOptions};
use tokio_stream::StreamExt;
use tokio_util::sync::CancellationToken;
#[tokio::main]
async fn main() -> codex_cli_sdk::Result<()> {
let codex = Codex::new(CodexConfig::default())?;
let mut thread = codex.start_thread(ThreadOptions::default());
let cancel = CancellationToken::new();
let turn_opts = TurnOptions {
cancel: Some(cancel.clone()),
..Default::default()
};
let cancel_trigger = cancel.clone();
tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
println!("\n[cancelling...]");
cancel_trigger.cancel();
});
println!("Streaming (will cancel after 3s)...\n");
let mut stream = thread
.run_streamed(
"Write a detailed explanation of every sorting algorithm, with examples in Rust",
turn_opts,
)
.await?;
let mut text_received = false;
loop {
match stream.next().await {
Some(Ok(ThreadEvent::ItemUpdated {
item: ThreadItem::AgentMessage { text, .. },
})) => {
print!("{text}");
text_received = true;
}
Some(Ok(ThreadEvent::TurnCompleted { usage })) => {
println!(
"\n\nCompleted normally. Tokens: {} in / {} out",
usage.input_tokens, usage.output_tokens
);
break;
}
Some(Ok(ThreadEvent::TurnFailed { error })) => {
eprintln!("\n\nTurn stopped: {}", error.message);
break;
}
Some(Ok(_)) => {}
Some(Err(e)) => {
eprintln!("\n\nStream ended: {e}");
break;
}
None => {
if text_received {
println!("\n\n[stream closed]");
}
break;
}
}
}
Ok(())
}