mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
## What changed - Map thread listing and creation, paginated turn and item history, and turn submission and interruption to Cloud operations. - Mark listed and activated threads as using paginated history, and warn when history items cannot be displayed. - Reject unsupported filters, custom settings, and structured input. Require stable submission IDs and avoid returning a running turn for duplicate or queued submissions. - Forward optional `turn_trigger` values through the Cloud client. ## Testing Add coverage for resume-picker pagination, unsupported filters, submission IDs and settings, duplicate and queued admissions, and `turn_trigger` wire encoding. GitOrigin-RevId: dcbd87d8190786da65e343a3a0f8d849b24a5b26
96 lines
3.5 KiB
Rust
96 lines
3.5 KiB
Rust
//! Standalone consumer; prints event kinds without logging payloads.
|
|
use codex_cloud_client::AddUserMessageRequest;
|
|
use codex_cloud_client::AdmissionOutcome;
|
|
use codex_cloud_client::Client;
|
|
use codex_cloud_client::Credentials;
|
|
use codex_cloud_client::ResumeRequest;
|
|
use codex_cloud_client::SubmissionMode;
|
|
use codex_http_client::HttpClientFactory;
|
|
use codex_http_client::OutboundProxyPolicy;
|
|
use futures::StreamExt;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
let mut args = std::env::args().skip(1);
|
|
let endpoint = args
|
|
.next()
|
|
.ok_or_else(|| anyhow::anyhow!("expected native gRPC origin"))?;
|
|
let thread_id = args
|
|
.next()
|
|
.ok_or_else(|| anyhow::anyhow!("expected existing thread ID"))?;
|
|
// Supplying both extra arguments explicitly opts into sending one message.
|
|
let submission = match (args.next(), args.next()) {
|
|
(None, None) => None,
|
|
(Some(client_user_message_id), Some(text)) => Some(AddUserMessageRequest {
|
|
thread_id: thread_id.clone(),
|
|
client_user_message_id,
|
|
text,
|
|
turn_trigger: None,
|
|
mode: SubmissionMode::StartIfIdle,
|
|
shared_access: false,
|
|
}),
|
|
_ => anyhow::bail!("expected both client message ID and text, or neither"),
|
|
};
|
|
if args.next().is_some() {
|
|
anyhow::bail!("unexpected argument");
|
|
}
|
|
let credentials = Credentials::new(
|
|
&std::env::var("CODEX_CLOUD_ACCESS_TOKEN")?,
|
|
&std::env::var("CODEX_CLOUD_ACCOUNT_ID")?,
|
|
)?;
|
|
let client = Client::new(
|
|
&HttpClientFactory::new(OutboundProxyPolicy::RespectSystemProxy),
|
|
&endpoint,
|
|
credentials,
|
|
)?;
|
|
client
|
|
.resume(&ResumeRequest {
|
|
thread_id: thread_id.clone(),
|
|
wait: false,
|
|
shared_access: false,
|
|
})
|
|
.await?;
|
|
let mut events = client.attach(&thread_id).await?;
|
|
if let Some(request) = submission {
|
|
// Drain Attach while admission is pending; events can precede its response.
|
|
let admission = client.add_user_message(&request);
|
|
tokio::pin!(admission);
|
|
let (result, stream_error) = loop {
|
|
tokio::select! {
|
|
result = &mut admission => {
|
|
break (result, None);
|
|
}
|
|
event = events.next() => match event {
|
|
Some(Ok(event)) => println!("{event:?}"),
|
|
Some(Err(error)) => break (admission.await, Some(anyhow::Error::new(error))),
|
|
None => break (admission.await, Some(anyhow::anyhow!("attachment ended"))),
|
|
}
|
|
}
|
|
};
|
|
match result {
|
|
Ok(admission) => println!(
|
|
"admission: {}",
|
|
match admission.outcome {
|
|
AdmissionOutcome::Started(_) => "started",
|
|
AdmissionOutcome::Steered(_) => "steered",
|
|
AdmissionOutcome::Duplicate { .. } => "duplicate",
|
|
AdmissionOutcome::Queued { .. } => "queued",
|
|
}
|
|
),
|
|
Err(error) => match stream_error {
|
|
Some(stream_error) => {
|
|
anyhow::bail!("attachment failed: {stream_error}; admission failed: {error}");
|
|
}
|
|
None => return Err(error.into()),
|
|
},
|
|
}
|
|
if let Some(error) = stream_error {
|
|
return Err(error.context("attachment failed"));
|
|
}
|
|
}
|
|
while let Some(event) = events.next().await {
|
|
println!("{:?}", event?);
|
|
}
|
|
Ok(())
|
|
}
|