use crate::tools::{MVP_TOOL_CAPABILITIES, ToolCapability, ToolRuntime};
use serde_json::{Value, json};
pub(crate) const COMPACT_DIRECT_TOOLS: &[&str] = &[
"read",
"hash_edit",
"bash",
"grep",
"view_image",
"subagents",
"web",
"magi_control",
];
#[derive(Clone, Copy)]
pub(crate) enum ToolCatalogSurface {
DirectProviderFull,
DirectProviderCompact,
CodeModeInternal,
}
pub(crate) fn code_mode_available(runtime: &ToolRuntime) -> bool {
runtime.code_mode.enabled && !runtime.is_tool_disabled(super::TOOL_NAME)
}
pub(crate) fn effective_catalog(runtime: &ToolRuntime, surface: ToolCatalogSurface) -> Vec<Value> {
let internal_runtime;
let runtime = if matches!(surface, ToolCatalogSurface::CodeModeInternal) {
internal_runtime = runtime.for_code_mode();
&internal_runtime
} else {
runtime
};
let mut definitions: Vec<_> = MVP_TOOL_CAPABILITIES
.iter()
.copied()
.filter(|tool| !runtime.is_tool_disabled(tool.canonical_name()))
.filter(|tool| *tool != ToolCapability::Subagents || runtime.subagents_schema_enabled())
.map(ToolCapability::provider_definition_json)
.chain(
runtime
.dynamic_provider_tool_definitions()
.into_iter()
.filter(|definition| {
definition["name"].as_str().is_some_and(|name| {
name != super::TOOL_NAME
&& ToolCapability::from_dispatch_name(name).is_none()
&& !runtime.is_tool_disabled(name)
})
}),
)
.filter(|definition| match surface {
ToolCatalogSurface::DirectProviderFull => true,
ToolCatalogSurface::DirectProviderCompact => definition["name"]
.as_str()
.is_some_and(|name| COMPACT_DIRECT_TOOLS.contains(&name)),
ToolCatalogSurface::CodeModeInternal => definition["name"] != "magi_control",
})
.collect();
if matches!(surface, ToolCatalogSurface::CodeModeInternal) {
let mut schemas = runtime.dynamic_tool_output_schemas();
for definition in &mut definitions {
if let Some(schema) = definition["name"]
.as_str()
.and_then(|name| schemas.remove(name))
{
definition["output_schema"] = json!({"type":"object","properties":{
"success":{"type":"boolean"},"content":{"type":"object","properties":{
"content":{"type":"array","items":{"type":"object"}},
"structuredContent":{"anyOf":[schema,{"type":"null"}]},
"complete":{"type":"boolean"}
}}
},"required":["success"]});
}
}
}
if !matches!(surface, ToolCatalogSurface::CodeModeInternal) && code_mode_available(runtime) {
definitions.push(super::definition());
}
definitions
}
pub(crate) struct Catalog(pub(crate) Vec<Value>);
impl Catalog {
pub(crate) fn discover(&self, operation: &str, query: &str) -> Value {
let canonical = ToolCapability::from_dispatch_name(query)
.map(ToolCapability::canonical_name)
.unwrap_or(query);
match operation {
"describe" => self
.0
.iter()
.find(|entry| entry["name"] == canonical)
.map(|entry| {
let mut entry = entry.clone();
entry.as_object_mut().unwrap().remove("type");
if let Some(tool) = ToolCapability::from_dispatch_name(query) {
entry["output_schema"] = tool.output_schema();
}
entry
})
.unwrap_or(Value::Null),
_ => {
let words: Vec<_> = query.split_whitespace().map(str::to_lowercase).collect();
Value::Array(self.0.iter().filter(|entry| {
let text = format!("{} {}", entry["name"], entry["description"]).to_lowercase();
words.iter().all(|word| text.contains(word))
}).map(|entry| json!({"name": entry["name"], "description": entry["description"]})).collect())
}
}
}
pub(crate) fn canonical_name(&self, name: &str) -> Option<String> {
let canonical = ToolCapability::from_dispatch_name(name)
.map(ToolCapability::canonical_name)
.unwrap_or(name);
self.0
.iter()
.any(|entry| entry["name"] == canonical)
.then(|| canonical.to_owned())
}
}