From 2f649094695081c387630dbbe2bf78c999bb45f7 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Wed, 1 Jul 2026 14:30:04 -0500 Subject: [PATCH] Update AI agent, settings, and terminal modules - Update AI agent conversation, task, and prompt builder - Add notebooks execution module for blocklist actions - Update Bedrock and OpenAI response translators - Refactor settings modules across multiple subsystems - Update terminal settings and window settings - Update drive settings and search command settings --- app/src/ai/agent/api/convert_from.rs | 11 +- app/src/ai/agent/conversation.rs | 7 +- app/src/ai/agent/mod.rs | 4 + app/src/ai/agent/task.rs | 8 +- app/src/ai/agent/task/helper.rs | 6 +- app/src/ai/bedrock/request_translator.rs | 141 +++++++----- app/src/ai/bedrock/response_translator.rs | 29 ++- app/src/ai/blocklist/action_model/execute.rs | 126 ++++++++--- .../action_model/execute/create_documents.rs | 14 +- .../action_model/execute/notebooks.rs | 207 ++++++++++++++++++ app/src/ai/blocklist/controller.rs | 9 +- app/src/ai/document/ai_document_model.rs | 66 ++++-- app/src/ai/llms.rs | 15 +- app/src/ai/openai/response_translator.rs | 7 + app/src/ai/prompt_builder/tests.rs | 2 +- app/src/ai/prompt_builder/tools.rs | 64 +++++- app/src/cloud_object/model/model_test.rs | 2 +- app/src/drive/settings.rs | 4 +- app/src/search/command_search/settings.rs | 4 +- .../cloud_objects/update_manager_test.rs | 2 +- app/src/settings/accessibility.rs | 4 +- app/src/settings/ai.rs | 156 ++++++------- app/src/settings/alias_expansion.rs | 4 +- app/src/settings/block_visibility.rs | 4 +- app/src/settings/changelog.rs | 4 +- app/src/settings/cloud_preferences.rs | 4 +- app/src/settings/code.rs | 4 +- app/src/settings/editor.rs | 5 +- app/src/settings/emacs_bindings.rs | 4 +- app/src/settings/font.rs | 4 +- app/src/settings/input_mode.rs | 4 +- app/src/settings/pane.rs | 4 +- app/src/settings/select.rs | 4 +- app/src/settings/ssh.rs | 4 +- app/src/settings/theme.rs | 4 +- app/src/settings_view/ai_page.rs | 15 +- app/src/terminal/alt_screen_reporting.rs | 4 +- app/src/terminal/block_list_settings.rs | 4 +- app/src/terminal/general_settings.rs | 4 +- app/src/terminal/keys_settings.rs | 4 +- app/src/terminal/ligature_settings.rs | 4 +- app/src/terminal/safe_mode_settings.rs | 4 +- app/src/terminal/session_settings.rs | 4 +- app/src/terminal/settings.rs | 4 +- app/src/terminal/shared_session/settings.rs | 4 +- app/src/undo_close/settings.rs | 4 +- app/src/util/file/external_editor/settings.rs | 4 +- app/src/window_settings.rs | 4 +- app/src/workspace/tab_settings.rs | 4 +- 49 files changed, 683 insertions(+), 325 deletions(-) create mode 100644 app/src/ai/blocklist/action_model/execute/notebooks.rs diff --git a/app/src/ai/agent/api/convert_from.rs b/app/src/ai/agent/api/convert_from.rs index afc6b554..91f5908c 100644 --- a/app/src/ai/agent/api/convert_from.rs +++ b/app/src/ai/agent/api/convert_from.rs @@ -613,12 +613,21 @@ impl ConvertAPIToolCallToAIAgentAction for api::message::ToolCall { return Err(ToolToAIAgentActionError::MissingTool); }; + // Detect notebook tool name encoded in tool_call_id prefix. + let (effective_tool_call_id, tool_name) = + if let Some(stripped) = self.tool_call_id.strip_prefix("notebook::") { + (stripped.to_string(), Some("notebook".to_string())) + } else { + (self.tool_call_id.clone(), None) + }; + let create_standard_action = |action: AIAgentActionType| { Ok(MaybeAIAgentAction::Action(AIAgentAction { - id: self.tool_call_id.clone().into(), + id: effective_tool_call_id.clone().into(), task_id: params.task_id.clone(), action, requires_result: true, + tool_name: tool_name.clone(), })) }; diff --git a/app/src/ai/agent/conversation.rs b/app/src/ai/agent/conversation.rs index 37d0c799..bec8720a 100644 --- a/app/src/ai/agent/conversation.rs +++ b/app/src/ai/agent/conversation.rs @@ -2109,7 +2109,12 @@ impl AIConversation { let streaming_exchange_ids: Vec<_> = self .task_store .all_exchanges() - .filter(|exchange| matches!(exchange.output_status, AIAgentOutputStatus::Streaming { .. })) + .filter(|exchange| { + matches!( + exchange.output_status, + AIAgentOutputStatus::Streaming { .. } + ) + }) .map(|exchange| exchange.id) .collect(); diff --git a/app/src/ai/agent/mod.rs b/app/src/ai/agent/mod.rs index 87b44349..da6a9732 100644 --- a/app/src/ai/agent/mod.rs +++ b/app/src/ai/agent/mod.rs @@ -845,6 +845,10 @@ pub struct AIAgentAction { /// /// If this is `true`, a corresponding result _must_ be included in the next query to the AI. pub requires_result: bool, + + /// The original tool name as sent by the model (e.g. "create_plan", "create_notebook"). + /// Used to distinguish between tools that share the same `AIAgentActionType` variant. + pub tool_name: Option, } impl Display for AIAgentAction { diff --git a/app/src/ai/agent/task.rs b/app/src/ai/agent/task.rs index 53f27679..b2ebd567 100644 --- a/app/src/ai/agent/task.rs +++ b/app/src/ai/agent/task.rs @@ -138,7 +138,8 @@ mod optimistic { #[derive(Debug, Clone)] pub(super) enum Task { Root, - #[allow(dead_code)] // Used in the server-mode path; Bedrock direct creates Server tasks directly + #[allow(dead_code)] + // Used in the server-mode path; Bedrock direct creates Server tasks directly CLIAgent(CLIAgentSubtask), } @@ -185,7 +186,10 @@ impl Task { } } - pub(super) fn new_optimistic_cli_agent_subtask(block_id: BlockId, parent_task_id: Option) -> Self { + pub(super) fn new_optimistic_cli_agent_subtask( + block_id: BlockId, + parent_task_id: Option, + ) -> Self { let task_id = Uuid::new_v4().to_string(); Self { id: TaskId::new(task_id.clone()), diff --git a/app/src/ai/agent/task/helper.rs b/app/src/ai/agent/task/helper.rs index b9355879..07b37a16 100644 --- a/app/src/ai/agent/task/helper.rs +++ b/app/src/ai/agent/task/helper.rs @@ -115,9 +115,9 @@ impl ToolExt for api::message::tool_call::Tool { Tool::ReadMcpResource(_) => "read_mcp_resource", Tool::CallMcpTool(_) => "call_mcp_tool", Tool::WriteToLongRunningShellCommand(_) => "write_to_lrc", - Tool::ReadDocuments(_) => "read_documents", - Tool::EditDocuments(_) => "edit_documents", - Tool::CreateDocuments(_) => "create_documents", + Tool::ReadDocuments(_) => "read_plan", + Tool::EditDocuments(_) => "edit_plan", + Tool::CreateDocuments(_) => "create_plan", Tool::ReadShellCommandOutput(_) => "read_shell_command_output", Tool::UseComputer(_) => "use_computer", Tool::RequestComputerUse(_) => "request_computer_use", diff --git a/app/src/ai/bedrock/request_translator.rs b/app/src/ai/bedrock/request_translator.rs index a167289f..5116cd6d 100644 --- a/app/src/ai/bedrock/request_translator.rs +++ b/app/src/ai/bedrock/request_translator.rs @@ -74,29 +74,30 @@ pub fn extract_new_input_messages(request: &api::Request) -> Vec { + Some( + api::request::input::user_inputs::user_input::Input::CliAgentUserQuery( + cli_query, + ), + ) => { if let Some(user_query) = &cli_query.user_query { if !user_query.query.is_empty() { - let query_text = if let Some(running_cmd) = &cli_query.running_command { - let mut context = format!( - "[Running command: {}]\n", - running_cmd.command - ); - if let Some(snapshot) = &running_cmd.snapshot { - if !snapshot.output.is_empty() { - context.push_str(&format!( - "[Terminal output:\n{}\n]\n", - snapshot.output - )); + let query_text = + if let Some(running_cmd) = &cli_query.running_command { + let mut context = + format!("[Running command: {}]\n", running_cmd.command); + if let Some(snapshot) = &running_cmd.snapshot { + if !snapshot.output.is_empty() { + context.push_str(&format!( + "[Terminal output:\n{}\n]\n", + snapshot.output + )); + } } - } - context.push_str(&user_query.query); - context - } else { - user_query.query.clone() - }; + context.push_str(&user_query.query); + context + } else { + user_query.query.clone() + }; user_queries.push(ConversationMessage { role: MessageRole::User, content: MessageContent::Text(query_text), @@ -256,9 +257,11 @@ pub fn extract_user_query_text(request: &api::Request) -> Option { return Some(query.query.clone()); } } - Some(api::request::input::user_inputs::user_input::Input::CliAgentUserQuery( - cli_query, - )) => { + Some( + api::request::input::user_inputs::user_input::Input::CliAgentUserQuery( + cli_query, + ), + ) => { if let Some(user_query) = &cli_query.user_query { if !user_query.query.is_empty() { return Some(user_query.query.clone()); @@ -388,29 +391,30 @@ fn extract_input_messages(request: &api::Request) -> Vec { }); } } - Some(api::request::input::user_inputs::user_input::Input::CliAgentUserQuery( - cli_query, - )) => { + Some( + api::request::input::user_inputs::user_input::Input::CliAgentUserQuery( + cli_query, + ), + ) => { if let Some(user_query) = &cli_query.user_query { if !user_query.query.is_empty() { - let query_text = if let Some(running_cmd) = &cli_query.running_command { - let mut context = format!( - "[Running command: {}]\n", - running_cmd.command - ); - if let Some(snapshot) = &running_cmd.snapshot { - if !snapshot.output.is_empty() { - context.push_str(&format!( - "[Terminal output:\n{}\n]\n", - snapshot.output - )); + let query_text = + if let Some(running_cmd) = &cli_query.running_command { + let mut context = + format!("[Running command: {}]\n", running_cmd.command); + if let Some(snapshot) = &running_cmd.snapshot { + if !snapshot.output.is_empty() { + context.push_str(&format!( + "[Terminal output:\n{}\n]\n", + snapshot.output + )); + } } - } - context.push_str(&user_query.query); - context - } else { - user_query.query.clone() - }; + context.push_str(&user_query.query); + context + } else { + user_query.query.clone() + }; results.push(api::Message { id: uuid::Uuid::new_v4().to_string(), task_id: task_id.clone(), @@ -1189,34 +1193,67 @@ pub fn default_tool_definitions() -> Vec { }), }, ToolDefinition { - name: "read_documents".to_string(), - description: "Read the contents of one or more Galaxy notebook documents by their IDs.".to_string(), + name: "read_plan".to_string(), + description: "Read the contents of one or more Galaxy plan documents by their IDs. Plans are rich-text documents that appear in the Plans folder of Galaxy Drive.".to_string(), input_schema: serde_json::json!({ "type": "object", "properties": { - "document_ids": { "type": "array", "items": { "type": "string" }, "description": "Document IDs to read" } + "document_ids": { "type": "array", "items": { "type": "string" }, "description": "Plan document IDs to read" } }, "required": ["document_ids"] }), }, ToolDefinition { - name: "create_documents".to_string(), - description: "Create new Galaxy notebook documents with the specified title and content.".to_string(), + name: "create_plan".to_string(), + description: "Create a new plan document in Galaxy Drive's Plans folder. Plans are rich-text documents for tracking tasks, architecture decisions, and project notes.".to_string(), input_schema: serde_json::json!({ "type": "object", "properties": { - "documents": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" } }, "required": ["title", "content"] }, "description": "Documents to create" } + "documents": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" } }, "required": ["title", "content"] }, "description": "Plan documents to create" } }, "required": ["documents"] }), }, ToolDefinition { - name: "edit_documents".to_string(), - description: "Edit existing Galaxy notebook documents using search/replace diffs.".to_string(), + name: "edit_plan".to_string(), + description: "Edit an existing plan document in Galaxy Drive using search/replace diffs.".to_string(), input_schema: serde_json::json!({ "type": "object", "properties": { - "diffs": { "type": "array", "items": { "type": "object", "properties": { "document_id": { "type": "string" }, "search": { "type": "string" }, "replace": { "type": "string" } }, "required": ["document_id", "search", "replace"] }, "description": "Edits to apply to documents" } + "diffs": { "type": "array", "items": { "type": "object", "properties": { "document_id": { "type": "string" }, "search": { "type": "string" }, "replace": { "type": "string" } }, "required": ["document_id", "search", "replace"] }, "description": "Edits to apply to plan documents" } + }, + "required": ["diffs"] + }), + }, + ToolDefinition { + name: "read_notebook".to_string(), + description: "Read the contents of one or more Galaxy Drive notebooks by their IDs. Notebooks are user-created rich-text documents stored in Galaxy Drive.".to_string(), + input_schema: serde_json::json!({ + "type": "object", + "properties": { + "document_ids": { "type": "array", "items": { "type": "string" }, "description": "Notebook IDs to read" } + }, + "required": ["document_ids"] + }), + }, + ToolDefinition { + name: "create_notebook".to_string(), + description: "Create a new notebook in Galaxy Drive. Notebooks are rich-text documents for general notes, documentation, and reference material.".to_string(), + input_schema: serde_json::json!({ + "type": "object", + "properties": { + "documents": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" } }, "required": ["title", "content"] }, "description": "Notebooks to create" } + }, + "required": ["documents"] + }), + }, + ToolDefinition { + name: "edit_notebook".to_string(), + description: "Edit an existing Galaxy Drive notebook using search/replace diffs.".to_string(), + input_schema: serde_json::json!({ + "type": "object", + "properties": { + "diffs": { "type": "array", "items": { "type": "object", "properties": { "document_id": { "type": "string" }, "search": { "type": "string" }, "replace": { "type": "string" } }, "required": ["document_id", "search", "replace"] }, "description": "Edits to apply to notebooks" } }, "required": ["diffs"] }), diff --git a/app/src/ai/bedrock/response_translator.rs b/app/src/ai/bedrock/response_translator.rs index 052051fe..dffe9a7e 100644 --- a/app/src/ai/bedrock/response_translator.rs +++ b/app/src/ai/bedrock/response_translator.rs @@ -998,7 +998,7 @@ pub fn build_tool_call_message( api::message::tool_call::ReadMcpResource { uri, server_id }, )) } - "read_documents" => { + "read_plan" | "read_documents" | "read_notebook" => { let documents = input .get("document_ids") .and_then(|v| v.as_array()) @@ -1016,7 +1016,7 @@ pub fn build_tool_call_message( api::message::tool_call::ReadDocuments { documents }, )) } - "create_documents" => { + "create_plan" | "create_documents" | "create_notebook" => { let new_documents = input .get("documents") .and_then(|v| v.as_array()) @@ -1035,7 +1035,7 @@ pub fn build_tool_call_message( api::message::tool_call::CreateDocuments { new_documents }, )) } - "edit_documents" => { + "edit_plan" | "edit_documents" | "edit_notebook" => { let diffs = input .get("diffs") .and_then(|v| v.as_array()) @@ -1211,16 +1211,24 @@ pub fn build_tool_call_message( } }; + // For notebook tools, encode the tool name into the tool_call_id so that + // the conversion layer can route them to the notebook executor. + let effective_tool_call_id = if is_notebook_tool(tool_name) { + format!("notebook::{tool_use_id}") + } else { + tool_use_id.to_string() + }; + let message = if let Some(tool_variant) = tool { api::Message { - id: tool_use_id.to_string(), + id: effective_tool_call_id.clone(), task_id: task_id.to_string(), request_id: String::new(), timestamp: None, server_message_data: String::new(), citations: vec![], message: Some(api::message::Message::ToolCall(api::message::ToolCall { - tool_call_id: tool_use_id.to_string(), + tool_call_id: effective_tool_call_id, tool: Some(tool_variant), })), } @@ -1275,6 +1283,13 @@ const KNOWN_TOOLS: &[&str] = &[ "write_to_long_running_shell_command", "read_shell_command_output", "read_mcp_resource", + "read_plan", + "create_plan", + "edit_plan", + "read_notebook", + "create_notebook", + "edit_notebook", + // Legacy aliases — accept old names so in-flight conversations don't break. "read_documents", "create_documents", "edit_documents", @@ -1291,6 +1306,10 @@ fn is_known_tool(name: &str) -> bool { KNOWN_TOOLS.contains(&name) || name.starts_with("mcp__") } +fn is_notebook_tool(name: &str) -> bool { + matches!(name, "create_notebook" | "read_notebook" | "edit_notebook") +} + /// Searches conversation message history for tool call results matching the given criteria. fn recall_from_history( messages: &[ConversationMessage], diff --git a/app/src/ai/blocklist/action_model/execute.rs b/app/src/ai/blocklist/action_model/execute.rs index 9ad7f9e1..5c149ba9 100644 --- a/app/src/ai/blocklist/action_model/execute.rs +++ b/app/src/ai/blocklist/action_model/execute.rs @@ -5,6 +5,7 @@ pub(super) mod edit_documents; pub(super) mod fetch_conversation; pub(super) mod file_glob; pub(super) mod grep; +pub(super) mod notebooks; pub(super) mod read_documents; pub(super) mod read_files; pub(super) mod read_mcp_resource; @@ -31,6 +32,7 @@ use file_glob::FileGlobExecutor; use futures::{future::BoxFuture, FutureExt}; use galaxy_core::{execution_mode::AppExecutionMode, features::FeatureFlag}; use grep::GrepExecutor; +use notebooks::NotebookExecutor; use parking_lot::FairMutex; use read_documents::ReadDocumentsExecutor; pub(super) use read_files::ReadFilesExecutor; @@ -253,6 +255,7 @@ pub struct BlocklistAIActionExecutor { read_documents_executor: ModelHandle, edit_documents_executor: ModelHandle, create_documents_executor: ModelHandle, + notebook_executor: ModelHandle, use_computer_executor: ModelHandle, request_computer_use_executor: ModelHandle, read_skill_executor: ModelHandle, @@ -317,6 +320,7 @@ impl BlocklistAIActionExecutor { let edit_documents_executor = ctx.add_model(|_| EditDocumentsExecutor::new()); let create_documents_executor = ctx .add_model(|_| CreateDocumentsExecutor::new(active_session.clone(), terminal_view_id)); + let notebook_executor = ctx.add_model(|_| NotebookExecutor::new()); let use_computer_executor = ctx.add_model(|_| UseComputerExecutor::new()); let request_computer_use_executor = ctx.add_model(|_| RequestComputerUseExecutor::new(terminal_view_id)); @@ -341,6 +345,7 @@ impl BlocklistAIActionExecutor { read_documents_executor, edit_documents_executor, create_documents_executor, + notebook_executor, use_computer_executor, request_computer_use_executor, async_executing_actions: Default::default(), @@ -487,15 +492,33 @@ impl BlocklistAIActionExecutor { AIAgentActionType::SuggestPrompt { .. } => self .suggest_prompt_executor .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)), - AIAgentActionType::ReadDocuments(_) => self - .read_documents_executor - .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)), - AIAgentActionType::EditDocuments(_) => self - .edit_documents_executor - .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)), - AIAgentActionType::CreateDocuments(_) => self - .create_documents_executor - .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)), + AIAgentActionType::ReadDocuments(_) => { + if action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)) + } else { + self.read_documents_executor + .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)) + } + } + AIAgentActionType::EditDocuments(_) => { + if action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)) + } else { + self.edit_documents_executor + .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)) + } + } + AIAgentActionType::CreateDocuments(_) => { + if action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)) + } else { + self.create_documents_executor + .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)) + } + } AIAgentActionType::UseComputer(_) => self .use_computer_executor .update(ctx, |executor, ctx| executor.preprocess_action(input, ctx)), @@ -683,20 +706,41 @@ impl BlocklistAIActionExecutor { .suggest_prompt_executor .update(ctx, |executor, ctx| executor.execute(input, ctx)) .into(), - AIAgentActionType::ReadDocuments(_) => self - .read_documents_executor - .update(ctx, |executor, ctx| executor.execute(input, ctx)) - .into(), - AIAgentActionType::EditDocuments(_) => self - .edit_documents_executor - .update(ctx, |executor, ctx| executor.execute(input, ctx)) - .into(), - AIAgentActionType::CreateDocuments(_) => self - .create_documents_executor - .update(ctx, |executor, ctx| { - executor.execute(input, conversation_id, ctx) - }) - .into(), + AIAgentActionType::ReadDocuments(_) => { + if action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.execute_read(input, ctx)) + .into() + } else { + self.read_documents_executor + .update(ctx, |executor, ctx| executor.execute(input, ctx)) + .into() + } + } + AIAgentActionType::EditDocuments(_) => { + if action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.execute_edit(input, ctx)) + .into() + } else { + self.edit_documents_executor + .update(ctx, |executor, ctx| executor.execute(input, ctx)) + .into() + } + } + AIAgentActionType::CreateDocuments(_) => { + if action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.execute_create(input, ctx)) + .into() + } else { + self.create_documents_executor + .update(ctx, |executor, ctx| { + executor.execute(input, conversation_id, ctx) + }) + .into() + } + } AIAgentActionType::UseComputer(_) => self .use_computer_executor .update(ctx, |executor, ctx| executor.execute(input, ctx)) @@ -924,15 +968,33 @@ impl BlocklistAIActionExecutor { AIAgentActionType::SuggestPrompt { .. } => self .suggest_prompt_executor .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)), - AIAgentActionType::ReadDocuments(_) => self - .read_documents_executor - .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)), - AIAgentActionType::EditDocuments(_) => self - .edit_documents_executor - .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)), - AIAgentActionType::CreateDocuments(_) => self - .create_documents_executor - .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)), + AIAgentActionType::ReadDocuments(_) => { + if input.action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)) + } else { + self.read_documents_executor + .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)) + } + } + AIAgentActionType::EditDocuments(_) => { + if input.action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)) + } else { + self.edit_documents_executor + .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)) + } + } + AIAgentActionType::CreateDocuments(_) => { + if input.action.tool_name.as_deref() == Some("notebook") { + self.notebook_executor + .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)) + } else { + self.create_documents_executor + .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)) + } + } AIAgentActionType::UseComputer(_) => self .use_computer_executor .update(ctx, |executor, ctx| executor.should_autoexecute(input, ctx)), diff --git a/app/src/ai/blocklist/action_model/execute/create_documents.rs b/app/src/ai/blocklist/action_model/execute/create_documents.rs index 14b18fbf..6fdce96f 100644 --- a/app/src/ai/blocklist/action_model/execute/create_documents.rs +++ b/app/src/ai/blocklist/action_model/execute/create_documents.rs @@ -10,7 +10,6 @@ use crate::{ artifacts::Artifact, blocklist::BlocklistAIHistoryModel, document::ai_document_model::{AIDocumentModel, AIDocumentVersion}, - execution_profiles::profiles::AIExecutionProfilesModel, }, notebooks::editor::model::FileLinkResolutionContext, terminal::model::session::active_session::ActiveSession, @@ -102,15 +101,10 @@ impl CreateDocumentsExecutor { }) }; - let profile = AIExecutionProfilesModel::as_ref(ctx) - .active_profile(Some(self.terminal_view_id), ctx); - let should_autosync = profile.data().autosync_plans_to_warp_drive; - - if should_autosync { - model.update(ctx, |model, model_ctx| { - model.sync_to_warp_drive(id, model_ctx); - }); - } + // Plans always sync to the Plans folder in Galaxy Drive. + model.update(ctx, |model, model_ctx| { + model.sync_to_warp_drive(id, model_ctx); + }); // Add plan artifact to the conversation. let artifact = Artifact::Plan { diff --git a/app/src/ai/blocklist/action_model/execute/notebooks.rs b/app/src/ai/blocklist/action_model/execute/notebooks.rs new file mode 100644 index 00000000..607acc57 --- /dev/null +++ b/app/src/ai/blocklist/action_model/execute/notebooks.rs @@ -0,0 +1,207 @@ +//! Executors for the `create_notebook`, `read_notebook`, and `edit_notebook` tools. +//! +//! These tools interact with Galaxy Drive CloudNotebook objects directly, +//! as opposed to the plan tools which work through AIDocumentModel. + +use futures::{future::BoxFuture, FutureExt}; +use galaxyui::{Entity, ModelContext, SingletonEntity}; + +use crate::{ + ai::{ + agent::{ + AIAgentAction, AIAgentActionType, CreateDocumentsRequest, CreateDocumentsResult, + DocumentContext, EditDocumentsRequest, EditDocumentsResult, ReadDocumentsRequest, + ReadDocumentsResult, + }, + document::ai_document_model::AIDocumentVersion, + }, + cloud_object::model::persistence::CloudModel, + notebooks::CloudNotebookModel, + server::{cloud_objects::update_manager::UpdateManager, ids::ClientId}, + workspaces::user_workspaces::UserWorkspaces, +}; + +use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput}; + +pub struct NotebookExecutor; + +impl NotebookExecutor { + pub fn new() -> Self { + Self + } + + pub(super) fn should_autoexecute( + &self, + _input: ExecuteActionInput, + _ctx: &mut ModelContext, + ) -> bool { + true + } + + pub(super) fn execute_create( + &mut self, + input: ExecuteActionInput, + ctx: &mut ModelContext, + ) -> impl Into { + let ExecuteActionInput { action, .. } = input; + let AIAgentAction { + action: AIAgentActionType::CreateDocuments(CreateDocumentsRequest { documents }), + .. + } = action + else { + return ActionExecution::::InvalidAction; + }; + + let Some(owner) = UserWorkspaces::as_ref(ctx).personal_drive(ctx) else { + return ActionExecution::Sync( + CreateDocumentsResult::Error("No personal drive available.".to_string()).into(), + ); + }; + + let mut created = Vec::new(); + + for document in documents { + let client_id = ClientId::new(); + let model = CloudNotebookModel { + title: document.title.clone(), + data: document.content.clone(), + ai_document_id: None, + conversation_id: None, + }; + + UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| { + update_manager.create_notebook( + client_id, + owner, + None, // root of personal space + model, + crate::cloud_object::CloudObjectEventEntrypoint::Unknown, + false, + ctx, + ); + }); + + created.push(DocumentContext { + document_id: crate::ai::document::ai_document_model::AIDocumentId::new(), + document_version: AIDocumentVersion::default(), + content: document.content.clone(), + line_ranges: vec![], + }); + } + + ActionExecution::Sync( + CreateDocumentsResult::Success { + created_documents: created, + } + .into(), + ) + } + + pub(super) fn execute_read( + &mut self, + input: ExecuteActionInput, + ctx: &mut ModelContext, + ) -> impl Into { + let ExecuteActionInput { action, .. } = input; + let AIAgentAction { + action: AIAgentActionType::ReadDocuments(ReadDocumentsRequest { document_ids }), + .. + } = action + else { + return ActionExecution::::InvalidAction; + }; + + let cloud_model = CloudModel::as_ref(ctx); + let mut documents = Vec::new(); + + for id in document_ids { + // Try to find the notebook by treating the ID as a SyncId string + let notebook = cloud_model + .get_all_active_notebooks() + .find(|nb| nb.id.uid() == id.to_string()); + + if let Some(notebook) = notebook { + documents.push(DocumentContext { + document_id: *id, + document_version: AIDocumentVersion::default(), + content: format!("# {}\n\n{}", notebook.model().title, notebook.model().data), + line_ranges: vec![], + }); + } + } + + ActionExecution::Sync(ReadDocumentsResult::Success { documents }.into()) + } + + pub(super) fn execute_edit( + &mut self, + input: ExecuteActionInput, + ctx: &mut ModelContext, + ) -> impl Into { + let ExecuteActionInput { action, .. } = input; + let AIAgentAction { + action: AIAgentActionType::EditDocuments(EditDocumentsRequest { diffs }), + .. + } = action + else { + return ActionExecution::::InvalidAction; + }; + + let mut updated_documents = Vec::new(); + let mut errors = Vec::new(); + + for diff in diffs { + let cloud_model = CloudModel::as_ref(ctx); + let notebook_data = cloud_model + .get_all_active_notebooks() + .find(|nb| nb.id.uid() == diff.document_id.to_string()) + .map(|nb| (nb.id, nb.model().data.clone())); + + let Some((notebook_id, current_data)) = notebook_data else { + errors.push(format!("Notebook {} not found.", diff.document_id)); + continue; + }; + + // Simple search/replace on the notebook data + if !current_data.contains(&diff.search) { + errors.push(format!( + "Could not find search text in notebook {}.", + diff.document_id + )); + continue; + } + + let new_data = current_data.replacen(&diff.search, &diff.replace, 1); + let new_data_arc = std::sync::Arc::new(new_data.clone()); + + UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| { + update_manager.update_notebook_data(new_data_arc, notebook_id, ctx); + }); + + updated_documents.push(DocumentContext { + document_id: diff.document_id, + document_version: AIDocumentVersion::default(), + content: new_data, + line_ranges: vec![], + }); + } + + if !errors.is_empty() { + return ActionExecution::Sync(EditDocumentsResult::Error(errors.join("\n")).into()); + } + + ActionExecution::Sync(EditDocumentsResult::Success { updated_documents }.into()) + } + + pub(super) fn preprocess_action( + &mut self, + _input: PreprocessActionInput, + _ctx: &mut ModelContext, + ) -> BoxFuture<'static, ()> { + futures::future::ready(()).boxed() + } +} + +impl Entity for NotebookExecutor { + type Event = (); +} diff --git a/app/src/ai/blocklist/controller.rs b/app/src/ai/blocklist/controller.rs index 816980a8..22eb809f 100644 --- a/app/src/ai/blocklist/controller.rs +++ b/app/src/ai/blocklist/controller.rs @@ -2226,11 +2226,9 @@ impl BlocklistAIController { { let history_model = BlocklistAIHistoryModel::as_ref(ctx); if let Some(conversation) = history_model.conversation(&conversation_id) { - let has_optimistic_cli_subagent = - conversation.has_active_subagent(); + let has_optimistic_cli_subagent = conversation.has_active_subagent(); if !has_optimistic_cli_subagent { - request_params.root_task_id = - Some(conversation.get_root_task_id().to_string()); + request_params.root_task_id = Some(conversation.get_root_task_id().to_string()); } } } @@ -2435,8 +2433,7 @@ impl BlocklistAIController { { let terminal_view_id = self.terminal_view_id; history_model.update(ctx, |history_model, ctx| { - if let Some(conversation) = - history_model.conversation_mut(&conversation_id) + if let Some(conversation) = history_model.conversation_mut(&conversation_id) { conversation.force_cancel_all_streaming_exchanges( terminal_view_id, diff --git a/app/src/ai/document/ai_document_model.rs b/app/src/ai/document/ai_document_model.rs index da4b76e8..5c81005f 100644 --- a/app/src/ai/document/ai_document_model.rs +++ b/app/src/ai/document/ai_document_model.rs @@ -242,23 +242,59 @@ impl AIDocumentModel { return false; }; - let Some(plan_folder_id) = self.get_or_create_plan_folder(owner, ctx).into_server() else { - // Plan folder is still being created (has ClientId only). - // If we save using the ClientId as the parent folder, the document - // will end up in a broken state once the folder is saved. - // Queue the document for creation until the folder gets a ServerId. - self.pending_document_queue - .push(PendingDocument { id, title, content }); - - if let Some(document) = self.documents.get_mut(&id) { - let client_id = ClientId::new(); - document.sync_id = Some(SyncId::ClientId(client_id)); + let plan_folder_sync_id = self.get_or_create_plan_folder(owner, ctx); + match plan_folder_sync_id.into_server() { + Some(plan_folder_id) => { + // Plan folder already exists on server — create notebook directly. + self.create_notebook_in_plan_folder( + id, + &title, + &content, + owner, + plan_folder_id, + ctx, + ); + ctx.emit(AIDocumentModelEvent::DocumentSaveStatusUpdated(id)); } - return true; - }; + None => { + // Plan folder is still being created (has ClientId only). + // Queue the document for creation until the folder gets a ServerId. + // Also create the notebook at the root level so it appears in Drive + // immediately in local/offline mode. + self.pending_document_queue.push(PendingDocument { + id, + title: title.clone(), + content: content.clone(), + }); - self.create_notebook_in_plan_folder(id, &title, &content, owner, plan_folder_id, ctx); - ctx.emit(AIDocumentModelEvent::DocumentSaveStatusUpdated(id)); + // Create a notebook at the root level so it's visible in Drive immediately. + let client_id = ClientId::new(); + if let Some(document) = self.documents.get_mut(&id) { + document.sync_id = Some(SyncId::ClientId(client_id)); + } + + let notebook_model = CloudNotebookModel { + title, + data: content, + ai_document_id: Some(id), + conversation_id: self.get_server_conversation_id(&id, ctx), + }; + + UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| { + update_manager.create_notebook( + client_id, + owner, + Some(plan_folder_sync_id), + notebook_model, + CloudObjectEventEntrypoint::Unknown, + true, + ctx, + ); + }); + + ctx.emit(AIDocumentModelEvent::DocumentSaveStatusUpdated(id)); + } + } true } diff --git a/app/src/ai/llms.rs b/app/src/ai/llms.rs index a450e01e..01dc1ab3 100644 --- a/app/src/ai/llms.rs +++ b/app/src/ai/llms.rs @@ -870,12 +870,11 @@ impl LLMPreferences { Some(key) } }; - let name = - if base_url.contains("localhost") || base_url.contains("127.0.0.1") { - "LiteLLM (local)".to_string() - } else { - "LiteLLM".to_string() - }; + let name = if base_url.contains("localhost") || base_url.contains("127.0.0.1") { + "LiteLLM (local)".to_string() + } else { + "LiteLLM".to_string() + }; provider_entries.push((name, base_url, api_key, legacy_models)); } @@ -931,9 +930,7 @@ impl LLMPreferences { } } - log::info!( - "[openai/litellm] Injected {total_injected} model(s) into available choices" - ); + log::info!("[openai/litellm] Injected {total_injected} model(s) into available choices"); } /// Returns the OpenAI client config for a given model ID, if it was injected diff --git a/app/src/ai/openai/response_translator.rs b/app/src/ai/openai/response_translator.rs index 09116081..21fc7780 100644 --- a/app/src/ai/openai/response_translator.rs +++ b/app/src/ai/openai/response_translator.rs @@ -498,6 +498,13 @@ const KNOWN_TOOLS: &[&str] = &[ "write_to_long_running_shell_command", "read_shell_command_output", "read_mcp_resource", + "read_plan", + "create_plan", + "edit_plan", + "read_notebook", + "create_notebook", + "edit_notebook", + // Legacy aliases — accept old names so in-flight conversations don't break. "read_documents", "create_documents", "edit_documents", diff --git a/app/src/ai/prompt_builder/tests.rs b/app/src/ai/prompt_builder/tests.rs index e39e5e36..78b0406b 100644 --- a/app/src/ai/prompt_builder/tests.rs +++ b/app/src/ai/prompt_builder/tests.rs @@ -39,7 +39,7 @@ mod prompt_builder_tests { assert!(prompt.system_prompt.contains("code review mode")); assert!(!prompt.tools.iter().any(|t| t.name == "apply_file_diffs")); - assert!(!prompt.tools.iter().any(|t| t.name == "create_documents")); + assert!(!prompt.tools.iter().any(|t| t.name == "create_plan")); assert!(prompt.tools.iter().any(|t| t.name == "read_files")); assert!(prompt.tools.iter().any(|t| t.name == "grep")); } diff --git a/app/src/ai/prompt_builder/tools.rs b/app/src/ai/prompt_builder/tools.rs index 2023fa19..c4111bd1 100644 --- a/app/src/ai/prompt_builder/tools.rs +++ b/app/src/ai/prompt_builder/tools.rs @@ -32,6 +32,9 @@ fn code_tools() -> Vec { read_documents(), create_documents(), edit_documents(), + read_notebook(), + create_notebook(), + edit_notebook(), start_agent(), send_message_to_agent(), ask_user_question(), @@ -217,13 +220,13 @@ fn read_mcp_resource() -> ToolDefinition { fn read_documents() -> ToolDefinition { ToolDefinition { - name: "read_documents".to_string(), - description: "Read the contents of one or more Galaxy notebook documents by their IDs." + name: "read_plan".to_string(), + description: "Read the contents of one or more Galaxy plan documents by their IDs. Plans are rich-text documents that appear in the Plans folder of Galaxy Drive." .to_string(), input_schema: serde_json::json!({ "type": "object", "properties": { - "document_ids": { "type": "array", "items": { "type": "string" }, "description": "Document IDs to read" } + "document_ids": { "type": "array", "items": { "type": "string" }, "description": "Plan document IDs to read" } }, "required": ["document_ids"] }), @@ -232,13 +235,13 @@ fn read_documents() -> ToolDefinition { fn create_documents() -> ToolDefinition { ToolDefinition { - name: "create_documents".to_string(), - description: "Create new Galaxy notebook documents with the specified title and content." + name: "create_plan".to_string(), + description: "Create a new plan document in Galaxy Drive's Plans folder. Plans are rich-text documents for tracking tasks, architecture decisions, and project notes." .to_string(), input_schema: serde_json::json!({ "type": "object", "properties": { - "documents": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" } }, "required": ["title", "content"] }, "description": "Documents to create" } + "documents": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" } }, "required": ["title", "content"] }, "description": "Plan documents to create" } }, "required": ["documents"] }), @@ -247,13 +250,13 @@ fn create_documents() -> ToolDefinition { fn edit_documents() -> ToolDefinition { ToolDefinition { - name: "edit_documents".to_string(), - description: "Edit existing Galaxy notebook documents using search/replace diffs." + name: "edit_plan".to_string(), + description: "Edit an existing plan document in Galaxy Drive using search/replace diffs." .to_string(), input_schema: serde_json::json!({ "type": "object", "properties": { - "diffs": { "type": "array", "items": { "type": "object", "properties": { "document_id": { "type": "string" }, "search": { "type": "string" }, "replace": { "type": "string" } }, "required": ["document_id", "search", "replace"] }, "description": "Edits to apply to documents" } + "diffs": { "type": "array", "items": { "type": "object", "properties": { "document_id": { "type": "string" }, "search": { "type": "string" }, "replace": { "type": "string" } }, "required": ["document_id", "search", "replace"] }, "description": "Edits to apply to plan documents" } }, "required": ["diffs"] }), @@ -334,3 +337,46 @@ fn fetch_conversation() -> ToolDefinition { }), } } + +fn read_notebook() -> ToolDefinition { + ToolDefinition { + name: "read_notebook".to_string(), + description: "Read the contents of one or more Galaxy Drive notebooks by their IDs. Notebooks are user-created rich-text documents stored in Galaxy Drive.".to_string(), + input_schema: serde_json::json!({ + "type": "object", + "properties": { + "document_ids": { "type": "array", "items": { "type": "string" }, "description": "Notebook IDs to read" } + }, + "required": ["document_ids"] + }), + } +} + +fn create_notebook() -> ToolDefinition { + ToolDefinition { + name: "create_notebook".to_string(), + description: "Create a new notebook in Galaxy Drive. Notebooks are rich-text documents for general notes, documentation, and reference material.".to_string(), + input_schema: serde_json::json!({ + "type": "object", + "properties": { + "documents": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" } }, "required": ["title", "content"] }, "description": "Notebooks to create" } + }, + "required": ["documents"] + }), + } +} + +fn edit_notebook() -> ToolDefinition { + ToolDefinition { + name: "edit_notebook".to_string(), + description: "Edit an existing Galaxy Drive notebook using search/replace diffs." + .to_string(), + input_schema: serde_json::json!({ + "type": "object", + "properties": { + "diffs": { "type": "array", "items": { "type": "object", "properties": { "document_id": { "type": "string" }, "search": { "type": "string" }, "replace": { "type": "string" } }, "required": ["document_id", "search", "replace"] }, "description": "Edits to apply to notebooks" } + }, + "required": ["diffs"] + }), + } +} diff --git a/app/src/cloud_object/model/model_test.rs b/app/src/cloud_object/model/model_test.rs index 72a32b6d..80402910 100644 --- a/app/src/cloud_object/model/model_test.rs +++ b/app/src/cloud_object/model/model_test.rs @@ -1,7 +1,7 @@ use chrono::Utc; use galaxyui::{App, ModelHandle}; use lazy_static::lazy_static; -use settings::{SyncToCloud}; +use settings::SyncToCloud; use crate::auth::auth_manager::AuthManager; use crate::auth::user::TEST_USER_UID; diff --git a/app/src/drive/settings.rs b/app/src/drive/settings.rs index 2449040a..53968ccf 100644 --- a/app/src/drive/settings.rs +++ b/app/src/drive/settings.rs @@ -1,7 +1,5 @@ use galaxy_core::features::FeatureFlag; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; use super::DriveSortOrder; diff --git a/app/src/search/command_search/settings.rs b/app/src/search/command_search/settings.rs index 26d814d2..89778990 100644 --- a/app/src/search/command_search/settings.rs +++ b/app/src/search/command_search/settings.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(CommandSearchSettings, settings: [ show_global_workflows_in_universal_search: ShowGlobalWorkflowsInUniversalSearch { diff --git a/app/src/server/cloud_objects/update_manager_test.rs b/app/src/server/cloud_objects/update_manager_test.rs index 08283b8a..d54ae5ec 100644 --- a/app/src/server/cloud_objects/update_manager_test.rs +++ b/app/src/server/cloud_objects/update_manager_test.rs @@ -5,7 +5,7 @@ use futures_lite::future; use galaxy_core::features::FeatureFlag; use galaxy_graphql::{object_permissions::AccessLevel, scalars::time::ServerTimestamp}; use galaxyui::{App, ModelHandle, SingletonEntity}; -use settings::{SyncToCloud}; +use settings::SyncToCloud; #[cfg(test)] use crate::server::server_api::object::MockObjectClient; diff --git a/app/src/settings/accessibility.rs b/app/src/settings/accessibility.rs index d0634671..c5e560e6 100644 --- a/app/src/settings/accessibility.rs +++ b/app/src/settings/accessibility.rs @@ -1,7 +1,5 @@ use galaxyui::accessibility::AccessibilityVerbosity; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(AccessibilitySettings, settings: [ a11y_verbosity: AccessibilityVerbosityState { diff --git a/app/src/settings/ai.rs b/app/src/settings/ai.rs index cebd9450..08cda782 100644 --- a/app/src/settings/ai.rs +++ b/app/src/settings/ai.rs @@ -24,9 +24,7 @@ use regex::Regex; use galaxy_core::execution_mode::AppExecutionMode; use galaxy_core::features::FeatureFlag; -use settings::{ - define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; use serde::{de::Deserializer, Deserialize, Serialize}; use strum::IntoEnumIterator; @@ -466,7 +464,9 @@ impl settings_value::SettingsValue for BedrockModelConfig {} #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, schemars::JsonSchema)] #[schemars(description = "Configuration for a single OpenAI-compatible model (e.g. via LiteLLM).")] pub struct OpenAIModelConfig { - #[schemars(description = "The model ID to send in the API request (e.g. claude-sonnet-4-20250514).")] + #[schemars( + description = "The model ID to send in the API request (e.g. claude-sonnet-4-20250514)." + )] pub model_id: String, #[schemars(description = "Display name shown in the model picker.")] pub display_name: String, @@ -477,7 +477,9 @@ pub struct OpenAIModelConfig { #[schemars(description = "Maximum context window size in tokens.")] pub context_size: u32, #[serde(default)] - #[schemars(description = "Optional provider hint (e.g. anthropic, openai, google) for icon display.")] + #[schemars( + description = "Optional provider hint (e.g. anthropic, openai, google) for icon display." + )] pub provider: Option, } @@ -825,7 +827,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.is_any_ai_enabled", description: "Controls whether all AI features are enabled.", @@ -836,7 +838,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.enabled", description: "Controls whether proactive AI features like suggestions are enabled.", @@ -847,7 +849,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.input.ai_auto_detection_enabled", description: "Controls whether AI automatically detects natural language input.", @@ -861,7 +863,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.input.nld_in_terminal_enabled", description: "Controls whether natural language detection is enabled in the terminal input.", @@ -870,7 +872,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: String::new(), supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.input.ai_command_denylist", description: "Commands to exclude from AI natural language autodetection.", @@ -882,7 +884,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.input.use_local_model", description: "Use a locally downloaded AI model for command recognition and suggestions instead of Bedrock.", @@ -893,7 +895,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, // TODO(roland): revisit this when launched to stable supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.intelligent_autosuggestions_enabled", description: "Controls whether AI-powered intelligent autosuggestions are enabled.", @@ -907,7 +909,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, // TODO(advait): revisit this when launched to stable supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.agent_mode_query_suggestions_enabled", description: "Controls whether prompt suggestions are shown in agent mode.", @@ -919,7 +921,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.code_suggestions_enabled", description: "Controls whether AI code suggestions are enabled.", @@ -931,7 +933,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.natural_language_autosuggestions_enabled", description: "Controls whether ghosted text autosuggestions are shown for AI input queries.", @@ -944,7 +946,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.shared_block_title_generation_enabled", description: "Controls whether titles are auto-generated when sharing blocks.", @@ -955,7 +957,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.git_operations_autogen_enabled", description: "Controls whether AI auto-generates commit messages and PR title/body in the code review dialogs.", @@ -966,7 +968,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.active_ai.rule_suggestions_enabled", description: "Controls whether the agent suggests rules to save after responses.", @@ -978,7 +980,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.voice.voice_input_enabled", description: "Controls whether voice input is enabled for AI interactions.", @@ -990,7 +992,7 @@ define_settings_group!(AISettings, settings: [ type: usize, default: 0, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, }, // Whether or not the user has manually dismissed the voice input new feature popup. @@ -998,7 +1000,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, }, // This field is used to store the key used for voice input toggling. @@ -1012,7 +1014,7 @@ define_settings_group!(AISettings, settings: [ default: false, supported_platforms: SupportedPlatforms::DESKTOP, sync_to_cloud: SyncToCloud::Never, // Never sync to cloud to keep state separate across devices, since microphone access is per-device. - + private: true, }, // Predicates that Agent Mode can use to decide if it can execute @@ -1024,7 +1026,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: DEFAULT_COMMAND_EXECUTION_ALLOWLIST.clone(), supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.profiles.agent_mode_command_execution_allowlist", description: "Commands that the agent can execute without explicit permission.", @@ -1038,7 +1040,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: DEFAULT_COMMAND_EXECUTION_DENYLIST.clone(), supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.profiles.agent_mode_command_execution_denylist", description: "Commands that the agent must always ask before executing.", @@ -1051,7 +1053,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.profiles.agent_mode_execute_readonly_commands", description: "Whether the agent can auto-execute read-only commands without asking.", @@ -1066,7 +1068,7 @@ define_settings_group!(AISettings, settings: [ type: AgentModeCodingPermissionsType, default: AgentModeCodingPermissionsType::default(), supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.profiles.agent_mode_coding_permissions", description: "The file read permission level for the agent.", @@ -1082,7 +1084,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: vec![], supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.profiles.agent_mode_coding_file_read_allowlist", description: "File paths the agent can read without asking for permission.", @@ -1095,7 +1097,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } // Whether or not we should show the speedbump for auto-executing readonly cmds. @@ -1106,7 +1108,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } // Whether or not we should show the speedbump for auto-writing to the PTY. @@ -1117,7 +1119,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } // Whether or not we should show the speedbump for auto-reading files. @@ -1128,7 +1130,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } // Whether direct Bedrock integration is enabled (client calls Bedrock API directly). @@ -1136,7 +1138,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.bedrock.enabled", description: "Whether to use AWS Bedrock directly for AI requests.", @@ -1148,7 +1150,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: "default".to_string(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.bedrock.profile", description: "The AWS profile name to use for Bedrock credentials.", @@ -1158,7 +1160,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: String::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.bedrock.region", description: "AWS region for Bedrock API calls. Leave empty to auto-detect from profile.", @@ -1168,7 +1170,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.bedrock.cross_region_inference", description: "Whether to automatically add cross-region inference prefixes to model IDs.", @@ -1178,7 +1180,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: Vec::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.bedrock.models", description: "Custom AWS Bedrock model configurations.", @@ -1188,7 +1190,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.bedrock.auto_login", description: "Whether to automatically run the login command when Bedrock credentials expire.", @@ -1198,7 +1200,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: "aws sso login".to_string(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.bedrock.auth_refresh_command", description: "The command to run to refresh AWS credentials for Bedrock.", @@ -1208,7 +1210,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: String::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } // AWS secret access key for static key authentication (stored in OS keychain). @@ -1216,7 +1218,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: String::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } // Whether the Bedrock login banner has been permanently dismissed. @@ -1224,7 +1226,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } // Whether the OpenAI-compatible (LiteLLM) provider is enabled. @@ -1232,7 +1234,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.openai.enabled", description: "Whether to use an OpenAI-compatible endpoint (e.g. LiteLLM) for AI requests.", @@ -1243,7 +1245,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: "http://localhost:4000/v1".to_string(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.openai.base_url", description: "Base URL for the OpenAI-compatible API endpoint (e.g. LiteLLM proxy).", @@ -1253,7 +1255,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: String::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.openai.api_key", description: "API key for the OpenAI-compatible endpoint (optional if proxy handles auth).", @@ -1264,7 +1266,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: String::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.openai.model", description: "Model name to send to the OpenAI-compatible endpoint. Leave empty to use the selected model ID.", @@ -1275,7 +1277,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: Vec::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.openai.models", description: "Custom OpenAI-compatible model configurations (e.g. from LiteLLM).", @@ -1287,7 +1289,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: Vec::new(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "ai.providers", description: "Multiple OpenAI-compatible provider endpoints (e.g. LiteLLM, Ollama, local models).", @@ -1297,7 +1299,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.knowledge.rules_enabled", description: "Whether the agent uses your saved rules during requests.", @@ -1307,7 +1309,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.knowledge.warp_drive_context_enabled", description: "Whether Galaxy Drive context is included in AI requests.", @@ -1320,7 +1322,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: vec![], supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1332,7 +1334,7 @@ define_settings_group!(AISettings, settings: [ type: Vec, default: vec![], supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1343,7 +1345,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1352,7 +1354,7 @@ define_settings_group!(AISettings, settings: [ type: AIRequestQuotaInfo, default: AIRequestQuotaInfo::default(), supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, }, @@ -1364,7 +1366,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1372,7 +1374,7 @@ define_settings_group!(AISettings, settings: [ type: Option, default: None, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, }, @@ -1385,7 +1387,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1398,7 +1400,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1410,7 +1412,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "cloud_platform.third_party_api_keys.can_use_warp_credits_with_byok", description: "Whether Galaxy credits can be used even when providing your own API key.", @@ -1420,7 +1422,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.other.should_render_use_agent_toolbar_for_user_commands", description: "Whether to show the \"Use Agent\" footer for terminal commands.", @@ -1432,7 +1434,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.third_party.should_render_cli_agent_toolbar", description: "Whether to show the CLI agent footer for coding agent commands.", @@ -1444,7 +1446,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.third_party.auto_toggle_composer", description: "Whether CLI agent Rich Input automatically closes and reopens based on the agent's blocked state.", @@ -1456,7 +1458,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.third_party.auto_open_composer_on_cli_agent_start", description: "Whether CLI agent Rich Input automatically opens when a CLI agent session starts.", @@ -1470,7 +1472,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.third_party.auto_dismiss_composer_after_submit", description: "Whether CLI agent Rich Input automatically closes after the user submits a prompt.", @@ -1484,7 +1486,7 @@ define_settings_group!(AISettings, settings: [ type: ToolbarCommandMap, default: ToolbarCommandMap::default(), supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.third_party.cli_agent_toolbar_enabled_commands", max_table_depth: 1, @@ -1501,7 +1503,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1516,7 +1518,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1526,7 +1528,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1537,7 +1539,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1552,7 +1554,7 @@ define_settings_group!(AISettings, settings: [ type: String, default: String::new(), supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "general.default_tab_config_path", } @@ -1565,7 +1567,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.mcp_servers.file_based_mcp_enabled", description: "Whether third-party file-based MCP servers are automatically detected.", @@ -1581,7 +1583,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.input.include_agent_commands_in_history", description: "Whether agent-executed commands are included in command history.", @@ -1592,7 +1594,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.other.show_conversation_history", description: "Whether conversation history appears in the tools panel.", @@ -1604,7 +1606,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.other.show_agent_notifications", description: "Whether agent notifications are shown.", @@ -1617,7 +1619,7 @@ define_settings_group!(AISettings, settings: [ type: HashMap, default: HashMap::default(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1629,7 +1631,7 @@ define_settings_group!(AISettings, settings: [ type: HashMap, default: HashMap::default(), supported_platforms: SupportedPlatforms::DESKTOP, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } @@ -1641,7 +1643,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: true, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: false, toml_path: "agents.warp_agent.other.agent_attribution_enabled", description: "Whether the Galaxy Agent adds an attribution co-author line to commit messages and pull requests it creates.", @@ -1654,7 +1656,7 @@ define_settings_group!(AISettings, settings: [ type: bool, default: false, supported_platforms: SupportedPlatforms::ALL, - sync_to_cloud: SyncToCloud::Never, + sync_to_cloud: SyncToCloud::Never, private: true, } ]); diff --git a/app/src/settings/alias_expansion.rs b/app/src/settings/alias_expansion.rs index 7883d3da..fa229bd6 100644 --- a/app/src/settings/alias_expansion.rs +++ b/app/src/settings/alias_expansion.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(AliasExpansionSettings, settings: [ alias_expansion_enabled: AliasExpansionEnabled { diff --git a/app/src/settings/block_visibility.rs b/app/src/settings/block_visibility.rs index e457c218..a001ca02 100644 --- a/app/src/settings/block_visibility.rs +++ b/app/src/settings/block_visibility.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; // Settings for visibility of non-user command blocks like the bootstrap block // and in-band command blocks. diff --git a/app/src/settings/changelog.rs b/app/src/settings/changelog.rs index 353f692c..7709933d 100644 --- a/app/src/settings/changelog.rs +++ b/app/src/settings/changelog.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(ChangelogSettings, settings: [ show_changelog_after_update: ShowChangelogAfterUpdate { diff --git a/app/src/settings/cloud_preferences.rs b/app/src/settings/cloud_preferences.rs index fd0649b3..5e5b0406 100644 --- a/app/src/settings/cloud_preferences.rs +++ b/app/src/settings/cloud_preferences.rs @@ -14,9 +14,7 @@ use crate::{ server::sync_queue::QueueItem, }; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(CloudPreferencesSettings, settings: [ settings_sync_enabled: IsSettingsSyncEnabled { type: bool, diff --git a/app/src/settings/code.rs b/app/src/settings/code.rs index b98ddcc3..a3d18791 100644 --- a/app/src/settings/code.rs +++ b/app/src/settings/code.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(CodeSettings, settings: [ code_as_default_editor: CodeAsDefaultEditor { diff --git a/app/src/settings/editor.rs b/app/src/settings/editor.rs index 39356935..6644c6df 100644 --- a/app/src/settings/editor.rs +++ b/app/src/settings/editor.rs @@ -3,10 +3,7 @@ use std::fmt::{Display, Formatter}; use enum_iterator::{all, Sequence}; use galaxyui::ModelContext; use serde::{Deserialize, Serialize}; -use settings::{ - macros::define_settings_group, Setting as _, SupportedPlatforms, - SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting as _, SupportedPlatforms, SyncToCloud}; #[derive( Clone, diff --git a/app/src/settings/emacs_bindings.rs b/app/src/settings/emacs_bindings.rs index e0afc4aa..7c556d76 100644 --- a/app/src/settings/emacs_bindings.rs +++ b/app/src/settings/emacs_bindings.rs @@ -1,7 +1,5 @@ use crate::banner::BannerState; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; // This isn't exactly a setting, but rather a record of a // user action that should be persisted the same way we would a setting. diff --git a/app/src/settings/font.rs b/app/src/settings/font.rs index 9e5fea37..8830d927 100644 --- a/app/src/settings/font.rs +++ b/app/src/settings/font.rs @@ -2,9 +2,7 @@ use galaxy_core::ui::builder::MIN_FONT_SIZE; use galaxyui::{fonts::Weight, rendering::ThinStrokes, AppContext, SingletonEntity}; use galaxyui::elements::DEFAULT_UI_LINE_HEIGHT_RATIO; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; use super::EnforceMinimumContrast as EnforceMinimumContrastEnum; diff --git a/app/src/settings/input_mode.rs b/app/src/settings/input_mode.rs index 5b92b8f4..aab1afc0 100644 --- a/app/src/settings/input_mode.rs +++ b/app/src/settings/input_mode.rs @@ -1,7 +1,5 @@ use crate::terminal::block_list_viewport::InputMode; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; define_settings_group!(InputModeSettings, settings: [ input_mode: InputModeState { diff --git a/app/src/settings/pane.rs b/app/src/settings/pane.rs index 8b4dd185..43d7b27b 100644 --- a/app/src/settings/pane.rs +++ b/app/src/settings/pane.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(PaneSettings, settings: [ should_dim_inactive_panes: ShouldDimInactivePanes { diff --git a/app/src/settings/select.rs b/app/src/settings/select.rs index 41c44724..2704518f 100644 --- a/app/src/settings/select.rs +++ b/app/src/settings/select.rs @@ -2,9 +2,7 @@ use std::ops::Not; use galaxyui::{clipboard::ClipboardContent, AppContext}; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; define_settings_group!(SelectionSettings, settings: [ copy_on_select: CopyOnSelect { diff --git a/app/src/settings/ssh.rs b/app/src/settings/ssh.rs index ab751a6f..51f59ef0 100644 --- a/app/src/settings/ssh.rs +++ b/app/src/settings/ssh.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(SshSettings, settings: [ diff --git a/app/src/settings/theme.rs b/app/src/settings/theme.rs index 2c61aa7f..4fe654ed 100644 --- a/app/src/settings/theme.rs +++ b/app/src/settings/theme.rs @@ -1,9 +1,7 @@ use galaxyui::{platform::SystemTheme, AppContext}; use crate::themes::theme::{RespectSystemTheme, SelectedSystemThemes, ThemeKind}; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; // Settings group for themes related settings. // Note that we store just the information needed to derive the current diff --git a/app/src/settings_view/ai_page.rs b/app/src/settings_view/ai_page.rs index 693806aa..fdcb636d 100644 --- a/app/src/settings_view/ai_page.rs +++ b/app/src/settings_view/ai_page.rs @@ -1429,10 +1429,7 @@ impl AISettingsPageView { }; if !response.status().is_success() { - log::error!( - "[litellm] Model fetch returned HTTP {}", - response.status() - ); + log::error!("[litellm] Model fetch returned HTTP {}", response.status()); return Vec::new(); } @@ -1473,9 +1470,7 @@ impl AISettingsPageView { let mut chars = word.chars(); match chars.next() { None => String::new(), - Some(c) => { - c.to_uppercase().to_string() + chars.as_str() - } + Some(c) => c.to_uppercase().to_string() + chars.as_str(), } }) .collect::>() @@ -1502,11 +1497,7 @@ impl AISettingsPageView { }) .collect(); - log::info!( - "[litellm] Fetched {} model(s) from {}", - models.len(), - url - ); + log::info!("[litellm] Fetched {} model(s) from {}", models.len(), url); models }, |_view, models, ctx| { diff --git a/app/src/terminal/alt_screen_reporting.rs b/app/src/terminal/alt_screen_reporting.rs index 6a3f6009..60d5485e 100644 --- a/app/src/terminal/alt_screen_reporting.rs +++ b/app/src/terminal/alt_screen_reporting.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(AltScreenReporting, settings: [ mouse_reporting_enabled: MouseReportingEnabled { diff --git a/app/src/terminal/block_list_settings.rs b/app/src/terminal/block_list_settings.rs index 5e8ab5b9..97649260 100644 --- a/app/src/terminal/block_list_settings.rs +++ b/app/src/terminal/block_list_settings.rs @@ -1,6 +1,4 @@ -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; // Settings for controlling the behavior of the block list. define_settings_group!(BlockListSettings, settings: [ diff --git a/app/src/terminal/general_settings.rs b/app/src/terminal/general_settings.rs index d7f5c11b..b24b5e0f 100644 --- a/app/src/terminal/general_settings.rs +++ b/app/src/terminal/general_settings.rs @@ -1,9 +1,7 @@ use std::collections::HashSet; use crate::{banner::BannerState, resource_center::Tip}; -use galaxy_core::settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use galaxy_core::settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(GeneralSettings, settings: [ show_warning_before_quitting: ShowWarningBeforeQuitting { diff --git a/app/src/terminal/keys_settings.rs b/app/src/terminal/keys_settings.rs index 290eab28..71d1d871 100644 --- a/app/src/terminal/keys_settings.rs +++ b/app/src/terminal/keys_settings.rs @@ -1,7 +1,5 @@ use galaxyui::{keymap::Keystroke, AppContext, DisplayIdx, ModelContext}; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; use crate::{ report_if_error, diff --git a/app/src/terminal/ligature_settings.rs b/app/src/terminal/ligature_settings.rs index aee792ee..cf084fce 100644 --- a/app/src/terminal/ligature_settings.rs +++ b/app/src/terminal/ligature_settings.rs @@ -1,9 +1,7 @@ use crate::features::FeatureFlag; use galaxyui::{AppContext, SingletonEntity}; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; define_settings_group!(LigatureSettings, settings: [ ligature_rendering_enabled: LigatureRenderingEnabled { diff --git a/app/src/terminal/safe_mode_settings.rs b/app/src/terminal/safe_mode_settings.rs index bd859262..715ec3dd 100644 --- a/app/src/terminal/safe_mode_settings.rs +++ b/app/src/terminal/safe_mode_settings.rs @@ -1,7 +1,5 @@ use galaxyui::{AppContext, SingletonEntity}; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; use crate::{terminal::model::ObfuscateSecrets, workspaces::user_workspaces::UserWorkspaces}; diff --git a/app/src/terminal/session_settings.rs b/app/src/terminal/session_settings.rs index af18d425..ad5456af 100644 --- a/app/src/terminal/session_settings.rs +++ b/app/src/terminal/session_settings.rs @@ -9,9 +9,7 @@ use serde::{Deserialize, Serialize}; pub use startup_shell::*; pub use working_directory_config::*; -use galaxy_core::settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use galaxy_core::settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; use crate::ai::blocklist::agent_view::toolbar_item::AgentToolbarItemKind; use crate::context_chips::prompt::PromptSelection; diff --git a/app/src/terminal/settings.rs b/app/src/terminal/settings.rs index d0239ab3..21fe1005 100644 --- a/app/src/terminal/settings.rs +++ b/app/src/terminal/settings.rs @@ -2,9 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::settings::{AISettings, InputSettings, TerminalSpacing}; use galaxyui::{units::Pixels, AppContext, SingletonEntity}; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; #[derive( Clone, diff --git a/app/src/terminal/shared_session/settings.rs b/app/src/terminal/shared_session/settings.rs index 19e84be4..0cf97c4b 100644 --- a/app/src/terminal/shared_session/settings.rs +++ b/app/src/terminal/shared_session/settings.rs @@ -1,8 +1,6 @@ use std::time::Duration; -use settings::{ - macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, Setting, SupportedPlatforms, SyncToCloud}; define_settings_group!(SharedSessionSettings, settings: [ onboarding_block_shown: SessionSharingOnboardingBlockShown { diff --git a/app/src/undo_close/settings.rs b/app/src/undo_close/settings.rs index 655e8942..b2bf3de8 100644 --- a/app/src/undo_close/settings.rs +++ b/app/src/undo_close/settings.rs @@ -1,8 +1,6 @@ use std::time::Duration; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(UndoCloseSettings, settings: [ enabled: UndoCloseEnabled { diff --git a/app/src/util/file/external_editor/settings.rs b/app/src/util/file/external_editor/settings.rs index cf4ac3b5..9dba618e 100644 --- a/app/src/util/file/external_editor/settings.rs +++ b/app/src/util/file/external_editor/settings.rs @@ -1,8 +1,6 @@ pub use crate::util::openable_file_type::EditorLayout; use serde::{Deserialize, Deserializer, Serialize}; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; #[derive( Debug, diff --git a/app/src/window_settings.rs b/app/src/window_settings.rs index a486f07d..fd2cb82c 100644 --- a/app/src/window_settings.rs +++ b/app/src/window_settings.rs @@ -1,7 +1,5 @@ use galaxyui::{AppContext, WindowId}; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; define_settings_group!(WindowSettings, settings: [ background_blur_radius: BackgroundBlurRadius { diff --git a/app/src/workspace/tab_settings.rs b/app/src/workspace/tab_settings.rs index 02330381..c96996a3 100644 --- a/app/src/workspace/tab_settings.rs +++ b/app/src/workspace/tab_settings.rs @@ -2,9 +2,7 @@ use std::collections::HashMap; use std::path::Path; use galaxy_core::ui::theme::AnsiColorIdentifier; -use settings::{ - macros::define_settings_group, SupportedPlatforms, SyncToCloud, -}; +use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud}; #[derive( Default,