This commit is contained in:
2026-08-11 18:57:53 +07:00
parent bad14fbe7f
commit 83c7770877
6 changed files with 30 additions and 24 deletions
+2 -2
View File
@@ -6,7 +6,7 @@ Julia framework for building agents with tool use.
1. Install dependencies: `]add JSON, DataStructures, UUIDs, Dates, ...` 1. Install dependencies: `]add JSON, DataStructures, UUIDs, Dates, ...`
2. Create a `yiemAgent` with `loadTools("src/tools")` 2. Create a `yiemAgent` with `loadTools("src/tools")`
3. Call `run_agent(agent, "message")` then `take_response(agent)` 3. Call `runAgent(agent, "message")` then `takeResponse(agent)`
## Architecture ## Architecture
@@ -16,7 +16,7 @@ src/
├── type.jl # Core types (messages, tools, agent state) ├── type.jl # Core types (messages, tools, agent state)
├── utils.jl # Message formatting, validation ├── utils.jl # Message formatting, validation
├── agentCore.jl # Agent loop, tool execution pipeline ├── agentCore.jl # Agent loop, tool execution pipeline
├── api.jl # Public API (run_agent, take_response, etc.) ├── api.jl # Public API (runAgent, takeResponse, etc.)
└── tools/ └── tools/
├── registry.jl # Tool registry (loadTools, registerTool, listTools) ├── registry.jl # Tool registry (loadTools, registerTool, listTools)
├── getWeather.jl # Weather lookup tool ├── getWeather.jl # Weather lookup tool
+6 -6
View File
@@ -151,7 +151,7 @@ result = getTime_tool.execute("call-1", Dict("city" => "Tokyo"), sig, op)
**Via agent loop (production):** **Via agent loop (production):**
``` ```
user message → run_agent(agent, Dict("role"=>"user", "content"=>...)) user message → runAgent(agent, Dict("role"=>"user", "content"=>...))
→ _agent_loop detects message → @spawn _process_message(agent) → _agent_loop detects message → @spawn _process_message(agent)
→ prepareContext → formatMsgForLLM → llmCall → prepareContext → formatMsgForLLM → llmCall
→ LLM returns tool_calls → LLM returns tool_calls
@@ -382,9 +382,9 @@ The `_agent_loop()` function runs as a background `@spawn` task, created when `y
``` ```
yiemAgent struct contains: yiemAgent struct contains:
- inputChannel (Channel, capacity 16) ← user sends messages here via run_agent() - inputChannel (Channel, capacity 16) ← user sends messages here via runAgent()
- followUpChannel (Channel, capacity 32) ← user sends follow-ups here via follow_up() - followUpChannel (Channel, capacity 32) ← user sends follow-ups here via followUp()
- outputChannel (Channel, capacity 16) ← agent sends responses here via take_response() - outputChannel (Channel, capacity 16) ← agent sends responses here via takeResponse()
- _tool_store (toolStore) ← per-agent isolated tool registry - _tool_store (toolStore) ← per-agent isolated tool registry
``` ```
@@ -1327,7 +1327,7 @@ Each `toolStore` gets its own `listTool` instance bound to that store via `listT
``` ```
USER SENDS MESSAGE USER SENDS MESSAGE
└─> run_agent(agent, "What's the weather in Tokyo?") └─> runAgent(agent, "What's the weather in Tokyo?")
└─> put!(agent.inputChannel, Dict("role" => "user", "content" => [...])) └─> put!(agent.inputChannel, Dict("role" => "user", "content" => [...]))
@@ -1430,7 +1430,7 @@ LOOP ITERATION 2 — LLM RETURNS FINAL TEXT RESPONSE
AGENT LOOP: SEND RESPONSE TO USER AGENT LOOP: SEND RESPONSE TO USER
└─> put!(agent.outputChannel, final_response) └─> put!(agent.outputChannel, final_response)
└─> take_response(agent) → assistantMessage("The weather in Tokyo is sunny, 22°C.") └─> takeResponse(agent) → assistantMessage("The weather in Tokyo is sunny, 22°C.")
``` ```
--- ---
+1 -1
View File
@@ -99,7 +99,7 @@ function yiemAgent(
sessionId::Union{String, Nothing}=nothing, sessionId::Union{String, Nothing}=nothing,
maxRetryDelayMs::Union{Int64, Nothing}=nothing, maxRetryDelayMs::Union{Int64, Nothing}=nothing,
parallelToolExecute::Bool=false, parallelToolExecute::Bool=false,
agentEventSink::Function, #WORKING agentEventSink::Function=agentEventSink, #WORKING
) )
# Create channels: input (user -> agent), followUp (async queue), output (agent -> user) # Create channels: input (user -> agent), followUp (async queue), output (agent -> user)
inputChannel = Channel(16) inputChannel = Channel(16)
+13 -13
View File
@@ -24,16 +24,16 @@ The agent processes messages from `inputChannel` in the background task.
- The same `agent` instance for chaining - The same `agent` instance for chaining
# Notes # Notes
- Use `take_response(agent)` to receive the agent's response after sending a message. - Use `takeResponse(agent)` to receive the agent's response after sending a message.
- Use `follow_up(agent, msg)` to send messages while the agent is still processing. - Use `followUp(agent, msg)` to send messages while the agent is still processing.
# Examples # Examples
```jldoctest ```jldoctest
julia> run_agent(agent, "Hello!") julia> runAgent(agent, "Hello!")
yiemAgent(...) yiemAgent(...)
``` ```
""" """
function run_agent(agent::yiemAgent, msg) function runAgent(agent::yiemAgent, msg)
put!(agent.inputChannel, msg) put!(agent.inputChannel, msg)
return agent return agent
end end
@@ -50,15 +50,15 @@ Blocks until the agent sends a response.
- An `assistantMessage` instance representing the agent's response - An `assistantMessage` instance representing the agent's response
# Notes # Notes
- Use `run_agent(agent, msg)` to send a message before calling this function. - Use `runAgent(agent, msg)` to send a message before calling this function.
# Examples # Examples
```jldoctest ```jldoctest
julia> response = take_response(agent) julia> response = takeResponse(agent)
assistantMessage(...) assistantMessage(...)
``` ```
""" """
function take_response(agent::yiemAgent) function takeResponse(agent::yiemAgent)
return take!(agent.outputChannel) return take!(agent.outputChannel)
end end
@@ -76,17 +76,17 @@ and before any tool call results are sent.
- The same `agent` instance for chaining - The same `agent` instance for chaining
# Notes # Notes
- Use `run_agent(agent, msg)` for the primary message and `follow_up(agent, msg)` for additional - Use `runAgent(agent, msg)` for the primary message and `followUp(agent, msg)` for additional
messages while the agent is processing. messages while the agent is processing.
- Follow-up messages are buffered in a separate channel (capacity 32 by default). - Follow-up messages are buffered in a separate channel (capacity 32 by default).
# Examples # Examples
```jldoctest ```jldoctest
julia> follow_up(agent, "Also consider red wines") julia> followUp(agent, "Also consider red wines")
yiemAgent(...) yiemAgent(...)
``` ```
""" """
function follow_up(agent::yiemAgent, msg) function followUp(agent::yiemAgent, msg)
put!(agent.followUpChannel, msg) put!(agent.followUpChannel, msg)
return agent return agent
end end
@@ -104,16 +104,16 @@ then closes all channels (`inputChannel`, `outputChannel`, `followUpChannel`).
- `nothing` - `nothing`
# Notes # Notes
- After calling `stop_agent`, the agent is no longer usable. A new agent must be created - After calling `stopAgent`, the agent is no longer usable. A new agent must be created
for further interaction. for further interaction.
- If the background task throws a `TaskFailedException`, it is rethrown. - If the background task throws a `TaskFailedException`, it is rethrown.
# Examples # Examples
```jldoctest ```jldoctest
julia> stop_agent(agent) julia> stopAgent(agent)
``` ```
""" """
function stop_agent(agent::yiemAgent) function stopAgent(agent::yiemAgent)
put!(agent.inputChannel, :shutdown) put!(agent.inputChannel, :shutdown)
try try
fetch(agent._agent_loop) fetch(agent._agent_loop)
+1 -1
View File
@@ -23,7 +23,7 @@
preparedToolCall, immediateOutcome, executedOutcome, finalizedOutcome, preparedToolCall, immediateOutcome, executedOutcome, finalizedOutcome,
agentToolCallBatch, agentToolCallBatch,
# Functions (defined elsewhere) # Functions (defined elsewhere)
run_agent, take_response, follow_up, stop_agent runAgent, takeResponse, followUp, stopAgent
using Dates, UUIDs, DataStructures, JSON, NATS, Base.Threads using Dates, UUIDs, DataStructures, JSON, NATS, Base.Threads
+7 -1
View File
@@ -3,7 +3,7 @@ module utils
export clearhistory, availableWineToText, prepareContext, formatMsgForLLM, validateRequiredArgs, export clearhistory, availableWineToText, prepareContext, formatMsgForLLM, validateRequiredArgs,
validateToolArguments, _userMessageToOpenAI, validateToolArguments, _userMessageToOpenAI,
_assistantMessageToOpenAI, _toolResultMessageToOpenAI, _messageContentToBlocks, _assistantMessageToOpenAI, _toolResultMessageToOpenAI, _messageContentToBlocks,
beforeToolCall, afterToolCall beforeToolCall, afterToolCall, agentEventSink
using UUIDs, Dates, DataStructures, HTTP, JSON using UUIDs, Dates, DataStructures, HTTP, JSON
using GeneralUtils using GeneralUtils
@@ -243,6 +243,12 @@ function afterToolCall(context::beforeToolCallContext, signal::abortSignal
end end
#TODO
function agentEventSink()
end
""" """
Convert a userMessage to OpenAI message format. Convert a userMessage to OpenAI message format.
""" """