harn-stdlib 0.8.39

Embedded Harn standard library source catalog
Documentation
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)
}