Tools
Tools let your agent interact with the outside world. NimbleAgents provides three ways to define tools.
The @tool Macro
The simplest way to create a tool:
@tool function add(x::Int, y::Int)
"Add two integers together."
x + y
endThis creates:
A Julia function
add(x, y)you can call directlyA
NimbleToolobjectadd_toolwith auto-generated JSON schema
The first string literal in the function body becomes the tool's description for the LLM. Parameter types are automatically mapped to JSON schema types.
Optional Parameters
@tool function search(query::String, limit::Int=10)
"Search for documents matching the query."
# ... implementation
endqueryis required (no default)limitis optional with default10
Return Direct
When a tool has return_direct=true, its result becomes the agent's final output immediately — the LLM does not process it further:
@tool return_direct=true function lookup_cache(key::String)
"Look up a cached value. Returns immediately if found."
cache[key]
endExample: FAQ bot with return_direct
# examples/tools/return_direct.jl
const FAQ = Dict(
"refund" => "Refunds are processed within 5–7 business days.",
"shipping" => "Standard shipping takes 3–5 business days. Express is 1–2.",
"password" => "Click 'Forgot password' on the login page to reset.",
)
@tool return_direct=true function lookup_faq(topic::String)
"Look up a frequently asked question by topic keyword."
get(FAQ, lowercase(topic), "No FAQ found for topic: $(topic)")
end
agent = Agent(
name = "SupportBot",
instructions = "You are a customer support assistant. Use lookup_faq for support topics.",
tools = [lookup_faq_tool],
)
# The tool result is returned directly — no LLM call to rephrase it
run!(agent, "How long do refunds take?")
# → "Refunds are processed within 5–7 business days."Run it with:
julia --project examples/tools/return_direct.jlBuilt-in Tools
NimbleAgents includes a library of built-in tools:
| Tool | Description |
|---|---|
read_file_tool | Read file contents |
write_file_tool | Write content to a file |
edit_file_tool | Replace a string in a file |
list_dir_tool | List directory contents |
glob_tool | Find files by glob pattern |
delete_file_tool | Delete a file |
grep_tool | Search file contents with regex |
find_files_tool | Find files by name pattern |
bash_tool | Execute shell commands |
http_get_tool | HTTP GET request |
http_post_tool | HTTP POST request |
eval_julia_tool | Evaluate Julia code in a persistent sandbox |
save_artifact_tool | Register a file as a session artifact |
agent = Agent(
name = "Coder",
instructions = "You help with coding tasks.",
tools = [read_file_tool, write_file_tool, bash_tool, eval_julia_tool],
)CLITool
Wrap shell commands as tools with typed arguments and placeholder substitution:
grep_cli = CLITool(
name = "grep_cli",
description = "Search for a pattern in files.",
command = ["grep", "-rn", "{pattern}", "{path}"],
args = [
"pattern" => CLIArg(String, "Regex pattern to search for"),
"path" => CLIArg(String, "Directory to search in"),
],
timeout = 10.0,
)The {placeholder} tokens in command are replaced with the LLM-provided argument values at runtime. The command is executed as a subprocess.
Example: Developer tools agent
# examples/tools/cli_tools_demo.jl
grep_tool = CLITool(
name = "grep",
description = "Search for a pattern in files or directories.",
command = ["grep", "-rn", "{pattern}", "{path}"],
args = [
"pattern" => CLIArg(String, "Regex pattern to search for."),
"path" => CLIArg(String, "File or directory path to search in."),
],
)
git_log_tool = CLITool(
name = "git_log",
description = "Show recent git commits as a compact one-line log.",
command = ["git", "log", "--oneline", "-{n}"],
args = ["n" => CLIArg(Int, "Number of recent commits to show.")],
)
agent = Agent(
name = "DevBot",
instructions = "You are a developer assistant with access to shell tools.",
tools = [grep_tool, git_log_tool],
)
run!(agent, "Search for all uses of 'CLITool' in the src/ directory.")
run!(agent, "Show me the last 5 git commits.")Run it with:
julia --project examples/tools/cli_tools_demo.jlCLITool Options
| Field | Type | Default | Description |
|---|---|---|---|
name | String | required | Tool name |
description | String | required | Description for the LLM |
command | Vector{String} | required | Command with {arg} placeholders |
args | Vector{Pair{String,CLIArg}} | required | Argument definitions |
timeout | Float64 | 30.0 | Subprocess timeout in seconds |
working_dir | String or nothing | nothing | Working directory |
return_direct | Bool | false | Short-circuit agent loop |
return_artifact | Bool | false | Register output as artifact |
CLIArg
CLIArg(type, description; required=true)type:String,Int,Float64, orBooldescription: Description shown to the LLMrequired: Whether the argument is mandatory (default:true)
Tool Dispatch
Under the hood, dispatch_tool routes LLM tool calls to the correct callable:
julia> using NimbleAgents
julia> @tool function add_dispatch(x::Int, y::Int)
"Add two integers."
x + y
end;
julia> tool_map = build_tool_map([add_dispatch_tool]);
julia> dispatch_tool(tool_map, "add_dispatch", Dict(:x => 10, :y => 32))
42
julia> tools_schema([add_dispatch_tool])[1]["function"]["name"]
"add_dispatch"A Note on Provider-Native Tools
Some LLM providers offer built-in server-side tools — for example, Google Search in Gemini, web search in Claude, or code interpreter in OpenAI. These are not standard function-calling tools; they require provider-specific API parameters and return results in different formats.
NimbleAgents currently supports standard function-calling tools for its built-in OpenAI and Gemini providers. Provider-native tools are not yet supported.
In the meantime, NimbleAgents includes built-in tools that cover similar ground:
| Provider-native tool | NimbleAgents equivalent |
|---|---|
| Gemini Google Search | search_web (via Tavily API) + fetch_webpage |
| Claude web search | search_web + fetch_webpage |
| OpenAI code interpreter | eval_julia_tool (persistent Julia sandbox) |
These work across all providers since they use standard function calling.