This commit is contained in:
2026-08-04 12:13:22 +07:00
parent 569f85333f
commit 937d52053f
3 changed files with 46 additions and 45 deletions
+25 -23
View File
@@ -12,9 +12,9 @@ using ..type, ..util, ..llmfunction
""" """
Private agent loop. Runs in a background `@spawn` task. Private agent loop. Runs in a background `@spawn` task.
Waits on `input_ch` and `followUpQueue`, processing whichever has a message first. Waits on `inputChannel` and `followUpChannel`, processing whichever has a message first.
On each iteration, dispatches the message through `_process_message` and sends the result On each iteration, dispatches the message through `_process_message` and sends the result
to `output_ch`. Exits on `:shutdown` signal. to `outputChannel`. Exits on `:shutdown` signal.
# Arguments # Arguments
- `agent::yiemAgent`: The agent whose loop to run - `agent::yiemAgent`: The agent whose loop to run
@@ -25,22 +25,26 @@ to `output_ch`. Exits on `:shutdown` signal.
# Notes # Notes
- This function is automatically spawned as a background task when a `yiemAgent` is created. - This function is automatically spawned as a background task when a `yiemAgent` is created.
- On any error, logs the error with `@error` and exits the loop. - On any error, logs the error with `@error` and exits the loop.
- Message priority: `input_ch` messages are checked before `followUpQueue` messages. - Message priority: `inputChannel` messages are checked before `followUpChannel` messages.
# Examples # Examples
```jldoctest ```jldoctest
julia> # Called automatically by yiemAgent constructor julia> # Called automatically by yiemAgent constructor
``` ```
""" """
function _agent_loop(agent::yiemAgent) #WORKING function _agent_loop(agent::yiemAgent)
try try
while true while true
# Wait on either channel — the one with a message fires first # Wait on either channel — the one with a message fires first
# Wait on either channel — the one with a message is taken first # Wait on either channel — the one with a message is taken first
msg = nothing msg = nothing
while msg === nothing while msg === nothing
if isready(agent.input_ch) if isready(agent.inputChannel)
msg = take!(agent.input_ch) msg = take!(agent.inputChannel)
#TODO convert raw user msg to userMessage type
#TODO add userMessage to agent._state.messages
else else
yield() yield()
end end
@@ -52,20 +56,19 @@ function _agent_loop(agent::yiemAgent) #WORKING
break break
end end
#TODO convert raw user msg to userMessage type # Dispatch message through the processing pipeline
#TODO add userMessage to agent._state.messages
if isready(agent.followUpQueue)
msg = take!(agent.followUpQueue)
end
# @spawn. Dispatch message through the processing pipeline.
result = _process_message(agent, msg) result = _process_message(agent, msg)
# Send response to user
put!(agent.output_ch, result)
# check followUp message. if there are, add them all to agent.inputChannel
# Send response to user if no user message in both agent.inputChannel and agent.followUpChannel,
# output the result
put!(agent.outputChannel, result)
end end
catch e catch e
# On any error, send error response and exit the loop # On any error, send error response and exit the loop
@@ -73,6 +76,7 @@ function _agent_loop(agent::yiemAgent) #WORKING
end end
end end
""" """
Process a single message through the agent pipeline. Process a single message through the agent pipeline.
@@ -81,7 +85,7 @@ should be implemented. Currently a placeholder that echoes back the received mes
# Arguments # Arguments
- `agent::yiemAgent`: The agent processing the message - `agent::yiemAgent`: The agent processing the message
- `msg`: The message to process (from `input_ch` or `followUpQueue`) - `msg`: The message to process (from `inputChannel` or `followUpChannel`)
# Returns # Returns
- An `assistantMessage` instance with the processed response - An `assistantMessage` instance with the processed response
@@ -102,14 +106,12 @@ julia> # Currently returns a placeholder echo response
""" """
function _process_message(agent::yiemAgent, msg) function _process_message(agent::yiemAgent, msg)
# WORKING Replace with actual processing logic # WORKING Replace with actual processing logic
# check steering message
while (# )
# 1. call agent.
# 2. Call agent.formatMsgForLLM(agent._state) to format for LLM # 2. Call agent.formatMsgForLLM(agent._state) to format for LLM
# 3. If preprocessMessages is set, call agent.preprocessMessages(...) # 3. If preprocessMessages is set, call agent.preprocessMessages(...)
# 4. Call the LLM (blocking — the task waits here) # 4. Call the LLM (blocking — the task waits here)
+10 -10
View File
@@ -15,7 +15,7 @@ using ..type, ..util, ..llmfunction
Send a message to the agent's input channel. Send a message to the agent's input channel.
Blocks if the input channel buffer is full (capacity 16 by default). Blocks if the input channel buffer is full (capacity 16 by default).
The agent processes messages from `input_ch` in the background task. The agent processes messages from `inputChannel` in the background task.
# Arguments # Arguments
- `agent::yiemAgent`: The agent instance to send a message to - `agent::yiemAgent`: The agent instance to send a message to
@@ -35,7 +35,7 @@ yiemAgent(...)
``` ```
""" """
function run_agent(agent::yiemAgent, msg) function run_agent(agent::yiemAgent, msg)
put!(agent.input_ch, msg) put!(agent.inputChannel, msg)
return agent return agent
end end
@@ -60,13 +60,13 @@ assistantMessage(...)
``` ```
""" """
function take_response(agent::yiemAgent) function take_response(agent::yiemAgent)
return take!(agent.output_ch) return take!(agent.outputChannel)
end end
""" """
Send a follow-up message while the agent is still processing. Send a follow-up message while the agent is still processing.
Follow-up messages are queued and processed after all `input_ch` messages Follow-up messages are queued and processed after all `inputChannel` messages
and before any tool call results are sent. and before any tool call results are sent.
# Arguments # Arguments
@@ -88,7 +88,7 @@ yiemAgent(...)
``` ```
""" """
function follow_up(agent::yiemAgent, msg) function follow_up(agent::yiemAgent, msg)
put!(agent.followUpQueue, msg) put!(agent.followUpChannel, msg)
return agent return agent
end end
@@ -96,7 +96,7 @@ end
Gracefully stop the agent. Gracefully stop the agent.
Sends a `:shutdown` signal to the input channel, waits for the background task to finish, Sends a `:shutdown` signal to the input channel, waits for the background task to finish,
then closes all channels (`input_ch`, `output_ch`, `followUpQueue`). then closes all channels (`inputChannel`, `outputChannel`, `followUpChannel`).
# Arguments # Arguments
- `agent::yiemAgent`: The agent instance to stop - `agent::yiemAgent`: The agent instance to stop
@@ -115,7 +115,7 @@ julia> stop_agent(agent)
``` ```
""" """
function stop_agent(agent::yiemAgent) function stop_agent(agent::yiemAgent)
put!(agent.input_ch, :shutdown) put!(agent.inputChannel, :shutdown)
try try
fetch(agent._task) fetch(agent._task)
catch e catch e
@@ -123,9 +123,9 @@ function stop_agent(agent::yiemAgent)
rethrow(e) rethrow(e)
end end
end end
close(agent.input_ch) close(agent.inputChannel)
close(agent.output_ch) close(agent.outputChannel)
close(agent.followUpQueue) close(agent.followUpChannel)
return nothing return nothing
end end
+11 -12
View File
@@ -353,18 +353,17 @@ docstring
mutable struct yiemAgent <: agent # High-level agent wrapper mutable struct yiemAgent <: agent # High-level agent wrapper
_state::agentState # Current state (prompt, model, messages, tools, etc.) _state::agentState # Current state (prompt, model, messages, tools, etc.)
input_ch::Channel # user sends prompt message to agent. inputChannel::Channel # user sends prompt message to agent.
# if agent is idle, it process user message right away. # if agent is idle, it process user message right away.
# if agent is running, it process user message after # if agent is running, it process user message after
# the current tool call finished. # the current tool call finished.
followUpQueue::Channel # Messages queued via follow_up() during agent is followUpChannel::Channel # Buffers messages the user sends while the agent is busy.
# running. After the agent loop process all input_ch # Processed after all inputChannel messages are handled
# and the agent isn't using tool call, it processes # and the agent is idle (not using a tool call).
# followUp messages
output_ch::Channel # agent sends response message to user after processing outputChannel::Channel # agent sends response message to user after processing
# all user messages in input_ch and all followUp messages. # all user messages in inputChannel and all followUp messages.
_task::Union{Task, Nothing} # Background task running the agent loop _task::Union{Task, Nothing} # Background task running the agent loop
@@ -383,7 +382,7 @@ end
Create a new yiemAgent instance with a background loop task. Create a new yiemAgent instance with a background loop task.
Spawns a background `@spawn` task that runs the agent loop, listening Spawns a background `@spawn` task that runs the agent loop, listening
on `input_ch` and `followUpQueue` channels concurrently. on `inputChannel` and `followUpChannel` channels concurrently.
# Keyword Arguments # Keyword Arguments
- `systemPrompt::String`: System prompt for the agent - `systemPrompt::String`: System prompt for the agent
@@ -425,16 +424,16 @@ function yiemAgent(
toolExecution=nothing, toolExecution=nothing,
) )
# Create channels: input (user -> agent), followUp (async queue), output (agent -> user) # Create channels: input (user -> agent), followUp (async queue), output (agent -> user)
input_ch = Channel(16) inputChannel = Channel(16)
followUp = Channel(32) followUp = Channel(32)
output_ch = Channel(16) outputChannel = Channel(16)
# Create struct with a placeholder task, then spawn and replace it # Create struct with a placeholder task, then spawn and replace it
agent = yiemAgent( agent = yiemAgent(
agentState(systemPrompt, model, tools, messages), agentState(systemPrompt, model, tools, messages),
input_ch, inputChannel,
followUp, followUp,
output_ch, outputChannel,
nothing, # placeholder — replaced below nothing, # placeholder — replaced below
formatMsgForLLM, formatMsgForLLM,
preprocessMessages, preprocessMessages,