type ToolRegistry = {_type: "tool_registry", tools: list<dict>}
type ToolDefinitionConfig = {
parameters?: dict,
returns?: dict,
output_schema?: dict,
handler?: any,
executor?: string,
host_capability?: string,
mcp_server?: string,
defer_loading?: bool,
namespace?: string,
annotations?: dict,
}
type ToolDefinitionSpec = {
name: string,
description?: string,
desc?: string,
config?: ToolDefinitionConfig,
parameters?: dict,
returns?: dict,
output_schema?: dict,
handler?: any,
executor?: string,
host_capability?: string,
mcp_server?: string,
defer_loading?: bool,
namespace?: string,
annotations?: dict,
}
type PathScopeMatcherOptions = {
scope?: string,
arg_keys?: list<string>,
mount_modes?: list<string>,
on_violation?: string,
patterns?: list<string>,
}?
/**
* path_scope returns a dynamic-permissions matcher that checks path args
* against the active session workspace anchor.
*
* @effects: []
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: path_scope({mount_modes: ["extend"]})
*/
pub fn path_scope(options: PathScopeMatcherOptions = nil) -> dict {
let opts = options ?? {}
var matcher = {
type: "path_scope",
scope: opts?.scope ?? "anchor_plus_mounted",
arg_keys: opts?.arg_keys ?? ["path", "destination", "source", "file"],
on_violation: opts?.on_violation ?? "deny",
}
if opts?.mount_modes != nil {
matcher = matcher + {mount_modes: opts.mount_modes}
}
if opts?.patterns != nil {
matcher = matcher + {patterns: opts.patterns}
}
return matcher
}
fn __tool_spec_config(spec: ToolDefinitionSpec) -> ToolDefinitionConfig {
if type_of(spec) != "dict" {
throw "tool_define_many: each spec must be a dict"
}
var config = spec.config ?? {}
for key in spec.keys() {
if !contains(["name", "description", "desc", "config"], key) {
config = config + {[key]: spec[key]}
}
}
return config
}
/**
* tool_define_many adds a list of tool specs to a registry.
*
* @effects: []
* @allocation: heap
* @errors: []
* @api_stability: stable
* @example: tool_define_many(registry, specs)
*/
pub fn tool_define_many(registry, specs: list<ToolDefinitionSpec>? = nil) -> ToolRegistry {
var target = registry
var items = specs
if items == nil {
target = tool_registry()
items = registry
}
if type_of(items) != "list" {
throw "tool_define_many: specs must be a list"
}
var tools = target ?? tool_registry()
for spec in items {
let name = spec.name
let description = spec.description ?? spec.desc
if name == nil || name == "" {
throw "tool_define_many: each spec needs a non-empty name"
}
if description == nil || description == "" {
throw "tool_define_many: each spec needs a non-empty description"
}
tools = tool_define(tools, name, description, __tool_spec_config(spec))
}
return tools
}
/**
* tool_registry_from creates a registry from a list of tool specs.
*
* @effects: []
* @allocation: heap
* @errors: []
* @api_stability: stable
* @example: tool_registry_from(specs)
*/
pub fn tool_registry_from(specs: list<ToolDefinitionSpec>) -> ToolRegistry {
return tool_define_many(tool_registry(), specs)
}