-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Add local child agents to TUI #13776
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: harry/code-1822-tui-multi-session
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| //! Frontend-neutral preparation and settings propagation for local Oz children. | ||
| #[cfg(not(target_family = "wasm"))] | ||
| use std::future::Future; | ||
|
|
||
| use warpui::{AppContext, EntityId, SingletonEntity as _}; | ||
| #[cfg(not(target_family = "wasm"))] | ||
| use { | ||
| crate::ai::ambient_agents::task::normalize_orchestrator_agent_name, | ||
| crate::ai::ambient_agents::{AgentConfigSnapshot, AmbientAgentTaskId}, | ||
| crate::server::server_api::ServerApiProvider, | ||
| }; | ||
|
|
||
| use crate::ai::llms::{LLMId, LLMPreferences}; | ||
| use crate::AIExecutionProfilesModel; | ||
|
|
||
| /// Server-side state prepared before a frontend creates the child's surface. | ||
| #[cfg(not(target_family = "wasm"))] | ||
| pub struct PreparedLocalOzChildLaunch { | ||
| pub task_id: AmbientAgentTaskId, | ||
| pub conversation_name: String, | ||
| } | ||
|
|
||
| /// Creates the server task row shared by the GUI hidden-pane and TUI | ||
| /// background-session launch paths. | ||
| #[cfg(not(target_family = "wasm"))] | ||
| pub fn prepare_local_oz_child_launch( | ||
| name: &str, | ||
| prompt: &str, | ||
| parent_run_id: Option<&str>, | ||
| ctx: &AppContext, | ||
| ) -> impl Future<Output = anyhow::Result<PreparedLocalOzChildLaunch>> + 'static { | ||
| let ai_client = ServerApiProvider::as_ref(ctx).get_ai_client(); | ||
| let agent_name = normalize_orchestrator_agent_name(name); | ||
| let conversation_name = agent_name.clone().unwrap_or_default(); | ||
| let prompt = prompt.to_owned(); | ||
| let parent_run_id = parent_run_id.map(str::to_owned); | ||
| async move { | ||
| let task_id = ai_client | ||
| .create_agent_task( | ||
| prompt, | ||
| None, | ||
| parent_run_id, | ||
| Some(AgentConfigSnapshot { | ||
| name: agent_name, | ||
| ..Default::default() | ||
| }), | ||
| ) | ||
| .await?; | ||
| Ok(PreparedLocalOzChildLaunch { | ||
| task_id, | ||
| conversation_name, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| /// Copies the parent's execution profile and effective base model to a child | ||
| /// surface before its first request is sent. | ||
| pub fn inherit_child_agent_settings( | ||
| parent_surface_id: EntityId, | ||
| child_surface_id: EntityId, | ||
| ctx: &mut AppContext, | ||
| ) { | ||
| let parent_profile_id = *AIExecutionProfilesModel::as_ref(ctx) | ||
| .active_profile(Some(parent_surface_id), ctx) | ||
| .id(); | ||
| AIExecutionProfilesModel::handle(ctx).update(ctx, |profiles, ctx| { | ||
| profiles.set_active_profile(child_surface_id, parent_profile_id, ctx); | ||
| }); | ||
|
|
||
| let parent_base_model_id = LLMPreferences::as_ref(ctx) | ||
| .get_active_base_model(ctx, Some(parent_surface_id)) | ||
| .id | ||
| .clone(); | ||
| LLMPreferences::handle(ctx).update(ctx, |preferences, ctx| { | ||
| preferences.update_preferred_agent_mode_llm(&parent_base_model_id, child_surface_id, ctx); | ||
| }); | ||
| } | ||
|
|
||
| /// Applies a non-empty run-wide model override after parent settings have | ||
| /// been inherited. | ||
| pub fn apply_child_agent_model_override( | ||
| child_surface_id: EntityId, | ||
| model_id: Option<&str>, | ||
| ctx: &mut AppContext, | ||
| ) { | ||
| let Some(model_id) = model_id.map(str::trim).filter(|id| !id.is_empty()) else { | ||
| return; | ||
| }; | ||
| let model_id = LLMId::from(model_id); | ||
| LLMPreferences::handle(ctx).update(ctx, |preferences, ctx| { | ||
| preferences.set_agent_mode_llm_override(child_surface_id, model_id, ctx); | ||
| }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2180,6 +2180,10 @@ impl BlocklistAIHistoryModel { | |||||||||||||||||||
|
|
||||||||||||||||||||
| self.all_conversations_metadata.remove(&conversation_id); | ||||||||||||||||||||
| self.conversations_by_id.remove(&conversation_id); | ||||||||||||||||||||
| self.children_by_parent.retain(|_, child_ids| { | ||||||||||||||||||||
| child_ids.retain(|child_id| *child_id != conversation_id); | ||||||||||||||||||||
| !child_ids.is_empty() | ||||||||||||||||||||
| }); | ||||||||||||||||||||
|
Comment on lines
+2183
to
+2186
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems valid? |
||||||||||||||||||||
|
|
||||||||||||||||||||
| if let Some(terminal_surface_id) = terminal_surface_id { | ||||||||||||||||||||
| if self | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -854,14 +854,6 @@ impl LLMPreferences { | |
| app: &AppContext, | ||
| terminal_view_id: Option<EntityId>, | ||
| ) -> &LLMInfo { | ||
| // In the TUI, the file-backed `agents.model` setting is the source of | ||
| // truth for the base model: it overrides both per-surface overrides | ||
| // and the cloud-synced execution profile, keeping the TUI's TOML file | ||
| // the single place the model is configured. | ||
| if settings_mode == settings::SettingsMode::Tui { | ||
| return self.tui_agent_model_info(AISettings::as_ref(app).agent_model.value(), app); | ||
| } | ||
|
|
||
| if let Some(terminal_view_id) = terminal_view_id { | ||
| let raw_override = self.base_llm_for_terminal_view.get(&terminal_view_id); | ||
| if let Some(llm_id) = raw_override { | ||
|
|
@@ -873,6 +865,12 @@ impl LLMPreferences { | |
| } | ||
| } | ||
|
|
||
| // In the TUI, the file-backed `agents.model` setting is the default | ||
| // for every surface. Explicit per-surface overrides still take | ||
| // precedence for orchestrated children launched with a model override. | ||
| if settings_mode == settings::SettingsMode::Tui { | ||
| return self.tui_agent_model_info(AISettings::as_ref(app).agent_model.value(), app); | ||
| } | ||
| let profile = AIExecutionProfilesModel::as_ref(app).active_profile(terminal_view_id, app); | ||
|
|
||
| profile | ||
|
|
@@ -1497,8 +1495,8 @@ impl LLMPreferences { | |
| .is_some() | ||
| } else { | ||
| self.base_llm_for_terminal_view | ||
| .insert(terminal_view_id, preferred_llm_id.clone()); | ||
| true | ||
| .insert(terminal_view_id, preferred_llm_id.clone()) | ||
| != Some(preferred_llm_id.clone()) | ||
| }; | ||
|
|
||
| if changed { | ||
|
|
@@ -1507,6 +1505,26 @@ impl LLMPreferences { | |
| } | ||
| } | ||
|
|
||
| /// Sets an explicit runtime override without normalizing it against the | ||
| /// execution profile. Orchestrated child runs use this because a requested | ||
| /// model equal to the profile default must still override the TUI's | ||
| /// file-backed model setting. | ||
| pub(crate) fn set_agent_mode_llm_override( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like emitting UpdatedActiveAgentModeLLM triggers a bunch of handlers downstream. ooc why do we need this specifically for TUI? |
||
| &mut self, | ||
| terminal_view_id: EntityId, | ||
| model_id: LLMId, | ||
| ctx: &mut ModelContext<Self>, | ||
| ) { | ||
| if self | ||
| .base_llm_for_terminal_view | ||
| .insert(terminal_view_id, model_id.clone()) | ||
| != Some(model_id) | ||
| { | ||
| self.trigger_snapshot_save(ctx); | ||
| ctx.emit(LLMPreferencesEvent::UpdatedActiveAgentModeLLM); | ||
| } | ||
| } | ||
|
|
||
| /// Copies the raw per-pane Agent Mode override from `source_terminal_view_id` | ||
| /// onto `new_terminal_view_id`, removing any existing override when the | ||
| /// source has none. Combined with copying the source's execution profile, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is mostly just code moved from GUI-specific places into shared helpers