diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index b6d87cd44..71256baa0 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -4415,6 +4415,13 @@ "type": "string" }, "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, + "MessagePhase2": { "description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.", "oneOf": [ { @@ -5344,7 +5351,7 @@ "phase": { "anyOf": [ { - "$ref": "#/definitions/MessagePhase" + "$ref": "#/definitions/MessagePhase2" }, { "type": "null" @@ -6594,6 +6601,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, @@ -7383,7 +7401,7 @@ "phase": { "anyOf": [ { - "$ref": "#/definitions/MessagePhase" + "$ref": "#/definitions/MessagePhase2" }, { "type": "null" diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index b6002dabd..e540fc68b 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -15351,6 +15351,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/v2/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json index 7fc1dab9b..1a0ef630a 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json @@ -236,6 +236,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -360,6 +367,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json index 5ed713e58..50e7e1e66 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json @@ -236,6 +236,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -360,6 +367,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json index 619455781..e71ebbdc7 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json @@ -350,6 +350,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -474,6 +481,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json index de1823e9d..214d54ae3 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -386,6 +386,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "NetworkAccess": { "enum": [ "restricted", @@ -850,6 +857,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json index 96e376197..ddda3ca35 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json @@ -373,6 +373,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -656,6 +663,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json index e0d4cc4f7..0a478b9f8 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json @@ -373,6 +373,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -656,6 +663,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json index 4385565f9..d73833f10 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -386,6 +386,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "NetworkAccess": { "enum": [ "restricted", @@ -850,6 +857,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json index 9f81c5ea7..63c9f794d 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json @@ -373,6 +373,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -656,6 +663,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json index fd75b56a2..4f98fd138 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -386,6 +386,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "NetworkAccess": { "enum": [ "restricted", @@ -850,6 +857,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json index 3ad16408e..5d3011500 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json @@ -373,6 +373,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -656,6 +663,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json index 3f8bd6686..64487a412 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json @@ -373,6 +373,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -656,6 +663,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json index 9fe3517e9..e20e71be2 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json @@ -350,6 +350,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -474,6 +481,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json index 116ded84c..4fb088a13 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json @@ -350,6 +350,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -474,6 +481,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json index 276ab3b46..4e7f82f4e 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json @@ -350,6 +350,13 @@ ], "type": "string" }, + "MessagePhase": { + "enum": [ + "commentary", + "finalAnswer" + ], + "type": "string" + }, "PatchApplyStatus": { "enum": [ "inProgress", @@ -474,6 +481,17 @@ "id": { "type": "string" }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ], + "default": null + }, "text": { "type": "string" }, diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/MessagePhase.ts b/codex-rs/app-server-protocol/schema/typescript/v2/MessagePhase.ts new file mode 100644 index 000000000..80d7236e7 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/MessagePhase.ts @@ -0,0 +1,5 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type MessagePhase = "commentary" | "finalAnswer"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts index fa098ed3e..cbdad0bf2 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts @@ -11,11 +11,12 @@ import type { FileUpdateChange } from "./FileUpdateChange"; import type { McpToolCallError } from "./McpToolCallError"; import type { McpToolCallResult } from "./McpToolCallResult"; import type { McpToolCallStatus } from "./McpToolCallStatus"; +import type { MessagePhase } from "./MessagePhase"; import type { PatchApplyStatus } from "./PatchApplyStatus"; import type { UserInput } from "./UserInput"; import type { WebSearchAction } from "./WebSearchAction"; -export type ThreadItem = { "type": "userMessage", id: string, content: Array, } | { "type": "agentMessage", id: string, text: string, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array, content: Array, } | { "type": "commandExecution", id: string, +export type ThreadItem = { "type": "userMessage", id: string, content: Array, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array, content: Array, } | { "type": "commandExecution", id: string, /** * The command to be executed. */ diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index 8b9453c17..d10b7f7d5 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -93,6 +93,7 @@ export type { McpToolCallProgressNotification } from "./McpToolCallProgressNotif export type { McpToolCallResult } from "./McpToolCallResult"; export type { McpToolCallStatus } from "./McpToolCallStatus"; export type { MergeStrategy } from "./MergeStrategy"; +export type { MessagePhase } from "./MessagePhase"; export type { Model } from "./Model"; export type { ModelListParams } from "./ModelListParams"; export type { ModelListResponse } from "./ModelListResponse"; diff --git a/codex-rs/app-server-protocol/src/protocol/thread_history.rs b/codex-rs/app-server-protocol/src/protocol/thread_history.rs index a54b550fd..bb8001032 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -149,9 +149,11 @@ impl ThreadHistoryBuilder { } let id = self.next_item_id(); - self.ensure_turn() - .items - .push(ThreadItem::AgentMessage { id, text }); + self.ensure_turn().items.push(ThreadItem::AgentMessage { + id, + text, + phase: None, + }); } fn handle_agent_reasoning(&mut self, payload: &AgentReasoningEvent) { @@ -839,6 +841,7 @@ mod tests { ThreadItem::AgentMessage { id: "item-2".into(), text: "Hi there".into(), + phase: None, } ); assert_eq!( @@ -869,6 +872,7 @@ mod tests { ThreadItem::AgentMessage { id: "item-5".into(), text: "Reply two".into(), + phase: None, } ); } @@ -975,6 +979,7 @@ mod tests { ThreadItem::AgentMessage { id: "item-2".into(), text: "Working...".into(), + phase: None, } ); @@ -996,6 +1001,7 @@ mod tests { ThreadItem::AgentMessage { id: "item-4".into(), text: "Second attempt complete.".into(), + phase: None, } ); } @@ -1057,6 +1063,7 @@ mod tests { ThreadItem::AgentMessage { id: "item-2".into(), text: "A1".into(), + phase: None, }, ] ); @@ -1073,6 +1080,7 @@ mod tests { ThreadItem::AgentMessage { id: "item-4".into(), text: "A3".into(), + phase: None, }, ] ); diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 52eeaf883..030d82ce7 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -18,6 +18,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::ResponseItem; use codex_protocol::openai_models::InputModality; use codex_protocol::openai_models::ReasoningEffort; @@ -2549,6 +2550,24 @@ impl From 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 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")] @@ -2559,7 +2578,12 @@ pub enum ThreadItem { UserMessage { id: String, content: Vec }, #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] - AgentMessage { id: String, text: String }, + AgentMessage { + id: String, + text: String, + #[serde(default)] + phase: Option, + }, #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] /// EXPERIMENTAL - proposed plan item content. The completed plan item is @@ -2710,7 +2734,11 @@ impl From for ThreadItem { CoreAgentMessageContent::Text { text } => text, }) .collect::(); - ThreadItem::AgentMessage { id: agent.id, text } + ThreadItem::AgentMessage { + id: agent.id, + text, + phase: agent.phase.map(Into::into), + } } CoreTurnItem::Plan(plan) => ThreadItem::Plan { id: plan.id, @@ -3485,6 +3513,7 @@ 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; @@ -3685,6 +3714,24 @@ mod tests { ThreadItem::AgentMessage { id: "agent-1".to_string(), text: "Hello world".to_string(), + phase: None, + } + ); + + let agent_item_with_phase = TurnItem::AgentMessage(AgentMessageItem { + id: "agent-2".to_string(), + content: vec![AgentMessageContent::Text { + text: "final".to_string(), + }], + phase: Some(CoreMessagePhase::FinalAnswer), + }); + + assert_eq!( + ThreadItem::from(agent_item_with_phase), + ThreadItem::AgentMessage { + id: "agent-2".to_string(), + text: "final".to_string(), + phase: Some(MessagePhase::FinalAnswer), } );