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
This commit is contained in:
@@ -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<ReadDocumentsExecutor>,
|
||||
edit_documents_executor: ModelHandle<EditDocumentsExecutor>,
|
||||
create_documents_executor: ModelHandle<CreateDocumentsExecutor>,
|
||||
notebook_executor: ModelHandle<NotebookExecutor>,
|
||||
use_computer_executor: ModelHandle<UseComputerExecutor>,
|
||||
request_computer_use_executor: ModelHandle<RequestComputerUseExecutor>,
|
||||
read_skill_executor: ModelHandle<ReadSkillExecutor>,
|
||||
@@ -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)),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<Self>,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub(super) fn execute_create(
|
||||
&mut self,
|
||||
input: ExecuteActionInput,
|
||||
ctx: &mut ModelContext<Self>,
|
||||
) -> impl Into<AnyActionExecution> {
|
||||
let ExecuteActionInput { action, .. } = input;
|
||||
let AIAgentAction {
|
||||
action: AIAgentActionType::CreateDocuments(CreateDocumentsRequest { documents }),
|
||||
..
|
||||
} = action
|
||||
else {
|
||||
return ActionExecution::<CreateDocumentsResult>::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<Self>,
|
||||
) -> impl Into<AnyActionExecution> {
|
||||
let ExecuteActionInput { action, .. } = input;
|
||||
let AIAgentAction {
|
||||
action: AIAgentActionType::ReadDocuments(ReadDocumentsRequest { document_ids }),
|
||||
..
|
||||
} = action
|
||||
else {
|
||||
return ActionExecution::<ReadDocumentsResult>::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<Self>,
|
||||
) -> impl Into<AnyActionExecution> {
|
||||
let ExecuteActionInput { action, .. } = input;
|
||||
let AIAgentAction {
|
||||
action: AIAgentActionType::EditDocuments(EditDocumentsRequest { diffs }),
|
||||
..
|
||||
} = action
|
||||
else {
|
||||
return ActionExecution::<EditDocumentsResult>::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<Self>,
|
||||
) -> BoxFuture<'static, ()> {
|
||||
futures::future::ready(()).boxed()
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity for NotebookExecutor {
|
||||
type Event = ();
|
||||
}
|
||||
Reference in New Issue
Block a user