This commit is contained in:
2026-08-12 23:47:10 +07:00
parent 77adeb3a6b
commit 90fb97a4e7
3 changed files with 81 additions and 41 deletions
+53 -20
View File
@@ -2,10 +2,10 @@ module utils
export clearhistory, availableWineToText, prepareContext, formatMsgForLLM, validateRequiredArgs,
validateToolArguments, _userMessageToOpenAI,
_assistantMessageToOpenAI, _toolResultMessageToOpenAI, _messageContentToBlocks,
_assistantMessageToOpenAI, _toolResultMessageToOpenAI, _messageContentToBlocks, _toolsToOpenAI,
beforeToolCall, afterToolCall, agentEventSink
using UUIDs, Dates, DataStructures, HTTP, JSON
using UUIDs, Dates, DataStructures, HTTP, JSON, NATS
using GeneralUtils
using ..type
@@ -75,7 +75,6 @@ function availableWineToText(vecd::Vector)::String
end
"""
prepareContext(state::agentState) -> agentContext
@@ -110,7 +109,7 @@ prepareContext(state).messages == deepcopy(state.messages)
# end
```
"""
function prepareContext(state::agentState)::agentContext
function prepareContext(state::agentState, agentEventSink)::agentContext
#TODO filter tools from state.tools based on user intend in user message and tool description
filteredTools = state.tools
@@ -157,7 +156,7 @@ formatMsgForLLm(ctx) == Dict("messages" => [
])
```
"""
function formatMsgForLLM(ctx::agentContext)::Dict{String, Any}
function formatMsgForLLM(ctx::agentContext, agentEventSink)::Dict{String, Any}
""" openai message format example
msg = Dict(
@@ -185,18 +184,12 @@ function formatMsgForLLM(ctx::agentContext)::Dict{String, Any}
Dict("type" => "text", "text" => "let me check."),
]
),
Dict(
"role" => "toolResult",
"content" => [
Dict("type" => "text", "text" => "name: Chateau Montelena ..."),
]
),
],
"tools"=> [
Dict(
"type" => "function",
"function" => Dict(
"name" => "get_weather",
"name" => "getWeather",
"description" => "Get current weather",
"parameters" => Dict(
"type" => "object",
@@ -212,8 +205,10 @@ function formatMsgForLLM(ctx::agentContext)::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")
# System prompt as system message
if !isempty(ctx.systemPrompt)
push!(messages, Dict(
@@ -221,7 +216,7 @@ function formatMsgForLLM(ctx::agentContext)::Dict{String, Any}
"content" => [Dict("type" => "text", "text" => ctx.systemPrompt)]
))
end
agentEventSink("formatMsgForLLM 2")
# Conversation messages
for msg in ctx.messages
if msg isa userMessage
@@ -232,14 +227,18 @@ function formatMsgForLLM(ctx::agentContext)::Dict{String, Any}
push!(messages, _toolResultMessageToOpenAI(msg))
end
end
agentEventSink("formatMsgForLLM 3")
# Convert ctx.tools into OpenAI tools format
tools_array = _toolsToOpenAI(ctx.tools, agentEventSink)
agentEventSink("formatMsgForLLM 4")
openaiReadyMsg["messages"] = messages
openaiReadyMsg["temperature"] = 0.7
#WORKING convert ctx.tools into openai's tools format.
# ctx.tools has the following format
# tools = OrderedDict{String, YiemAgent.type.agentTool}("getTime" => YiemAgent.type.agentTool("getTime", "Time Lookup", "Get current local time for a timezone or city.", Dict{String, Any}("properties" => Dict("city" => Dict("type" => "string", "description" => "City name as fallback"), "timezone" => Dict("type" => "string", "description" => "IANA timezone, e.g. 'America/New_York'")), "required" => Any[], "type" => "object"), YiemAgent.toolRegistry._tool_getTime.executeTool, nothing, YiemAgent.toolRegistry._tool_getTime.validateRequiredArgs, false), "getWeather" => YiemAgent.type.agentTool("getWeather", "Weather Lookup", "Fetch current weather and forecast for a given city.", Dict{String, Any}("properties" => Dict{String, Dict{String}}("units" => Dict{String, Any}("default" => "celsius", "type" => "string", "description" => "Temperature scale", "enum" => ["celsius", "fahrenheit"]), "city" => Dict("type" => "string", "description" => "City and country, e.g., 'San Francisco, CA' or 'Tokyo, Japan'")), "required" => ["city"], "type" => "object"), YiemAgent.toolRegistry._tool_getWeather.executeTool, nothing, nothing, false), "listTools" => YiemAgent.type.agentTool("listTools", "List Tools", "List all available tools with their names, labels, and descriptions. Use this before creating a new tool to check for name collisions.", Dict{String, Any}("properties" => Dict{String, Any}(), "required" => Any[], "type" => "object"), YiemAgent.toolRegistry.var"#listTool##0#listTool##1"{YiemAgent.toolRegistry.toolStore}(YiemAgent.toolRegistry.toolStore(OrderedDict{String, YiemAgent.type.agentTool}(#= circular reference @-4 =#), "myagent")), nothing, nothing, false))
if !isempty(tools_array)
openaiReadyMsg["tools"] = tools_array
end
return Dict("messages" => messages)
return openaiReadyMsg
end
#TODO
@@ -331,6 +330,40 @@ function _messageContentToBlocks(contents::Vector{messageContent})::Vector{Dict{
end
"""
_toolsToOpenAI(tools::Union{OrderedDict{String, agentTool}, Nothing}) -> Vector{Dict{String, Any}}
Convert an OrderedDict of agentTool definitions into OpenAI function tool format.
Returns an empty vector when `tools` is `nothing` or empty.
# Examples
```julia
_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}}
tools_array = Vector{Dict{String, Any}}()
agentEventSink("_toolsToOpenAI 1")
agentEventSink(string(typeof(tools)))
if tools !== nothing
for (_, tool) in tools
push!(tools_array, Dict(
"type" => "function",
"function" => Dict(
"name" => tool.name,
"description" => tool.description,
"parameters" => tool.inputSchema
)
))
end
end
agentEventSink("_toolsToOpenAI 2")
return tools_array
end
"""
validateRequiredArgs(args::Dict{String,Any}, inputSchema::Dict{String,Any}) -> Union{Nothing,String}