diff --git a/codex-rs/app-server/tests/suite/list_resume.rs b/codex-rs/app-server/tests/suite/list_resume.rs index 983553e06e..f2b82c6111 100644 --- a/codex-rs/app-server/tests/suite/list_resume.rs +++ b/codex-rs/app-server/tests/suite/list_resume.rs @@ -307,6 +307,7 @@ async fn test_list_and_resume_conversations() -> Result<()> { content: vec![ContentItem::InputText { text: fork_history_text.to_string(), }], + end_turn: None, }]; let resume_with_history_req_id = mcp .send_resume_conversation_request(ResumeConversationParams { diff --git a/codex-rs/app-server/tests/suite/v2/thread_resume.rs b/codex-rs/app-server/tests/suite/v2/thread_resume.rs index d2fa72ef14..2865d73649 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_resume.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_resume.rs @@ -218,6 +218,7 @@ async fn thread_resume_supports_history_and_overrides() -> Result<()> { content: vec![ContentItem::InputText { text: history_text.to_string(), }], + end_turn: None, }]; // Resume with explicit history and override the model. diff --git a/codex-rs/codex-api/src/endpoint/chat.rs b/codex-rs/codex-api/src/endpoint/chat.rs index 8fe1d2a521..2148a5ad93 100644 --- a/codex-rs/codex-api/src/endpoint/chat.rs +++ b/codex-rs/codex-api/src/endpoint/chat.rs @@ -193,6 +193,7 @@ impl Stream for AggregatedStream { content: vec![ContentItem::OutputText { text: std::mem::take(&mut this.cumulative), }], + end_turn: None, }; this.pending .push_back(ResponseEvent::OutputItemDone(aggregated_message)); diff --git a/codex-rs/codex-api/src/requests/chat.rs b/codex-rs/codex-api/src/requests/chat.rs index 30d8b478d2..5c16a5fb58 100644 --- a/codex-rs/codex-api/src/requests/chat.rs +++ b/codex-rs/codex-api/src/requests/chat.rs @@ -386,6 +386,7 @@ mod tests { content: vec![ContentItem::InputText { text: "hi".to_string(), }], + end_turn: None, }]; let req = ChatRequestBuilder::new("gpt-test", "inst", &prompt_input, &[]) .conversation_id(Some("conv-1".into())) @@ -412,6 +413,7 @@ mod tests { content: vec![ContentItem::InputText { text: "read these".to_string(), }], + end_turn: None, }, ResponseItem::FunctionCall { id: None, diff --git a/codex-rs/codex-api/src/requests/responses.rs b/codex-rs/codex-api/src/requests/responses.rs index 65f7dc0243..73a413dd93 100644 --- a/codex-rs/codex-api/src/requests/responses.rs +++ b/codex-rs/codex-api/src/requests/responses.rs @@ -223,11 +223,13 @@ mod tests { id: Some("m1".into()), role: "assistant".into(), content: Vec::new(), + end_turn: None, }, ResponseItem::Message { id: None, role: "assistant".into(), content: Vec::new(), + end_turn: None, }, ]; diff --git a/codex-rs/codex-api/src/sse/chat.rs b/codex-rs/codex-api/src/sse/chat.rs index afd7c8852b..a3effce2e7 100644 --- a/codex-rs/codex-api/src/sse/chat.rs +++ b/codex-rs/codex-api/src/sse/chat.rs @@ -330,6 +330,7 @@ async fn append_assistant_text( id: None, role: "assistant".to_string(), content: vec![], + end_turn: None, }; *assistant_item = Some(item.clone()); let _ = tx_event diff --git a/codex-rs/codex-api/tests/clients.rs b/codex-rs/codex-api/tests/clients.rs index 1a513bdca4..b71edf3244 100644 --- a/codex-rs/codex-api/tests/clients.rs +++ b/codex-rs/codex-api/tests/clients.rs @@ -308,6 +308,7 @@ async fn streaming_client_retries_on_transport_error() -> Result<()> { content: vec![ContentItem::InputText { text: "hi".to_string(), }], + end_turn: None, }], tools: Vec::::new(), parallel_tool_calls: false, diff --git a/codex-rs/core/dfa_unless_trusted_5_1.txt b/codex-rs/core/dfa_unless_trusted_5_1.txt deleted file mode 100644 index 72b7d8ecde..0000000000 --- a/codex-rs/core/dfa_unless_trusted_5_1.txt +++ /dev/null @@ -1 +0,0 @@ -danger-unless-trusted \ No newline at end of file diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index cb81c9aa4d..9ca11cd73b 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -1504,6 +1504,7 @@ impl Session { content: vec![ContentItem::InputText { text: format!("Warning: {}", message.into()), }], + end_turn: None, }; self.record_conversation_items(ctx, &[item]).await; @@ -3613,6 +3614,7 @@ mod tests { content: vec![ContentItem::InputText { text: "turn 1 user".to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -3620,6 +3622,7 @@ mod tests { content: vec![ContentItem::OutputText { text: "turn 1 assistant".to_string(), }], + end_turn: None, }, ]; sess.record_into_history(&turn_1, tc.as_ref()).await; @@ -3631,6 +3634,7 @@ mod tests { content: vec![ContentItem::InputText { text: "turn 2 user".to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -3638,6 +3642,7 @@ mod tests { content: vec![ContentItem::OutputText { text: "turn 2 assistant".to_string(), }], + end_turn: None, }, ]; sess.record_into_history(&turn_2, tc.as_ref()).await; @@ -3669,6 +3674,7 @@ mod tests { content: vec![ContentItem::InputText { text: "turn 1 user".to_string(), }], + end_turn: None, }]; sess.record_into_history(&turn_1, tc.as_ref()).await; @@ -4561,6 +4567,7 @@ mod tests { content: vec![ContentItem::InputText { text: "first user".to_string(), }], + end_turn: None, }; live_history.record_items(std::iter::once(&user1), turn_context.truncation_policy); rollout_items.push(RolloutItem::ResponseItem(user1.clone())); @@ -4571,6 +4578,7 @@ mod tests { content: vec![ContentItem::OutputText { text: "assistant reply one".to_string(), }], + end_turn: None, }; live_history.record_items(std::iter::once(&assistant1), turn_context.truncation_policy); rollout_items.push(RolloutItem::ResponseItem(assistant1.clone())); @@ -4595,6 +4603,7 @@ mod tests { content: vec![ContentItem::InputText { text: "second user".to_string(), }], + end_turn: None, }; live_history.record_items(std::iter::once(&user2), turn_context.truncation_policy); rollout_items.push(RolloutItem::ResponseItem(user2.clone())); @@ -4605,6 +4614,7 @@ mod tests { content: vec![ContentItem::OutputText { text: "assistant reply two".to_string(), }], + end_turn: None, }; live_history.record_items(std::iter::once(&assistant2), turn_context.truncation_policy); rollout_items.push(RolloutItem::ResponseItem(assistant2.clone())); @@ -4629,6 +4639,7 @@ mod tests { content: vec![ContentItem::InputText { text: "third user".to_string(), }], + end_turn: None, }; live_history.record_items(std::iter::once(&user3), turn_context.truncation_policy); rollout_items.push(RolloutItem::ResponseItem(user3)); @@ -4639,6 +4650,7 @@ mod tests { content: vec![ContentItem::OutputText { text: "assistant reply three".to_string(), }], + end_turn: None, }; live_history.record_items(std::iter::once(&assistant3), turn_context.truncation_policy); rollout_items.push(RolloutItem::ResponseItem(assistant3)); diff --git a/codex-rs/core/src/compact.rs b/codex-rs/core/src/compact.rs index 958686c149..5c3d56f8d5 100644 --- a/codex-rs/core/src/compact.rs +++ b/codex-rs/core/src/compact.rs @@ -305,6 +305,7 @@ fn build_compacted_history_with_limit( content: vec![ContentItem::InputText { text: message.clone(), }], + end_turn: None, }); } @@ -318,6 +319,7 @@ fn build_compacted_history_with_limit( id: None, role: "user".to_string(), content: vec![ContentItem::InputText { text: summary_text }], + end_turn: None, }); history @@ -406,6 +408,7 @@ mod tests { content: vec![ContentItem::OutputText { text: "ignored".to_string(), }], + end_turn: None, }, ResponseItem::Message { id: Some("user".to_string()), @@ -413,6 +416,7 @@ mod tests { content: vec![ContentItem::InputText { text: "first".to_string(), }], + end_turn: None, }, ResponseItem::Other, ]; @@ -432,6 +436,7 @@ mod tests { text: "# AGENTS.md instructions for project\n\n\ndo things\n" .to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -439,6 +444,7 @@ mod tests { content: vec![ContentItem::InputText { text: "cwd=/tmp".to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -446,6 +452,7 @@ mod tests { content: vec![ContentItem::InputText { text: "real user message".to_string(), }], + end_turn: None, }, ]; @@ -530,6 +537,7 @@ mod tests { content: vec![ContentItem::InputText { text: marker.clone(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -537,6 +545,7 @@ mod tests { content: vec![ContentItem::InputText { text: "real user message".to_string(), }], + end_turn: None, }, ]; diff --git a/codex-rs/core/src/context_manager/history_tests.rs b/codex-rs/core/src/context_manager/history_tests.rs index b3d061babf..50ee98e5b6 100644 --- a/codex-rs/core/src/context_manager/history_tests.rs +++ b/codex-rs/core/src/context_manager/history_tests.rs @@ -23,6 +23,7 @@ fn assistant_msg(text: &str) -> ResponseItem { content: vec![ContentItem::OutputText { text: text.to_string(), }], + end_turn: None, } } @@ -41,6 +42,7 @@ fn user_msg(text: &str) -> ResponseItem { content: vec![ContentItem::OutputText { text: text.to_string(), }], + end_turn: None, } } @@ -51,6 +53,7 @@ fn user_input_text_msg(text: &str) -> ResponseItem { content: vec![ContentItem::InputText { text: text.to_string(), }], + end_turn: None, } } @@ -93,6 +96,7 @@ fn filters_non_api_messages() { content: vec![ContentItem::OutputText { text: "ignored".to_string(), }], + end_turn: None, }; let reasoning = reasoning_msg("thinking..."); h.record_items([&system, &reasoning, &ResponseItem::Other], policy); @@ -121,14 +125,16 @@ fn filters_non_api_messages() { role: "user".to_string(), content: vec![ContentItem::OutputText { text: "hi".to_string() - }] + }], + end_turn: None, }, ResponseItem::Message { id: None, role: "assistant".to_string(), content: vec![ContentItem::OutputText { text: "hello".to_string() - }] + }], + end_turn: None, } ] ); @@ -255,6 +261,7 @@ fn replace_last_turn_images_does_not_touch_user_images() { content: vec![ContentItem::InputImage { image_url: "data:image/png;base64,AAA".to_string(), }], + end_turn: None, }]; let mut history = create_history_with_items(items.clone()); diff --git a/codex-rs/core/src/environment_context.rs b/codex-rs/core/src/environment_context.rs index 28b5032fac..f0b0877eba 100644 --- a/codex-rs/core/src/environment_context.rs +++ b/codex-rs/core/src/environment_context.rs @@ -79,6 +79,7 @@ impl From for ResponseItem { content: vec![ContentItem::InputText { text: ec.serialize_to_xml(), }], + end_turn: None, } } } diff --git a/codex-rs/core/src/event_mapping.rs b/codex-rs/core/src/event_mapping.rs index deee79ae70..55a1037542 100644 --- a/codex-rs/core/src/event_mapping.rs +++ b/codex-rs/core/src/event_mapping.rs @@ -89,7 +89,9 @@ fn parse_agent_message(id: Option<&String>, message: &[ContentItem]) -> AgentMes pub fn parse_turn_item(item: &ResponseItem) -> Option { match item { - ResponseItem::Message { role, content, id } => match role.as_str() { + ResponseItem::Message { + role, content, id, .. + } => match role.as_str() { "user" => parse_user_message(content).map(TurnItem::UserMessage), "assistant" => Some(TurnItem::AgentMessage(parse_agent_message( id.as_ref(), @@ -169,6 +171,7 @@ mod tests { image_url: img2.clone(), }, ], + end_turn: None, }; let turn_item = parse_turn_item(&item).expect("expected user message turn item"); @@ -210,6 +213,7 @@ mod tests { text: user_text.clone(), }, ], + end_turn: None, }; let turn_item = parse_turn_item(&item).expect("expected user message turn item"); @@ -250,6 +254,7 @@ mod tests { text: user_text.clone(), }, ], + end_turn: None, }; let turn_item = parse_turn_item(&item).expect("expected user message turn item"); @@ -278,6 +283,7 @@ mod tests { content: vec![ContentItem::InputText { text: "test_text".to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -285,6 +291,7 @@ mod tests { content: vec![ContentItem::InputText { text: "test_text".to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -292,6 +299,7 @@ mod tests { content: vec![ContentItem::InputText { text: "# AGENTS.md instructions for test_directory\n\n\ntest_text\n".to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -300,6 +308,7 @@ mod tests { text: "\ndemo\nskills/demo/SKILL.md\nbody\n" .to_string(), }], + end_turn: None, }, ResponseItem::Message { id: None, @@ -307,6 +316,7 @@ mod tests { content: vec![ContentItem::InputText { text: "echo 42".to_string(), }], + end_turn: None, }, ]; @@ -324,6 +334,7 @@ mod tests { content: vec![ContentItem::OutputText { text: "Hello from Codex".to_string(), }], + end_turn: None, }; let turn_item = parse_turn_item(&item).expect("expected agent message turn item"); diff --git a/codex-rs/core/src/instructions/user_instructions.rs b/codex-rs/core/src/instructions/user_instructions.rs index 9c563c29c5..611bf4cbf8 100644 --- a/codex-rs/core/src/instructions/user_instructions.rs +++ b/codex-rs/core/src/instructions/user_instructions.rs @@ -38,6 +38,7 @@ impl From for ResponseItem { contents = ui.text ), }], + end_turn: None, } } } @@ -71,6 +72,7 @@ impl From for ResponseItem { si.name, si.path, si.contents ), }], + end_turn: None, } } } diff --git a/codex-rs/core/src/rollout/tests.rs b/codex-rs/core/src/rollout/tests.rs index 08d4a1e2c9..4dcd07ca7c 100644 --- a/codex-rs/core/src/rollout/tests.rs +++ b/codex-rs/core/src/rollout/tests.rs @@ -806,6 +806,7 @@ async fn test_updated_at_uses_file_mtime() -> Result<()> { content: vec![ContentItem::OutputText { text: format!("reply-{idx}"), }], + end_turn: None, }), }; writeln!(file, "{}", serde_json::to_string(&response_line)?)?; diff --git a/codex-rs/core/src/rollout/truncation.rs b/codex-rs/core/src/rollout/truncation.rs index 0f72cfc50e..e6a84628fc 100644 --- a/codex-rs/core/src/rollout/truncation.rs +++ b/codex-rs/core/src/rollout/truncation.rs @@ -85,6 +85,7 @@ mod tests { content: vec![ContentItem::OutputText { text: text.to_string(), }], + end_turn: None, } } @@ -95,6 +96,7 @@ mod tests { content: vec![ContentItem::OutputText { text: text.to_string(), }], + end_turn: None, } } diff --git a/codex-rs/core/src/tasks/mod.rs b/codex-rs/core/src/tasks/mod.rs index 91303a3bdc..a2f30aa522 100644 --- a/codex-rs/core/src/tasks/mod.rs +++ b/codex-rs/core/src/tasks/mod.rs @@ -256,6 +256,7 @@ impl Session { "{TURN_ABORTED_OPEN_TAG}\n {sub_id}\n interrupted\n {TURN_ABORTED_INTERRUPTED_GUIDANCE}\n" ), }], + end_turn: None, }; self.record_into_history(std::slice::from_ref(&marker), task.turn_context.as_ref()) .await; diff --git a/codex-rs/core/src/tasks/review.rs b/codex-rs/core/src/tasks/review.rs index 5b0d0bebe9..d156d3e0d5 100644 --- a/codex-rs/core/src/tasks/review.rs +++ b/codex-rs/core/src/tasks/review.rs @@ -221,6 +221,7 @@ pub(crate) async fn exit_review_mode( id: Some(REVIEW_USER_MESSAGE_ID.to_string()), role: "user".to_string(), content: vec![ContentItem::InputText { text: user_message }], + end_turn: None, }], ) .await; @@ -239,6 +240,7 @@ pub(crate) async fn exit_review_mode( content: vec![ContentItem::OutputText { text: assistant_message, }], + end_turn: None, }, ) .await; diff --git a/codex-rs/core/src/thread_manager.rs b/codex-rs/core/src/thread_manager.rs index 6aa4d378d2..70d8cb7900 100644 --- a/codex-rs/core/src/thread_manager.rs +++ b/codex-rs/core/src/thread_manager.rs @@ -411,6 +411,7 @@ mod tests { content: vec![ContentItem::OutputText { text: text.to_string(), }], + end_turn: None, } } fn assistant_msg(text: &str) -> ResponseItem { @@ -420,6 +421,7 @@ mod tests { content: vec![ContentItem::OutputText { text: text.to_string(), }], + end_turn: None, } } diff --git a/codex-rs/core/src/user_shell_command.rs b/codex-rs/core/src/user_shell_command.rs index fb8efcc09c..566f39958e 100644 --- a/codex-rs/core/src/user_shell_command.rs +++ b/codex-rs/core/src/user_shell_command.rs @@ -62,6 +62,7 @@ pub fn user_shell_command_record_item( content: vec![ContentItem::InputText { text: format_user_shell_command_record(command, exec_output, turn_context), }], + end_turn: None, } } diff --git a/codex-rs/core/tests/chat_completions_payload.rs b/codex-rs/core/tests/chat_completions_payload.rs index 23b50823f9..cdb92fe672 100644 --- a/codex-rs/core/tests/chat_completions_payload.rs +++ b/codex-rs/core/tests/chat_completions_payload.rs @@ -135,6 +135,7 @@ fn user_message(text: &str) -> ResponseItem { content: vec![ContentItem::InputText { text: text.to_string(), }], + end_turn: None, } } @@ -145,6 +146,7 @@ fn assistant_message(text: &str) -> ResponseItem { content: vec![ContentItem::OutputText { text: text.to_string(), }], + end_turn: None, } } diff --git a/codex-rs/core/tests/chat_completions_sse.rs b/codex-rs/core/tests/chat_completions_sse.rs index f6d7eb24fe..05ef476a05 100644 --- a/codex-rs/core/tests/chat_completions_sse.rs +++ b/codex-rs/core/tests/chat_completions_sse.rs @@ -109,6 +109,7 @@ async fn run_stream_with_bytes(sse_body: &[u8]) -> Vec { content: vec![ContentItem::InputText { text: "hello".to_string(), }], + end_turn: None, }]; let mut stream = match client.stream(&prompt).await { diff --git a/codex-rs/core/tests/responses_headers.rs b/codex-rs/core/tests/responses_headers.rs index 8eba3eabe7..22d9fa8b79 100644 --- a/codex-rs/core/tests/responses_headers.rs +++ b/codex-rs/core/tests/responses_headers.rs @@ -104,6 +104,7 @@ async fn responses_stream_includes_subagent_header_on_review() { content: vec![ContentItem::InputText { text: "hello".into(), }], + end_turn: None, }]; let mut stream = client_session.stream(&prompt).await.expect("stream failed"); @@ -200,6 +201,7 @@ async fn responses_stream_includes_subagent_header_on_other() { content: vec![ContentItem::InputText { text: "hello".into(), }], + end_turn: None, }]; let mut stream = client_session.stream(&prompt).await.expect("stream failed"); @@ -354,6 +356,7 @@ async fn responses_respects_model_info_overrides_from_config() { content: vec![ContentItem::InputText { text: "hello".into(), }], + end_turn: None, }]; let mut stream = client.stream(&prompt).await.expect("stream failed"); diff --git a/codex-rs/core/tests/suite/client.rs b/codex-rs/core/tests/suite/client.rs index 1b43f7932f..2231599890 100644 --- a/codex-rs/core/tests/suite/client.rs +++ b/codex-rs/core/tests/suite/client.rs @@ -194,6 +194,7 @@ async fn resume_includes_initial_messages_and_sends_prior_items() { content: vec![codex_protocol::models::ContentItem::InputText { text: "resumed user message".to_string(), }], + end_turn: None, }; let prior_user_json = serde_json::to_value(&prior_user).unwrap(); writeln!( @@ -214,6 +215,7 @@ async fn resume_includes_initial_messages_and_sends_prior_items() { content: vec![codex_protocol::models::ContentItem::OutputText { text: "resumed system instruction".to_string(), }], + end_turn: None, }; let prior_system_json = serde_json::to_value(&prior_system).unwrap(); writeln!( @@ -234,6 +236,7 @@ async fn resume_includes_initial_messages_and_sends_prior_items() { content: vec![codex_protocol::models::ContentItem::OutputText { text: "resumed assistant message".to_string(), }], + end_turn: None, }; let prior_item_json = serde_json::to_value(&prior_item).unwrap(); writeln!( @@ -1275,6 +1278,7 @@ async fn azure_responses_request_includes_store_and_reasoning_ids() { content: vec![ContentItem::OutputText { text: "message".into(), }], + end_turn: None, }); prompt.input.push(ResponseItem::WebSearchCall { id: Some("web-search-id".into()), diff --git a/codex-rs/core/tests/suite/client_websockets.rs b/codex-rs/core/tests/suite/client_websockets.rs index 1532ac74d1..d55d71d0d8 100644 --- a/codex-rs/core/tests/suite/client_websockets.rs +++ b/codex-rs/core/tests/suite/client_websockets.rs @@ -170,6 +170,7 @@ fn message_item(text: &str) -> ResponseItem { id: None, role: "user".into(), content: vec![ContentItem::InputText { text: text.into() }], + end_turn: None, } } diff --git a/codex-rs/core/tests/suite/compact.rs b/codex-rs/core/tests/suite/compact.rs index b06f5ef14b..94f768b77f 100644 --- a/codex-rs/core/tests/suite/compact.rs +++ b/codex-rs/core/tests/suite/compact.rs @@ -1221,6 +1221,7 @@ async fn auto_compact_runs_after_resume_when_token_usage_is_over_limit() { content: vec![codex_protocol::models::ContentItem::OutputText { text: remote_summary.to_string(), }], + end_turn: None, }, codex_protocol::models::ResponseItem::Compaction { encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(), @@ -2071,6 +2072,7 @@ async fn auto_compact_counts_encrypted_reasoning_before_last_user() { content: vec![codex_protocol::models::ContentItem::OutputText { text: "REMOTE_COMPACT_SUMMARY".to_string(), }], + end_turn: None, }, codex_protocol::models::ResponseItem::Compaction { encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(), @@ -2190,6 +2192,7 @@ async fn auto_compact_runs_when_reasoning_header_clears_between_turns() { content: vec![codex_protocol::models::ContentItem::OutputText { text: "REMOTE_COMPACT_SUMMARY".to_string(), }], + end_turn: None, }, codex_protocol::models::ResponseItem::Compaction { encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(), diff --git a/codex-rs/core/tests/suite/compact_remote.rs b/codex-rs/core/tests/suite/compact_remote.rs index a18baab540..a2cf73e110 100644 --- a/codex-rs/core/tests/suite/compact_remote.rs +++ b/codex-rs/core/tests/suite/compact_remote.rs @@ -58,6 +58,7 @@ async fn remote_compact_replaces_history_for_followups() -> Result<()> { content: vec![ContentItem::InputText { text: "REMOTE_COMPACTED_SUMMARY".to_string(), }], + end_turn: None, }, ResponseItem::Compaction { encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(), @@ -179,6 +180,7 @@ async fn remote_compact_runs_automatically() -> Result<()> { content: vec![ContentItem::InputText { text: "REMOTE_COMPACTED_SUMMARY".to_string(), }], + end_turn: None, }, ResponseItem::Compaction { encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(), @@ -246,6 +248,7 @@ async fn remote_compact_persists_replacement_history_in_rollout() -> Result<()> content: vec![ContentItem::InputText { text: "COMPACTED_USER_SUMMARY".to_string(), }], + end_turn: None, }, ResponseItem::Compaction { encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(), @@ -256,6 +259,7 @@ async fn remote_compact_persists_replacement_history_in_rollout() -> Result<()> content: vec![ContentItem::OutputText { text: "COMPACTED_ASSISTANT_NOTE".to_string(), }], + end_turn: None, }, ]; let compact_mock = responses::mount_compact_json_once( diff --git a/codex-rs/core/tests/suite/image_rollout.rs b/codex-rs/core/tests/suite/image_rollout.rs index 3c3f92ce45..e18f324125 100644 --- a/codex-rs/core/tests/suite/image_rollout.rs +++ b/codex-rs/core/tests/suite/image_rollout.rs @@ -156,6 +156,7 @@ async fn copy_paste_local_image_persists_rollout_request_shape() -> anyhow::Resu text: "pasted image".to_string(), }, ], + end_turn: None, }; assert_eq!(actual, expected); @@ -235,6 +236,7 @@ async fn drag_drop_image_persists_rollout_request_shape() -> anyhow::Result<()> text: "dropped image".to_string(), }, ], + end_turn: None, }; assert_eq!(actual, expected); diff --git a/codex-rs/core/tests/suite/review.rs b/codex-rs/core/tests/suite/review.rs index e5c980f681..1f0913470b 100644 --- a/codex-rs/core/tests/suite/review.rs +++ b/codex-rs/core/tests/suite/review.rs @@ -532,6 +532,7 @@ async fn review_input_isolated_from_parent_history() { content: vec![codex_protocol::models::ContentItem::InputText { text: "parent: earlier user message".to_string(), }], + end_turn: None, }; let user_json = serde_json::to_value(&user).unwrap(); let user_line = serde_json::json!({ @@ -550,6 +551,7 @@ async fn review_input_isolated_from_parent_history() { content: vec![codex_protocol::models::ContentItem::OutputText { text: "parent: assistant reply".to_string(), }], + end_turn: None, }; let assistant_json = serde_json::to_value(&assistant).unwrap(); let assistant_line = serde_json::json!({ diff --git a/codex-rs/protocol/src/models.rs b/codex-rs/protocol/src/models.rs index 1b22fb925f..ff440ac1c8 100644 --- a/codex-rs/protocol/src/models.rs +++ b/codex-rs/protocol/src/models.rs @@ -80,6 +80,10 @@ pub enum ResponseItem { id: Option, role: String, content: Vec, + // Do not use directly, no available consistently across all providers. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional)] + end_turn: Option, }, Reasoning { #[serde(default, skip_serializing)] @@ -328,6 +332,7 @@ impl From for ResponseItem { content: vec![ContentItem::InputText { text: di.into_text(), }], + end_turn: None, } } } @@ -497,6 +502,7 @@ impl From for ResponseItem { role, content, id: None, + end_turn: None, }, ResponseInputItem::FunctionCallOutput { call_id, output } => { Self::FunctionCallOutput { call_id, output } diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 0eb5e102a7..70bbf28aca 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -1607,6 +1607,7 @@ impl From for ResponseItem { content: vec![ContentItem::OutputText { text: value.message, }], + end_turn: None, } } }