mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
## Summary - break service tier session/op/app-server protocol fields from the closed enum to string tier ids - send the service tier string directly through model requests, prewarm, compaction, memories, and TUI/app-server turn starts - regenerate app-server protocol JSON/TypeScript schemas, removing the standalone ServiceTier TS enum ## Verification - just fmt - cargo check -p codex-core -p codex-app-server -p codex-tui - just write-app-server-schema --------- Co-authored-by: Codex <noreply@openai.com>
390 lines
12 KiB
Rust
390 lines
12 KiB
Rust
use super::ApprovalsReviewer;
|
|
use super::AskForApproval;
|
|
use super::PermissionProfileSelectionParams;
|
|
use super::SandboxPolicy;
|
|
use super::Turn;
|
|
use codex_experimental_api_macros::ExperimentalApi;
|
|
use codex_protocol::config_types::CollaborationMode;
|
|
use codex_protocol::config_types::Personality;
|
|
use codex_protocol::config_types::ReasoningSummary;
|
|
use codex_protocol::openai_models::ReasoningEffort;
|
|
use codex_protocol::plan_tool::PlanItemArg as CorePlanItemArg;
|
|
use codex_protocol::plan_tool::StepStatus as CorePlanStepStatus;
|
|
use codex_protocol::user_input::ByteRange as CoreByteRange;
|
|
use codex_protocol::user_input::TextElement as CoreTextElement;
|
|
use codex_protocol::user_input::UserInput as CoreUserInput;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
use schemars::JsonSchema;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use serde_json::Value as JsonValue;
|
|
use std::collections::HashMap;
|
|
use std::path::PathBuf;
|
|
use ts_rs::TS;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum TurnStatus {
|
|
Completed,
|
|
Interrupted,
|
|
Failed,
|
|
InProgress,
|
|
}
|
|
|
|
// Turn APIs
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnEnvironmentParams {
|
|
pub environment_id: String,
|
|
pub cwd: AbsolutePathBuf,
|
|
}
|
|
|
|
#[derive(
|
|
Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS, ExperimentalApi,
|
|
)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnStartParams {
|
|
pub thread_id: String,
|
|
pub input: Vec<UserInput>,
|
|
/// Optional turn-scoped Responses API client metadata.
|
|
#[experimental("turn/start.responsesapiClientMetadata")]
|
|
#[ts(optional = nullable)]
|
|
pub responsesapi_client_metadata: Option<HashMap<String, String>>,
|
|
/// Optional turn-scoped environments.
|
|
///
|
|
/// Omitted uses the thread sticky environments. Empty disables
|
|
/// environment access for this turn. Non-empty selects the first
|
|
/// environment as the current turn environment for this turn.
|
|
#[experimental("turn/start.environments")]
|
|
#[ts(optional = nullable)]
|
|
pub environments: Option<Vec<TurnEnvironmentParams>>,
|
|
/// Override the working directory for this turn and subsequent turns.
|
|
#[ts(optional = nullable)]
|
|
pub cwd: Option<PathBuf>,
|
|
/// Override the approval policy for this turn and subsequent turns.
|
|
#[experimental(nested)]
|
|
#[ts(optional = nullable)]
|
|
pub approval_policy: Option<AskForApproval>,
|
|
/// Override where approval requests are routed for review on this turn and
|
|
/// subsequent turns.
|
|
#[ts(optional = nullable)]
|
|
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
|
/// Override the sandbox policy for this turn and subsequent turns.
|
|
#[ts(optional = nullable)]
|
|
pub sandbox_policy: Option<SandboxPolicy>,
|
|
/// Select a named permissions profile for this turn and subsequent turns.
|
|
/// Cannot be combined with `sandboxPolicy`. Use bounded `modifications`
|
|
/// for supported turn adjustments instead of replacing the full
|
|
/// permissions profile.
|
|
#[experimental("turn/start.permissions")]
|
|
#[ts(optional = nullable)]
|
|
pub permissions: Option<PermissionProfileSelectionParams>,
|
|
/// Override the model for this turn and subsequent turns.
|
|
#[ts(optional = nullable)]
|
|
pub model: Option<String>,
|
|
/// Override the service tier for this turn and subsequent turns.
|
|
#[serde(
|
|
default,
|
|
deserialize_with = "crate::protocol::serde_helpers::deserialize_double_option",
|
|
serialize_with = "crate::protocol::serde_helpers::serialize_double_option",
|
|
skip_serializing_if = "Option::is_none"
|
|
)]
|
|
#[ts(optional = nullable)]
|
|
pub service_tier: Option<Option<String>>,
|
|
/// Override the reasoning effort for this turn and subsequent turns.
|
|
#[ts(optional = nullable)]
|
|
pub effort: Option<ReasoningEffort>,
|
|
/// Override the reasoning summary for this turn and subsequent turns.
|
|
#[ts(optional = nullable)]
|
|
pub summary: Option<ReasoningSummary>,
|
|
/// Override the personality for this turn and subsequent turns.
|
|
#[ts(optional = nullable)]
|
|
pub personality: Option<Personality>,
|
|
/// Optional JSON Schema used to constrain the final assistant message for
|
|
/// this turn.
|
|
#[ts(optional = nullable)]
|
|
pub output_schema: Option<JsonValue>,
|
|
|
|
/// EXPERIMENTAL - Set a pre-set collaboration mode.
|
|
/// Takes precedence over model, reasoning_effort, and developer instructions if set.
|
|
///
|
|
/// For `collaboration_mode.settings.developer_instructions`, `null` means
|
|
/// "use the built-in instructions for the selected mode".
|
|
#[experimental("turn/start.collaborationMode")]
|
|
#[ts(optional = nullable)]
|
|
pub collaboration_mode: Option<CollaborationMode>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnStartResponse {
|
|
pub turn: Turn,
|
|
}
|
|
|
|
#[derive(
|
|
Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS, ExperimentalApi,
|
|
)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnSteerParams {
|
|
pub thread_id: String,
|
|
pub input: Vec<UserInput>,
|
|
/// Optional turn-scoped Responses API client metadata.
|
|
#[experimental("turn/steer.responsesapiClientMetadata")]
|
|
#[ts(optional = nullable)]
|
|
pub responsesapi_client_metadata: Option<HashMap<String, String>>,
|
|
/// Required active turn id precondition. The request fails when it does not
|
|
/// match the currently active turn.
|
|
pub expected_turn_id: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnSteerResponse {
|
|
pub turn_id: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnInterruptParams {
|
|
pub thread_id: String,
|
|
pub turn_id: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnInterruptResponse {}
|
|
|
|
// User input types
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ByteRange {
|
|
pub start: usize,
|
|
pub end: usize,
|
|
}
|
|
|
|
impl From<CoreByteRange> for ByteRange {
|
|
fn from(value: CoreByteRange) -> Self {
|
|
Self {
|
|
start: value.start,
|
|
end: value.end,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<ByteRange> for CoreByteRange {
|
|
fn from(value: ByteRange) -> Self {
|
|
Self {
|
|
start: value.start,
|
|
end: value.end,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TextElement {
|
|
/// Byte range in the parent `text` buffer that this element occupies.
|
|
pub byte_range: ByteRange,
|
|
/// Optional human-readable placeholder for the element, displayed in the UI.
|
|
placeholder: Option<String>,
|
|
}
|
|
|
|
impl TextElement {
|
|
pub fn new(byte_range: ByteRange, placeholder: Option<String>) -> Self {
|
|
Self {
|
|
byte_range,
|
|
placeholder,
|
|
}
|
|
}
|
|
|
|
pub fn set_placeholder(&mut self, placeholder: Option<String>) {
|
|
self.placeholder = placeholder;
|
|
}
|
|
|
|
pub fn placeholder(&self) -> Option<&str> {
|
|
self.placeholder.as_deref()
|
|
}
|
|
}
|
|
|
|
impl From<CoreTextElement> for TextElement {
|
|
fn from(value: CoreTextElement) -> Self {
|
|
Self::new(
|
|
value.byte_range.into(),
|
|
value._placeholder_for_conversion_only().map(str::to_string),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl From<TextElement> for CoreTextElement {
|
|
fn from(value: TextElement) -> Self {
|
|
Self::new(value.byte_range.into(), value.placeholder)
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
#[ts(tag = "type")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum UserInput {
|
|
Text {
|
|
text: String,
|
|
/// UI-defined spans within `text` used to render or persist special elements.
|
|
#[serde(default)]
|
|
text_elements: Vec<TextElement>,
|
|
},
|
|
Image {
|
|
url: String,
|
|
},
|
|
LocalImage {
|
|
path: PathBuf,
|
|
},
|
|
Skill {
|
|
name: String,
|
|
path: PathBuf,
|
|
},
|
|
Mention {
|
|
name: String,
|
|
path: String,
|
|
},
|
|
}
|
|
|
|
impl UserInput {
|
|
pub fn into_core(self) -> CoreUserInput {
|
|
match self {
|
|
UserInput::Text {
|
|
text,
|
|
text_elements,
|
|
} => CoreUserInput::Text {
|
|
text,
|
|
text_elements: text_elements.into_iter().map(Into::into).collect(),
|
|
},
|
|
UserInput::Image { url } => CoreUserInput::Image { image_url: url },
|
|
UserInput::LocalImage { path } => CoreUserInput::LocalImage { path },
|
|
UserInput::Skill { name, path } => CoreUserInput::Skill { name, path },
|
|
UserInput::Mention { name, path } => CoreUserInput::Mention { name, path },
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<CoreUserInput> for UserInput {
|
|
fn from(value: CoreUserInput) -> Self {
|
|
match value {
|
|
CoreUserInput::Text {
|
|
text,
|
|
text_elements,
|
|
} => UserInput::Text {
|
|
text,
|
|
text_elements: text_elements.into_iter().map(Into::into).collect(),
|
|
},
|
|
CoreUserInput::Image { image_url } => UserInput::Image { url: image_url },
|
|
CoreUserInput::LocalImage { path } => UserInput::LocalImage { path },
|
|
CoreUserInput::Skill { name, path } => UserInput::Skill { name, path },
|
|
CoreUserInput::Mention { name, path } => UserInput::Mention { name, path },
|
|
_ => unreachable!("unsupported user input variant"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl UserInput {
|
|
pub fn text_char_count(&self) -> usize {
|
|
match self {
|
|
UserInput::Text { text, .. } => text.chars().count(),
|
|
UserInput::Image { .. }
|
|
| UserInput::LocalImage { .. }
|
|
| UserInput::Skill { .. }
|
|
| UserInput::Mention { .. } => 0,
|
|
}
|
|
}
|
|
}
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnStartedNotification {
|
|
pub thread_id: String,
|
|
pub turn: Turn,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct Usage {
|
|
pub input_tokens: i32,
|
|
pub cached_input_tokens: i32,
|
|
pub output_tokens: i32,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnCompletedNotification {
|
|
pub thread_id: String,
|
|
pub turn: Turn,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
/// Notification that the turn-level unified diff has changed.
|
|
/// Contains the latest aggregated diff across all file changes in the turn.
|
|
pub struct TurnDiffUpdatedNotification {
|
|
pub thread_id: String,
|
|
pub turn_id: String,
|
|
pub diff: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnPlanUpdatedNotification {
|
|
pub thread_id: String,
|
|
pub turn_id: String,
|
|
pub explanation: Option<String>,
|
|
pub plan: Vec<TurnPlanStep>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct TurnPlanStep {
|
|
pub step: String,
|
|
pub status: TurnPlanStepStatus,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum TurnPlanStepStatus {
|
|
Pending,
|
|
InProgress,
|
|
Completed,
|
|
}
|
|
|
|
impl From<CorePlanItemArg> for TurnPlanStep {
|
|
fn from(value: CorePlanItemArg) -> Self {
|
|
Self {
|
|
step: value.step,
|
|
status: value.status.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<CorePlanStepStatus> for TurnPlanStepStatus {
|
|
fn from(value: CorePlanStepStatus) -> Self {
|
|
match value {
|
|
CorePlanStepStatus::Pending => Self::Pending,
|
|
CorePlanStepStatus::InProgress => Self::InProgress,
|
|
CorePlanStepStatus::Completed => Self::Completed,
|
|
}
|
|
}
|
|
}
|