mirror of
https://github.com/openai/codex.git
synced 2026-11-14 21:40:39 +00:00
Enable conversation-scoped speed selection for Cloud turns (#61178)
## What changed - Stage Cloud speed choices for the next new turn in the conversation, alongside pending model and effort selections. Update the displayed conversation speed after admission without changing the local default. - Offer speed commands supported by the pending model. Clear an incompatible pending speed change with a warning when switching models. - Carry `service_tier` through Cloud message requests, preserving omission to inherit the thread tier and explicit null to clear it. Translate `default` to null and reject tier overrides on queued requests. ## Testing Add tests for Cloud speed toggling, model-dependent speed choices, admission-time updates, and preserving the conversation tier when selecting a model. Extend request and wire tests to cover service-tier values, explicit clearing, and queue rejection. GitOrigin-RevId: b4daa701f1fe29593d90a938e60cc20cb980298a
This commit is contained in:
committed by
copyberry
parent
72532ecae5
commit
b279cfb170
@@ -3016,6 +3016,39 @@ impl App {
|
||||
AppEvent::PersistRealtimeVoiceSelection { voice } => {
|
||||
self.persist_realtime_voice(app_server, voice).await;
|
||||
}
|
||||
AppEvent::ToggleCloudServiceTier { thread_id, tier } => {
|
||||
if self.active_thread_id == Some(thread_id)
|
||||
&& self.chat_widget.thread_id() == Some(thread_id)
|
||||
&& app_server.thread_params_mode() == crate::ThreadParamsMode::Cloud
|
||||
{
|
||||
if !self.chat_widget.current_model_service_tier_commands().iter()
|
||||
.any(|command| command.id == tier)
|
||||
{
|
||||
self.chat_widget.add_error_message(
|
||||
"The selected Cloud model does not support that speed.".into(),
|
||||
);
|
||||
return Ok(AppRunControl::Continue);
|
||||
}
|
||||
let current = self.chat_widget.config_ref().service_tier.as_deref();
|
||||
match app_server.toggle_cloud_service_tier(thread_id, current, tier) {
|
||||
Some(tier) => {
|
||||
let label = match tier.as_str() {
|
||||
codex_protocol::config_types::SERVICE_TIER_DEFAULT_REQUEST_VALUE => "standard",
|
||||
"priority" => "fast",
|
||||
tier => tier,
|
||||
};
|
||||
self.chat_widget.add_info_message(
|
||||
format!("Selected {label} speed for the next new turn in this conversation"),
|
||||
/*hint*/ None,
|
||||
);
|
||||
}
|
||||
None => self.chat_widget.add_error_message(
|
||||
"The Cloud account changed. Reopen the conversation before choosing a speed."
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
AppEvent::PersistServiceTierSelection { service_tier } => {
|
||||
self.refresh_status_line();
|
||||
self.config.service_tier = service_tier.clone();
|
||||
|
||||
@@ -103,36 +103,44 @@ impl App {
|
||||
);
|
||||
return;
|
||||
};
|
||||
if service_tier.is_some()
|
||||
|| model == crate::model_catalog::LUNA_RESERVE_MODEL
|
||||
|| !self.model_catalog.models.iter().any(|preset| {
|
||||
preset.model == model
|
||||
&& effort.as_ref().is_none_or(|effort| {
|
||||
*effort == preset.default_reasoning_effort
|
||||
|| preset
|
||||
.supported_reasoning_efforts
|
||||
.iter()
|
||||
.any(|preset| &preset.effort == effort)
|
||||
})
|
||||
&& preset.model_specialty.as_deref() != Some(MODEL_SPECIALTY_CYBER)
|
||||
})
|
||||
{
|
||||
let preset = self.model_catalog.models.iter().find(|preset| {
|
||||
preset.model == model
|
||||
&& effort.as_ref().is_none_or(|effort| {
|
||||
*effort == preset.default_reasoning_effort
|
||||
|| preset
|
||||
.supported_reasoning_efforts
|
||||
.iter()
|
||||
.any(|preset| &preset.effort == effort)
|
||||
})
|
||||
&& preset.model_specialty.as_deref() != Some(MODEL_SPECIALTY_CYBER)
|
||||
});
|
||||
let Some(preset) = preset.filter(|_| {
|
||||
service_tier.is_none() && model != crate::model_catalog::LUNA_RESERVE_MODEL
|
||||
}) else {
|
||||
self.chat_widget.add_error_message(
|
||||
"Choose a supported Cloud model and effort at the current speed.".into(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let label = Self::reasoning_label_for(&model, effort.as_ref())
|
||||
.map_or_else(String::new, |label| format!(" {label}"));
|
||||
let message =
|
||||
format!("Selected {model}{label} for the next new turn in this conversation");
|
||||
if app_server.stage_cloud_model_selection(thread_id, model, effort) {
|
||||
self.chat_widget.add_info_message(message, /*hint*/ None);
|
||||
} else {
|
||||
self.chat_widget.add_error_message(
|
||||
match app_server.stage_cloud_model_selection(thread_id, preset, effort) {
|
||||
Ok(dropped_tier) => {
|
||||
self.chat_widget.sync_service_tier_commands();
|
||||
self.chat_widget.add_info_message(message, /*hint*/ None);
|
||||
if let Some(tier) = dropped_tier {
|
||||
let tier = if tier == "priority" { "fast" } else { &tier };
|
||||
self.chat_widget.add_warning_message(format!(
|
||||
"{model} does not support {tier} speed. Cleared the pending speed change."
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(()) => self.chat_widget.add_error_message(
|
||||
"The Cloud account changed. Reopen the conversation before choosing a model."
|
||||
.into(),
|
||||
);
|
||||
),
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -327,6 +327,8 @@ impl App {
|
||||
search_dir: PathBuf,
|
||||
) {
|
||||
self.chat_widget.snapshot_local_images = self.app_server_target.uses_remote_workspace();
|
||||
self.chat_widget.thread_settings_owner = app_server.thread_params_mode().settings_owner();
|
||||
self.chat_widget.pending_cloud_turn_settings = app_server.pending_cloud_turn_settings();
|
||||
self.chat_widget.set_local_worktree_operations(
|
||||
!crate::uses_remote_workspace_or_environment(
|
||||
&self.app_server_target,
|
||||
|
||||
@@ -564,6 +564,9 @@ impl App {
|
||||
chat_widget.config_panel_tui = self.chat_widget.config_panel_tui.clone();
|
||||
chat_widget.remote_connection = self.chat_widget.remote_connection.clone();
|
||||
chat_widget.snapshot_local_images = self.app_server_target.uses_remote_workspace();
|
||||
chat_widget.thread_settings_owner = self.chat_widget.thread_settings_owner;
|
||||
chat_widget.pending_cloud_turn_settings =
|
||||
self.chat_widget.pending_cloud_turn_settings.clone();
|
||||
chat_widget.set_local_worktree_operations(self.chat_widget.local_worktree_operations);
|
||||
chat_widget.windows_sandbox_local_server = self.chat_widget.windows_sandbox_local_server;
|
||||
chat_widget.windows_sandbox_host = WindowsSandboxHost::Unknown;
|
||||
|
||||
@@ -936,6 +936,8 @@ impl App {
|
||||
}
|
||||
chat_widget.remote_connection = remote_connection;
|
||||
chat_widget.snapshot_local_images = app_server_target.uses_remote_workspace();
|
||||
chat_widget.thread_settings_owner = app_server.thread_params_mode().settings_owner();
|
||||
chat_widget.pending_cloud_turn_settings = app_server.pending_cloud_turn_settings();
|
||||
chat_widget.set_local_worktree_operations(!crate::uses_remote_workspace_or_environment(
|
||||
&app_server_target,
|
||||
environment_manager.as_ref(),
|
||||
|
||||
@@ -156,6 +156,253 @@ async fn standard_speed_selection_falls_back_for_older_app_servers() -> Result<(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn cloud_ultrafast_toggle_updates_the_conversation_on_admission() -> Result<()> {
|
||||
for (current, expected) in [
|
||||
(None, "ultrafast"),
|
||||
(Some("default"), "ultrafast"),
|
||||
(Some("ultrafast"), "default"),
|
||||
] {
|
||||
let (mut app, mut events, mut ops) = make_test_app_with_channels().await;
|
||||
let thread_id = ThreadId::new();
|
||||
let mut session = test_thread_session(thread_id, app.config.cwd.to_path_buf());
|
||||
session.service_tier = current.map(str::to_owned);
|
||||
app.chat_widget.handle_thread_session(session);
|
||||
app.active_thread_id = Some(thread_id);
|
||||
app.config.service_tier = Some("flex".into());
|
||||
let (client, mut commands, _server_events) =
|
||||
codex_app_server_client::CloudClient::channel(/*capacity*/ 1);
|
||||
let mut server = AppServerSession::new(
|
||||
crate::backend_id::BackendId::new(),
|
||||
AppServerClient::Cloud(client),
|
||||
crate::ThreadParamsMode::Cloud,
|
||||
);
|
||||
app.app_server_target = crate::AppServerTarget::Cloud;
|
||||
app.bind_backend_workspace(&server, app.config.cwd.to_path_buf());
|
||||
app.chat_widget
|
||||
.set_feature_enabled(Feature::FastMode, /*enabled*/ false);
|
||||
app.chat_widget
|
||||
.set_feature_enabled(Feature::UltrafastMode, /*enabled*/ true);
|
||||
let mut tui = crate::tui::test_support::make_test_tui()?;
|
||||
while events.try_recv().is_ok() {}
|
||||
app.chat_widget.open_model_popup();
|
||||
let request_id = std::iter::from_fn(|| events.try_recv().ok())
|
||||
.find_map(|event| match event {
|
||||
AppEvent::FetchModels { request_id } => Some(request_id),
|
||||
_ => None,
|
||||
})
|
||||
.expect("Cloud catalog request");
|
||||
let mut model = app.model_catalog.models[0].clone();
|
||||
model.model = app.chat_widget.current_model().to_owned();
|
||||
app.chat_widget.local_settings.tui.terminal_title = Some(vec!["fast-mode".into()]);
|
||||
model.default_service_tier = Some("ultrafast".into());
|
||||
model.service_tiers = vec![codex_protocol::openai_models::ModelServiceTier {
|
||||
id: "ultrafast".into(),
|
||||
name: "Ultrafast".into(),
|
||||
description: String::new(),
|
||||
}];
|
||||
assert!(
|
||||
app.chat_widget
|
||||
.on_models_loaded(request_id, Ok(vec![model]))
|
||||
);
|
||||
if current.is_none() {
|
||||
insta::assert_snapshot!(app.chat_widget.last_terminal_title.as_deref().unwrap(), @"Standard");
|
||||
}
|
||||
app.chat_widget.handle_key_event(KeyCode::Esc.into());
|
||||
while events.try_recv().is_ok() {}
|
||||
|
||||
app.chat_widget.apply_external_edit("/ultrafast".into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Esc.into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Enter.into());
|
||||
if !app.chat_widget.composer_text_with_pending().is_empty() {
|
||||
app.chat_widget.handle_key_event(KeyCode::Enter.into());
|
||||
}
|
||||
assert_eq!(app.chat_widget.composer_text_with_pending(), "");
|
||||
let event = std::iter::from_fn(|| events.try_recv().ok())
|
||||
.find(|event| matches!(event, AppEvent::ToggleCloudServiceTier { .. }))
|
||||
.expect("Cloud service tier toggle");
|
||||
Box::pin(app.handle_event(&mut tui, &mut server, event)).await?;
|
||||
assert!(commands.try_recv().is_err());
|
||||
assert_eq!(app.chat_widget.current_service_tier(), current);
|
||||
|
||||
let messages = std::iter::from_fn(|| events.try_recv().ok())
|
||||
.filter_map(|event| match event {
|
||||
AppEvent::InsertHistoryCell(cell) => {
|
||||
Some(lines_to_single_string(&cell.transcript_lines(/*width*/ 80)))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if expected == "ultrafast" {
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(messages.join("\n"), @"• Selected ultrafast speed for the next new turn in this conversation");
|
||||
}
|
||||
} else {
|
||||
insta::assert_snapshot!(messages.join("\n"), @"• Selected standard speed for the next new turn in this conversation");
|
||||
}
|
||||
|
||||
app.chat_widget.apply_external_edit("continue".into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Esc.into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Enter.into());
|
||||
let op = next_user_turn_op(&mut ops);
|
||||
let admit = async {
|
||||
let command = commands.recv().await.expect("native admission request");
|
||||
let CloudOperation::SubmitUserMessage(params) = command.operation else {
|
||||
panic!("expected native admission");
|
||||
};
|
||||
assert_eq!(
|
||||
(params.model, params.effort, params.service_tier),
|
||||
(None, None, Some(Some(expected.into()))),
|
||||
);
|
||||
let turn = test_turn("cloud-turn", TurnStatus::InProgress, Vec::new());
|
||||
let receipt = serde_json::to_value(CloudUserMessageReceipt::Started(turn)).unwrap();
|
||||
command.response.send(Ok(Ok(receipt))).unwrap();
|
||||
};
|
||||
let (result, ()) = tokio::join!(
|
||||
Box::pin(super::super::user_turn_submission::try_submit_user_turn(
|
||||
&mut app,
|
||||
&mut server,
|
||||
thread_id,
|
||||
&op,
|
||||
)),
|
||||
admit,
|
||||
);
|
||||
assert!(result?);
|
||||
assert_eq!(
|
||||
(
|
||||
app.chat_widget.current_service_tier(),
|
||||
app.config.service_tier.as_deref()
|
||||
),
|
||||
(Some(expected), Some("flex")),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn cloud_speed_tracks_the_model_staged_for_the_next_turn() -> Result<()> {
|
||||
for (initial, selected, expected_tier) in [
|
||||
(
|
||||
"standard-model",
|
||||
"fast-model",
|
||||
Some(Some("ultrafast".into())),
|
||||
),
|
||||
("fast-model", "standard-model", None),
|
||||
] {
|
||||
let (mut app, mut events, mut ops) = make_test_app_with_channels().await;
|
||||
let (client, mut commands, _server_events) =
|
||||
codex_app_server_client::CloudClient::channel(/*capacity*/ 1);
|
||||
let mut server = AppServerSession::new(
|
||||
crate::backend_id::BackendId::new(),
|
||||
AppServerClient::Cloud(client),
|
||||
crate::ThreadParamsMode::Cloud,
|
||||
);
|
||||
app.app_server_target = crate::AppServerTarget::Cloud;
|
||||
app.bind_backend_workspace(&server, app.config.cwd.to_path_buf());
|
||||
let thread_id = ThreadId::new();
|
||||
let mut session = test_thread_session(thread_id, app.config.cwd.to_path_buf());
|
||||
session.model = initial.into();
|
||||
app.chat_widget.handle_thread_session(session);
|
||||
app.active_thread_id = Some(thread_id);
|
||||
app.chat_widget
|
||||
.set_feature_enabled(Feature::UltrafastMode, /*enabled*/ true);
|
||||
let mut tui = crate::tui::test_support::make_test_tui()?;
|
||||
app.chat_widget.open_model_popup();
|
||||
let request_id = std::iter::from_fn(|| events.try_recv().ok())
|
||||
.find_map(|event| match event {
|
||||
AppEvent::FetchModels { request_id } => Some(request_id),
|
||||
_ => None,
|
||||
})
|
||||
.expect("Cloud catalog request");
|
||||
let mut standard = app.model_catalog.models[0].clone();
|
||||
standard.id = "standard-model".into();
|
||||
standard.model = standard.id.clone();
|
||||
standard.model_specialty = None;
|
||||
standard.default_service_tier = None;
|
||||
standard.service_tiers.clear();
|
||||
let mut fast = standard.clone();
|
||||
fast.id = "fast-model".into();
|
||||
fast.model = fast.id.clone();
|
||||
fast.service_tiers = vec![codex_protocol::openai_models::ModelServiceTier {
|
||||
id: "ultrafast".into(),
|
||||
name: "Ultrafast".into(),
|
||||
description: String::new(),
|
||||
}];
|
||||
let event = AppEvent::ModelsLoaded {
|
||||
request_id,
|
||||
result: Ok(vec![standard, fast]),
|
||||
};
|
||||
Box::pin(app.handle_event(&mut tui, &mut server, event)).await?;
|
||||
app.chat_widget.handle_key_event(KeyCode::Esc.into());
|
||||
while events.try_recv().is_ok() {}
|
||||
|
||||
let select_model = || AppEvent::ApplyModelSelection {
|
||||
model: selected.into(),
|
||||
effort: None,
|
||||
};
|
||||
if selected == "fast-model" {
|
||||
Box::pin(app.handle_event(&mut tui, &mut server, select_model())).await?;
|
||||
}
|
||||
app.chat_widget.apply_external_edit("/ultrafast".into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Esc.into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Enter.into());
|
||||
if !app.chat_widget.composer_text_with_pending().is_empty() {
|
||||
app.chat_widget.handle_key_event(KeyCode::Enter.into());
|
||||
}
|
||||
let event = std::iter::from_fn(|| events.try_recv().ok())
|
||||
.find(|event| matches!(event, AppEvent::ToggleCloudServiceTier { .. }))
|
||||
.expect("Cloud service tier toggle");
|
||||
Box::pin(app.handle_event(&mut tui, &mut server, event)).await?;
|
||||
if selected == "standard-model" {
|
||||
Box::pin(app.handle_event(&mut tui, &mut server, select_model())).await?;
|
||||
let warning = std::iter::from_fn(|| events.try_recv().ok())
|
||||
.filter_map(|event| match event {
|
||||
AppEvent::InsertHistoryCell(cell) => {
|
||||
Some(lines_to_single_string(
|
||||
&cell.transcript_lines(/*width*/ 120),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.find(|line| line.contains("Cleared the pending speed change."))
|
||||
.expect("speed warning before submission");
|
||||
insta::assert_snapshot!(warning, @"⚠ standard-model does not support ultrafast speed. Cleared the pending speed change.");
|
||||
}
|
||||
|
||||
assert!(commands.try_recv().is_err());
|
||||
assert!(app.chat_widget.cloud_picker_selection.is_none());
|
||||
app.chat_widget.apply_external_edit("continue".into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Esc.into());
|
||||
app.chat_widget.handle_key_event(KeyCode::Enter.into());
|
||||
let op = next_user_turn_op(&mut ops);
|
||||
let admit = async {
|
||||
let command = commands.recv().await.expect("native admission request");
|
||||
let CloudOperation::SubmitUserMessage(params) = command.operation else {
|
||||
panic!("expected native admission");
|
||||
};
|
||||
assert_eq!(
|
||||
(params.model.as_deref(), params.service_tier),
|
||||
(Some(selected), expected_tier)
|
||||
);
|
||||
let turn = test_turn("cloud-turn", TurnStatus::InProgress, Vec::new());
|
||||
let receipt = serde_json::to_value(CloudUserMessageReceipt::Started(turn)).unwrap();
|
||||
command.response.send(Ok(Ok(receipt))).unwrap();
|
||||
};
|
||||
let submit = Box::pin(super::super::user_turn_submission::try_submit_user_turn(
|
||||
&mut app,
|
||||
&mut server,
|
||||
thread_id,
|
||||
&op,
|
||||
));
|
||||
let (result, ()) = tokio::time::timeout(std::time::Duration::from_secs(5), async {
|
||||
tokio::join!(submit, admit)
|
||||
})
|
||||
.await?;
|
||||
assert!(result?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn cloud_model_selection_waits_for_native_admission() -> Result<()> {
|
||||
let turn = test_turn("cloud-turn", TurnStatus::InProgress, Vec::new());
|
||||
@@ -182,6 +429,7 @@ async fn cloud_model_selection_waits_for_native_admission() -> Result<()> {
|
||||
app.active_thread_id = Some(thread_id);
|
||||
let original_model = app.chat_widget.current_model().to_string();
|
||||
let original_effort = app.chat_widget.current_reasoning_effort();
|
||||
let original_tier = app.chat_widget.current_service_tier().map(str::to_owned);
|
||||
let (client, mut commands, _server_events) =
|
||||
codex_app_server_client::CloudClient::channel(/*capacity*/ 1);
|
||||
let mut server = AppServerSession::new(
|
||||
@@ -192,6 +440,32 @@ async fn cloud_model_selection_waits_for_native_admission() -> Result<()> {
|
||||
let mut tui = crate::tui::test_support::make_test_tui()?;
|
||||
while events.try_recv().is_ok() {}
|
||||
|
||||
app.app_server_target = crate::AppServerTarget::Cloud;
|
||||
app.bind_backend_workspace(&server, app.config.cwd.to_path_buf());
|
||||
app.chat_widget
|
||||
.set_feature_enabled(Feature::UltrafastMode, /*enabled*/ true);
|
||||
app.chat_widget.open_model_popup();
|
||||
let request_id = std::iter::from_fn(|| events.try_recv().ok())
|
||||
.find_map(|event| match event {
|
||||
AppEvent::FetchModels { request_id } => Some(request_id),
|
||||
_ => None,
|
||||
})
|
||||
.expect("Cloud catalog request");
|
||||
let mut models = app.model_catalog.models.clone();
|
||||
let selected = models
|
||||
.iter_mut()
|
||||
.find(|model| model.model == "gpt-5.6-terra")
|
||||
.expect("Cloud model");
|
||||
selected.default_service_tier = Some("ultrafast".into());
|
||||
selected.service_tiers = vec![codex_protocol::openai_models::ModelServiceTier {
|
||||
id: "ultrafast".into(),
|
||||
name: "Ultrafast".into(),
|
||||
description: String::new(),
|
||||
}];
|
||||
assert!(app.chat_widget.on_models_loaded(request_id, Ok(models)));
|
||||
app.chat_widget.handle_key_event(KeyCode::Esc.into());
|
||||
while events.try_recv().is_ok() {}
|
||||
|
||||
let event = AppEvent::ApplyModelSelection {
|
||||
model: "gpt-5.6-terra".into(),
|
||||
effort: Some(ReasoningEffortConfig::High),
|
||||
@@ -223,8 +497,12 @@ async fn cloud_model_selection_waits_for_native_admission() -> Result<()> {
|
||||
panic!("expected StartOrSteer");
|
||||
};
|
||||
assert_eq!(
|
||||
(params.model.as_deref(), params.effort),
|
||||
(Some("gpt-5.6-terra"), Some(ReasoningEffortConfig::High))
|
||||
(params.model.as_deref(), params.effort, params.service_tier),
|
||||
(
|
||||
Some("gpt-5.6-terra"),
|
||||
Some(ReasoningEffortConfig::High),
|
||||
None
|
||||
)
|
||||
);
|
||||
let response = receipt.map(|receipt| serde_json::to_value(receipt).unwrap());
|
||||
command.response.send(Ok(response)).unwrap();
|
||||
@@ -244,8 +522,13 @@ async fn cloud_model_selection_waits_for_native_admission() -> Result<()> {
|
||||
(
|
||||
app.chat_widget.current_model(),
|
||||
app.chat_widget.current_reasoning_effort(),
|
||||
app.chat_widget.current_service_tier(),
|
||||
),
|
||||
(
|
||||
original_model.as_str(),
|
||||
original_effort,
|
||||
original_tier.as_deref()
|
||||
),
|
||||
(original_model.as_str(), original_effort),
|
||||
);
|
||||
let input = app.chat_widget.capture_thread_input_state();
|
||||
let held = input.is_some_and(|input| input.has_unconfirmed_messages());
|
||||
|
||||
@@ -94,8 +94,16 @@ pub(super) async fn try_submit_user_turn(
|
||||
|
||||
match result {
|
||||
Ok((admission, selection)) => {
|
||||
if selection.is_some() {
|
||||
app.chat_widget.cloud_picker_selection = selection;
|
||||
if let Some(selection) = selection {
|
||||
if selection.model.is_some() {
|
||||
app.chat_widget.cloud_picker_selection = selection.model;
|
||||
}
|
||||
let service_tier = selection
|
||||
.service_tier
|
||||
.or_else(|| app.chat_widget.configured_service_tier());
|
||||
app.chat_widget.set_service_tier(service_tier);
|
||||
app.sync_active_thread_service_tier_to_cached_session()
|
||||
.await;
|
||||
}
|
||||
if !matches!(&admission, UserMessageAdmission::Queued(_)) {
|
||||
crate::startup_recovery::acknowledged(client_user_message_id);
|
||||
|
||||
Reference in New Issue
Block a user