mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
fix(extension-manager): require extension_name on read_resource (#8989)
Signed-off-by: olaservo <olahungerford@gmail.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1304,76 +1304,19 @@ impl ExtensionManager {
|
||||
cancellation_token: CancellationToken,
|
||||
) -> Result<Vec<Content>, ErrorData> {
|
||||
let uri = require_str_parameter(¶ms, "uri")?;
|
||||
let extension_name = require_str_parameter(¶ms, "extension_name")?;
|
||||
|
||||
let extension_name = params.get("extension_name").and_then(|v| v.as_str());
|
||||
let read_result = self
|
||||
.read_resource(session_id, uri, extension_name, cancellation_token)
|
||||
.await?;
|
||||
|
||||
// If extension name is provided, we can just look it up
|
||||
if let Some(ext_name) = extension_name {
|
||||
let read_result = self
|
||||
.read_resource(session_id, uri, ext_name, cancellation_token.clone())
|
||||
.await?;
|
||||
|
||||
let mut result = Vec::new();
|
||||
for content in read_result.contents {
|
||||
if let ResourceContents::TextResourceContents { text, .. } = content {
|
||||
let content_str = format!("{}\n\n{}", uri, text);
|
||||
result.push(Content::text(content_str));
|
||||
}
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
// If extension name is not provided, we need to search for the resource across all extensions
|
||||
// Loop through each extension and try to read the resource, don't raise an error if the resource is not found
|
||||
// TODO: do we want to find if a provided uri is in multiple extensions?
|
||||
// currently it will return the first match and skip any others
|
||||
let extension_names: Vec<String> = self
|
||||
.extensions
|
||||
.lock()
|
||||
.await
|
||||
.iter()
|
||||
.filter(|(_name, ext)| ext.supports_resources())
|
||||
.map(|(name, _)| name.clone())
|
||||
.collect();
|
||||
|
||||
for extension_name in extension_names {
|
||||
let read_result = self
|
||||
.read_resource(session_id, uri, &extension_name, cancellation_token.clone())
|
||||
.await;
|
||||
match read_result {
|
||||
Ok(read_result) => {
|
||||
let mut result = Vec::new();
|
||||
for content in read_result.contents {
|
||||
if let ResourceContents::TextResourceContents { text, .. } = content {
|
||||
let content_str = format!("{}\n\n{}", uri, text);
|
||||
result.push(Content::text(content_str));
|
||||
}
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
Err(_) => continue,
|
||||
let mut result = Vec::new();
|
||||
for content in read_result.contents {
|
||||
if let ResourceContents::TextResourceContents { text, .. } = content {
|
||||
result.push(Content::text(format!("{}\n\n{}", uri, text)));
|
||||
}
|
||||
}
|
||||
|
||||
// None of the extensions had the resource so we raise an error
|
||||
let available_extensions = self
|
||||
.extensions
|
||||
.lock()
|
||||
.await
|
||||
.keys()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join(", ");
|
||||
let error_msg = format!(
|
||||
"Resource with uri '{}' not found. Here are the available extensions: {}",
|
||||
uri, available_extensions
|
||||
);
|
||||
|
||||
Err(ErrorData::new(
|
||||
ErrorCode::RESOURCE_NOT_FOUND,
|
||||
error_msg,
|
||||
None,
|
||||
))
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn read_resource(
|
||||
@@ -1493,7 +1436,7 @@ impl ExtensionManager {
|
||||
params: Value,
|
||||
cancellation_token: CancellationToken,
|
||||
) -> Result<Vec<Content>, ErrorData> {
|
||||
let extension = params.get("extension").and_then(|v| v.as_str());
|
||||
let extension = params.get("extension_name").and_then(|v| v.as_str());
|
||||
|
||||
match extension {
|
||||
Some(extension_name) => {
|
||||
|
||||
@@ -53,8 +53,7 @@ pub struct ManageExtensionsParams {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ReadResourceParams {
|
||||
pub uri: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub extension_name: Option<String>,
|
||||
pub extension_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
@@ -325,15 +324,17 @@ impl ExtensionManagerClient {
|
||||
files, database schemas, or application-specific information. This tool lists resources
|
||||
in the provided extension, and returns a list for the user to browse. If no extension
|
||||
is provided, the tool will search all extensions for the resource.
|
||||
"#}.to_string(),
|
||||
"#}
|
||||
.to_string(),
|
||||
Arc::new(
|
||||
serde_json::to_value(schema_for!(ListResourcesParams))
|
||||
.expect("Failed to serialize schema")
|
||||
.as_object()
|
||||
.expect("Schema must be an object")
|
||||
.clone()
|
||||
.clone(),
|
||||
),
|
||||
).annotate(ToolAnnotations::from_raw(
|
||||
)
|
||||
.annotate(ToolAnnotations::from_raw(
|
||||
Some("List resources".to_string()),
|
||||
Some(true),
|
||||
Some(false),
|
||||
@@ -343,21 +344,24 @@ impl ExtensionManagerClient {
|
||||
Tool::new(
|
||||
READ_RESOURCE_TOOL_NAME.to_string(),
|
||||
indoc! {r#"
|
||||
Read a resource from an extension.
|
||||
Read a resource from a specific extension.
|
||||
|
||||
Resources allow extensions to share data that provide context to LLMs, such as
|
||||
files, database schemas, or application-specific information. This tool searches for the
|
||||
resource URI in the provided extension, and reads in the resource content. If no extension
|
||||
is provided, the tool will search all extensions for the resource.
|
||||
"#}.to_string(),
|
||||
files, database schemas, or application-specific information. You must pass the
|
||||
owning extension as `extension_name`; if you don't know which extension owns a
|
||||
URI, call `list_resources` first — its output labels each resource with its
|
||||
extension.
|
||||
"#}
|
||||
.to_string(),
|
||||
Arc::new(
|
||||
serde_json::to_value(schema_for!(ReadResourceParams))
|
||||
.expect("Failed to serialize schema")
|
||||
.as_object()
|
||||
.expect("Schema must be an object")
|
||||
.clone()
|
||||
.clone(),
|
||||
),
|
||||
).annotate(ToolAnnotations::from_raw(
|
||||
)
|
||||
.annotate(ToolAnnotations::from_raw(
|
||||
Some("Read a resource".to_string()),
|
||||
Some(true),
|
||||
Some(false),
|
||||
|
||||
Reference in New Issue
Block a user