This commit is contained in:
2026-08-15 20:03:01 +07:00
parent 2543e6cbf1
commit fd616409dd
3 changed files with 62 additions and 151 deletions
+9 -75
View File
@@ -1,77 +1,11 @@
i am not sure that's the case. see my NATS message log: _processMessage 10
<NATS debug message> JSON.Object{String, Any}("finish_reason" => "stop", "index" => 0, "message" => JSON.Object{String, Any}("role" => "assistant", "content" => "The weather in Bangkok is currently Sunny with a temperature of 22°C.", "reasoning_content" => "The user is asking for the weather in Bangkok.\nI have already retrieved the weather information in the previous turn and provided it to the user.\nThe user's current input is \"What's the weather in Bangkok?\", which is the same question as before.\nI should provide the same answer again.\nNo new tool calls are needed.\nI will simply state the weather information retrieved previously.\nWeather in Bangkok: Sunny, 22°C.\nI will output the answer directly.\n"))
Info: debug _processMessage 11
payload = "new user msg" hasToolCalls: false
Info: debug toolCallList: YiemAgent.type.agentToolCall[]
payload = "new user msg" _processMessage 17
Info: debug _processMessage 18
payload = "new user msg"
Info: debug
payload = "new user msg"
Info: debug
payload = "new user msg"
Info: debug
payload = "new user msg"
Info: debug
payload = "new user msg"
Info: debug
payload = "_process_message 3"
Info: debug
payload = "_process_message 5"
Info: debug
payload = "_process_message 6"
Info: debug
payload = "_process_message 7"
</NATS debug message>
my NATS receiver report the following for a long time
Info: debug
payload = "new user msg"
untill I Ctrl + d so shutdown the process then i got the following report
Info: debug
payload = "_process_message 3"
Info: debug
payload = "_process_message 5"
Info: debug
payload = "_process_message 6"
Info: debug
payload = "_process_message 7"
my point is if _process_message() actually run then this code in _process_message()
"raw_msg = take!(agent.inputChannel)"
should take the new msg message out of agent.inputChannel and there should be only one debug message showing
Info: debug
payload = "new user msg"
before reaching error("debug marker")
---
here is my log. from the log, it seems like _processMessage() is finished but somehow the log didn't show _agentLoop 5 message. _processMessage() may not exit properly but why?
+53 -74
View File
@@ -169,62 +169,77 @@ julia> # Called automatically by yiemAgent constructor
function _agentLoop(agent::yiemAgent) function _agentLoop(agent::yiemAgent)
processMessageInputCh = Channel(32) processMessageInputCh = Channel(32)
try try
newUserMsg = nothing
processingTask = nothing processingTask = nothing
result = nothing
""" cases: """ cases:
1) agent -> idle, user msg -> nothing 1) agent -> idle, user msg -> nothing
typeof(processingTask) == Nothing typeof(processingTask) == Nothing
agent._state.activeRun -> false
agent.inputChannel -> nothing agent.inputChannel -> nothing
agent.followUpChannel -> nothing agent.followUpChannel -> nothing
2) agent -> idle, user msg -> new msg 2) agent -> idle, user msg -> new msg
typeof(processingTask) == Nothing typeof(processingTask) == Nothing
agent._state.activeRun -> false
agent.inputChannel -> new msg agent.inputChannel -> new msg
agent.followUpChannel -> nothing agent.followUpChannel -> nothing
3) agent -> running, user msg -> nothing 3) agent -> running, user msg -> nothing
typeof(processingTask) == Task, istaskdone(processingTask) -> false typeof(processingTask) == Task, istaskdone(processingTask) -> false
agent._state.activeRun -> true
agent.inputChannel -> nothing agent.inputChannel -> nothing
agent.followUpChannel -> nothing agent.followUpChannel -> nothing
4) agent -> running, user msg -> new msg 4) agent -> running, user msg -> new msg
typeof(processingTask) == Task, istaskdone(processingTask) -> false typeof(processingTask) == Task, istaskdone(processingTask) -> false
agent._state.activeRun -> true
agent.inputChannel -> new msg agent.inputChannel -> new msg
agent.followUpChannel -> nothing agent.followUpChannel -> nothing
5) agent -> running, user msg -> nothing, user msg follow up -> new msg 5) agent -> running, user msg -> nothing, user msg follow up -> new msg
typeof(processingTask) == Task, istaskdone(processingTask) -> false typeof(processingTask) == Task, istaskdone(processingTask) -> false
agent._state.activeRun -> true
agent.inputChannel -> nothing agent.inputChannel -> nothing
agent.followUpChannel -> new msg agent.followUpChannel -> new msg
6) agent -> idle, user msg -> nothing 6) agent -> idle, user msg -> nothing
typeof(processingTask) == Task, istaskdone(processingTask) -> true typeof(processingTask) == Task, istaskdone(processingTask) -> true
agent._state.activeRun -> false
agent.inputChannel -> nothing agent.inputChannel -> nothing
agent.followUpChannel -> nothing agent.followUpChannel -> nothing
""" """
while true while true
result = nothing while newUserMsg === nothing
msg = nothing
while msg === nothing
if isready(agent.inputChannel) if isready(agent.inputChannel)
agent.agentEventSink("_agentLoop 1")
# message will be taken in _processMessage() # agent process new user msg immediately after the current tool call finished.
msg = take!(agent.inputChannel) newUserMsg = take!(agent.inputChannel)
agent.agentEventSink("new user msg") agent.agentEventSink("new user msg")
else else
# check followUp message after _processMessage() is done
if typeof(processingTask) == Task && istaskdone(processingTask) == true
agent.agentEventSink("_agentLoop 2")
# if agent runs is done but followUpChannel has messages,
# put new message in inputChannel instead
if isready(agent.followUpChannel)
agent.agentEventSink("_agentLoop 3")
while isready(agent.followUpChannel)
followUpMsg = take!(agent.followUpChannel)
put!(agent.inputChannel, followUpMsg)
end
else # _processMessage() done and no followUp message.
agent.agentEventSink("_agentLoop 4")
result = fetch(processingTask)
put!(agent.outputChannel, result)
agent.agentEventSink(result.content[1].text)
processingTask = nothing # reset
newUserMsg = nothing # reset
result = nothing # reset
end
end
yield() yield()
end end
end end
# Check for shutdown signal # Check for shutdown signal
if msg === :shutdown if newUserMsg === :shutdown
# Drain all remaining messages in the input channel # Drain all remaining messages in the input channel
if isready(agent.inputChannel) if isready(agent.inputChannel)
while isready(agent.inputChannel) while isready(agent.inputChannel)
@@ -238,67 +253,31 @@ function _agentLoop(agent::yiemAgent)
end end
#TODO make sure every running tools ended properly #TODO make sure every running tools ended properly
newUserMsg = nothing # reset
break break
else else
agent.agentEventSink("_agentLoop push 1") # spawn new _processMessage() if it is not already running.
put!(processMessageInputCh, msg) if processingTask === nothing
agent.agentEventSink("_agentLoop push 2") agent.agentEventSink("_agentLoop 2")
end # Dispatch message through the processing pipeline
processingTask = @spawn _processMessage(
# start _processMessage loop processMessageInputCh,
if agent._state.activeRun == false agent.agentEventSink,
agent.agentEventSink("_agentLoop 2") agent._state.messages,
# Dispatch message through the processing pipeline agent._state.systemPrompt,
processingTask = @spawn _processMessage( agent._state.tools,
processMessageInputCh, agent.prepareContext,
agent.agentEventSink, agent.formatMsgForLLM,
agent._state.messages, agent.llmCall,
agent._state.systemPrompt, agent.beforeToolCall,
agent._state.tools, agent.afterToolCall,
agent.prepareContext, agent.parallelToolExecute,
agent.formatMsgForLLM, )
agent.llmCall,
agent.beforeToolCall,
agent.afterToolCall,
agent.parallelToolExecute,
)
agent._state.activeRun = true
agent.agentEventSink("_agentLoop 3")
end
# during agent runs, check followUp message after _processMessage() is done
if typeof(processingTask) == Task && istaskdone(processingTask) == false
agent.agentEventSink("_agentLoop 4")
# if followUp message available, add them all to agent.inputChannel
if isready(agent.followUpChannel)
agent.agentEventSink("_agentLoop 4-1")
while isready(agent.followUpChannel)
agent.agentEventSink("_agentLoop 4-2")
followMsg = take!(agent.followUpChannel)
put!(agent.inputChannel, followMsg)
end
end end
agent.agentEventSink("_agentLoop 4-3") put!(processMessageInputCh, newUserMsg)
continue # continue to process user message in the next loop newUserMsg = nothing # reset
elseif typeof(processingTask) == Task && istaskdone(processingTask) == true
agent.agentEventSink("_agentLoop 5")
# if agent runs is done but followUpChannel has messages, discard all message in it.
# when agent work is done it should not accept follow up msg.
# user should put new message in inputChannel instead
if isready(agent.followUpChannel)
while isready(agent.followUpChannel)
_ = take!(agent.followUpChannel)
end
end
result = fetch(processingTask)
put!(agent.outputChannel, result)
agent._state.activeRun = false # reset
processingTask = nothing # reset
end end
agent.agentEventSink("_agentLoop 6")
agent.agentEventSink(string(typeof(processingTask)))
agent.agentEventSink("_agentLoop 7")
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
@@ -368,17 +347,17 @@ function _processMessage(
# Drain inputChannel and convert OpenAI-format messages to userMessage type # Drain inputChannel and convert OpenAI-format messages to userMessage type
while isready(inputChannel) while isready(inputChannel)
agentEventSink("_processMessage 2") agentEventSink("_processMessage 2")
raw_msg = take!(inputChannel) newUserMsg_openai = take!(inputChannel)
agentEventSink("_processMessage 3") agentEventSink("_processMessage 3")
if raw_msg === :shutdown if newUserMsg_openai === :shutdown
agentEventSink("_processMessage 4") agentEventSink("_processMessage 4")
# Re-emit shutdown signal for the loop to handle # Re-emit shutdown signal for the loop to handle
put!(inputChannel, :shutdown) put!(inputChannel, :shutdown)
break break
end end
agentEventSink("_processMessage 5") agentEventSink("_processMessage 5")
user_msg = OpenAiToUserMessage(raw_msg) newUserMsg = OpenAiToUserMessage(newUserMsg_openai)
push!(agentMsgHistory, user_msg) push!(agentMsgHistory, newUserMsg)
agentEventSink("_processMessage 6") agentEventSink("_processMessage 6")
end end
agentEventSink("_processMessage 7") agentEventSink("_processMessage 7")
-2
View File
@@ -317,7 +317,6 @@ mutable struct agentState # Mutable runtime state of an agen
messages::Vector{agentMessage} messages::Vector{agentMessage}
pendingToolCalls::Vector{String} # Tool call IDs waiting for results pendingToolCalls::Vector{String} # Tool call IDs waiting for results
activeRun::Bool # is agent processing user message?
errorMessage::Union{String, Nothing} # Last error message errorMessage::Union{String, Nothing} # Last error message
end end
@@ -354,7 +353,6 @@ function agentState(
deepcopy(tools), deepcopy(tools),
deepcopy(messages), deepcopy(messages),
Vector{String}(), Vector{String}(),
false,
nothing, nothing,
) )
end end