Cloud Tasks
codex cloud は prompt を OpenAI クラウドに投げて走らせるサブコマンドだ:ローカルではモデルを呼ばず、Agent ループも回さず、タスクの提出、状態のポーリング、diff の取得、パッチの適用だけを担う。cloud-tasks は TUI + CLI の入口で、cloud-tasks-client が CloudBackend trait + HTTP 実装を提供し、cloud-tasks-mock-client が debug モードに偽バックエンドを差し込み、backend-client は下層の HTTP(他の backend API にも再利用される)。Model Provider のローカル推論とは異なり——こちらでは「モデル推論」はクラウドのコンテナ内で起きる。
責務
- タスク提出:
run_exec_commandが prompt + git ref + environment id をパッケージしてPOST /wham/tasks(または/api/codex/tasks)に送り、task id を返す (codex-rs/cloud-tasks/src/lib.rs:161-184)。 - リスト/詳細/差分:
run_list_command、run_status_command、run_diff_commandの三つの CLI サブコマンドがそれぞれlist_tasks/get_task_summary/get_task_diffに対応する (codex-rs/cloud-tasks/src/cli.rs:16-27)。 - パッチ適用:
apply_taskは dry-run preflight を走らせてから実際に apply する。diff_overrideでユーザが best-of-N のうちの一回を選べる (codex-rs/cloud-tasks-client/src/http.rs:99-121)。 - trait 抽象:
CloudBackendがバックエンドとの全やり取りを trait に集約し、debug build はMockClient、release はHttpClientに進む (codex-rs/cloud-tasks-client/src/api.rs:136-176)。 - バックエンド初期化:
init_backendが base URL、UA、auth provider、ChatGPT-Account-Id を組み立て、CODEX_CLOUD_TASKS_BASE_URLに従い WHAM / Codex API のパススタイルを切り替える (codex-rs/cloud-tasks/src/lib.rs:43-107)。
設計動機
core に詰め込むのではなく独立 crate にしたのは、このパスがAgent メインループを走らせないからだ。core の client はモデルに stream リクエストを送り、SSE をパースし、turn state を管理する。cloud task は「長いタスクをクラウドに提出し、非同期で結果を待つ」。両者の並発モデルは全く異なる:前者は長接続 stream、後者は poll + 取得。CloudBackend trait が存在するのは、TUI を debug build で走らせるためだ——init_backend が CODEX_CLOUD_TASKS_MODE=mock を検出したら直接 MockClient に切り替え、ローカルで ChatGPT バックエンドに接続せずに UI 状態機械を调试できる。HttpClient は内部で backend-client::Client を再利用し、HTTP をもう一つ作らない。backend-api の認証ヘッダ、Cloudflare cookie store、パススタイル(wham vs codex-api)などのロジックが他の backend API 呼び出しと一致するからだ。
best-of-N はこのパスの特色だ:create_task は attempts: usize(1-4)を受け付け、クラウドは複数 attempt を走らせる。list_sibling_attempts がそれらを全部引き戻し、ApplyCommand はユーザが --attempt N で特定の結果を選べるようにする。diff_override フィールドは apply_task_preflight と apply_task を貫き、apply 段階で diff を再取得せず、ユーザが選んだものを使う。
主要ファイル
codex-rs/cloud-tasks/src/lib.rs:735-744 — run_main。サブコマンドディスパッチ + TUI モード起動入口。codex-rs/cloud-tasks/src/lib.rs:43-107 — BackendContext と init_backend。環境変数で mock / http を決め、auth を組み立てる。codex-rs/cloud-tasks/src/cli.rs:29-50 — ExecCommand。--env、--attempts、--branch の三つのコア引数を定義。codex-rs/cloud-tasks-client/src/api.rs:136-176 — CloudBackend trait。11 個のメソッドが list / get / apply / create をカバー。codex-rs/cloud-tasks-client/src/http.rs:25-63 — HttpClient。backend-client::Client を包み、CloudBackend を実装。codex-rs/backend-client/src/client.rs:451-482 — create_task の base client での実装。JSON から task id を抽出。codex-rs/cloud-tasks-mock-client/src/mock.rs:163-189 — MockClient が trait を実装し、内部の mock データ生成関数に転送。ファクトリ init_backend は debug build で環境変数を検査し、mock か本物の HTTP かを決める:
// cloud-tasks/src/lib.rs:43-60 — 后端选择
async fn init_backend(user_agent_suffix: &str) -> anyhow::Result<BackendContext> {
#[cfg(debug_assertions)]
let use_mock = matches!(
std::env::var("CODEX_CLOUD_TASKS_MODE").ok().as_deref(),
Some("mock") | Some("MOCK")
);
let base_url = std::env::var("CODEX_CLOUD_TASKS_BASE_URL")
.unwrap_or_else(|_| "https://chatgpt.com/backend-api".to_string());
#[cfg(debug_assertions)]
if use_mock {
return Ok(BackendContext {
backend: Arc::new(codex_cloud_tasks_mock_client::MockClient),
base_url,
});
}CloudBackend trait は CloudBackendFuture で戻り型を boxed future に統一し、mock と http の実装が同じシグネチャを共有する:
// cloud-tasks-client/src/api.rs:136-176 — 后端抽象
pub trait CloudBackend: Send + Sync {
fn list_tasks<'a>(
&'a self,
env: Option<&'a str>,
limit: Option<i64>,
cursor: Option<&'a str>,
) -> CloudBackendFuture<'a, TaskListPage>;
fn get_task_summary(&self, id: TaskId) -> CloudBackendFuture<'_, TaskSummary>;
fn get_task_diff(&self, id: TaskId) -> CloudBackendFuture<'_, Option<String>>;
// ...messages / sibling attempts / apply preflight / apply / create
fn create_task<'a>(
&'a self,
env_id: &'a str,
prompt: &'a str,
git_ref: &'a str,
qa_mode: bool,
best_of_n: usize,
) -> CloudBackendFuture<'a, CreatedTask>;
}create_task は base client で POST し、JSON から task id を抽出する(task.id を優先し、顶层 id にフォールバック):
// backend-client/src/client.rs:451-482 — POST /wham/tasks 并提取 task id
pub async fn create_task(&self, request_body: serde_json::Value) -> Result<String> {
let url = match self.path_style {
PathStyle::CodexApi => format!("{}/api/codex/tasks", self.base_url),
PathStyle::ChatGptApi => format!("{}/wham/tasks", self.base_url),
};
// ...发请求,解析 body
match serde_json::from_str::<serde_json::Value>(&body) {
Ok(v) => {
if let Some(id) = v.get("task").and_then(|t| t.get("id")).and_then(|s| s.as_str()) {
Ok(id.to_string())
} else if let Some(id) = v.get("id").and_then(|s| s.as_str()) {
Ok(id.to_string())
} else {
anyhow::bail!("POST {url} succeeded but no task id found; ...");
}
}
Err(e) => anyhow::bail!("Decode error for {url}: {e}; ..."),
}
}データフロー
境界と失敗
- 未ログインは直接退出:
init_backendはauthが None またはuses_codex_backend()が false の場合、process::exit(1)する (codex-rs/cloud-tasks/src/lib.rs:76-95)。 - パススタイルは base URL で決まる:
https://chatgpt.com/backend-apiは WHAM(/wham/tasks)に進み、それ以外は Codex API(/api/codex/tasks)に進む。PathStyle::from_base_urlが判定する (codex-rs/backend-client/src/client.rs:151-177)。 - attempts 範囲は制限される:
parse_attemptsは 1-4 を強制し、バックエンドの best-of-N 上限と一致させる (codex-rs/cloud-tasks/src/cli.rs:52-61)。 - apply 失敗時の終了コードは非 0:
run_apply_commandはApplyStatusを検査し、Successでなければprocess::exit(1)してスクリプト連鎖を便利にする (codex-rs/cloud-tasks/src/lib.rs:589-608)。 - create_task id は二種 JSON に対応:
task.idと顶层idを両方受け付け、バックエンドごとに返却構造が異なるのを吸収する (codex-rs/backend-client/src/client.rs:464-481)。
まとめ
Cloud Tasks は「提出、照会、適用」の三ステップを CloudBackend trait に圧縮し、HTTP と mock が同じ trait を実装する。これにより TUI はローカルでバックエンドなしで调试できる。下層 HTTP は backend-client::Client を再利用し、Model Provider と認証・パススタイル判定を共有する。クラウドタスク自身の設定(許可される environment、enterprise ポリシー)は 設定システム 内の cloud config bundle が提供し、起動時に取得して適用する。