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
This commit is contained in:
rka-oai
2026-08-13 22:30:59 +00:00
committed by copyberry
parent bff03ecce5
commit 6344a655a5
2 changed files with 35 additions and 7 deletions
+8 -5
View File
@@ -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,
) {
@@ -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("<current_time_reminder>"))
.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(