feat: improve tool loading (#2193)
This commit is contained in:
@@ -2,6 +2,10 @@ use cliclack::spinner;
|
|||||||
use console::style;
|
use console::style;
|
||||||
use goose::agents::extension::ToolInfo;
|
use goose::agents::extension::ToolInfo;
|
||||||
use goose::agents::extension_manager::get_parameter_names;
|
use goose::agents::extension_manager::get_parameter_names;
|
||||||
|
use goose::agents::platform_tools::{
|
||||||
|
PLATFORM_ENABLE_EXTENSION_TOOL_NAME, PLATFORM_LIST_RESOURCES_TOOL_NAME,
|
||||||
|
PLATFORM_READ_RESOURCE_TOOL_NAME,
|
||||||
|
};
|
||||||
use goose::agents::Agent;
|
use goose::agents::Agent;
|
||||||
use goose::agents::{extension::Envs, ExtensionConfig};
|
use goose::agents::{extension::Envs, ExtensionConfig};
|
||||||
use goose::config::extensions::name_to_key;
|
use goose::config::extensions::name_to_key;
|
||||||
@@ -921,6 +925,24 @@ pub fn toggle_experiments_dialog() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn configure_tool_permissions_dialog() -> Result<(), Box<dyn Error>> {
|
pub async fn configure_tool_permissions_dialog() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut extensions: Vec<String> = ExtensionConfigManager::get_all()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|ext| ext.enabled)
|
||||||
|
.map(|ext| ext.config.name().clone())
|
||||||
|
.collect();
|
||||||
|
extensions.push("platform".to_string());
|
||||||
|
|
||||||
|
let selected_extension_name = cliclack::select("Choose an extension to configure tools")
|
||||||
|
.items(
|
||||||
|
&extensions
|
||||||
|
.iter()
|
||||||
|
.map(|ext| (ext.clone(), ext.clone(), ""))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.interact()?;
|
||||||
|
|
||||||
|
// Fetch tools for the selected extension
|
||||||
// Load config and get provider/model
|
// Load config and get provider/model
|
||||||
let config = Config::global();
|
let config = Config::global();
|
||||||
|
|
||||||
@@ -937,28 +959,36 @@ pub async fn configure_tool_permissions_dialog() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
// Create the agent
|
// Create the agent
|
||||||
let mut agent = Agent::new(provider);
|
let mut agent = Agent::new(provider);
|
||||||
for extension in ExtensionConfigManager::get_all().expect("should load extensions") {
|
if let Ok(Some(config)) = ExtensionConfigManager::get_config_by_name(&selected_extension_name) {
|
||||||
if extension.enabled {
|
agent
|
||||||
let config = extension.config.clone();
|
.add_extension(config.clone())
|
||||||
agent
|
.await
|
||||||
.add_extension(config.clone())
|
.unwrap_or_else(|_| {
|
||||||
.await
|
println!(
|
||||||
.unwrap_or_else(|_| {
|
"{} Failed to check extension: {}",
|
||||||
println!(
|
style("Error").red().italic(),
|
||||||
"{} Failed to check extension: {}",
|
config.name()
|
||||||
style("Error").red().italic(),
|
);
|
||||||
config.name()
|
});
|
||||||
);
|
} else {
|
||||||
});
|
println!(
|
||||||
}
|
"{} Configuration not found for extension: {}",
|
||||||
|
style("Warning").yellow().italic(),
|
||||||
|
selected_extension_name
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut permission_manager = PermissionManager::default();
|
let mut permission_manager = PermissionManager::default();
|
||||||
// Fetch the list of tools grouped by extension
|
let selected_tools = agent
|
||||||
let tools: Vec<ToolInfo> = agent
|
.list_tools(Some(selected_extension_name.clone()))
|
||||||
.list_tools()
|
|
||||||
.await
|
.await
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.filter(|tool| {
|
||||||
|
tool.name != PLATFORM_ENABLE_EXTENSION_TOOL_NAME
|
||||||
|
&& tool.name != PLATFORM_LIST_RESOURCES_TOOL_NAME
|
||||||
|
&& tool.name != PLATFORM_READ_RESOURCE_TOOL_NAME
|
||||||
|
})
|
||||||
.map(|tool| {
|
.map(|tool| {
|
||||||
ToolInfo::new(
|
ToolInfo::new(
|
||||||
&tool.name,
|
&tool.name,
|
||||||
@@ -967,37 +997,21 @@ pub async fn configure_tool_permissions_dialog() -> Result<(), Box<dyn Error>> {
|
|||||||
permission_manager.get_user_permission(&tool.name),
|
permission_manager.get_user_permission(&tool.name),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Vec<ToolInfo>>();
|
||||||
|
|
||||||
let mut tools_by_extension: HashMap<String, Vec<ToolInfo>> = HashMap::new();
|
|
||||||
|
|
||||||
for tool in tools {
|
|
||||||
if let Some((extension_name, _tool_name)) = tool.name.split_once("__") {
|
|
||||||
tools_by_extension
|
|
||||||
.entry(extension_name.to_string())
|
|
||||||
.or_default()
|
|
||||||
.push(tool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask the user to choose an extension
|
|
||||||
let extension_name = cliclack::select("Choose an extension to configure tools")
|
|
||||||
.items(
|
|
||||||
&tools_by_extension
|
|
||||||
.keys()
|
|
||||||
.map(|ext| (ext.clone(), ext.clone(), ""))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
.interact()?;
|
|
||||||
|
|
||||||
// Fetch tools for the selected extension
|
|
||||||
let selected_tools = tools_by_extension.get(&extension_name).unwrap();
|
|
||||||
|
|
||||||
let tool_name = cliclack::select("Choose a tool to update permission")
|
let tool_name = cliclack::select("Choose a tool to update permission")
|
||||||
.items(
|
.items(
|
||||||
&selected_tools
|
&selected_tools
|
||||||
.iter()
|
.iter()
|
||||||
.map(|tool| (tool.name.clone(), tool.name.clone(), &tool.description))
|
.map(|tool| {
|
||||||
|
let first_description = tool
|
||||||
|
.description
|
||||||
|
.split('.')
|
||||||
|
.next()
|
||||||
|
.unwrap_or("No description available")
|
||||||
|
.trim();
|
||||||
|
(tool.name.clone(), tool.name.clone(), first_description)
|
||||||
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
.interact()?;
|
.interact()?;
|
||||||
|
|||||||
@@ -203,17 +203,9 @@ async fn get_tools(
|
|||||||
let permission_manager = PermissionManager::default();
|
let permission_manager = PermissionManager::default();
|
||||||
|
|
||||||
let mut tools: Vec<ToolInfo> = agent
|
let mut tools: Vec<ToolInfo> = agent
|
||||||
.list_tools()
|
.list_tools(query.extension_name)
|
||||||
.await
|
.await
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|tool| {
|
|
||||||
// Apply the filter only if the extension name is present in the query
|
|
||||||
if let Some(extension_name) = &query.extension_name {
|
|
||||||
tool.name.starts_with(extension_name)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|tool| {
|
.map(|tool| {
|
||||||
let permission = permission_manager
|
let permission = permission_manager
|
||||||
.get_user_permission(&tool.name)
|
.get_user_permission(&tool.name)
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ impl Agent {
|
|||||||
.extension_manager
|
.extension_manager
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.get_prefixed_tools()
|
.get_prefixed_tools(None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Add frontend tools directly - they don't need prefixing since they're already uniquely named
|
// Add frontend tools directly - they don't need prefixing since they're already uniquely named
|
||||||
@@ -271,21 +271,23 @@ impl Agent {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_tools(&self) -> Vec<Tool> {
|
pub async fn list_tools(&self, extension_name: Option<String>) -> Vec<Tool> {
|
||||||
let extension_manager = self.extension_manager.lock().await;
|
let extension_manager = self.extension_manager.lock().await;
|
||||||
let mut prefixed_tools = extension_manager
|
let mut prefixed_tools = extension_manager
|
||||||
.get_prefixed_tools()
|
.get_prefixed_tools(extension_name.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
// Add platform tools
|
if extension_name.is_none() || extension_name.as_deref() == Some("platform") {
|
||||||
prefixed_tools.push(platform_tools::search_available_extensions_tool());
|
// Add platform tools
|
||||||
prefixed_tools.push(platform_tools::enable_extension_tool());
|
prefixed_tools.push(platform_tools::search_available_extensions_tool());
|
||||||
|
prefixed_tools.push(platform_tools::enable_extension_tool());
|
||||||
|
|
||||||
// Add resource tools if supported
|
// Add resource tools if supported
|
||||||
if extension_manager.supports_resources() {
|
if extension_manager.supports_resources() {
|
||||||
prefixed_tools.push(platform_tools::read_resource_tool());
|
prefixed_tools.push(platform_tools::read_resource_tool());
|
||||||
prefixed_tools.push(platform_tools::list_resources_tool());
|
prefixed_tools.push(platform_tools::list_resources_tool());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixed_tools
|
prefixed_tools
|
||||||
@@ -580,7 +582,7 @@ impl Agent {
|
|||||||
|
|
||||||
pub async fn get_plan_prompt(&self) -> anyhow::Result<String> {
|
pub async fn get_plan_prompt(&self) -> anyhow::Result<String> {
|
||||||
let extension_manager = self.extension_manager.lock().await;
|
let extension_manager = self.extension_manager.lock().await;
|
||||||
let tools = extension_manager.get_prefixed_tools().await?;
|
let tools = extension_manager.get_prefixed_tools(None).await?;
|
||||||
let tools_info = tools
|
let tools_info = tools
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tool| {
|
.map(|tool| {
|
||||||
@@ -612,7 +614,7 @@ impl Agent {
|
|||||||
.build_system_prompt(extensions_info, self.frontend_instructions.clone());
|
.build_system_prompt(extensions_info, self.frontend_instructions.clone());
|
||||||
|
|
||||||
let recipe_prompt = self.prompt_manager.get_recipe_prompt().await;
|
let recipe_prompt = self.prompt_manager.get_recipe_prompt().await;
|
||||||
let tools = extension_manager.get_prefixed_tools().await?;
|
let tools = extension_manager.get_prefixed_tools(None).await?;
|
||||||
|
|
||||||
messages.push(Message::user().with_text(recipe_prompt));
|
messages.push(Message::user().with_text(recipe_prompt));
|
||||||
|
|
||||||
|
|||||||
@@ -231,8 +231,20 @@ impl ExtensionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get all tools from all clients with proper prefixing
|
/// Get all tools from all clients with proper prefixing
|
||||||
pub async fn get_prefixed_tools(&self) -> ExtensionResult<Vec<Tool>> {
|
pub async fn get_prefixed_tools(
|
||||||
let client_futures = self.clients.iter().map(|(name, client)| {
|
&self,
|
||||||
|
extension_name: Option<String>,
|
||||||
|
) -> ExtensionResult<Vec<Tool>> {
|
||||||
|
// Filter clients based on the provided extension_name or include all if None
|
||||||
|
let filtered_clients = self.clients.iter().filter(|(name, _)| {
|
||||||
|
if let Some(ref name_filter) = extension_name {
|
||||||
|
*name == name_filter
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let client_futures = filtered_clients.map(|(name, client)| {
|
||||||
let name = name.clone();
|
let name = name.clone();
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ impl Agent {
|
|||||||
&self,
|
&self,
|
||||||
) -> anyhow::Result<(Vec<Tool>, Vec<Tool>, String)> {
|
) -> anyhow::Result<(Vec<Tool>, Vec<Tool>, String)> {
|
||||||
// Get tools from extension manager
|
// Get tools from extension manager
|
||||||
let mut tools = self.list_tools().await;
|
let mut tools = self.list_tools(None).await;
|
||||||
|
|
||||||
// Add frontend tools
|
// Add frontend tools
|
||||||
for frontend_tool in self.frontend_tools.values() {
|
for frontend_tool in self.frontend_tools.values() {
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ export default function PermissionModal({ extensionName, onClose }: PermissionMo
|
|||||||
console.error('Failed to get tools');
|
console.error('Failed to get tools');
|
||||||
} else {
|
} else {
|
||||||
const filteredTools = (response.data || []).filter(
|
const filteredTools = (response.data || []).filter(
|
||||||
(tool) => tool.name !== 'platform__enable_extension'
|
(tool) =>
|
||||||
|
tool.name !== 'platform__enable_extension' &&
|
||||||
|
tool.name !== 'platform__read_resource' &&
|
||||||
|
tool.name !== 'platform__list_resources'
|
||||||
);
|
);
|
||||||
setTools(filteredTools);
|
setTools(filteredTools);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user