chore(event_mapping) handle new ide context format

This commit is contained in:
Dylan Hurd
2026-01-08 01:39:41 -08:00
parent 0f8bb4579b
commit cb2584fd09
4 changed files with 79 additions and 21 deletions
+6
View File
@@ -8,11 +8,17 @@ use codex_protocol::models::ContentItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::protocol::ENVIRONMENT_CONTEXT_CLOSE_TAG;
use codex_protocol::protocol::ENVIRONMENT_CONTEXT_OPEN_TAG;
use codex_protocol::protocol::USER_IDE_CONTEXT_CLOSE_TAG;
use codex_protocol::protocol::USER_IDE_CONTEXT_OPEN_TAG;
use codex_utils_absolute_path::AbsolutePathBuf;
use serde::Deserialize;
use serde::Serialize;
use std::path::PathBuf;
pub(crate) fn is_user_ide_context(text: &str) -> bool {
text.starts_with(USER_IDE_CONTEXT_OPEN_TAG) && text.ends_with(USER_IDE_CONTEXT_CLOSE_TAG)
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename = "environment_context", rename_all = "snake_case")]
pub(crate) struct EnvironmentContext {
+65 -15
View File
@@ -13,6 +13,7 @@ use codex_protocol::user_input::UserInput;
use tracing::warn;
use uuid::Uuid;
use crate::environment_context::is_user_ide_context;
use crate::user_instructions::SkillInstructions;
use crate::user_instructions::UserInstructions;
use crate::user_shell_command::is_user_shell_command_text;
@@ -38,6 +39,10 @@ fn parse_user_message(message: &[ContentItem]) -> Option<UserMessageItem> {
if is_session_prefix(text) || is_user_shell_command_text(text) {
return None;
}
// user_ide_context is bundled with the user's prompt in its own content item
if is_user_ide_context(text) {
continue;
}
content.push(UserInput::Text { text: text.clone() });
}
ContentItem::InputImage { image_url } => {
@@ -49,12 +54,16 @@ fn parse_user_message(message: &[ContentItem]) -> Option<UserMessageItem> {
if is_session_prefix(text) {
return None;
}
warn!("Output text in user message: {}", text);
warn!("Output text in user message: {text}");
}
}
}
Some(UserMessageItem::new(&content))
if content.is_empty() {
None
} else {
Some(UserMessageItem::new(&content))
}
}
fn parse_agent_message(id: Option<&String>, message: &[ContentItem]) -> AgentMessageItem {
@@ -131,14 +140,26 @@ mod tests {
use super::parse_turn_item;
use codex_protocol::items::AgentMessageContent;
use codex_protocol::items::TurnItem;
use codex_protocol::items::UserMessageItem;
use codex_protocol::models::ContentItem;
use codex_protocol::models::ReasoningItemContent;
use codex_protocol::models::ReasoningItemReasoningSummary;
use codex_protocol::models::ResponseItem;
use codex_protocol::models::WebSearchAction;
use codex_protocol::protocol::USER_IDE_CONTEXT_CLOSE_TAG;
use codex_protocol::protocol::USER_IDE_CONTEXT_OPEN_TAG;
use codex_protocol::user_input::UserInput;
use pretty_assertions::assert_eq;
fn assert_eq_user_message_content(actual: TurnItem, expected_content: &[UserInput]) {
match actual {
TurnItem::UserMessage(user) => {
assert_eq!(user.content, expected_content);
}
other => panic!("expected TurnItem::UserMessage, got {other:?}"),
}
}
#[test]
fn parses_user_message_with_text_and_two_images() {
let img1 = "https://example.com/one.png".to_string();
@@ -162,19 +183,14 @@ mod tests {
let turn_item = parse_turn_item(&item).expect("expected user message turn item");
match turn_item {
TurnItem::UserMessage(user) => {
let expected_content = vec![
UserInput::Text {
text: "Hello world".to_string(),
},
UserInput::Image { image_url: img1 },
UserInput::Image { image_url: img2 },
];
assert_eq!(user.content, expected_content);
}
other => panic!("expected TurnItem::UserMessage, got {other:?}"),
}
let expected_content = vec![
UserInput::Text {
text: "Hello world".to_string(),
},
UserInput::Image { image_url: img1 },
UserInput::Image { image_url: img2 },
];
assert_eq_user_message_content(turn_item, &expected_content);
}
#[test]
@@ -216,6 +232,13 @@ mod tests {
text: "<user_shell_command>echo 42</user_shell_command>".to_string(),
}],
},
ResponseItem::Message {
id: None,
role: "user".to_string(),
content: vec![ContentItem::InputText {
text: "<user_ide_context>echo 42</user_ide_context>".to_string(),
}],
},
];
for item in items {
@@ -224,6 +247,33 @@ mod tests {
}
}
#[test]
fn trims_user_ide_context_item_from_user_message() {
let message = ResponseItem::Message {
id: Some("user-1".to_string()),
role: "user".to_string(),
content: vec![
ContentItem::InputText {
text: format!(
"{USER_IDE_CONTEXT_OPEN_TAG}some context{USER_IDE_CONTEXT_CLOSE_TAG}"
),
},
ContentItem::InputText {
text: "Hello world".to_string(),
},
],
};
let turn_item = parse_turn_item(&message).expect("expected user message turn item");
assert_eq_user_message_content(
turn_item,
&[UserInput::Text {
text: "Hello world".to_string(),
}],
);
}
#[test]
fn parses_agent_message() {
let item = ResponseItem::Message {
+6 -6
View File
@@ -10,7 +10,7 @@ use serde::Deserialize;
use serde::Serialize;
use ts_rs::TS;
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
#[serde(tag = "type")]
#[ts(tag = "type")]
pub enum TurnItem {
@@ -20,26 +20,26 @@ pub enum TurnItem {
WebSearch(WebSearchItem),
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
pub struct UserMessageItem {
pub id: String,
pub content: Vec<UserInput>,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
#[serde(tag = "type")]
#[ts(tag = "type")]
pub enum AgentMessageContent {
Text { text: String },
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
pub struct AgentMessageItem {
pub id: String,
pub content: Vec<AgentMessageContent>,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
pub struct ReasoningItem {
pub id: String,
pub summary_text: Vec<String>,
@@ -47,7 +47,7 @@ pub struct ReasoningItem {
pub raw_content: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
pub struct WebSearchItem {
pub id: String,
pub query: String,
+2
View File
@@ -49,6 +49,8 @@ pub const USER_INSTRUCTIONS_OPEN_TAG: &str = "<user_instructions>";
pub const USER_INSTRUCTIONS_CLOSE_TAG: &str = "</user_instructions>";
pub const ENVIRONMENT_CONTEXT_OPEN_TAG: &str = "<environment_context>";
pub const ENVIRONMENT_CONTEXT_CLOSE_TAG: &str = "</environment_context>";
pub const USER_IDE_CONTEXT_OPEN_TAG: &str = "<user_ide_context>";
pub const USER_IDE_CONTEXT_CLOSE_TAG: &str = "</user_ide_context>";
pub const USER_MESSAGE_BEGIN: &str = "## My request for Codex:";
/// Submission Queue Entry - requests from user