Files
YiemAgent/src/tools/registry.jl
T
2026-08-09 06:27:48 +07:00

172 lines
5.0 KiB
Julia

module toolRegistry
export loadTools, registerTool, getTools, clearTools
using ..type
# Global registry — populated at runtime by loadTools() or registerTool()
const _registry = Vector{agentTool}()
# Auto-register the built-in listTools tool
function __init__()
registerTool(_listTool())
end
"""
List tool definition — lets the agent query available tools for collision detection
when creating new tools via writeTool.
"""
function _listTool()::agentTool
return agentTool(
name = "listTools",
label = "List Tools",
description = "List all available tools with their names, labels, and descriptions. Use this before creating a new tool to check for name collisions.",
inputSchema = Dict{String,Any}(
"type" => "object",
"properties" => Dict{String,Any}(),
"required" => Any[]
),
execute = (toolCallId, args, signal, onPartialResult) -> begin
tools = getTools()
if isempty(tools)
result_text = "No tools registered."
else
lines = String["- $(t.name): $(t.label)$(t.description)" for t in tools]
result_text = "Available tools:\n" * join(lines, "\n")
end
return agentToolResult(
[textContent(result_text)],
Dict{Any,Any}("count" => length(tools)),
nothing, false
)
end,
prepareArguments = nothing,
validateRequiredArgs = nothing,
parallelToolExecute = false
)
end
"""
Load all tool modules from a directory.
Scans `dir` for `.jl` files. Each file must define a function named
`getTool()::agentTool`. Files are sorted alphabetically so tool
registration order is deterministic.
# Tool file format
Each `.jl` file defines one function `getTool()` that returns an `agentTool`:
```julia
# src/tools/getWeather.jl
function getTool()::agentTool
return agentTool(
name = "getWeather",
label = "Weather Lookup",
description = "Fetch current weather and forecast for a given city.",
inputSchema = Dict{String,Any}(
"type" => "object",
"properties" => Dict(
"city" => Dict("type" => "string", "description" => "City and country"),
"units" => Dict("type" => "string", "enum" => ["celsius", "fahrenheit"], "default" => "celsius")
),
"required" => ["city"]
),
execute = (toolCallId, args, signal, onPartialResult) -> begin
city = args["city"]
return agentToolResult(
[textContent("Sunny, 22C in Bangkok")],
Dict{Any,Any}(), nothing, false
)
end,
prepareArguments = nothing,
parallelToolExecute = false
)
end
```
# Arguments
- `dir::String`: Directory path to scan for `.jl` tool files
# Returns
- `Vector{agentTool}`: All loaded tools
# Errors
- Throws `ArgumentError` if a tool file does not define a `getTool` function
"""
function loadTools(dir::String)::Vector{agentTool}
if !isdir(dir)
throw(ArgumentError("Tool directory does not exist: $dir"))
end
tools = agentTool[]
jl_files = filter(f -> endswith(f, ".jl"), readdir(dir))
sort!(jl_files)
for filename in jl_files
filepath = joinpath(dir, filename)
println("[toolRegistry] Loading tool from: $filepath")
# Include the file in the current module scope so all types resolve
# (agentTool, textContent, agentToolResult, etc. are all available)
include(filepath)
# Validate that getTool was defined (include() places it in current module scope)
if !isdefined(@__MODULE__, :getTool)
throw(ArgumentError(
"Tool file $(filepath) does not define a `getTool()` function. " *
"Each tool file must define: function getTool()::agentTool ... end"
))
end
# Call getTool() — it runs in current scope where types are visible
tool = getTool()
if !(tool isa agentTool)
throw(ArgumentError(
"getTool() in $(filepath) did not return an agentTool instance, got: $(typeof(tool))"
))
end
push!(_registry, tool)
push!(tools, tool)
println("[toolRegistry] Loaded tool: $(tool.name)$(tool.label)")
end
return tools
end
"""
Register a single agentTool into the global registry.
# Arguments
- `tool::agentTool`: The tool to register
# Returns
- `Vector{agentTool}`: Updated registry
"""
function registerTool(tool::agentTool)::Vector{agentTool}
push!(_registry, tool)
println("[toolRegistry] Registered tool: $(tool.name)")
return _registry
end
"""
Get all registered tools.
# Returns
- `Vector{agentTool}`: Copy of the registry
"""
function getTools()::Vector{agentTool}
return deepcopy(_registry)
end
"""
Clear all registered tools from the global registry.
"""
function clearTools()::Nothing
empty!(_registry)
println("[toolRegistry] Registry cleared")
return nothing
end
end # module