From 6344a655a5966f92e009a74928fb0559b41f9093 Mon Sep 17 00:00:00 2001 From: rka-oai Date: Thu, 13 Aug 2026 22:16:10 +0000 Subject: [PATCH] Refresh current-time reminders for full-history subagents (#38446) ## What changed - Exclude current-time reminder developer messages when copying parent history into a full-history subagent. - Keep the child's newly generated reminder, preventing inherited reminders from accumulating while preserving the rest of the forked context. ## Testing - Extend the full-history V2 spawn test to verify that two reminders in the parent become one fresh reminder in the child request. GitOrigin-RevId: fb61c72f7f0d61d1068f2c599a8b8caf1788b7e2 --- codex-rs/core/src/agent/control/spawn.rs | 13 +++++---- .../tests/suite/subagent_notifications.rs | 29 +++++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/codex-rs/core/src/agent/control/spawn.rs b/codex-rs/core/src/agent/control/spawn.rs index 9029352329..3bbdc5afc5 100644 --- a/codex-rs/core/src/agent/control/spawn.rs +++ b/codex-rs/core/src/agent/control/spawn.rs @@ -2,6 +2,8 @@ use super::residency::is_v2_resident_session_source; use super::*; use crate::agent::role::apply_role_to_config_for_multi_agent_v2; use crate::config::PermissionProfileSnapshot; +use crate::context::ContextualUserFragment; +use crate::context::CurrentTimeReminder; use codex_extension_api::ExtensionDataInit; const AGENT_NAMES: &str = include_str!("../agent_names.txt"); @@ -81,7 +83,7 @@ fn keep_forked_rollout_item(item: &RolloutItem, preserve_reference_context_item: } } -fn is_multi_agent_v2_usage_hint_message(item: &ResponseItem, usage_hint_texts: &[String]) -> bool { +fn is_fork_excluded_developer_message(item: &ResponseItem, usage_hint_texts: &[String]) -> bool { let ResponseItem::Message { role, content, .. } = item else { return false; }; @@ -92,9 +94,10 @@ fn is_multi_agent_v2_usage_hint_message(item: &ResponseItem, usage_hint_texts: & return false; }; - usage_hint_texts - .iter() - .any(|usage_hint_text| usage_hint_text == text) + CurrentTimeReminder::matches_text(text) + || usage_hint_texts + .iter() + .any(|usage_hint_text| usage_hint_text == text) } async fn load_agent_model_context( @@ -720,7 +723,7 @@ impl AgentControl { if matches!(response_item, ResponseItem::AgentMessage { .. }) { return false; } - if is_multi_agent_v2_usage_hint_message( + if is_fork_excluded_developer_message( response_item, &multi_agent_v2_usage_hint_texts_to_filter, ) { diff --git a/codex-rs/core/tests/suite/subagent_notifications.rs b/codex-rs/core/tests/suite/subagent_notifications.rs index 1f6b171ee5..4f6490f60e 100644 --- a/codex-rs/core/tests/suite/subagent_notifications.rs +++ b/codex-rs/core/tests/suite/subagent_notifications.rs @@ -3,6 +3,7 @@ use codex_core::StartThreadOptions; use codex_core::ThreadConfigSnapshot; use codex_core::TurnInputRequest; use codex_core::config::AgentRoleConfig; +use codex_core::config::CurrentTimeReminderConfig; use codex_features::Feature; use codex_history::RolloutItem; use codex_models_manager::bundled_models_response; @@ -1046,11 +1047,13 @@ enum FullHistoryV2ModelSelection { ConfiguredDefault, ExplicitOverride, WorldStateIdentity, + CurrentTimeReminders, } #[test_case(FullHistoryV2ModelSelection::ConfiguredDefault; "configured default with omitted fork_turns")] #[test_case(FullHistoryV2ModelSelection::ExplicitOverride; "explicit override with fork_turns all")] #[test_case(FullHistoryV2ModelSelection::WorldStateIdentity; "world state appends context window when agent identity changes")] +#[test_case(FullHistoryV2ModelSelection::CurrentTimeReminders; "full fork drops inherited current-time reminders")] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn spawned_full_history_v2_child_uses_model_precedence_without_dropping_context( selection: FullHistoryV2ModelSelection, @@ -1070,7 +1073,8 @@ async fn spawned_full_history_v2_child_uses_model_precedence_without_dropping_co .await; let (spawn_args, expected_model, expected_reasoning_effort) = match selection { FullHistoryV2ModelSelection::ConfiguredDefault - | FullHistoryV2ModelSelection::WorldStateIdentity => ( + | FullHistoryV2ModelSelection::WorldStateIdentity + | FullHistoryV2ModelSelection::CurrentTimeReminders => ( json!({ "message": CHILD_PROMPT, "task_name": "worker", @@ -1144,6 +1148,16 @@ async fn spawned_full_history_v2_child_uses_model_precedence_without_dropping_co .expect("test config should allow feature update"); config.model_context_window = Some(128_000); } + if matches!(selection, FullHistoryV2ModelSelection::CurrentTimeReminders) { + config + .features + .enable(Feature::CurrentTimeReminder) + .expect("test config should allow feature update"); + config.current_time_reminder = Some(CurrentTimeReminderConfig { + reminder_interval_seconds: 0, + ..CurrentTimeReminderConfig::default() + }); + } config.model = Some(INHERITED_MODEL.to_string()); config.model_reasoning_effort = Some(INHERITED_REASONING_EFFORT); config.agent_default_subagent_model = Some(V2_DEFAULT_MODEL.to_string()); @@ -1164,10 +1178,21 @@ async fn spawned_full_history_v2_child_uses_model_precedence_without_dropping_co test.submit_turn(TURN_0_FORK_PROMPT).await?; let _ = seed_turn.single_request(); test.submit_turn(TURN_1_PROMPT).await?; - let _ = spawn_turn.single_request(); + let parent_request = spawn_turn.single_request(); let child_request = wait_for_request_with_model(&child_request_log, expected_model).await?; assert!(child_request.body_contains_text(TURN_0_FORK_PROMPT)); + if matches!(selection, FullHistoryV2ModelSelection::CurrentTimeReminders) { + let reminder_count = |request: &ResponsesRequest| { + request + .message_input_texts("developer") + .into_iter() + .filter(|text| text.starts_with("")) + .count() + }; + assert_eq!(reminder_count(&parent_request), 2); + assert_eq!(reminder_count(&child_request), 1); + } let child_body = child_request.body_json(); if matches!(selection, FullHistoryV2ModelSelection::WorldStateIdentity) { let child_thread_id = ThreadId::from_string(