Resolve saved Daybreak choices for each subagent turn (#60773)

## Why

A subagent can use a different model from its parent, with different supported access programs. Saved Daybreak choices need to resolve against the subagent's model and remain consistent throughout its turn, including compaction.

## What changed

- Resolve saved choices before native subagent turns start, preserving explicit turn overrides and applying saved toggles on later turns.
- Distinguish inherited parent programs from explicit child selections. Adapt inherited Daybreak Blue/Red selections to the child model while retaining the saved choice as the default for later turns and nested subagents.
- Validate the account associated with automatic selections and reject incompatible saved choices before sending model requests, while retaining rejected user input in conversation history.
- Require model changes to wait until the next turn when a saved Daybreak choice is present.

## Testing

Add coverage for both multi-agent spawn versions, model-specific selection, automatic compaction, WebSocket response reuse, account changes, unsupported choices, and rejected-input persistence across resume.

GitOrigin-RevId: 11971138d656600d9878187225e4d33217e68ad4
This commit is contained in:
sayan-oai
2026-11-11 10:10:37 +00:00
committed by copyberry
parent 340a18ed7c
commit c1934fc99e
12 changed files with 1043 additions and 82 deletions
@@ -269,6 +269,20 @@ impl Session {
let Some((turn_context, task_done, current)) = target else {
return TurnSettingsUpdateOutcome::TargetUnavailable;
};
if update
.model
.as_ref()
.is_some_and(|model| *model != current.model_info.slug)
&& turn_context
.extension_data
.get::<crate::agent::helper_daybreak::SavedIntent>()
.is_some()
{
return TurnSettingsUpdateOutcome::Rejected {
reason: "Change the model on the next turn when using a saved Daybreak choice"
.to_string(),
};
}
let TurnSettingsUpdate {
approvals_reviewer,
environments: environment_requests,
+1 -1
View File
@@ -1491,7 +1491,7 @@ impl Session {
turn_context.cyber_access_program =
cyber_access_program::for_provider(&turn_context.config, options.cyber_access_program);
if let Some(admission) = options.helper_admission {
admission.capture_intent(self, &turn_context).await;
admission.capture_intent(self, &mut turn_context).await;
}
// Tool observers retain this turn's selection even after a later turn starts.
if let Some(program) = turn_context.cyber_access_program {