feat: use OAI Responses API MessagePhase type directly in App Server v2 (#12422)

https://github.com/openai/codex/pull/10455 introduced the `phase` field,
and then https://github.com/openai/codex/pull/12072 introduced a
`MessagePhase` type in `v2.rs` that paralleled the `MessagePhase` type
in `codex-rs/protocol/src/models.rs`.

The app server protocol prefers `camelCase` while the Responses API uses
`snake_case`, so this meant we had two versions of `MessagePhase` with
different serialization rules. When the app server protocol refers to
types from the Responses API, we use the wire format of the the
Responses API even though it is inconsistent with the app server API.

This PR deletes `MessagePhase` from `v2.rs` and consolidates on the
Responses API version to eliminate confusion.
This commit is contained in:
Michael Bolin
2026-02-20 20:43:36 -08:00
committed by GitHub
parent a73efab8dd
commit 48af93399e
20 changed files with 251 additions and 117 deletions

View File

@@ -20,7 +20,7 @@ use codex_protocol::items::TurnItem as CoreTurnItem;
use codex_protocol::mcp::Resource as McpResource;
use codex_protocol::mcp::ResourceTemplate as McpResourceTemplate;
use codex_protocol::mcp::Tool as McpTool;
use codex_protocol::models::MessagePhase as CoreMessagePhase;
use codex_protocol::models::MessagePhase;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::InputModality;
use codex_protocol::openai_models::ReasoningEffort;
@@ -2666,24 +2666,6 @@ impl From<CoreUserInput> for UserInput {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub enum MessagePhase {
Commentary,
FinalAnswer,
}
impl From<CoreMessagePhase> for MessagePhase {
fn from(value: CoreMessagePhase) -> Self {
match value {
CoreMessagePhase::Commentary => Self::Commentary,
CoreMessagePhase::FinalAnswer => Self::FinalAnswer,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "camelCase")]
#[ts(tag = "type")]
@@ -2873,7 +2855,7 @@ impl From<CoreTurnItem> for ThreadItem {
ThreadItem::AgentMessage {
id: agent.id,
text,
phase: agent.phase.map(Into::into),
phase: agent.phase,
}
}
CoreTurnItem::Plan(plan) => ThreadItem::Plan {
@@ -3692,7 +3674,6 @@ mod tests {
use codex_protocol::items::TurnItem;
use codex_protocol::items::UserMessageItem;
use codex_protocol::items::WebSearchItem;
use codex_protocol::models::MessagePhase as CoreMessagePhase;
use codex_protocol::models::WebSearchAction as CoreWebSearchAction;
use codex_protocol::protocol::NetworkAccess as CoreNetworkAccess;
use codex_protocol::protocol::ReadOnlyAccess as CoreReadOnlyAccess;
@@ -3902,7 +3883,7 @@ mod tests {
content: vec![AgentMessageContent::Text {
text: "final".to_string(),
}],
phase: Some(CoreMessagePhase::FinalAnswer),
phase: Some(MessagePhase::FinalAnswer),
});
assert_eq!(