mirror of
https://github.com/openai/codex.git
synced 2026-10-26 18:38:47 +00:00
[core] expose rollout history boundaries
This commit is contained in:
@@ -5,6 +5,7 @@ use crate::context_manager::normalize;
|
||||
use crate::event_mapping::has_non_contextual_dev_message_content;
|
||||
use crate::event_mapping::is_contextual_dev_message_content;
|
||||
use crate::event_mapping::is_contextual_user_message_content;
|
||||
use crate::rollout_history::is_user_turn_boundary;
|
||||
use crate::session::turn_context::TurnContext;
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
|
||||
@@ -16,7 +17,6 @@ use codex_protocol::models::FunctionCallOutputPayload;
|
||||
use codex_protocol::models::ImageDetail;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::InputModality;
|
||||
use codex_protocol::protocol::InterAgentCommunication;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use codex_protocol::protocol::TokenUsageInfo;
|
||||
use codex_protocol::protocol::TurnContextItem;
|
||||
@@ -747,22 +747,6 @@ fn is_model_generated_item(item: &ResponseItem) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_user_turn_boundary(item: &ResponseItem) -> bool {
|
||||
if matches!(item, ResponseItem::AgentMessage { .. }) {
|
||||
return true;
|
||||
}
|
||||
let ResponseItem::Message { role, content, .. } = item else {
|
||||
return false;
|
||||
};
|
||||
|
||||
(role == "user" && !is_contextual_user_message_content(content))
|
||||
|| (role == "assistant" && is_inter_agent_instruction_content(content))
|
||||
}
|
||||
|
||||
fn is_inter_agent_instruction_content(content: &[ContentItem]) -> bool {
|
||||
InterAgentCommunication::is_message_content(content)
|
||||
}
|
||||
|
||||
fn user_message_positions(items: &[ResponseItem]) -> Vec<usize> {
|
||||
let mut positions = Vec::new();
|
||||
for (idx, item) in items.iter().enumerate() {
|
||||
|
||||
@@ -3,5 +3,4 @@ mod normalize;
|
||||
pub(crate) mod updates;
|
||||
|
||||
pub(crate) use history::ContextManager;
|
||||
pub(crate) use history::is_user_turn_boundary;
|
||||
pub(crate) use history::truncate_function_output_payload;
|
||||
|
||||
@@ -136,6 +136,7 @@ pub use agents_md::LOCAL_AGENTS_MD_FILENAME;
|
||||
pub use agents_md::LoadedAgentsMd;
|
||||
mod rollout;
|
||||
mod rollout_budget;
|
||||
pub mod rollout_history;
|
||||
pub(crate) mod safety;
|
||||
mod session_rollout_init_error;
|
||||
pub mod shell;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
use crate::event_mapping::is_contextual_user_message_content;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::protocol::InterAgentCommunication;
|
||||
|
||||
/// Returns whether a response item starts a user-directed turn in stored history.
|
||||
///
|
||||
/// Context-only user messages do not start turns. Agent messages and structured
|
||||
/// assistant instructions do, since they represent input that expects a response.
|
||||
pub fn is_user_turn_boundary(item: &ResponseItem) -> bool {
|
||||
if matches!(item, ResponseItem::AgentMessage { .. }) {
|
||||
return true;
|
||||
}
|
||||
let ResponseItem::Message { role, content, .. } = item else {
|
||||
return false;
|
||||
};
|
||||
|
||||
(role == "user" && !is_contextual_user_message_content(content))
|
||||
|| (role == "assistant" && InterAgentCommunication::is_message_content(content))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "rollout_history_tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,66 @@
|
||||
use super::is_user_turn_boundary;
|
||||
use codex_protocol::AgentPath;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::protocol::InterAgentCommunication;
|
||||
|
||||
fn message(role: &str, content: ContentItem) -> ResponseItem {
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: role.to_string(),
|
||||
content: vec![content],
|
||||
phase: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn classifies_user_directed_turn_boundaries() {
|
||||
let user_message = message(
|
||||
"user",
|
||||
ContentItem::InputText {
|
||||
text: "hello".to_string(),
|
||||
},
|
||||
);
|
||||
let agent_message = ResponseItem::AgentMessage {
|
||||
author: "/root".to_string(),
|
||||
recipient: "/root/worker".to_string(),
|
||||
content: Vec::new(),
|
||||
};
|
||||
let instruction = InterAgentCommunication::new(
|
||||
AgentPath::root(),
|
||||
AgentPath::root().join("worker").expect("valid agent path"),
|
||||
Vec::new(),
|
||||
"continue".to_string(),
|
||||
/*trigger_turn*/ true,
|
||||
);
|
||||
let assistant_instruction = message(
|
||||
"assistant",
|
||||
ContentItem::OutputText {
|
||||
text: serde_json::to_string(&instruction).expect("instruction should serialize"),
|
||||
},
|
||||
);
|
||||
|
||||
assert!(is_user_turn_boundary(&user_message));
|
||||
assert!(is_user_turn_boundary(&agent_message));
|
||||
assert!(is_user_turn_boundary(&assistant_instruction));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn excludes_context_and_non_input_items() {
|
||||
let context_message = message(
|
||||
"user",
|
||||
ContentItem::InputText {
|
||||
text: "<environment_context><cwd>/tmp</cwd></environment_context>".to_string(),
|
||||
},
|
||||
);
|
||||
let assistant_message = message(
|
||||
"assistant",
|
||||
ContentItem::OutputText {
|
||||
text: "done".to_string(),
|
||||
},
|
||||
);
|
||||
|
||||
assert!(!is_user_turn_boundary(&context_message));
|
||||
assert!(!is_user_turn_boundary(&assistant_message));
|
||||
assert!(!is_user_turn_boundary(&ResponseItem::Other));
|
||||
}
|
||||
@@ -49,7 +49,7 @@ use codex_protocol::protocol::WarningEvent;
|
||||
use codex_protocol::request_permissions::RequestPermissionsResponse;
|
||||
use codex_protocol::request_user_input::RequestUserInputResponse;
|
||||
|
||||
use crate::context_manager::is_user_turn_boundary;
|
||||
use crate::rollout_history::is_user_turn_boundary;
|
||||
use codex_protocol::dynamic_tools::DynamicToolResponse;
|
||||
use codex_protocol::mcp::RequestId as ProtocolRequestId;
|
||||
use codex_rmcp_client::ElicitationAction;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use crate::context::world_state::WorldStateSnapshot;
|
||||
use crate::context_manager::is_user_turn_boundary;
|
||||
use crate::rollout_history::is_user_turn_boundary;
|
||||
use codex_protocol::protocol::SessionContextWindow;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
//! In core, "user turns" are detected by scanning `ResponseItem::Message` items and
|
||||
//! interpreting them via `event_mapping::parse_turn_item(...)`.
|
||||
|
||||
use crate::context_manager::is_user_turn_boundary;
|
||||
use crate::event_mapping;
|
||||
use crate::rollout_history::is_user_turn_boundary;
|
||||
use codex_protocol::items::TurnItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
|
||||
Reference in New Issue
Block a user