This commit is contained in:
2026-08-21 13:13:38 +07:00
parent c59f6bfa61
commit da21790263
8 changed files with 276 additions and 323 deletions
+19 -19
View File
@@ -3,7 +3,7 @@ module utils
export clearhistory, availableWineToText, prepareContext, formatMsgForLLM, validateRequiredArgs,
validateToolArguments, _userMessageToOpenAI,
_assistantMessageToOpenAI, _toolResultMessageToOpenAI, _messageContentToBlocks, _toolsToOpenAI,
beforeToolCall, afterToolCall, agentEventSink
beforeToolCall, afterToolCall, eventSink
using UUIDs, Dates, DataStructures, HTTP, JSON, NATS
using GeneralUtils
@@ -109,7 +109,7 @@ prepareContext(state).messages == deepcopy(state.messages)
# end
```
"""
function prepareContext(state::agentState, agentEventSink, llmCall=nothing)::agentContext
function prepareContext(state::agentState, eventSink, llmCall=nothing)::agentContext
#TODO filter tools from state.tools based on user intend in user message and tool description
filteredTools = state.tools
@@ -156,7 +156,7 @@ formatMsgForLLm(ctx) == Dict("messages" => [
])
```
"""
function formatMsgForLLM(ctx::agentContext, agentEventSink)::Dict{String, Any}
function formatMsgForLLM(ctx::agentContext, eventSink)::Dict{String, Any}
""" openai message format example
msg = Dict(
@@ -208,7 +208,7 @@ function formatMsgForLLM(ctx::agentContext, agentEventSink)::Dict{String, Any}
openaiReadyMsg = Dict{String, Any}()
# openaiReadyMsg["model"] = "gemma-4-E4B-it-UD-Q4_K_XL"
messages = Vector{Dict{String, Any}}()
agentEventSink("formatMsgForLLM 1")
eventSink("formatMsgForLLM 1")
# System prompt as system message
if !isempty(ctx.systemPrompt)
push!(messages, Dict(
@@ -216,7 +216,7 @@ function formatMsgForLLM(ctx::agentContext, agentEventSink)::Dict{String, Any}
"content" => [Dict("type" => "text", "text" => ctx.systemPrompt)]
))
end
agentEventSink("formatMsgForLLM 2")
eventSink("formatMsgForLLM 2")
# Conversation messages
for msg in ctx.messages
if msg isa userMessage
@@ -229,10 +229,10 @@ function formatMsgForLLM(ctx::agentContext, agentEventSink)::Dict{String, Any}
push!(messages, _toolResultMessageToOpenAI(msg))
end
end
agentEventSink("formatMsgForLLM 3")
eventSink("formatMsgForLLM 3")
# Convert ctx.tools into OpenAI tools format
tools_array = _toolsToOpenAI(ctx.tools, agentEventSink)
agentEventSink("formatMsgForLLM 4")
tools_array = _toolsToOpenAI(ctx.tools, eventSink)
eventSink("formatMsgForLLM 4")
openaiReadyMsg["messages"] = messages
openaiReadyMsg["temperature"] = 0.7
@@ -321,7 +321,7 @@ end
#TODO
function agentEventSink(x)
function eventSink(x)
end
@@ -375,7 +375,7 @@ function _assistantMessageToolCallToOpenAI(msg::assistantMessageToolCall)::Dict{
)
end
"""
"""
Convert an assistantMessage to OpenAI message format.
"""
function _assistantMessageToOpenAI(msg::assistantMessage)::Dict{String, Any}
@@ -437,10 +437,10 @@ _toolsToOpenAI(nothing) # => Dict{String, Any}[]
_toolsToOpenAI(tools) # => [Dict("type" => "function", "function" => Dict("name" => "getWeather", ...))]
```
"""
function _toolsToOpenAI(tools::Union{OrderedDict{String, agentTool}, Nothing}, agentEventSink)::Vector{Dict{String, Any}}
function _toolsToOpenAI(tools::Union{OrderedDict{String, agentTool}, Nothing}, eventSink)::Vector{Dict{String, Any}}
tools_array = Vector{Dict{String, Any}}()
agentEventSink("_toolsToOpenAI 1")
agentEventSink(string(typeof(tools)))
eventSink("_toolsToOpenAI 1")
eventSink(string(typeof(tools)))
if tools !== nothing
for (_, tool) in tools
push!(tools_array, Dict(
@@ -453,13 +453,13 @@ function _toolsToOpenAI(tools::Union{OrderedDict{String, agentTool}, Nothing}, a
))
end
end
agentEventSink("_toolsToOpenAI 2")
eventSink("_toolsToOpenAI 2")
return tools_array
end
"""
validateRequiredArgs(args::Dict{String,Any}, inputSchema::Dict{String,Any}) -> Union{Nothing,String}
validateRequiredArgs(args::AbstractDict{String, Any}, inputSchema::AbstractDict{String, Any}) -> Union{Nothing,String}
Validates that all required fields listed in the tool's JSON Schema are present
in `args`. Returns `nothing` if validation passes, or a descriptive error string
@@ -470,8 +470,8 @@ with a custom validation function that performs additional checks (e.g. type
coercion, format validation, cross-field constraints).
# Arguments
- `args::Dict{String,Any}`: The arguments provided by the LLM
- `inputSchema::Dict{String,Any}`: The tool's `inputSchema` (JSON Schema format)
- `args::AbstractDict{String, Any}`: The arguments provided by the LLM
- `inputSchema::AbstractDict{String, Any}`: The tool's `inputSchema` (JSON Schema format)
# Returns
- `nothing` if all required args are present
@@ -487,7 +487,7 @@ args2 = Dict("city" => "Tokyo")
validateRequiredArgs(args2, schema) # => nothing
```
"""
function validateRequiredArgs(args::Dict{String,Any}, inputSchema::Dict{String,Any})::Union{Nothing,String}
function validateRequiredArgs(args::AbstractDict{String, Any}, inputSchema::AbstractDict{String, Any})::Union{Nothing,String}
required = get(inputSchema, "required", Any[])
if isempty(required)
return nothing
@@ -541,7 +541,7 @@ validateToolArguments(toolWithHook, tc) # => validated args or throws
validateToolArguments(toolDefault, tc) # => args or throws
```
"""
function validateToolArguments(tool::agentTool, prepared::agentToolCall)::Dict{String,Any}
function validateToolArguments(tool::agentTool, prepared::agentToolCall)::AbstractDict{String, Any}
# Use default (2-arg: args + schema) or tool-specific hook (1-arg: args only)
if isnothing(tool.validateRequiredArgs)
result = validateRequiredArgs(prepared.arguments, tool.inputSchema)