Restore collaboration mode when resuming threads (#45519)

## Why

Resuming a thread initialized its collaboration mode to Default, losing the saved Plan mode and its developer instructions. Reconnecting clients also lacked a server-reported mode to reconcile changes made by another client.

## What changed

- Restore the saved collaboration mode from the latest matching `ThreadSettingsApplied` event, falling back to the last legacy `TurnContext`. Apply the effective model and reasoning effort while retaining the saved mode and developer instructions.
- Include `collaborationMode` in `thread/resume` responses and update the generated schemas and bindings.
- Use the restored mode in the TUI, including the first prompt after resume. Prefer the server's mode when restoring disconnected input, while preserving the local selection for older servers that omit it.

## Testing

Add regression coverage for persisted and legacy collaboration modes, model and reasoning-effort overrides, the resumed Plan mode display and first prompt, and reconnect behavior with and without a server-reported mode.

GitOrigin-RevId: ed064516e7fae1c1668152ab448f510cbcacfe06
This commit is contained in:
Eric Traut authored and copyberry committed 2026-09-14 21:33:45 +00:00
1 parent 7c73903be2
commit 91d54f1667
22 files changed
+309 -13

No files matched your search

+35
View File
@@ -761,6 +761,34 @@ impl Session {
});
// TODO (aibrahim): Consolidate config.model and config.model_reasoning_effort into config.collaboration_mode
// to avoid extracting these fields separately and constructing CollaborationMode here.
let persisted_collaboration_mode = match &conversation_history {
InitialHistory::Resumed(resumed) => resumed
.history
.iter()
.rev()
.find_map(|item| match item {
RolloutItem::EventMsg(EventMsg::ThreadSettingsApplied(event))
if event.thread_id == Some(resumed.conversation_id) =>
{
Some(&event.thread_settings.collaboration_mode)
}
_ => None,
})
.or_else(|| {
resumed
.history
.iter()
.rev()
.find_map(|item| match item {
RolloutItem::TurnContext(context) => {
Some(context.collaboration_mode.as_ref())
}
_ => None,
})
.flatten()
}),
InitialHistory::New | InitialHistory::Cleared | InitialHistory::Forked(_) => None,
};
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
settings: Settings {
@@ -769,6 +797,13 @@ impl Session {
developer_instructions: None,
},
};
let collaboration_mode = persisted_collaboration_mode.map_or(collaboration_mode, |saved| {
saved.with_updates(
Some(model.clone()),
Some(config.model_reasoning_effort.clone()),
/*developer_instructions*/ None,
)
});
let fast_mode_enabled = config.features.enabled(Feature::FastMode);
let initial_service_tier_warning = unsupported_service_tier_warning(
config.service_tier.as_deref(),