Skip to content

Commit 76252aa

Browse files
committed
Merge branch 'main' of github.com:block/goose into dkatz/system-notify
* 'main' of github.com:block/goose: Rewrite extension management tools (#5057) fix: re-sync package-lock.json (#5235) docs: Hacktoberfest MCP youtube short entry to community-content.json (#5150) feat: add schedule button to recipe entries (#5217) Autocompact threshold UI cleanup (#5232) fix: correct schema for openai tools (#5229)
2 parents 97aa4ab + bccfa01 commit 76252aa

File tree

26 files changed

+1004
-435
lines changed

26 files changed

+1004
-435
lines changed

crates/goose-cli/src/commands/configure.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ use cliclack::spinner;
33
use console::style;
44
use goose::agents::extension::ToolInfo;
55
use goose::agents::extension_manager::get_parameter_names;
6-
use goose::agents::platform_tools::{
7-
PLATFORM_LIST_RESOURCES_TOOL_NAME, PLATFORM_READ_RESOURCE_TOOL_NAME,
8-
};
96
use goose::agents::Agent;
107
use goose::agents::{extension::Envs, ExtensionConfig};
118
use goose::config::declarative_providers::{create_custom_provider, remove_custom_provider};
@@ -1449,10 +1446,6 @@ pub async fn configure_tool_permissions_dialog() -> Result<(), Box<dyn Error>> {
14491446
.list_tools(Some(selected_extension_name.clone()))
14501447
.await
14511448
.into_iter()
1452-
.filter(|tool| {
1453-
tool.name != PLATFORM_LIST_RESOURCES_TOOL_NAME
1454-
&& tool.name != PLATFORM_READ_RESOURCE_TOOL_NAME
1455-
})
14561449
.map(|tool| {
14571450
ToolInfo::new(
14581451
&tool.name,

crates/goose-cli/src/session/builder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
324324
.extension_manager
325325
.set_context(PlatformExtensionContext {
326326
session_id: session_id.clone(),
327+
extension_manager: Some(Arc::downgrade(&agent.extension_manager)),
328+
tool_route_manager: Some(Arc::downgrade(&agent.tool_route_manager)),
327329
})
328330
.await;
329331

crates/goose/src/agents/agent.rs

Lines changed: 16 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@ use uuid::Uuid;
1010

1111
use crate::agents::extension::{ExtensionConfig, ExtensionError, ExtensionResult, ToolInfo};
1212
use crate::agents::extension_manager::{get_parameter_names, ExtensionManager};
13+
use crate::agents::extension_manager_extension::MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE;
1314
use crate::agents::final_output_tool::{FINAL_OUTPUT_CONTINUATION_MESSAGE, FINAL_OUTPUT_TOOL_NAME};
14-
use crate::agents::platform_tools::{
15-
PLATFORM_LIST_RESOURCES_TOOL_NAME, PLATFORM_MANAGE_EXTENSIONS_TOOL_NAME,
16-
PLATFORM_MANAGE_SCHEDULE_TOOL_NAME, PLATFORM_READ_RESOURCE_TOOL_NAME,
17-
PLATFORM_SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME,
18-
};
15+
use crate::agents::platform_tools::PLATFORM_MANAGE_SCHEDULE_TOOL_NAME;
1916
use crate::agents::prompt_manager::PromptManager;
2017
use crate::agents::recipe_tools::dynamic_task_tools::{
2118
create_dynamic_task, create_dynamic_task_tool, DYNAMIC_TASK_TOOL_NAME_PREFIX,
@@ -32,7 +29,7 @@ use crate::agents::tool_route_manager::ToolRouteManager;
3229
use crate::agents::tool_router_index_manager::ToolRouterIndexManager;
3330
use crate::agents::types::SessionConfig;
3431
use crate::agents::types::{FrontendTool, ToolResultReceiver};
35-
use crate::config::{get_enabled_extensions, get_extension_by_name, Config};
32+
use crate::config::{get_enabled_extensions, Config};
3633
use crate::context_mgmt::DEFAULT_COMPACTION_THRESHOLD;
3734
use crate::conversation::{debug_conversation_fix, fix_conversation, Conversation};
3835
use crate::mcp_utils::ToolResult;
@@ -88,7 +85,7 @@ pub struct ToolCategorizeResult {
8885
/// The main goose Agent
8986
pub struct Agent {
9087
pub(super) provider: Mutex<Option<Arc<dyn Provider>>>,
91-
pub extension_manager: ExtensionManager,
88+
pub extension_manager: Arc<ExtensionManager>,
9289
pub(super) sub_recipe_manager: Mutex<SubRecipeManager>,
9390
pub(super) tasks_manager: TasksManager,
9491
pub(super) final_output_tool: Arc<Mutex<Option<FinalOutputTool>>>,
@@ -100,7 +97,7 @@ pub struct Agent {
10097
pub(super) tool_result_tx: mpsc::Sender<(String, ToolResult<Vec<Content>>)>,
10198
pub(super) tool_result_rx: ToolResultReceiver,
10299

103-
pub(super) tool_route_manager: ToolRouteManager,
100+
pub tool_route_manager: Arc<ToolRouteManager>,
104101
pub(super) scheduler_service: Mutex<Option<Arc<dyn SchedulerTrait>>>,
105102
pub(super) retry_manager: RetryManager,
106103
pub(super) tool_inspection_manager: ToolInspectionManager,
@@ -163,7 +160,7 @@ impl Agent {
163160

164161
Self {
165162
provider: Mutex::new(None),
166-
extension_manager: ExtensionManager::new(),
163+
extension_manager: Arc::new(ExtensionManager::new()),
167164
sub_recipe_manager: Mutex::new(SubRecipeManager::new()),
168165
tasks_manager: TasksManager::new(),
169166
final_output_tool: Arc::new(Mutex::new(None)),
@@ -174,7 +171,7 @@ impl Agent {
174171
confirmation_rx: Mutex::new(confirm_rx),
175172
tool_result_tx: tool_tx,
176173
tool_result_rx: Arc::new(Mutex::new(tool_rx)),
177-
tool_route_manager: ToolRouteManager::new(),
174+
tool_route_manager: Arc::new(ToolRouteManager::new()),
178175
scheduler_service: Mutex::new(None),
179176
retry_manager: RetryManager::new(),
180177
tool_inspection_manager: Self::create_default_tool_inspection_manager(),
@@ -404,28 +401,6 @@ impl Agent {
404401
return (request_id, Ok(ToolCallResult::from(result)));
405402
}
406403

407-
if tool_call.name == PLATFORM_MANAGE_EXTENSIONS_TOOL_NAME {
408-
let extension_name = tool_call
409-
.arguments
410-
.as_ref()
411-
.and_then(|args| args.get("extension_name"))
412-
.and_then(|v| v.as_str())
413-
.unwrap_or("")
414-
.to_string();
415-
let action = tool_call
416-
.arguments
417-
.as_ref()
418-
.and_then(|args| args.get("action"))
419-
.and_then(|v| v.as_str())
420-
.unwrap_or("")
421-
.to_string();
422-
let (request_id, result) = self
423-
.manage_extensions(action, extension_name, request_id)
424-
.await;
425-
426-
return (request_id, Ok(ToolCallResult::from(result)));
427-
}
428-
429404
if tool_call.name == FINAL_OUTPUT_TOOL_NAME {
430405
return if let Some(final_output_tool) = self.final_output_tool.lock().await.as_mut() {
431406
let result = final_output_tool.execute_tool_call(tool_call.clone()).await;
@@ -488,12 +463,12 @@ impl Agent {
488463
let parent_session_id = session.id.to_string();
489464
let parent_working_dir = session.working_dir.clone();
490465

491-
let task_config = TaskConfig::new(
492-
provider,
493-
parent_session_id,
494-
parent_working_dir,
495-
get_enabled_extensions(),
496-
);
466+
// Get extensions from the agent's runtime state rather than global config
467+
// This ensures subagents inherit extensions that were dynamically enabled by the parent
468+
let extensions = self.get_extension_configs().await;
469+
470+
let task_config =
471+
TaskConfig::new(provider, parent_session_id, parent_working_dir, extensions);
497472

498473
let arguments = match tool_call.arguments.clone() {
499474
Some(args) => Value::Object(args),
@@ -560,31 +535,6 @@ impl Agent {
560535
.map(Value::Object)
561536
.unwrap_or(Value::Object(serde_json::Map::new()));
562537
create_dynamic_task(arguments, &self.tasks_manager, loaded_extensions).await
563-
} else if tool_call.name == PLATFORM_READ_RESOURCE_TOOL_NAME {
564-
// Check if the tool is read_resource and handle it separately
565-
let arguments = tool_call
566-
.arguments
567-
.clone()
568-
.map(Value::Object)
569-
.unwrap_or(Value::Object(serde_json::Map::new()));
570-
ToolCallResult::from(
571-
self.extension_manager
572-
.read_resource(arguments, cancellation_token.unwrap_or_default())
573-
.await,
574-
)
575-
} else if tool_call.name == PLATFORM_LIST_RESOURCES_TOOL_NAME {
576-
let arguments = tool_call
577-
.arguments
578-
.clone()
579-
.map(Value::Object)
580-
.unwrap_or(Value::Object(serde_json::Map::new()));
581-
ToolCallResult::from(
582-
self.extension_manager
583-
.list_resources(arguments, cancellation_token.unwrap_or_default())
584-
.await,
585-
)
586-
} else if tool_call.name == PLATFORM_SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME {
587-
ToolCallResult::from(self.extension_manager.search_available_extensions().await)
588538
} else if self.is_frontend_tool(&tool_call.name).await {
589539
// For frontend tools, return an error indicating we need frontend execution
590540
ToolCallResult::from(Err(ErrorData::new(
@@ -653,109 +603,6 @@ impl Agent {
653603
Ok(())
654604
}
655605

656-
#[allow(clippy::too_many_lines)]
657-
pub(super) async fn manage_extensions(
658-
&self,
659-
action: String,
660-
extension_name: String,
661-
request_id: String,
662-
) -> (String, Result<Vec<Content>, ErrorData>) {
663-
if self.tool_route_manager.is_router_functional().await {
664-
let selector = self.tool_route_manager.get_router_tool_selector().await;
665-
if let Some(selector) = selector {
666-
let selector_action = if action == "disable" { "remove" } else { "add" };
667-
let selector = Arc::new(selector);
668-
if let Err(e) = ToolRouterIndexManager::update_extension_tools(
669-
&selector,
670-
&self.extension_manager,
671-
&extension_name,
672-
selector_action,
673-
)
674-
.await
675-
{
676-
return (
677-
request_id,
678-
Err(ErrorData::new(
679-
ErrorCode::INTERNAL_ERROR,
680-
format!("Failed to update LLM index: {}", e),
681-
None,
682-
)),
683-
);
684-
}
685-
}
686-
}
687-
if action == "disable" {
688-
let result = self
689-
.extension_manager
690-
.remove_extension(&extension_name)
691-
.await
692-
.map(|_| {
693-
vec![Content::text(format!(
694-
"The extension '{}' has been disabled successfully",
695-
extension_name
696-
))]
697-
})
698-
.map_err(|e| ErrorData::new(ErrorCode::INTERNAL_ERROR, e.to_string(), None));
699-
return (request_id, result);
700-
}
701-
702-
let config = match get_extension_by_name(&extension_name) {
703-
Some(config) => config,
704-
None => {
705-
return (
706-
request_id,
707-
Err(ErrorData::new(
708-
ErrorCode::RESOURCE_NOT_FOUND,
709-
format!(
710-
"Extension '{}' not found. Please check the extension name and try again.",
711-
extension_name
712-
),
713-
None,
714-
)),
715-
)
716-
}
717-
};
718-
let result = self
719-
.extension_manager
720-
.add_extension(config)
721-
.await
722-
.map(|_| {
723-
vec![Content::text(format!(
724-
"The extension '{}' has been installed successfully",
725-
extension_name
726-
))]
727-
})
728-
.map_err(|e| ErrorData::new(ErrorCode::INTERNAL_ERROR, e.to_string(), None));
729-
730-
// Update LLM index if operation was successful and LLM routing is functional
731-
if result.is_ok() && self.tool_route_manager.is_router_functional().await {
732-
let selector = self.tool_route_manager.get_router_tool_selector().await;
733-
if let Some(selector) = selector {
734-
let llm_action = if action == "disable" { "remove" } else { "add" };
735-
let selector = Arc::new(selector);
736-
if let Err(e) = ToolRouterIndexManager::update_extension_tools(
737-
&selector,
738-
&self.extension_manager,
739-
&extension_name,
740-
llm_action,
741-
)
742-
.await
743-
{
744-
return (
745-
request_id,
746-
Err(ErrorData::new(
747-
ErrorCode::INTERNAL_ERROR,
748-
format!("Failed to update LLM index: {}", e),
749-
None,
750-
)),
751-
);
752-
}
753-
}
754-
}
755-
756-
(request_id, result)
757-
}
758-
759606
pub async fn add_extension(&self, extension: ExtensionConfig) -> ExtensionResult<()> {
760607
match &extension {
761608
ExtensionConfig::Frontend {
@@ -824,21 +671,10 @@ impl Agent {
824671

825672
if extension_name.is_none() || extension_name.as_deref() == Some("platform") {
826673
// Add platform tools
827-
prefixed_tools.extend([
828-
platform_tools::search_available_extensions_tool(),
829-
platform_tools::manage_extensions_tool(),
830-
platform_tools::manage_schedule_tool(),
831-
]);
674+
// TODO: migrate the manage schedule tool as well
675+
prefixed_tools.extend([platform_tools::manage_schedule_tool()]);
832676
// Dynamic task tool
833677
prefixed_tools.push(create_dynamic_task_tool());
834-
835-
// Add resource tools if supported
836-
if self.extension_manager.supports_resources().await {
837-
prefixed_tools.extend([
838-
platform_tools::read_resource_tool(),
839-
platform_tools::list_resources_tool(),
840-
]);
841-
}
842678
}
843679

844680
if extension_name.is_none() {
@@ -1220,7 +1056,7 @@ impl Agent {
12201056
let mut enable_extension_request_ids = vec![];
12211057
for request in &remaining_requests {
12221058
if let Ok(tool_call) = &request.tool_call {
1223-
if tool_call.name == PLATFORM_MANAGE_EXTENSIONS_TOOL_NAME {
1059+
if tool_call.name == MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE {
12241060
enable_extension_request_ids.push(request.id.clone());
12251061
}
12261062
}

crates/goose/src/agents/extension.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::agents::extension_manager_extension;
12
use crate::agents::todo_extension;
23
use std::collections::HashMap;
34

@@ -34,8 +35,8 @@ impl ProcessExit {
3435
}
3536
}
3637

37-
pub static PLATFORM_EXTENSIONS: Lazy<HashMap<&'static str, PlatformExtensionDef>> =
38-
Lazy::new(|| {
38+
pub static PLATFORM_EXTENSIONS: Lazy<HashMap<&'static str, PlatformExtensionDef>> = Lazy::new(
39+
|| {
3940
let mut map = HashMap::new();
4041

4142
map.insert(
@@ -49,12 +50,28 @@ pub static PLATFORM_EXTENSIONS: Lazy<HashMap<&'static str, PlatformExtensionDef>
4950
},
5051
);
5152

53+
map.insert(
54+
"extensionmanager",
55+
PlatformExtensionDef {
56+
name: extension_manager_extension::EXTENSION_NAME,
57+
description:
58+
"Enable extension management tools for discovering, enabling, and disabling extensions",
59+
default_enabled: true,
60+
client_factory: |ctx| Box::new(extension_manager_extension::ExtensionManagerClient::new(ctx).unwrap()),
61+
},
62+
);
63+
5264
map
53-
});
65+
},
66+
);
5467

55-
#[derive(Debug, Clone)]
68+
#[derive(Clone)]
5669
pub struct PlatformExtensionContext {
5770
pub session_id: Option<String>,
71+
pub extension_manager:
72+
Option<std::sync::Weak<crate::agents::extension_manager::ExtensionManager>>,
73+
pub tool_route_manager:
74+
Option<std::sync::Weak<crate::agents::tool_route_manager::ToolRouteManager>>,
5875
}
5976

6077
#[derive(Debug, Clone)]

crates/goose/src/agents/extension_manager.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,11 @@ impl ExtensionManager {
238238
pub fn new() -> Self {
239239
Self {
240240
extensions: Mutex::new(HashMap::new()),
241-
context: Mutex::new(PlatformExtensionContext { session_id: None }),
241+
context: Mutex::new(PlatformExtensionContext {
242+
session_id: None,
243+
extension_manager: None,
244+
tool_route_manager: None,
245+
}),
242246
}
243247
}
244248

0 commit comments

Comments
 (0)