From ed9126046835e0e5d9c4c3df5135040747a812ef Mon Sep 17 00:00:00 2001 From: narawat Date: Mon, 10 Aug 2026 20:37:28 +0700 Subject: [PATCH] update --- src/toolRegistry.jl | 46 ++++++++++++++++++++++----------------------- src/tools/README.md | 34 ++++++++++++++++----------------- src/type.jl | 6 +++--- test/toolTest.jl | 12 ++++++------ 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/toolRegistry.jl b/src/toolRegistry.jl index 8cf9a45..3d786b3 100644 --- a/src/toolRegistry.jl +++ b/src/toolRegistry.jl @@ -1,6 +1,6 @@ module toolRegistry -export ToolStore, loadTools, registerTool, getTools, clearTools, listTool +export toolStore, loadTools, registerTool, getTools, clearTools, listTool using Dates using JSON, DataStructures @@ -9,14 +9,14 @@ using ..type """ Per-agent isolated tool storage. -Each agent gets its own `ToolStore` so tool registration is independent — +Each agent gets its own `toolStore` so tool registration is independent — `registerTool(store, tool)` only affects that agent's tool set. # Fields - `tools::OrderedDict{String, agentTool}` — keyed by name for O(1) lookup + ordered iteration - `name::String` — identifier for debugging/logs """ -struct ToolStore +struct toolStore tools::OrderedDict{String, agentTool} name::String end @@ -29,14 +29,14 @@ Create a new isolated tool store. # Examples ```julia -store = ToolStore(name="agent1") +store = toolStore(name="agent1") tools = loadTools(store, "src/tools") registerTool(store, my_tool) agent = yiemAgent(tools=getTools(store), llmCall=..., _tool_store=store) ``` """ -function ToolStore(; name::String="default")::ToolStore - ToolStore(OrderedDict{String, agentTool}(), name) +function toolStore(; name::String="default")::toolStore + toolStore(OrderedDict{String, agentTool}(), name) end """ @@ -44,12 +44,12 @@ List tool definition — lets the agent query available tools for collision dete when creating new tools via writeTool. # Arguments -- `store::ToolStore`: The tool store to list from +- `store::toolStore`: The tool store to list from -Each `ToolStore` gets its own `listTool` instance bound to that store, +Each `toolStore` gets its own `listTool` instance bound to that store, so each agent sees only its own tools. """ -function listTool(store::ToolStore)::agentTool +function listTool(store::toolStore)::agentTool return agentTool( name = "listTools", label = "List Tools", @@ -80,7 +80,7 @@ function listTool(store::ToolStore)::agentTool end """ -Load all tool modules from a directory into a specific ToolStore. +Load all tool modules from a directory into a specific toolStore. Scans `dir` for `.jl` files. Each file must define a function named `getTool()::agentTool`. Files are sorted alphabetically so tool @@ -91,7 +91,7 @@ defined in the file (`validateRequiredArgs`, `prepareArguments`, `executeTool`, and any helper functions) are namespaced and never collide with other tools. # Arguments -- `store::ToolStore`: The tool store to register tools into +- `store::toolStore`: The tool store to register tools into - `dir::String`: Directory path to scan for `.jl` tool files # Returns @@ -102,7 +102,7 @@ and any helper functions) are namespaced and never collide with other tools. # Examples ```julia -julia> store = ToolStore(name="agent1") +julia> store = toolStore(name="agent1") julia> tools = loadTools(store, "src/tools") OrderedDict{String, agentTool} with 3 entries: "getWeather" => agentTool(...) @@ -110,7 +110,7 @@ OrderedDict{String, agentTool} with 3 entries: "listTools" => agentTool(...) ``` """ -function loadTools(store::ToolStore, dir::String)::OrderedDict{String, agentTool} +function loadTools(store::toolStore, dir::String)::OrderedDict{String, agentTool} if !isdir(dir) throw(ArgumentError("Tool directory does not exist: $dir")) end @@ -172,10 +172,10 @@ function loadTools(store::ToolStore, dir::String)::OrderedDict{String, agentTool end """ -Register a single agentTool into a specific ToolStore. +Register a single agentTool into a specific toolStore. # Arguments -- `store::ToolStore`: The tool store to register into +- `store::toolStore`: The tool store to register into - `tool::agentTool`: The tool to register # Returns @@ -183,25 +183,25 @@ Register a single agentTool into a specific ToolStore. # Examples ```julia -julia> store = ToolStore(name="agent1") +julia> store = toolStore(name="agent1") julia> registerTool(store, my_tool) [toolRegistry:agent1] Registered tool: my_tool ``` """ -function registerTool(store::ToolStore, tool::agentTool)::OrderedDict{String, agentTool} +function registerTool(store::toolStore, tool::agentTool)::OrderedDict{String, agentTool} store.tools[tool.name] = tool println("[$(store.name)] Registered tool: $(tool.name)") return store.tools end """ -Get the registered tools from a specific ToolStore. +Get the registered tools from a specific toolStore. Returns the internal `OrderedDict` directly — O(1) lookup by name, ordered iteration preserving registration order. # Arguments -- `store::ToolStore`: The tool store to query +- `store::toolStore`: The tool store to query # Returns - `OrderedDict{String, agentTool}`: Tools keyed by name, in registration order @@ -215,15 +215,15 @@ OrderedDict{String, agentTool} with 3 entries: "getTime" => agentTool(...) ``` """ -function getTools(store::ToolStore)::OrderedDict{String, agentTool} +function getTools(store::toolStore)::OrderedDict{String, agentTool} return store.tools end """ -Clear all registered tools from a specific ToolStore. +Clear all registered tools from a specific toolStore. # Arguments -- `store::ToolStore`: The tool store to clear +- `store::toolStore`: The tool store to clear # Returns - `nothing` @@ -234,7 +234,7 @@ julia> clearTools(store) [toolRegistry:agent1] Registry cleared ``` """ -function clearTools(store::ToolStore)::Nothing +function clearTools(store::toolStore)::Nothing empty!(store.tools) println("[$(store.name)] Registry cleared") return nothing diff --git a/src/tools/README.md b/src/tools/README.md index de6986f..f981e3c 100644 --- a/src/tools/README.md +++ b/src/tools/README.md @@ -52,12 +52,12 @@ result = tool.execute("call-1", Dict{String,Any}(), nothing, x->x) ### Step 2: Load — `loadTools()` -Load all tool modules from a directory into a `ToolStore`. Each `.jl` file must define `getTool()::agentTool`. +Load all tool modules from a directory into a `toolStore`. Each `.jl` file must define `getTool()::agentTool`. ```julia using YiemAgent, YiemAgent.toolRegistry -store = ToolStore(name="myAgent") +store = toolStore(name="myAgent") tools = loadTools(store, "src/tools") # Scans src/tools/ for .jl files, wraps each in a submodule, calls getTool(), registers in store.tools ``` @@ -84,8 +84,8 @@ Wire the loaded tools into a new `yiemAgent` instance. The `tools` parameter is ```julia using YiemAgent, YiemAgent.type, YiemAgent.toolRegistry -# 1. Set up ToolStore and load tools -store = ToolStore(name="myAgent") +# 1. Set up toolStore and load tools +store = toolStore(name="myAgent") loadTools(store, "src/tools") # 2. Create agent — pass tools + _tool_store @@ -102,7 +102,7 @@ agent = yiemAgent( **Manual registration** (without `loadTools`): ```julia -store = ToolStore(name="myAgent") +store = toolStore(name="myAgent") registerTool(store, getTime_tool) registerTool(store, getWeather_tool) @@ -124,7 +124,7 @@ agent = yiemAgent( | `messages` | `Vector{agentMessage}` | No (default: empty) | Initial conversation history | | `llmCall` | `Function` | **Yes** | `(messages::Dict) -> assistantMessage` — invokes the LLM | | `agentEventSink` | `Function` | **Yes** | `(event) -> nothing` — receives tool lifecycle events | -| `_tool_store` | `ToolStore` | No | Runtime tool registry for `registerTool()` | +| `_tool_store` | `toolStore` | No | Runtime tool registry for `registerTool()` | Optional hooks: `prepareContext`, `formatMsgForLLM`, `beforeToolCall`, `afterToolCall`, `sessionId`, `maxRetryDelayMs`, `parallelToolExecute`. @@ -278,12 +278,12 @@ The `terminate` flag is checked at the batch level. See [Section 10](#10-tool-ca **Source:** `toolRegistry.jl` -### How `ToolStore` Works +### How `toolStore` Works -The registry uses **per-agent isolated storage** via the `ToolStore` struct. Each agent gets its own store, so tool registration is independent — `registerTool(store, tool)` only affects that agent's tool set. +The registry uses **per-agent isolated storage** via the `toolStore` struct. Each agent gets its own store, so tool registration is independent — `registerTool(store, tool)` only affects that agent's tool set. ```julia -struct ToolStore +struct toolStore tools::OrderedDict{String, agentTool} # keyed by name for O(1) lookup + ordered iteration name::String # identifier for debugging/logs end @@ -294,7 +294,7 @@ end ### How `loadTools(store, dir)` Works ```julia -function loadTools(store::ToolStore, dir::String)::OrderedDict{String, agentTool} +function loadTools(store::toolStore, dir::String)::OrderedDict{String, agentTool} ``` **Source:** `toolRegistry.jl:113-172` @@ -325,8 +325,8 @@ Each tool file is loaded into its own **namespaced submodule**. This means: ```julia # Create per-agent stores -store1 = ToolStore(name="agent1") -store2 = ToolStore(name="agent2") +store1 = toolStore(name="agent1") +store2 = toolStore(name="agent2") # Load tools into specific stores tools1 = loadTools(store1, "src/tools/weather_tools") # agent1 only @@ -350,11 +350,11 @@ clearTools(store1) # only clears store1 ### Per-Agent Isolation -Each `ToolStore` is completely independent — tools registered in one store do not appear in another: +Each `toolStore` is completely independent — tools registered in one store do not appear in another: ```julia -storeA = ToolStore(name="A") -storeB = ToolStore(name="B") +storeA = toolStore(name="A") +storeB = toolStore(name="B") registerTool(storeA, getTime_tool) registerTool(storeB, getWeather_tool) @@ -382,7 +382,7 @@ yiemAgent struct contains: - inputChannel (Channel, capacity 16) ← user sends messages here via run_agent() - followUpChannel (Channel, capacity 32) ← user sends follow-ups here via follow_up() - outputChannel (Channel, capacity 16) ← agent sends responses here via take_response() - - _tool_store (ToolStore) ← per-agent isolated tool registry + - _tool_store (toolStore) ← per-agent isolated tool registry ``` ### Loop States @@ -1284,7 +1284,7 @@ The framework supports tools that modify the tool system itself at runtime. **Source:** `toolRegistry.jl:54-82` -Each `ToolStore` gets its own `listTool` instance bound to that store via `listTool(store)`, so each agent sees only its own tools. Primarily useful for **collision detection** before creating a new tool via `writeTool`. +Each `toolStore` gets its own `listTool` instance bound to that store via `listTool(store)`, so each agent sees only its own tools. Primarily useful for **collision detection** before creating a new tool via `writeTool`. ### Self-Tooling Workflow diff --git a/src/type.jl b/src/type.jl index 37b614f..f01b623 100644 --- a/src/type.jl +++ b/src/type.jl @@ -569,7 +569,7 @@ mutable struct yiemAgent <: agent # High-level agent wrapper maxRetryDelayMs::Union{Int64, Nothing} # Maximum delay between retries (ms) parallelToolExecute::Bool # Default: false agentEventSink::Function # agent emits its status via this function - _tool_store::Any # Reference to the ToolStore for runtime registration + _tool_store::Any # Reference to the toolStore for runtime registration end """ @@ -594,14 +594,14 @@ on `inputChannel` and `followUpChannel` channels concurrently. - `maxRetryDelayMs::Union{Int64, Nothing}`: Maximum delay between retries in milliseconds (default: `nothing`) - `parallelToolExecute::Bool`: Run tool calls in parallel (default: `false`) - `agentEventSink::Function`: Callback to receive agent events -- `tool_store::Union{Any, Nothing}`: ToolStore for runtime tool registration (default: `nothing`) +- `tool_store::Union{Any, Nothing}`: toolStore for runtime tool registration (default: `nothing`) # Returns - A new `yiemAgent` instance with an active background task # Examples ```julia -julia> store = ToolStore(name="agent1") +julia> store = toolStore(name="agent1") julia> tools = loadTools(store, "src/tools") julia> agent = yiemAgent(systemPrompt="You are a helpful assistant", model=my_model, tools=tools, llmCall=..., tool_store=store) yiemAgent(agentState(...), Channel(...), Channel(...), Channel(...), ..., store) diff --git a/test/toolTest.jl b/test/toolTest.jl index 8057cf1..69e59b3 100644 --- a/test/toolTest.jl +++ b/test/toolTest.jl @@ -6,12 +6,12 @@ using YiemAgent.type # Path to the real tools directory TOOLS_DIR = joinpath(@__DIR__, "..", "src", "tools") -@testset "loadTools with ToolStore" begin +@testset "loadTools with toolStore" begin # ------------------------------------------------------------------ # # 1. loadTools throws on non-existent directory # # ------------------------------------------------------------------ # - store = ToolStore(name="test1") + store = toolStore(name="test1") @test_throws ArgumentError loadTools(store, "/nonexistent/dir/that/does/not/exist") # ------------------------------------------------------------------ # @@ -26,7 +26,7 @@ TOOLS_DIR = joinpath(@__DIR__, "..", "src", "tools") # ------------------------------------------------------------------ # # 3. loadTools loads actual tool files from src/tools/ # # ------------------------------------------------------------------ # - store2 = ToolStore(name="test2") + store2 = toolStore(name="test2") loaded = loadTools(store2, TOOLS_DIR) @test !isempty(loaded) @test length(loaded) == 3 @@ -102,7 +102,7 @@ TOOLS_DIR = joinpath(@__DIR__, "..", "src", "tools") # ------------------------------------------------------------------ # # 7. getTools / registerTool / clearTools (per-store isolation) # # ------------------------------------------------------------------ # - store3 = ToolStore(name="test3") + store3 = toolStore(name="test3") registry_tools = getTools(store3) @test isempty(registry_tools) @@ -153,8 +153,8 @@ TOOLS_DIR = joinpath(@__DIR__, "..", "src", "tools") # ------------------------------------------------------------------ # # 9. Per-store isolation — two stores don't share tools # # ------------------------------------------------------------------ # - storeA = ToolStore(name="isolationA") - storeB = ToolStore(name="isolationB") + storeA = toolStore(name="isolationA") + storeB = toolStore(name="isolationB") registerTool(storeA, loaded["getTime"]) registerTool(storeB, loaded["getWeather"])