Honor null thread instructions (#16964)

- Treat explicit null thread instructions as a blank-slate override
while preserving omitted-field fallback behavior.
- Preserve null through rollout resume/fork and keep explicit empty
strings distinct.
- Add app-server v2 start/fork coverage for the tri-state instruction
params.
This commit is contained in:
Ahmed Ibrahim
2026-04-06 21:10:19 -07:00
committed by GitHub
parent 4bb507d2c4
commit 24c598e8a9
39 changed files with 550 additions and 101 deletions

View File

@@ -591,11 +591,15 @@ async fn get_base_instructions_no_user_content() {
{
let mut state = session.state.lock().await;
state.session_configuration.base_instructions = model_info.base_instructions.clone();
state.session_configuration.base_instructions =
Some(model_info.base_instructions.clone());
}
let base_instructions = session.get_base_instructions().await;
assert_eq!(base_instructions.text, model_info.base_instructions);
assert_eq!(
base_instructions.expect("base instructions").text,
model_info.base_instructions
);
}
}
@@ -1091,7 +1095,7 @@ async fn recompute_token_usage_uses_session_base_instructions() {
let override_instructions = "SESSION_OVERRIDE_INSTRUCTIONS_ONLY".repeat(120);
{
let mut state = session.state.lock().await;
state.session_configuration.base_instructions = override_instructions.clone();
state.session_configuration.base_instructions = Some(override_instructions.clone());
}
let item = user_message("hello");
@@ -1855,7 +1859,7 @@ async fn set_rate_limits_retains_previous_credits() {
base_instructions: config
.base_instructions
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
.unwrap_or_else(|| Some(model_info.get_model_instructions(config.personality))),
compact_prompt: config.compact_prompt.clone(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
@@ -1957,7 +1961,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
base_instructions: config
.base_instructions
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
.unwrap_or_else(|| Some(model_info.get_model_instructions(config.personality))),
compact_prompt: config.compact_prompt.clone(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
@@ -2222,7 +2226,7 @@ async fn attach_rollout_recorder(session: &Arc<Session>) -> PathBuf {
ThreadId::default(),
/*forked_from_id*/ None,
SessionSource::Exec,
BaseInstructions::default(),
Some(BaseInstructions::default()),
Vec::new(),
EventPersistenceMode::Limited,
),
@@ -2306,7 +2310,7 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
base_instructions: config
.base_instructions
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
.unwrap_or_else(|| Some(model_info.get_model_instructions(config.personality))),
compact_prompt: config.compact_prompt.clone(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
@@ -2572,7 +2576,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
base_instructions: config
.base_instructions
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
.unwrap_or_else(|| Some(model_info.get_model_instructions(config.personality))),
compact_prompt: config.compact_prompt.clone(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
@@ -2675,7 +2679,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
base_instructions: config
.base_instructions
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
.unwrap_or_else(|| Some(model_info.get_model_instructions(config.personality))),
compact_prompt: config.compact_prompt.clone(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
@@ -3515,7 +3519,7 @@ pub(crate) async fn make_session_and_context_with_dynamic_tools_and_rx(
base_instructions: config
.base_instructions
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
.unwrap_or_else(|| Some(model_info.get_model_instructions(config.personality))),
compact_prompt: config.compact_prompt.clone(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
@@ -4264,7 +4268,7 @@ async fn record_context_updates_and_set_reference_context_item_persists_baseline
ThreadId::default(),
/*forked_from_id*/ None,
SessionSource::Exec,
BaseInstructions::default(),
Some(BaseInstructions::default()),
Vec::new(),
EventPersistenceMode::Limited,
),
@@ -4361,7 +4365,7 @@ async fn record_context_updates_and_set_reference_context_item_persists_full_rei
ThreadId::default(),
/*forked_from_id*/ None,
SessionSource::Exec,
BaseInstructions::default(),
Some(BaseInstructions::default()),
Vec::new(),
EventPersistenceMode::Limited,
),