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:
@@ -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