210 lines
4.3 KiB
Julia
210 lines
4.3 KiB
Julia
module agentCore
|
|
|
|
# export prompt
|
|
|
|
using JSON, DataStructures, Dates, UUIDs, HTTP, Random, PrettyPrinting, Serialization,
|
|
DataFrames, Serde
|
|
using GeneralUtils
|
|
using ..type, ..util, ..llmfunction
|
|
|
|
# ---------------------------------------------- 100 --------------------------------------------- #
|
|
|
|
"""
|
|
Private agent loop. Runs in a background `@spawn` task.
|
|
|
|
Waits on `inputChannel` and `followUpChannel`, processing whichever has a message first.
|
|
On each iteration, dispatches the message through `_process_message` and sends the result
|
|
to `outputChannel`. Exits on `:shutdown` signal.
|
|
|
|
# Arguments
|
|
- `agent::yiemAgent`: The agent whose loop to run
|
|
|
|
# Returns
|
|
- `nothing` — the loop runs until `:shutdown` is received or an error occurs
|
|
|
|
# Notes
|
|
- 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.
|
|
- Message priority: `inputChannel` messages are checked before `followUpChannel` messages.
|
|
|
|
# Examples
|
|
```jldoctest
|
|
julia> # Called automatically by yiemAgent constructor
|
|
```
|
|
"""
|
|
function _agent_loop(agent::yiemAgent)
|
|
try
|
|
while true
|
|
msg = nothing
|
|
while msg === nothing
|
|
if isready(agent.inputChannel) && agent._state.activeRun == false
|
|
# allow _process_message() to run
|
|
yield()
|
|
elseif isready(agent.inputChannel) && agent._state.activeRun == true
|
|
msg = fetch!(agent.inputChannel)
|
|
# Check for shutdown signal
|
|
if msg === :shutdown
|
|
msg = take!(agent.inputChannel)
|
|
end
|
|
else
|
|
error("undefined condition: isready(inputChannel)=$(isready(agent.inputChannel)), activeRun=$(agent._state.activeRun), msg=$msg")
|
|
end
|
|
end
|
|
|
|
# Check for shutdown signal
|
|
if msg === :shutdown
|
|
#TODO make sure every running tools ended properly
|
|
break
|
|
end
|
|
|
|
# make active
|
|
agent._state.activeRun = true
|
|
# Dispatch message through the processing pipeline
|
|
result = _process_message(agent, msg)
|
|
|
|
# check followUp message. if there are, add them all to agent.inputChannel
|
|
hasMore = isready(agent.followUpChannel)
|
|
while isready(agent.followUpChannel)
|
|
followMsg = take!(agent.followUpChannel)
|
|
put!(agent.inputChannel, followMsg)
|
|
hasMore = true
|
|
end
|
|
|
|
if !isready(agent.inputChannel) && !hasMore
|
|
# no more messages queued — safe to send response
|
|
put!(agent.outputChannel, result)
|
|
end
|
|
end
|
|
catch e
|
|
# On any error, send error response and exit the loop
|
|
@error "Agent loop failed" error=e
|
|
end
|
|
end
|
|
|
|
|
|
"""
|
|
Process a single message through the agent pipeline.
|
|
|
|
This is the core processing function where LLM calls, tool execution, and response generation
|
|
should be implemented. Currently a placeholder that echoes back the received message.
|
|
|
|
# Arguments
|
|
- `agent::yiemAgent`: The agent processing the message
|
|
- `msg`: The message to process (from `inputChannel` or `followUpChannel`)
|
|
|
|
# Returns
|
|
- An `assistantMessage` instance with the processed response
|
|
|
|
# Notes
|
|
- Implement the full processing pipeline:
|
|
1. Add `msg` to `agent._state.messages`
|
|
2. Call `agent.formatMsgForLLM(agent._state)` 1 to format for LLM
|
|
3. If `agent.preprocessMessages` is set, call it on the formatted messages
|
|
4. Call the LLM (blocking — the task waits here)
|
|
5. If agent has tools, handle tool calls in a loop
|
|
6. Build `assistantMessage` and return it
|
|
|
|
# Examples
|
|
```jldoctest
|
|
julia> # Currently returns a placeholder echo response
|
|
```
|
|
"""
|
|
function _process_message(agent::yiemAgent, msg)
|
|
# WORKING Replace with actual processing logic
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 2. Call agent.formatMsgForLLM(agent._state) to format for LLM
|
|
# 3. If preprocessMessages is set, call agent.preprocessMessages(...)
|
|
# 4. Call the LLM (blocking — the task waits here)
|
|
# 5. If agent has tools, handle tool calls in a loop
|
|
# 6. Build assistantMessage and return it
|
|
|
|
# Placeholder: echo back the message as a simple response
|
|
@warn "TODO: implement _process_message"
|
|
return assistantMessage(
|
|
role="assistant",
|
|
content=[textContent("Received: $(msg)")],
|
|
api="", model="", usage=nothing,
|
|
stopReason="end_turn",
|
|
errorMessage=nothing,
|
|
timestamp=now(),
|
|
)
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end # end of module |