mirror of
https://github.com/openai/codex.git
synced 2026-11-06 20:20:34 +00:00
## Why Multi-agent v2 `send_message` deliveries already reach the receiving model as typed `agent_message` items with encrypted content. Child-completion notifications are generated by Codex itself, so their content is plaintext and previously fell back to a serialized JSON envelope inside an assistant message. With plaintext `input_text` supported for `agent_message`, both delivery paths can use the same model-visible type while preserving explicit author and recipient metadata. ## What changed - add plaintext `input_text` support to `AgentMessageInputContent` and regenerate the affected app-server schemas - preserve `InterAgentCommunication` as structured mailbox input instead of converting it to assistant text - record delivered communications as typed `agent_message` history items - persist a dedicated rollout item so local delivery metadata such as `trigger_turn` remains available without leaking into the Responses request - reconstruct typed agent messages on resume and preserve fork-turn truncation behavior - remove request-time assistant-content parsing - preserve plaintext and encrypted inter-agent deliveries in stage-one memory inputs - normalize and link plaintext and encrypted agent messages in rollout traces without treating inbound messages as child results - cover the real MultiAgent V2 child-completion path end to end with deterministic mailbox synchronization ## Verification - `just test -p codex-core plaintext_multi_agent_v2_completion_sends_agent_message` - `just test -p codex-core input_queue_drains_mailbox_in_delivery_order record_initial_history_reconstructs_typed_inter_agent_message fork_turn_positions_use_inter_agent_delivery_metadata` - `just test -p codex-memories-write serializes_inter_agent_communications_for_memory` - `just test -p codex-rollout-trace agent_messages_preserve_routing_and_content sub_agent_started_activity_creates_spawn_edge` - `just test -p codex-rollout-trace agent_result_edge_falls_back_to_child_thread_without_result_message` - `just test -p codex-protocol -p codex-rollout -p codex-app-server-protocol`
162 lines
6.4 KiB
Rust
162 lines
6.4 KiB
Rust
use crate::protocol::EventMsg;
|
|
use crate::protocol::RolloutItem;
|
|
use codex_protocol::models::ResponseItem;
|
|
|
|
/// Whether a rollout `item` should be persisted in rollout files.
|
|
pub fn is_persisted_rollout_item(item: &RolloutItem) -> bool {
|
|
match item {
|
|
RolloutItem::ResponseItem(item) => should_persist_response_item(item),
|
|
RolloutItem::InterAgentCommunication(_) => true,
|
|
RolloutItem::EventMsg(ev) => should_persist_event_msg(ev),
|
|
// Persist Codex executive markers so we can analyze flows (e.g., compaction, API turns).
|
|
RolloutItem::Compacted(_) | RolloutItem::TurnContext(_) | RolloutItem::SessionMeta(_) => {
|
|
true
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Return the canonical rollout items that should be persisted for a live append.
|
|
pub fn persisted_rollout_items(items: &[RolloutItem]) -> Vec<RolloutItem> {
|
|
let mut persisted = Vec::new();
|
|
for item in items {
|
|
if is_persisted_rollout_item(item) {
|
|
persisted.push(item.clone());
|
|
}
|
|
}
|
|
persisted
|
|
}
|
|
|
|
/// Whether a `ResponseItem` should be persisted in rollout files.
|
|
#[inline]
|
|
pub fn should_persist_response_item(item: &ResponseItem) -> bool {
|
|
match item {
|
|
ResponseItem::Message { .. }
|
|
| ResponseItem::AgentMessage { .. }
|
|
| ResponseItem::Reasoning { .. }
|
|
| ResponseItem::LocalShellCall { .. }
|
|
| ResponseItem::FunctionCall { .. }
|
|
| ResponseItem::ToolSearchCall { .. }
|
|
| ResponseItem::FunctionCallOutput { .. }
|
|
| ResponseItem::ToolSearchOutput { .. }
|
|
| ResponseItem::CustomToolCall { .. }
|
|
| ResponseItem::CustomToolCallOutput { .. }
|
|
| ResponseItem::WebSearchCall { .. }
|
|
| ResponseItem::ImageGenerationCall { .. }
|
|
| ResponseItem::Compaction { .. }
|
|
| ResponseItem::ContextCompaction { .. } => true,
|
|
ResponseItem::CompactionTrigger => false,
|
|
ResponseItem::Other => false,
|
|
}
|
|
}
|
|
|
|
/// Whether a `ResponseItem` should be persisted for the memories.
|
|
#[inline]
|
|
pub fn should_persist_response_item_for_memories(item: &ResponseItem) -> bool {
|
|
match item {
|
|
ResponseItem::Message { role, .. } => role != "developer",
|
|
ResponseItem::LocalShellCall { .. }
|
|
| ResponseItem::FunctionCall { .. }
|
|
| ResponseItem::ToolSearchCall { .. }
|
|
| ResponseItem::FunctionCallOutput { .. }
|
|
| ResponseItem::ToolSearchOutput { .. }
|
|
| ResponseItem::CustomToolCall { .. }
|
|
| ResponseItem::CustomToolCallOutput { .. }
|
|
| ResponseItem::WebSearchCall { .. } => true,
|
|
ResponseItem::AgentMessage { .. }
|
|
| ResponseItem::Reasoning { .. }
|
|
| ResponseItem::ImageGenerationCall { .. }
|
|
| ResponseItem::Compaction { .. }
|
|
| ResponseItem::CompactionTrigger
|
|
| ResponseItem::ContextCompaction { .. }
|
|
| ResponseItem::Other => false,
|
|
}
|
|
}
|
|
|
|
/// Whether an `EventMsg` should be persisted in rollout files.
|
|
#[inline]
|
|
pub fn should_persist_event_msg(ev: &EventMsg) -> bool {
|
|
match ev {
|
|
EventMsg::UserMessage(_)
|
|
| EventMsg::AgentMessage(_)
|
|
| EventMsg::AgentReasoning(_)
|
|
| EventMsg::AgentReasoningRawContent(_)
|
|
| EventMsg::PatchApplyEnd(_)
|
|
| EventMsg::TokenCount(_)
|
|
| EventMsg::ThreadGoalUpdated(_)
|
|
| EventMsg::ContextCompacted(_)
|
|
| EventMsg::EnteredReviewMode(_)
|
|
| EventMsg::ExitedReviewMode(_)
|
|
| EventMsg::McpToolCallEnd(_)
|
|
| EventMsg::ThreadRolledBack(_)
|
|
| EventMsg::TurnAborted(_)
|
|
| EventMsg::TurnStarted(_)
|
|
| EventMsg::TurnComplete(_)
|
|
| EventMsg::WebSearchEnd(_)
|
|
| EventMsg::ImageGenerationEnd(_)
|
|
| EventMsg::SubAgentActivity(_) => true,
|
|
EventMsg::ItemCompleted(event) => {
|
|
// Plan items are derived from streaming tags and are not part of the
|
|
// raw ResponseItem history, so we persist their completion to replay
|
|
// them on resume without bloating rollouts with every item lifecycle.
|
|
matches!(event.item, codex_protocol::items::TurnItem::Plan(_))
|
|
}
|
|
EventMsg::Error(_)
|
|
| EventMsg::GuardianAssessment(_)
|
|
| EventMsg::ExecCommandEnd(_)
|
|
| EventMsg::ViewImageToolCall(_)
|
|
| EventMsg::CollabAgentSpawnEnd(_)
|
|
| EventMsg::CollabAgentInteractionEnd(_)
|
|
| EventMsg::CollabWaitingEnd(_)
|
|
| EventMsg::CollabCloseEnd(_)
|
|
| EventMsg::CollabResumeEnd(_)
|
|
| EventMsg::DynamicToolCallRequest(_)
|
|
| EventMsg::DynamicToolCallResponse(_)
|
|
| EventMsg::Warning(_)
|
|
| EventMsg::GuardianWarning(_)
|
|
| EventMsg::RealtimeConversationStarted(_)
|
|
| EventMsg::RealtimeConversationSdp(_)
|
|
| EventMsg::RealtimeConversationRealtime(_)
|
|
| EventMsg::RealtimeConversationClosed(_)
|
|
| EventMsg::ModelReroute(_)
|
|
| EventMsg::ModelVerification(_)
|
|
| EventMsg::TurnModerationMetadata(_)
|
|
| EventMsg::AgentReasoningSectionBreak(_)
|
|
| EventMsg::RawResponseItem(_)
|
|
| EventMsg::SessionConfigured(_)
|
|
| EventMsg::ThreadSettingsApplied(_)
|
|
| EventMsg::McpToolCallBegin(_)
|
|
| EventMsg::ExecCommandBegin(_)
|
|
| EventMsg::TerminalInteraction(_)
|
|
| EventMsg::ExecCommandOutputDelta(_)
|
|
| EventMsg::ExecApprovalRequest(_)
|
|
| EventMsg::RequestPermissions(_)
|
|
| EventMsg::RequestUserInput(_)
|
|
| EventMsg::ElicitationRequest(_)
|
|
| EventMsg::ApplyPatchApprovalRequest(_)
|
|
| EventMsg::StreamError(_)
|
|
| EventMsg::PatchApplyBegin(_)
|
|
| EventMsg::PatchApplyUpdated(_)
|
|
| EventMsg::TurnDiff(_)
|
|
| EventMsg::RealtimeConversationListVoicesResponse(_)
|
|
| EventMsg::McpStartupUpdate(_)
|
|
| EventMsg::McpStartupComplete(_)
|
|
| EventMsg::WebSearchBegin(_)
|
|
| EventMsg::PlanUpdate(_)
|
|
| EventMsg::ShutdownComplete
|
|
| EventMsg::DeprecationNotice(_)
|
|
| EventMsg::ItemStarted(_)
|
|
| EventMsg::HookStarted(_)
|
|
| EventMsg::HookCompleted(_)
|
|
| EventMsg::AgentMessageContentDelta(_)
|
|
| EventMsg::PlanDelta(_)
|
|
| EventMsg::ReasoningContentDelta(_)
|
|
| EventMsg::ReasoningRawContentDelta(_)
|
|
| EventMsg::ImageGenerationBegin(_)
|
|
| EventMsg::CollabAgentSpawnBegin(_)
|
|
| EventMsg::CollabAgentInteractionBegin(_)
|
|
| EventMsg::CollabWaitingBegin(_)
|
|
| EventMsg::CollabCloseBegin(_)
|
|
| EventMsg::CollabResumeBegin(_) => false,
|
|
}
|
|
}
|