Add ItemStarted/ItemCompleted events for UserInputItem (#5306)
Adds a new ItemStarted event and delivers UserMessage as the first item type (more to come). Renames `InputItem` to `UserInput` considering we're using the `Item` suffix for actual items.
This commit is contained in:
@@ -29,7 +29,7 @@ ts-rs = { workspace = true, features = [
|
||||
"serde-json-impl",
|
||||
"no-serde-warnings",
|
||||
] }
|
||||
uuid = { workspace = true, features = ["serde", "v7"] }
|
||||
uuid = { workspace = true, features = ["serde", "v7", "v4"] }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
||||
33
codex-rs/protocol/src/items.rs
Normal file
33
codex-rs/protocol/src/items.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use crate::user_input::UserInput;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
|
||||
pub enum TurnItem {
|
||||
UserMessage(UserMessageItem),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
|
||||
pub struct UserMessageItem {
|
||||
pub id: String,
|
||||
pub content: Vec<UserInput>,
|
||||
}
|
||||
|
||||
impl UserMessageItem {
|
||||
pub fn new(content: &[UserInput]) -> Self {
|
||||
Self {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
content: content.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TurnItem {
|
||||
pub fn id(&self) -> String {
|
||||
match self {
|
||||
TurnItem::UserMessage(item) => item.id.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,11 @@ mod conversation_id;
|
||||
pub use conversation_id::ConversationId;
|
||||
pub mod config_types;
|
||||
pub mod custom_prompts;
|
||||
pub mod items;
|
||||
pub mod message_history;
|
||||
pub mod models;
|
||||
pub mod num_format;
|
||||
pub mod parse_command;
|
||||
pub mod plan_tool;
|
||||
pub mod protocol;
|
||||
pub mod user_input;
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde::Serialize;
|
||||
use serde::ser::Serializer;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::protocol::InputItem;
|
||||
use crate::user_input::UserInput;
|
||||
use schemars::JsonSchema;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)]
|
||||
@@ -206,16 +206,16 @@ pub enum ReasoningItemContent {
|
||||
Text { text: String },
|
||||
}
|
||||
|
||||
impl From<Vec<InputItem>> for ResponseInputItem {
|
||||
fn from(items: Vec<InputItem>) -> Self {
|
||||
impl From<Vec<UserInput>> for ResponseInputItem {
|
||||
fn from(items: Vec<UserInput>) -> Self {
|
||||
Self::Message {
|
||||
role: "user".to_string(),
|
||||
content: items
|
||||
.into_iter()
|
||||
.filter_map(|c| match c {
|
||||
InputItem::Text { text } => Some(ContentItem::InputText { text }),
|
||||
InputItem::Image { image_url } => Some(ContentItem::InputImage { image_url }),
|
||||
InputItem::LocalImage { path } => match std::fs::read(&path) {
|
||||
UserInput::Text { text } => Some(ContentItem::InputText { text }),
|
||||
UserInput::Image { image_url } => Some(ContentItem::InputImage { image_url }),
|
||||
UserInput::LocalImage { path } => match std::fs::read(&path) {
|
||||
Ok(bytes) => {
|
||||
let mime = mime_guess::from_path(&path)
|
||||
.first()
|
||||
|
||||
@@ -14,12 +14,14 @@ use crate::ConversationId;
|
||||
use crate::config_types::ReasoningEffort as ReasoningEffortConfig;
|
||||
use crate::config_types::ReasoningSummary as ReasoningSummaryConfig;
|
||||
use crate::custom_prompts::CustomPrompt;
|
||||
use crate::items::TurnItem;
|
||||
use crate::message_history::HistoryEntry;
|
||||
use crate::models::ContentItem;
|
||||
use crate::models::ResponseItem;
|
||||
use crate::num_format::format_with_separators;
|
||||
use crate::parse_command::ParsedCommand;
|
||||
use crate::plan_tool::UpdatePlanArgs;
|
||||
use crate::user_input::UserInput;
|
||||
use mcp_types::CallToolResult;
|
||||
use mcp_types::Resource as McpResource;
|
||||
use mcp_types::ResourceTemplate as McpResourceTemplate;
|
||||
@@ -62,14 +64,14 @@ pub enum Op {
|
||||
/// Input from the user
|
||||
UserInput {
|
||||
/// User input items, see `InputItem`
|
||||
items: Vec<InputItem>,
|
||||
items: Vec<UserInput>,
|
||||
},
|
||||
|
||||
/// Similar to [`Op::UserInput`], but contains additional context required
|
||||
/// for a turn of a [`crate::codex_conversation::CodexConversation`].
|
||||
UserTurn {
|
||||
/// User input items, see `InputItem`
|
||||
items: Vec<InputItem>,
|
||||
items: Vec<UserInput>,
|
||||
|
||||
/// `cwd` to use with the [`SandboxPolicy`] and potentially tool calls
|
||||
/// such as `local_shell`.
|
||||
@@ -403,28 +405,8 @@ impl SandboxPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
/// User input
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum InputItem {
|
||||
Text {
|
||||
text: String,
|
||||
},
|
||||
/// Pre‑encoded data: URI image.
|
||||
Image {
|
||||
image_url: String,
|
||||
},
|
||||
|
||||
/// Local image path provided by the user. This will be converted to an
|
||||
/// `Image` variant (base64 data URL) during request serialization.
|
||||
LocalImage {
|
||||
path: std::path::PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
/// Event Queue Entry - events from agent
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Event {
|
||||
/// Submission `id` that this event is correlated with.
|
||||
pub id: String,
|
||||
@@ -538,6 +520,23 @@ pub enum EventMsg {
|
||||
|
||||
/// Exited review mode with an optional final result to apply.
|
||||
ExitedReviewMode(ExitedReviewModeEvent),
|
||||
|
||||
ItemStarted(ItemStartedEvent),
|
||||
ItemCompleted(ItemCompletedEvent),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
|
||||
pub struct ItemStartedEvent {
|
||||
pub thread_id: ConversationId,
|
||||
pub turn_id: String,
|
||||
pub item: TurnItem,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
|
||||
pub struct ItemCompletedEvent {
|
||||
pub thread_id: ConversationId,
|
||||
pub turn_id: String,
|
||||
pub item: TurnItem,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
|
||||
24
codex-rs/protocol/src/user_input.rs
Normal file
24
codex-rs/protocol/src/user_input.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
/// User input
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS, JsonSchema)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum UserInput {
|
||||
Text {
|
||||
text: String,
|
||||
},
|
||||
/// Pre‑encoded data: URI image.
|
||||
Image {
|
||||
image_url: String,
|
||||
},
|
||||
|
||||
/// Local image path provided by the user. This will be converted to an
|
||||
/// `Image` variant (base64 data URL) during request serialization.
|
||||
LocalImage {
|
||||
path: std::path::PathBuf,
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user