mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Make MultiAgentV2 interruption markers assistant-authored (#19124)
## Why `MultiAgentV2` follow-up messages are delivered to agents as assistant-authored `InterAgentCommunication` envelopes. When `followup_task` used `interrupt: true`, the interrupted-turn guidance was still persisted as a contextual user message, so model-visible history made a system-generated interruption boundary look user-authored. This keeps interruption guidance consistent with the rest of the v2 inter-agent message stream while preserving the legacy marker shape for non-v2 sessions. ## What changed - Make `interrupted_turn_history_marker` feature-aware. - Record the interrupted-turn marker as an assistant `OutputText` message when `Feature::MultiAgentV2` is enabled. - Keep the existing user contextual fragment for non-v2 sessions. - Apply the same feature-aware marker to interrupted fork snapshots. - Add coverage for the live `followup_task` interrupt path and the helper-level v2 marker shape. ## Testing - `cargo test -p codex-core multi_agent_v2_followup_task_interrupts_busy_child_without_losing_message -- --nocapture` - `cargo test -p codex-core multi_agent_v2_interrupted_marker_uses_assistant_output_message -- --nocapture` - `cargo test -p codex-core interrupted_fork_snapshot -- --nocapture`
This commit is contained in:
committed by
GitHub
Unverified
parent
21463a5074
commit
120aa07d81
@@ -446,12 +446,19 @@ fn interrupted_fork_snapshot_appends_interrupt_boundary() {
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(
|
||||
append_interrupted_boundary(committed_history, /*turn_id*/ None).get_rollout_items()
|
||||
append_interrupted_boundary(
|
||||
committed_history,
|
||||
/*turn_id*/ None,
|
||||
/*multi_agent_v2_enabled*/ false,
|
||||
)
|
||||
.get_rollout_items()
|
||||
)
|
||||
.expect("serialize interrupted fork history"),
|
||||
serde_json::to_value(vec![
|
||||
RolloutItem::ResponseItem(user_msg("hello")),
|
||||
RolloutItem::ResponseItem(interrupted_turn_history_marker()),
|
||||
RolloutItem::ResponseItem(interrupted_turn_history_marker(
|
||||
/*multi_agent_v2_enabled*/ false,
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id: None,
|
||||
reason: TurnAbortReason::Interrupted,
|
||||
@@ -463,11 +470,18 @@ fn interrupted_fork_snapshot_appends_interrupt_boundary() {
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_value(
|
||||
append_interrupted_boundary(InitialHistory::New, /*turn_id*/ None).get_rollout_items()
|
||||
append_interrupted_boundary(
|
||||
InitialHistory::New,
|
||||
/*turn_id*/ None,
|
||||
/*multi_agent_v2_enabled*/ false,
|
||||
)
|
||||
.get_rollout_items()
|
||||
)
|
||||
.expect("serialize interrupted empty fork history"),
|
||||
serde_json::to_value(vec![
|
||||
RolloutItem::ResponseItem(interrupted_turn_history_marker()),
|
||||
RolloutItem::ResponseItem(interrupted_turn_history_marker(
|
||||
/*multi_agent_v2_enabled*/ false,
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id: None,
|
||||
reason: TurnAbortReason::Interrupted,
|
||||
@@ -484,7 +498,9 @@ fn interrupted_snapshot_is_not_mid_turn() {
|
||||
let interrupted_history = InitialHistory::Forked(vec![
|
||||
RolloutItem::ResponseItem(user_msg("hello")),
|
||||
RolloutItem::ResponseItem(assistant_msg("partial")),
|
||||
RolloutItem::ResponseItem(interrupted_turn_history_marker()),
|
||||
RolloutItem::ResponseItem(interrupted_turn_history_marker(
|
||||
/*multi_agent_v2_enabled*/ false,
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id: Some("turn-1".to_string()),
|
||||
reason: TurnAbortReason::Interrupted,
|
||||
@@ -503,6 +519,24 @@ fn interrupted_snapshot_is_not_mid_turn() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_agent_v2_interrupted_marker_uses_developer_input_message() {
|
||||
let marker = interrupted_turn_history_marker(/*multi_agent_v2_enabled*/ true);
|
||||
|
||||
let ResponseItem::Message { role, content, .. } = marker else {
|
||||
panic!("expected interrupted marker to be a message");
|
||||
};
|
||||
assert_eq!(role, "developer");
|
||||
assert!(
|
||||
matches!(
|
||||
content.as_slice(),
|
||||
[ContentItem::InputText { text }]
|
||||
if text.contains(crate::context::TurnAborted::INTERRUPTED_DEVELOPER_GUIDANCE)
|
||||
),
|
||||
"expected interrupted marker to use developer InputText content"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completed_legacy_event_history_is_not_mid_turn() {
|
||||
let completed_history = InitialHistory::Forked(vec![
|
||||
@@ -618,9 +652,10 @@ async fn interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_histor
|
||||
.into_iter()
|
||||
.filter(|item| !matches!(item, RolloutItem::SessionMeta(_)))
|
||||
.collect();
|
||||
let interrupted_marker_json =
|
||||
serde_json::to_value(RolloutItem::ResponseItem(interrupted_turn_history_marker()))
|
||||
.expect("serialize interrupted marker");
|
||||
let interrupted_marker_json = serde_json::to_value(RolloutItem::ResponseItem(
|
||||
interrupted_turn_history_marker(/*multi_agent_v2_enabled*/ false),
|
||||
))
|
||||
.expect("serialize interrupted marker");
|
||||
let interrupted_abort_json = serde_json::to_value(RolloutItem::EventMsg(
|
||||
EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id: expected_turn_id,
|
||||
@@ -809,9 +844,10 @@ async fn interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_
|
||||
.into_iter()
|
||||
.filter(|item| !matches!(item, RolloutItem::SessionMeta(_)))
|
||||
.collect();
|
||||
let interrupted_marker_json =
|
||||
serde_json::to_value(RolloutItem::ResponseItem(interrupted_turn_history_marker()))
|
||||
.expect("serialize interrupted marker");
|
||||
let interrupted_marker_json = serde_json::to_value(RolloutItem::ResponseItem(
|
||||
interrupted_turn_history_marker(/*multi_agent_v2_enabled*/ false),
|
||||
))
|
||||
.expect("serialize interrupted marker");
|
||||
assert_eq!(
|
||||
forked_rollout_items
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user