mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
5a56caf18c
## Why First-party async traits should expose their `Send` contracts explicitly without requiring `async_trait`. This completes the migration pattern established in #27303 and #27304. ## What changed - Replaced the remaining first-party `async_trait` traits with native return-position `impl Future + Send` where statically dispatched and explicit boxed `Send` futures where object safety is required. - Kept implementations behavior-preserving, outlining existing async bodies into inherent methods where that keeps the diff reviewable. - Removed all direct first-party `async-trait` dependencies and the workspace dependency declaration. - Added a cargo-deny policy that permits `async-trait` only through the remaining transitive wrapper crates. - Updated `rand` from 0.8.5 to 0.8.6 to resolve RUSTSEC-2026-0097 and keep the full cargo-deny check passing. ## Validation - `just test -p codex-exec-server`: 216 passed, 2 skipped. - `just test -p codex-model-provider`: 39 passed. - `just test -p codex-core` and `just test`: changed tests passed; remaining failures are environment-sensitive suites unrelated to this migration. - `cargo deny check` - `just fix` - `just fmt` - `cargo shear` - `just bazel-lock-check`
177 lines
5.0 KiB
Rust
177 lines
5.0 KiB
Rust
use chrono::DateTime;
|
|
use chrono::Utc;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::future::Future;
|
|
use std::pin::Pin;
|
|
|
|
pub type Result<T> = std::result::Result<T, CloudTaskError>;
|
|
pub type CloudBackendFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T>> + Send + 'a>>;
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum CloudTaskError {
|
|
#[error("unimplemented: {0}")]
|
|
Unimplemented(&'static str),
|
|
#[error("http error: {0}")]
|
|
Http(String),
|
|
#[error("io error: {0}")]
|
|
Io(String),
|
|
#[error("{0}")]
|
|
Msg(String),
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(transparent)]
|
|
pub struct TaskId(pub String);
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub enum TaskStatus {
|
|
Pending,
|
|
Ready,
|
|
Applied,
|
|
Error,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct TaskSummary {
|
|
pub id: TaskId,
|
|
pub title: String,
|
|
pub status: TaskStatus,
|
|
pub updated_at: DateTime<Utc>,
|
|
/// Backend environment identifier (when available)
|
|
pub environment_id: Option<String>,
|
|
/// Human-friendly environment label (when available)
|
|
pub environment_label: Option<String>,
|
|
pub summary: DiffSummary,
|
|
/// True when the backend reports this task as a code review.
|
|
#[serde(default)]
|
|
pub is_review: bool,
|
|
/// Number of assistant attempts (best-of-N), when reported by the backend.
|
|
#[serde(default)]
|
|
pub attempt_total: Option<usize>,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
|
pub enum AttemptStatus {
|
|
Pending,
|
|
InProgress,
|
|
Completed,
|
|
Failed,
|
|
Cancelled,
|
|
#[default]
|
|
Unknown,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct TurnAttempt {
|
|
pub turn_id: String,
|
|
pub attempt_placement: Option<i64>,
|
|
pub created_at: Option<DateTime<Utc>>,
|
|
pub status: AttemptStatus,
|
|
pub diff: Option<String>,
|
|
pub messages: Vec<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum ApplyStatus {
|
|
Success,
|
|
Partial,
|
|
Error,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct ApplyOutcome {
|
|
pub applied: bool,
|
|
pub status: ApplyStatus,
|
|
pub message: String,
|
|
#[serde(default)]
|
|
pub skipped_paths: Vec<String>,
|
|
#[serde(default)]
|
|
pub conflict_paths: Vec<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct CreatedTask {
|
|
pub id: TaskId,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct TaskListPage {
|
|
pub tasks: Vec<TaskSummary>,
|
|
pub cursor: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
pub struct DiffSummary {
|
|
pub files_changed: usize,
|
|
pub lines_added: usize,
|
|
pub lines_removed: usize,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct TaskText {
|
|
pub prompt: Option<String>,
|
|
pub messages: Vec<String>,
|
|
pub turn_id: Option<String>,
|
|
pub sibling_turn_ids: Vec<String>,
|
|
pub attempt_placement: Option<i64>,
|
|
pub attempt_status: AttemptStatus,
|
|
}
|
|
|
|
impl Default for TaskText {
|
|
fn default() -> Self {
|
|
Self {
|
|
prompt: None,
|
|
messages: Vec::new(),
|
|
turn_id: None,
|
|
sibling_turn_ids: Vec::new(),
|
|
attempt_placement: None,
|
|
attempt_status: AttemptStatus::Unknown,
|
|
}
|
|
}
|
|
}
|
|
|
|
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>>;
|
|
/// Return assistant output messages (no diff) when available.
|
|
fn get_task_messages(&self, id: TaskId) -> CloudBackendFuture<'_, Vec<String>>;
|
|
/// Return the creating prompt and assistant messages (when available).
|
|
fn get_task_text(&self, id: TaskId) -> CloudBackendFuture<'_, TaskText>;
|
|
/// Return any sibling attempts (best-of-N) for the given assistant turn.
|
|
fn list_sibling_attempts(
|
|
&self,
|
|
task: TaskId,
|
|
turn_id: String,
|
|
) -> CloudBackendFuture<'_, Vec<TurnAttempt>>;
|
|
/// Dry-run apply (preflight) that validates whether the patch would apply cleanly.
|
|
/// Never modifies the working tree. When `diff_override` is supplied, the provided diff is
|
|
/// used instead of re-fetching the task details so callers can apply alternate attempts.
|
|
fn apply_task_preflight(
|
|
&self,
|
|
id: TaskId,
|
|
diff_override: Option<String>,
|
|
) -> CloudBackendFuture<'_, ApplyOutcome>;
|
|
fn apply_task(
|
|
&self,
|
|
id: TaskId,
|
|
diff_override: Option<String>,
|
|
) -> CloudBackendFuture<'_, ApplyOutcome>;
|
|
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>;
|
|
}
|