update
This commit is contained in:
@@ -393,9 +393,140 @@ println(response.content)
|
|||||||
# => "[textContent(\"The weather in Tokyo is sunny, 22°C.\")]"
|
# => "[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
|
## Available Tools
|
||||||
|
|
||||||
| Tool | Description | Validation |
|
| Tool | Description | Validation |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `getWeather` | Fetch weather for a city | Default (JSON Schema required) |
|
| `getWeather` | Fetch weather for a city | Default (JSON Schema required) |
|
||||||
| `getTime` | Get current time for a timezone or city | Custom (cross-field + format) |
|
| `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) |
|
||||||
|
|||||||
+40
-11
@@ -1,12 +1,51 @@
|
|||||||
module toolRegistry
|
module toolRegistry
|
||||||
|
|
||||||
export loadTools, registerTool, getTools, listTools, clearTools
|
export loadTools, registerTool, getTools, clearTools
|
||||||
|
|
||||||
using ..type
|
using ..type
|
||||||
|
|
||||||
# Global registry — populated at runtime by loadTools() or registerTool()
|
# Global registry — populated at runtime by loadTools() or registerTool()
|
||||||
const _registry = Vector{agentTool}()
|
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.
|
Load all tool modules from a directory.
|
||||||
|
|
||||||
@@ -120,16 +159,6 @@ function getTools()::Vector{agentTool}
|
|||||||
return deepcopy(_registry)
|
return deepcopy(_registry)
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
|
||||||
List all registered tool names and labels.
|
|
||||||
|
|
||||||
# Returns
|
|
||||||
- `Vector{Tuple{String,String}}`: Pairs of (name, label)
|
|
||||||
"""
|
|
||||||
function listTools()::Vector{Tuple{String,String}}
|
|
||||||
return [(t.name, t.label) for t in _registry]
|
|
||||||
end
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Clear all registered tools from the global registry.
|
Clear all registered tools from the global registry.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -0,0 +1,269 @@
|
|||||||
|
"""
|
||||||
|
Tool that generates new Julia tool module files.
|
||||||
|
|
||||||
|
The agent can use this tool when it encounters a task that no existing tool
|
||||||
|
can handle. Provide the tool's name, label, description, inputSchema, and
|
||||||
|
execute logic as Julia code. The tool is written to `src/tools/<name>.jl`.
|
||||||
|
|
||||||
|
After calling this tool, restart the agent so the new tool is loaded by
|
||||||
|
`loadTools("src/tools")`. Then call `listTools` to verify the new tool
|
||||||
|
is available.
|
||||||
|
|
||||||
|
# Example
|
||||||
|
|
||||||
|
1. Agent calls writeTool with a spec for a "searchWine" tool
|
||||||
|
2. writeTool generates src/tools/searchWine.jl
|
||||||
|
3. Restart agent — loadTools() picks up the new file
|
||||||
|
4. Agent calls searchWine with args
|
||||||
|
|
||||||
|
# Important Notes
|
||||||
|
|
||||||
|
- The `executeCode` string is embedded literally into the generated tool.
|
||||||
|
Use `args["param_name"]` to access input parameters.
|
||||||
|
- The code string should be the function body (NOT wrapped in a function).
|
||||||
|
Lines will be indented with 4 spaces inside the execute function.
|
||||||
|
- Tool names must be valid Julia identifiers (lowercase letters, digits, underscores,
|
||||||
|
no leading digits or special characters).
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
Validate that a tool name is a valid Julia identifier.
|
||||||
|
"""
|
||||||
|
function validateToolName(name::String)::Union{Nothing,String}
|
||||||
|
if !occursin(r"^[a-zA-Z_][a-zA-Z0-9_!]*$", name)
|
||||||
|
return "Invalid tool name: '$name'. Tool names must be valid Julia identifiers (letters, digits, underscores, starting with a letter or underscore)."
|
||||||
|
end
|
||||||
|
return nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
Execute the writeTool.
|
||||||
|
|
||||||
|
Generates a new .jl tool file and registers it with the tool registry.
|
||||||
|
"""
|
||||||
|
function executeTool(toolCallId::String, args::Dict{String,Any}, signal::Union{Nothing,abortSignal}, onPartialResult::Function)::agentToolResult
|
||||||
|
tool_name = get(args, "name", "")::String
|
||||||
|
tool_label = get(args, "label", tool_name)::String
|
||||||
|
tool_description = get(args, "description", "")::String
|
||||||
|
tool_schema = get(args, "inputSchema", Dict{String,Any}())::Dict{String,Any}
|
||||||
|
execute_code = get(args, "executeCode", "")::String
|
||||||
|
validate_code = get(args, "validateCode", nothing)::Union{String,Nothing}
|
||||||
|
prepare_code = get(args, "prepareCode", nothing)::Union{String,Nothing}
|
||||||
|
parallel = get(args, "parallel", false)::Bool
|
||||||
|
|
||||||
|
# Validate tool name
|
||||||
|
name_err = validateToolName(tool_name)
|
||||||
|
if name_err !== nothing
|
||||||
|
return agentToolResult(
|
||||||
|
[textContent(name_err)],
|
||||||
|
Dict{Any,Any}(), nothing, false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Validate required fields
|
||||||
|
if isempty(tool_name)
|
||||||
|
return agentToolResult(
|
||||||
|
[textContent("Missing required field: 'name'")],
|
||||||
|
Dict{Any,Any}(), nothing, false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if isempty(tool_description)
|
||||||
|
return agentToolResult(
|
||||||
|
[textContent("Missing required field: 'description'")],
|
||||||
|
Dict{Any,Any}(), nothing, false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if isempty(execute_code)
|
||||||
|
return agentToolResult(
|
||||||
|
[textContent("Missing required field: 'executeCode'")],
|
||||||
|
Dict{Any,Any}(), nothing, false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
onPartialResult(Dict("status" => "Generating tool: $tool_name"))
|
||||||
|
|
||||||
|
# Build the tool file path
|
||||||
|
script_dir = dirname(@__FILE__)
|
||||||
|
tools_dir = dirname(script_dir)
|
||||||
|
filepath = joinpath(tools_dir, "$(tool_name).jl")
|
||||||
|
|
||||||
|
# Check for naming conflicts
|
||||||
|
if isfile(filepath)
|
||||||
|
return agentToolResult(
|
||||||
|
[textContent("Tool file already exists: $filepath. Rename the tool or delete the existing file first.")],
|
||||||
|
Dict{Any,Any}(), nothing, false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
onPartialResult(Dict("status" => "Writing file: $(basename(filepath))"))
|
||||||
|
|
||||||
|
# Convert schema Dict to a Julia Dict literal string
|
||||||
|
schema_literal = dict_to_julia_literal(tool_schema)
|
||||||
|
|
||||||
|
# Build optional validation function
|
||||||
|
validate_section = if validate_code !== nothing && !isempty(validate_code)
|
||||||
|
indented = indent_code(validate_code, 4)
|
||||||
|
"function validateRequiredArgs(args::Dict{String,Any})::Union{Nothing,String}\n$indented\n return nothing\nend\n"
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
|
# Build optional prepare function
|
||||||
|
prepare_section = if prepare_code !== nothing && !isempty(prepare_code)
|
||||||
|
indented = indent_code(prepare_code, 4)
|
||||||
|
"function prepareArguments(args::Dict{String,Any})::Dict{String,Any}\n$indented\n return args\nend\n"
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
|
# Indent user's execute code for embedding inside execute function body
|
||||||
|
indented_exec = indent_code(execute_code, 4)
|
||||||
|
|
||||||
|
# Escape description for Julia string literal
|
||||||
|
escaped_desc = replace(tool_description, "\\" => "\\\\")
|
||||||
|
escaped_desc = replace(escaped_desc, "\"" => "\\\"")
|
||||||
|
|
||||||
|
# Build the complete tool file content
|
||||||
|
parts = String[]
|
||||||
|
push!(parts, "# Auto-generated tool: $tool_name\n")
|
||||||
|
push!(parts, "# Generated by writeTool at $(now())\n\n")
|
||||||
|
if !isempty(validate_section)
|
||||||
|
push!(parts, validate_section)
|
||||||
|
push!(parts, "\n")
|
||||||
|
end
|
||||||
|
if !isempty(prepare_section)
|
||||||
|
push!(parts, prepare_section)
|
||||||
|
push!(parts, "\n")
|
||||||
|
end
|
||||||
|
push!(parts, "\n")
|
||||||
|
push!(parts, "# Execute function\n")
|
||||||
|
push!(parts, "function executeTool(toolCallId::String, args::Dict{String,Any}, signal::Union{Nothing,abortSignal}, onPartialResult::Function)::agentToolResult\n")
|
||||||
|
push!(parts, "$indented_exec\n")
|
||||||
|
push!(parts, "end\n\n")
|
||||||
|
push!(parts, "# Tool definition\n")
|
||||||
|
push!(parts, "function getTool()::agentTool\n")
|
||||||
|
push!(parts, " return agentTool(\n")
|
||||||
|
push!(parts, " name = \"$(tool_name)\",\n")
|
||||||
|
push!(parts, " label = \"$(tool_label)\",\n")
|
||||||
|
push!(parts, " description = \"$(escaped_desc)\",\n")
|
||||||
|
push!(parts, " inputSchema = $schema_literal,\n")
|
||||||
|
push!(parts, " execute = executeTool,\n")
|
||||||
|
if validate_code !== nothing && !isempty(validate_code)
|
||||||
|
push!(parts, " validateRequiredArgs = validateRequiredArgs,\n")
|
||||||
|
else
|
||||||
|
push!(parts, " validateRequiredArgs = nothing,\n")
|
||||||
|
end
|
||||||
|
if prepare_code !== nothing && !isempty(prepare_code)
|
||||||
|
push!(parts, " prepareArguments = prepareArguments,\n")
|
||||||
|
else
|
||||||
|
push!(parts, " prepareArguments = nothing,\n")
|
||||||
|
end
|
||||||
|
push!(parts, " parallelToolExecute = $parallel\n")
|
||||||
|
push!(parts, " )\n")
|
||||||
|
push!(parts, "end\n")
|
||||||
|
|
||||||
|
tool_code = join(parts)
|
||||||
|
|
||||||
|
# Write the file — tool is loaded on next agent restart via loadTools()
|
||||||
|
write(filepath, tool_code)
|
||||||
|
|
||||||
|
onPartialResult(Dict("status" => "Done"))
|
||||||
|
|
||||||
|
return agentToolResult(
|
||||||
|
[textContent("Tool '$(tool_name)' written to $filepath. Restart the agent so loadTools() picks it up, then call listTools to verify.")],
|
||||||
|
Dict{Any,Any}(
|
||||||
|
"file" => filepath,
|
||||||
|
"name" => tool_name,
|
||||||
|
"label" => tool_label,
|
||||||
|
"description" => tool_description,
|
||||||
|
),
|
||||||
|
nothing, false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
Indent a multi-line code string by the specified number of spaces.
|
||||||
|
"""
|
||||||
|
function indent_code(code::String, n::Int)::String
|
||||||
|
prefix = " "^n
|
||||||
|
lines = split(code, '\n')
|
||||||
|
result_lines = String[prefix * line for line in lines]
|
||||||
|
return join(result_lines, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
Convert a Julia Dict to a valid Julia Dict{String,Any}(...) literal string.
|
||||||
|
"""
|
||||||
|
function dict_to_julia_literal(d)::String
|
||||||
|
if d isa Dict
|
||||||
|
items = String[]
|
||||||
|
for (k, v) in d
|
||||||
|
key_str = json_string(k)
|
||||||
|
val_str = value_to_julia(v)
|
||||||
|
push!(items, "$key_str => $val_str")
|
||||||
|
end
|
||||||
|
return "Dict{String,Any}(" * join(items, ", ") * ")"
|
||||||
|
else
|
||||||
|
return value_to_julia(d)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function value_to_julia(v)::String
|
||||||
|
if v isa Dict
|
||||||
|
return dict_to_julia_literal(v)
|
||||||
|
elseif v isa Vector
|
||||||
|
items = [value_to_julia(x) for x in v]
|
||||||
|
return "[" * join(items, ", ") * "]"
|
||||||
|
elseif v isa String
|
||||||
|
escaped = replace(v, "\\" => "\\\\")
|
||||||
|
escaped = replace(escaped, "\"" => "\\\"")
|
||||||
|
return "\"$escaped\""
|
||||||
|
elseif v isa Number
|
||||||
|
return string(v)
|
||||||
|
elseif v isa Bool
|
||||||
|
return string(v)
|
||||||
|
elseif v === nothing
|
||||||
|
return "nothing"
|
||||||
|
else
|
||||||
|
return "\"$(v)\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
Convert any Julia value to a JSON string.
|
||||||
|
"""
|
||||||
|
function json_string(v)::String
|
||||||
|
return JSON.json(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
Define and return the writeTool agentTool.
|
||||||
|
"""
|
||||||
|
function getTool()::agentTool
|
||||||
|
return agentTool(
|
||||||
|
name = "writeTool",
|
||||||
|
label = "Create Tool",
|
||||||
|
description = "Generate a new Julia tool module file at src/tools/<name>.jl. After creation, restart the agent and call listTools to verify the new tool is loaded.",
|
||||||
|
inputSchema = Dict{String,Any}(
|
||||||
|
"type" => "object",
|
||||||
|
"properties" => Dict(
|
||||||
|
"name" => Dict("type" => "string", "description" => "Unique tool name (valid Julia identifier, no spaces or special chars)"),
|
||||||
|
"label" => Dict("type" => "string", "description" => "Human-readable tool name shown in tool descriptions"),
|
||||||
|
"description" => Dict("type" => "string", "description" => "What the tool does (shown to LLM for tool selection decisions)"),
|
||||||
|
"inputSchema" => Dict(
|
||||||
|
"type" => "object",
|
||||||
|
"description" => "JSON Schema describing tool parameters in MCP format"
|
||||||
|
),
|
||||||
|
"executeCode" => Dict("type" => "string", "description" => "Julia code for the execute function body. Use args[\"key\"] to access parameters. Do NOT wrap in a function definition."),
|
||||||
|
"validateCode" => Dict("type" => "string", "optional" => true, "description" => "Optional custom validation Julia code (runs before execute). Use args[\"key\"] to access parameters. Return nothing to pass, or a string error message to fail."),
|
||||||
|
"prepareCode" => Dict("type" => "string", "optional" => true, "description" => "Optional argument preparation code (runs before validation). Return modified args dict."),
|
||||||
|
"parallel" => Dict("type" => "boolean", "default" => false, "description" => "Whether this tool can run in parallel with other tools")
|
||||||
|
),
|
||||||
|
"required" => ["name", "label", "description", "inputSchema", "executeCode"]
|
||||||
|
),
|
||||||
|
execute = executeTool,
|
||||||
|
prepareArguments = nothing,
|
||||||
|
validateRequiredArgs = nothing,
|
||||||
|
parallelToolExecute = false
|
||||||
|
)
|
||||||
|
end
|
||||||
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
# Message types
|
# Message types
|
||||||
userMessage, assistantMessage, toolResultMessage,
|
userMessage, assistantMessage, toolResultMessage,
|
||||||
# Tool types
|
# Tool types
|
||||||
agentTool, validateRequiredArgs
|
agentTool, validateRequiredArgs
|
||||||
# Context types
|
# Context types
|
||||||
agentContext, agentState, agentToolCall, prepareNextTurnContext,
|
agentContext, agentState, agentToolCall, prepareNextTurnContext,
|
||||||
# Loop & execution types
|
# Loop & execution types
|
||||||
|
|||||||
Reference in New Issue
Block a user