feat: register plugin tool surfaces

This commit is contained in:
2026-06-16 01:18:54 +09:00
parent fcae886044
commit 05a9c52217
8 changed files with 660 additions and 59 deletions
+37 -1
View File
@@ -188,14 +188,19 @@ pub struct PluginPackageManifest {
pub runtime: Option<PluginRuntimeManifest>,
#[serde(default)]
pub hooks: Vec<PluginHookManifest>,
#[serde(default)]
pub tools: Vec<PluginToolManifest>,
}
impl PluginPackageManifest {
fn declared_surfaces(&self) -> BTreeSet<PluginSurface> {
pub fn declared_surfaces(&self) -> BTreeSet<PluginSurface> {
let mut surfaces: BTreeSet<_> = self.surfaces.iter().copied().collect();
if !self.hooks.is_empty() {
surfaces.insert(PluginSurface::Hook);
}
if !self.tools.is_empty() {
surfaces.insert(PluginSurface::Tool);
}
if self.runtime.is_some() {
surfaces.insert(PluginSurface::Wasm);
}
@@ -218,6 +223,14 @@ pub struct PluginHookManifest {
pub file: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PluginToolManifest {
pub name: String,
pub description: String,
pub input_schema: serde_json::Value,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PluginDiscoveryLimits {
pub max_packages_per_store: usize,
@@ -1653,6 +1666,29 @@ file = "hooks/summary.md"
);
}
#[test]
fn package_manifest_tool_surface_shape_is_accepted() {
let manifest: PluginPackageManifest = toml::from_str(
r#"
schema_version = 1
id = "example.tool"
name = "Example Tool"
version = "0.1.0"
[[tools]]
name = "ExampleTool"
description = "Runs a package-defined tool."
input_schema = { type = "object", properties = { query = { type = "string" } }, required = ["query"], additionalProperties = false }
"#,
)
.unwrap();
assert_eq!(manifest.tools.len(), 1);
assert!(manifest.declared_surfaces().contains(&PluginSurface::Tool));
assert_eq!(manifest.tools[0].name, "ExampleTool");
assert_eq!(manifest.tools[0].input_schema["type"], "object");
}
#[test]
fn malformed_manifest_multibyte_diagnostic_is_bounded_and_redacted() {
let temp = TempDir::new().unwrap();