This commit is contained in:
2026-08-08 18:49:51 +07:00
parent 70296a3bf2
commit 03e1dd7628
4 changed files with 441 additions and 12 deletions
+131
View File
@@ -393,9 +393,140 @@ println(response.content)
# => "[textContent(\"The weather in Tokyo is sunny, 22°C.\")]"
```
## Self-Modifying Tools
The framework includes tools that allow the agent to create new tools at runtime.
### `writeTool` — Create New Tool Files
The `writeTool` tool generates a new Julia tool file at `src/tools/<name>.jl`. The agent writes the tool, then the agent (or system) restarts so `loadTools("src/tools")` picks it up.
**Workflow:**
1. Agent identifies a task that no existing tool can handle
2. Agent calls `writeTool` with a tool specification:
```julia
# Agent sends this to writeTool:
Dict(
"name" => "searchWine",
"label" => "Wine Search",
"description" => "Search a wine database by name, region, or variety",
"inputSchema" => Dict(
"type" => "object",
"properties" => Dict(
"query" => Dict("type" => "string", "description" => "Search query"),
"maxResults" => Dict("type" => "integer", "default" => 10)
),
"required" => ["query"]
),
"executeCode" => """
query = args["query"]
max_results = get(args, "maxResults", 10)
# Perform search logic here
result = "Found 3 wines matching: $query"
return agentToolResult([textContent(result)], Dict{Any,Any}(), nothing, false)
""",
"parallel" => false
)
```
3. Agent calls `listTools` to check for name collisions (built-in, auto-registered)
4. Agent calls `writeTool` with a unique name
5. Restart agent — `loadTools("src/tools")` picks up the new file
6. Agent's next LLM turn discovers and calls the new tool
**Generated file format:**
```julia
# Auto-generated tool: searchWine
# Generated by writeTool at 2026-08-08T14:00:00
function executeTool(toolCallId::String, args::Dict{String,Any}, signal::Union{Nothing,abortSignal}, onPartialResult::Function)::agentToolResult
query = args["query"]
max_results = get(args, "maxResults", 10)
result = "Found 3 wines matching: $query"
return agentToolResult([textContent(result)], Dict{Any,Any}(), nothing, false)
end
function getTool()::agentTool
return agentTool(
name = "searchWine",
label = "Wine Search",
description = "Search a wine database by name, region, or variety",
inputSchema = Dict{String,Any}(
"type" => "object",
"properties" => Dict(
"query" => Dict("type" => "string", "description" => "Search query"),
"maxResults" => Dict("type" => "integer", "default" => 10)
),
"required" => ["query"]
),
execute = executeTool,
validateRequiredArgs = nothing,
prepareArguments = nothing,
parallelToolExecute = false
)
end
```
**Optional hooks:**
| Field | Description |
|---|---|
| `validateCode` | Custom validation Julia code (runs before execute). Return `nothing` to pass, or an error `String` to fail. |
| `prepareCode` | Argument preparation code (runs before validation). Return modified args dict. |
### `listTools` — Discover Available Tools
Returns a list of all registered tools with names, labels, and descriptions.
```julia
# Result from listTools:
# Available tools:
# - getWeather: Weather Lookup — Fetch current weather and forecast for a given city.
# - getTime: Time Lookup — Get current local time for a timezone or city.
# - writeTool: Create Tool — Generate new tool files...
# - listTools: List Tools — List all available tools with their names and labels...
```
### Complete Self-Tooling Example
```
User: "I need to search for wines. Do you have a tool for that?"
# ─── LOOP: Agent realizes no wine search tool exists ─────────────────
[Tool Call] listTools()
# Result: lists all available tools — no collision with existing tools
[Tool Call] writeTool(name="searchWine", label="Wine Search",
description="Search a wine database by name, region, or variety",
inputSchema={...},
executeCode="query = args[\"query\"]\nresult = \"Found wines...\"\nreturn agentToolResult([textContent(result)], ...)")
# writeTool generates searchWine.jl
# ─── SYSTEM RESTARTS ─────────────────────────────────────────────────
# Agent restarts — loadTools("src/tools") picks up searchWine.jl
# searchWine is now available — agent uses it directly
# ─── Agent calls the new tool ─────────────────────────────────────────
[Tool Call] searchWine(query="cabernet", maxResults=5)
# Result: "Found 5 cabernet wines..."
# ─── Final response ──────────────────────────────────────────────────
"The search found 5 cabernet wines: ..."
```
## Available Tools
| Tool | Description | Validation |
|---|---|---|
| `getWeather` | Fetch weather for a city | Default (JSON Schema required) |
| `getTime` | Get current time for a timezone or city | Custom (cross-field + format) |
| `writeTool` | Create a new Julia tool module at runtime | Built-in (name + schema validation) |
| `listTools` | List all available tools with descriptions | None (no arguments) |