Add developer instructions for persistent mode (#41050)

## What changed

- Add bundled proactivity and follow-up guidance when `ReasoningEffort::Persistent` is selected.
- Allow model metadata to override or disable the guidance with `persistent_instructions`.
- Track the instructions as world state so effort and model changes replace or retire stale guidance without duplicating unchanged context.
- Tailor approval guidance to `send_user_message_async` availability, rebuild it for forked agents and rolled-back history, and exclude Guardian sessions.

## Testing

- Cover default, overridden, disabled, replaced, and retired instructions.
- Cover model changes, history transitions, agent forks, Guardian sessions, and asynchronous-message tool availability.

GitOrigin-RevId: 78e05d0335a70b385bd069b45edcd4ba570cef91
This commit is contained in:
brianz-openai authored and copyberry committed 2026-08-27 04:58:21 +00:00
1 parent 72c96598c6
commit f1433fc71f
24 files changed
+565 -9

No files matched your search

@@ -1051,6 +1051,12 @@ async fn guardian_allows_unified_exec_additional_permissions_requests_past_polic
#[tokio::test]
async fn process_compacted_history_preserves_separate_guardian_developer_message() {
let (session, mut turn_context) = make_session_and_context().await;
update_turn_settings_for_test(&mut turn_context, |settings| {
update_selected_settings_for_test(settings, |selected| {
selected.collaboration_mode.settings.reasoning_effort =
Some(ReasoningEffortConfig::Persistent);
});
});
let guardian_policy = "guardian policy".to_string();
let guardian_source =
SessionSource::SubAgent(SubAgentSource::Other(GUARDIAN_REVIEWER_NAME.to_string()));
@@ -1121,6 +1127,12 @@ async fn process_compacted_history_preserves_separate_guardian_developer_message
.iter()
.any(|(message, _)| message.contains("stale developer message"))
);
assert!(
!developer_messages
.iter()
.any(|(message, _)| message.contains("<persistent_mode>")),
"guardian context must not inherit persistent-mode proactivity"
);
assert!(developer_messages.len() >= 2);
assert_eq!(
developer_messages.last(),
+21
View File
@@ -17,6 +17,7 @@ use crate::context::world_state::ModelInstructionsState;
use crate::context::world_state::MultiAgentModeState;
use crate::context::world_state::MultiAgentUsageHintState;
use crate::context::world_state::PermissionsState;
use crate::context::world_state::PersistentModeState;
use crate::context::world_state::PersonalityState;
use crate::context::world_state::PluginsInstructionsState;
use crate::context::world_state::RealtimeState;
@@ -189,6 +190,26 @@ impl Session {
.and_then(|messages| messages.collaboration_modes.as_ref()),
));
}
if !crate::guardian::is_basic_session_source(&turn_context.session_source) {
let send_user_message_async_available =
!turn_context.session_source.is_non_root_agent()
&& step_context
.settings
.model_info
.experimental_supported_tools
.iter()
.any(|tool| tool == "send_user_message_async");
world_state.add_section(PersistentModeState::new(
step_context.settings.effective_reasoning_effort().as_ref(),
step_context
.settings
.model_info
.model_messages
.as_ref()
.and_then(|messages| messages.persistent_instructions.as_deref()),
send_user_message_async_available,
));
}
if turn_context.config.include_environment_context {
let current_date = self
.services