update
This commit is contained in:
+21
-17
@@ -19,6 +19,7 @@ mutable struct yiemAgent <: agent # High-level agent wrapper
|
|||||||
|
|
||||||
# user sends prompt message to agent. if agent is idle, it process user message right away.
|
# user sends prompt message to agent. if agent is idle, it process user message right away.
|
||||||
# if agent is running, it process user message after the current tool call finished.
|
# if agent is running, it process user message after the current tool call finished.
|
||||||
|
# Expect each message in OpenAI chat format
|
||||||
inputChannel::Channel
|
inputChannel::Channel
|
||||||
|
|
||||||
# Buffers messages the user sends while the agent is busy. Processed after all inputChannel
|
# Buffers messages the user sends while the agent is busy. Processed after all inputChannel
|
||||||
@@ -422,7 +423,7 @@ function _processMessage(
|
|||||||
response = JSON.Object{String, Any}("finish_reason" => "tool_calls", "index" => 0, "message" => JSON.Object{String, Any}("role" => "assistant", "content" => "", "reasoning_content" => "Here's a thinking process:\n\n1. **Identify User Request**: The user is asking for the weather in Bangkok.\n2. **Locate Relevant Tool**: I have a `getWeather` function available.\n3. **Check Function Parameters**:\n - `city` (required): City and country, e.g., 'San Francisco, CA' or 'Tokyo, Japan'\n - `units` (optional, default \"celsius\"): Temperature scale (\"celsius\" or \"fahrenheit\")\n4. **Prepare Parameters**:\n - `city`: \"Bangkok, Thailand\" (adding country for clarity, though just \"Bangkok\" might work, following the example format is safer)\n - `units`: Not specified, so I'll use the default (\"celsius\")\n5. **Execute Tool Call**: Call `getWeather` with `city: \"Bangkok, Thailand\"`\n6. **Anticipate Response**: The function will return current weather and forecast data for Bangkok. I'll then format it nicely for the user.\n - *Self-Correction/Verification during thought*: The prompt says \"city: City and country, e.g., 'San Francisco, CA' or 'Tokyo, Japan'\". I'll use \"Bangkok, Thailand\". The `units` parameter is optional, so I'll omit it to use the default.\n - Proceed with tool call.✅\n", "tool_calls" => Any[JSON.Object{String, Any}("type" => "function", "function" => JSON.Object{String, Any}("name" => "getWeather", "arguments" => "{\"city\":\"Bangkok, Thailand\"}"), "id" => "6fOilR5QPcdppbAAHluhkRyUDu3oWMAL")]))
|
response = JSON.Object{String, Any}("finish_reason" => "tool_calls", "index" => 0, "message" => JSON.Object{String, Any}("role" => "assistant", "content" => "", "reasoning_content" => "Here's a thinking process:\n\n1. **Identify User Request**: The user is asking for the weather in Bangkok.\n2. **Locate Relevant Tool**: I have a `getWeather` function available.\n3. **Check Function Parameters**:\n - `city` (required): City and country, e.g., 'San Francisco, CA' or 'Tokyo, Japan'\n - `units` (optional, default \"celsius\"): Temperature scale (\"celsius\" or \"fahrenheit\")\n4. **Prepare Parameters**:\n - `city`: \"Bangkok, Thailand\" (adding country for clarity, though just \"Bangkok\" might work, following the example format is safer)\n - `units`: Not specified, so I'll use the default (\"celsius\")\n5. **Execute Tool Call**: Call `getWeather` with `city: \"Bangkok, Thailand\"`\n6. **Anticipate Response**: The function will return current weather and forecast data for Bangkok. I'll then format it nicely for the user.\n - *Self-Correction/Verification during thought*: The prompt says \"city: City and country, e.g., 'San Francisco, CA' or 'Tokyo, Japan'\". I'll use \"Bangkok, Thailand\". The `units` parameter is optional, so I'll omit it to use the default.\n - Proceed with tool call.✅\n", "tool_calls" => Any[JSON.Object{String, Any}("type" => "function", "function" => JSON.Object{String, Any}("name" => "getWeather", "arguments" => "{\"city\":\"Bangkok, Thailand\"}"), "id" => "6fOilR5QPcdppbAAHluhkRyUDu3oWMAL")]))
|
||||||
"""
|
"""
|
||||||
response = llmCall(formattedMessages)
|
response = llmCall(formattedMessages)
|
||||||
eventSink("LLM response " * string(response); publish=false, log=true)
|
# eventSink("LLM response " * string(response); publish=false, log=true)
|
||||||
|
|
||||||
eventSink("_processMessage 11 _state.messages length $(length(agentMsgHistory))"; publish=false, log=true)
|
eventSink("_processMessage 11 _state.messages length $(length(agentMsgHistory))"; publish=false, log=true)
|
||||||
# Extract tool calls from LLM response content blocks
|
# Extract tool calls from LLM response content blocks
|
||||||
@@ -453,7 +454,7 @@ function _processMessage(
|
|||||||
|
|
||||||
# save toolResults to messages
|
# save toolResults to messages
|
||||||
for toolResult in toolResultBatch.messages
|
for toolResult in toolResultBatch.messages
|
||||||
eventSink("toolResult " * string(toolResult); publish=false, log=true)
|
# eventSink("toolResult " * string(toolResult); publish=false, log=true)
|
||||||
push!(agentMsgHistory, toolResult)
|
push!(agentMsgHistory, toolResult)
|
||||||
end
|
end
|
||||||
eventSink("_processMessage 14 _state.messages length $(length(agentMsgHistory))"; publish=false, log=true)
|
eventSink("_processMessage 14 _state.messages length $(length(agentMsgHistory))"; publish=false, log=true)
|
||||||
@@ -538,7 +539,7 @@ agentToolResult([textContent("text", "Tool not found")], Dict{Any,Any}())
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
function createErrorToolResult(msg::String)::agentToolResult
|
function createErrorToolResult(msg::String)::agentToolResult
|
||||||
return agentToolResult([textContent("text", msg)], dict{any,any}())
|
return agentToolResult([textContent("text", msg)], Dict{Any,Any}())
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -830,10 +831,10 @@ stopping the agent when other tools in the batch did not intend to terminate.
|
|||||||
julia> shouldTerminate(finalizedOutcome[])
|
julia> shouldTerminate(finalizedOutcome[])
|
||||||
false
|
false
|
||||||
|
|
||||||
julia> shouldTerminate([finalizedOutcome(tc, agentToolResult([], dict{any,any}(), dict{any,any}(), false), false) for _ in 1:2])
|
julia> shouldTerminate([finalizedOutcome(tc, agentToolResult([], Dict{Any,Any}(), Dict{Any,Any}(), false), false) for _ in 1:2])
|
||||||
false
|
false
|
||||||
|
|
||||||
julia> shouldTerminate([finalizedOutcome(tc, agentToolResult([], dict{any,any}(), dict{any,any}(), true), false) for _ in 1:2])
|
julia> shouldTerminate([finalizedOutcome(tc, agentToolResult([], Dict{Any,Any}(), Dict{Any,Any}(), true), false) for _ in 1:2])
|
||||||
true
|
true
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
@@ -972,7 +973,8 @@ function prepareToolCall(
|
|||||||
|
|
||||||
before = config.beforeToolCall(
|
before = config.beforeToolCall(
|
||||||
beforeToolCallContext(assistantMsg, toolCall, validatedArgs, context),
|
beforeToolCallContext(assistantMsg, toolCall, validatedArgs, context),
|
||||||
signal
|
signal,
|
||||||
|
eventSink
|
||||||
)
|
)
|
||||||
eventSink("prepareToolCall 7"; publish=false, log=true)
|
eventSink("prepareToolCall 7"; publish=false, log=true)
|
||||||
if signal.aborted
|
if signal.aborted
|
||||||
@@ -1034,7 +1036,7 @@ emitted after the result has already been captured.
|
|||||||
```julia
|
```julia
|
||||||
# Successful execution
|
# Successful execution
|
||||||
executePreparedToolCall(prep, nothing, emit)
|
executePreparedToolCall(prep, nothing, emit)
|
||||||
# => executedOutcome(agentToolResult([textContent("text", "Found 3 wines")], dict{any,any}(), dict{any,any}()), false)
|
# => executedOutcome(agentToolResult([textContent("text", "Found 3 wines")], Dict{Any,Any}(), Dict{Any,Any}()), false)
|
||||||
|
|
||||||
# Execution error
|
# Execution error
|
||||||
executePreparedToolCall(prep, nothing, emit)
|
executePreparedToolCall(prep, nothing, emit)
|
||||||
@@ -1049,8 +1051,11 @@ function executePreparedToolCall(
|
|||||||
)::executedOutcome
|
)::executedOutcome
|
||||||
eventSink("executePreparedToolCall 1"; publish=false, log=true)
|
eventSink("executePreparedToolCall 1"; publish=false, log=true)
|
||||||
|
|
||||||
try #WORKING pass sessionId from yiemAgent to tool call
|
try
|
||||||
|
|
||||||
result = prep.tool.execute(prep.toolCall.id, prep.args, signal, eventSink)
|
result = prep.tool.execute(prep.toolCall.id, prep.args, signal, eventSink)
|
||||||
|
|
||||||
|
|
||||||
eventSink("executePreparedToolCall 2"; publish=false, log=true)
|
eventSink("executePreparedToolCall 2"; publish=false, log=true)
|
||||||
eventSink("tool execute raw result: " * sprint(show, result); publish=false, log=true)
|
eventSink("tool execute raw result: " * sprint(show, result); publish=false, log=true)
|
||||||
eventSink("executePreparedToolCall 3"; publish=false, log=true)
|
eventSink("executePreparedToolCall 3"; publish=false, log=true)
|
||||||
@@ -1065,6 +1070,7 @@ function executePreparedToolCall(
|
|||||||
|
|
||||||
return executedOutcome(createErrorToolResult(sprint(showerror, e)), true)
|
return executedOutcome(createErrorToolResult(sprint(showerror, e)), true)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -1136,20 +1142,18 @@ function finalizeExecutedToolCall(
|
|||||||
eventSink("finalizeExecutedToolCall 1"; publish=false, log=true)
|
eventSink("finalizeExecutedToolCall 1"; publish=false, log=true)
|
||||||
result = executed.result
|
result = executed.result
|
||||||
isError = executed.isError
|
isError = executed.isError
|
||||||
eventSink("finalizeExecutedToolCall 2"; publish=false, log=true)
|
eventSink("finalizeExecutedToolCall result before afterToolCall\n$result"; publish=false, log=true)
|
||||||
if config.afterToolCall !== nothing
|
if config.afterToolCall !== nothing
|
||||||
try
|
try
|
||||||
after = config.afterToolCall(
|
after = config.afterToolCall(
|
||||||
afterToolCallContext(assistantMsg, prep.toolCall, prep.args, result, isError, context),
|
afterToolCallContext(assistantMsg, prep.toolCall, prep.args, result, isError, context),
|
||||||
signal
|
signal,
|
||||||
|
eventSink
|
||||||
)
|
)
|
||||||
eventSink("finalizeExecutedToolCall 3"; publish=false, log=true)
|
eventSink("finalizeExecutedToolCall 3"; publish=false, log=true)
|
||||||
if after !== nothing
|
if after !== nothing
|
||||||
result = merge(result, dict(:content=>get(after,:content,result.content),
|
result = after
|
||||||
:details=>get(after,:details,result.details),
|
isError = false
|
||||||
:usage=>get(after,:usage,result.usage),
|
|
||||||
:terminate=>get(after,:terminate,result.terminate)))
|
|
||||||
isError = get(after, :isError, isError)
|
|
||||||
end
|
end
|
||||||
catch e
|
catch e
|
||||||
bt = catch_backtrace()
|
bt = catch_backtrace()
|
||||||
@@ -1252,8 +1256,8 @@ function executeToolCallsSequential(
|
|||||||
eventSink("executeToolCallsSequential 3-2"; publish=false, log=true)
|
eventSink("executeToolCallsSequential 3-2"; publish=false, log=true)
|
||||||
end
|
end
|
||||||
eventSink("executeToolCallsSequential 4"; publish=false, log=true)
|
eventSink("executeToolCallsSequential 4"; publish=false, log=true)
|
||||||
eventSink("finalized $(finalized.toolCall.id), $(finalized.toolCall.name),
|
# eventSink("finalized $(finalized.toolCall.id), $(finalized.toolCall.name),
|
||||||
$(finalized.result), $(finalized.isError)"; publish=false, log=true)
|
# $(finalized.result), $(finalized.isError)"; publish=false, log=true)
|
||||||
push!(messages, createToolResultMessage(finalized))
|
push!(messages, createToolResultMessage(finalized))
|
||||||
push!(finalizedCalls, finalized)
|
push!(finalizedCalls, finalized)
|
||||||
eventSink("executeToolCallsSequential 5"; publish=false, log=true)
|
eventSink("executeToolCallsSequential 5"; publish=false, log=true)
|
||||||
|
|||||||
+4
-8
@@ -275,14 +275,10 @@ function beforeToolCall(context::beforeToolCallContext, signal::abortSignal)
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
function beforeToolCall(context::beforeToolCallContext, signal::abortSignal
|
function beforeToolCall(context::beforeToolCallContext, signal::abortSignal, eventSink
|
||||||
)::beforeToolCallResult
|
)::beforeToolCallResult
|
||||||
|
|
||||||
# final context check
|
eventSink("beforeToolCall: $(context.toolCall.name) args=$(context.args)")
|
||||||
|
|
||||||
# seek user approval via UI
|
|
||||||
|
|
||||||
# other check
|
|
||||||
|
|
||||||
return beforeToolCallResult(false, "N/A")
|
return beforeToolCallResult(false, "N/A")
|
||||||
end
|
end
|
||||||
@@ -311,10 +307,10 @@ Common use cases:
|
|||||||
terminate flag can all be overridden).
|
terminate flag can all be overridden).
|
||||||
|
|
||||||
""" #WORKING arrange result from searchWine tool
|
""" #WORKING arrange result from searchWine tool
|
||||||
function afterToolCall(context::afterToolCallContext, signal::abortSignal
|
function afterToolCall(context::afterToolCallContext, signal::abortSignal, eventSink
|
||||||
)::Union{agentToolResult, Nothing}
|
)::Union{agentToolResult, Nothing}
|
||||||
|
|
||||||
# modify context.result if needed and return agentToolResult
|
eventSink("afterToolCall: $(context.toolCall.name) result=$(context.result) error=$(context.isError)")
|
||||||
|
|
||||||
return nothing
|
return nothing
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user