From 8a4e882dc1ad5eb9b32c0cf2b8307068cbccd560 Mon Sep 17 00:00:00 2001 From: narawat Date: Tue, 30 Jun 2026 22:02:17 +0700 Subject: [PATCH] add new func() --- Project.toml | 2 +- src/interface.jl | 49 +------------------- src/llmUtil.jl | 115 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 116 insertions(+), 50 deletions(-) diff --git a/Project.toml b/Project.toml index 45c05ba..dec26a3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "GeneralUtils" uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe" -version = "0.4.3" +version = "0.4.4" authors = ["tonaerospace "] [deps] diff --git a/src/interface.jl b/src/interface.jl index 8ff94b9..54359ff 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -6,8 +6,7 @@ export noNegative!, randomWithProb, randomChoiceWithProb, findIndex, limitvalue, matMul_3Dto4D_batchwise, isNotEqual, linearToCartesian, vectorMax, findMax, multiply_last, multiplyRandomElements, replaceElements, replaceElements!, isBetween, isLess, allTrue, getStringBetweenCharacters, mkDictPath!, dict_to_string_html, - getDictPath, detectKeywordVariation, textToDict, dictify, ordereddictify, - clean_json_response + getDictPath, detectKeywordVariation, textToDict, dictify, ordereddictify using JSON, DataStructures, Distributions, Random, Dates, UUIDs, DataFrames, CSV using ..util, ..communication @@ -1697,52 +1696,6 @@ function dict_to_string_html(d::AbstractDict; indent_level=1, indent_str=" ") return join(lines, "\n") end -""" Convert a plain text string containing key-value pairs into a JSON-formatted string. - -This function takes text containing key-value pairs (typically extracted from LLM responses) -and wraps them in proper JSON braces to create a valid JSON string. It cleans the input -by removing common formatting artifacts like braces, code block markers, and language -specifiers before wrapping the content. - -# Arguments -- `text::String` - A string containing key-value pairs, typically in the format `key: value, key: value`. - May contain leading/trailing braces, code block markers (```), or language specifiers - (e.g., `json`) that will be removed. - -# Return -- `String` - A JSON-formatted string with the key-value pairs wrapped in `{}` braces. - -# Notes -- The function removes `{`, `}`, `````, and `json` from the input before wrapping. -- The output is always wrapped in curly braces to create valid JSON structure. -- This is typically used to sanitize LLM responses that contain key-value data - but may include formatting artifacts. - -# Examples -```jldoctest -julia> text = "thought: Hello, action: CHATBOX, input: How can I help?" -julia> clean_json_response(text) -"{thought: Hello, action: CHATBOX, input: How can I help?}" - -julia> text = "{thought: Hello, action: CHATBOX}" -julia> clean_json_response(text) -"{thought: Hello, action: CHATBOX}" - -julia> text = "```json{thought: Hello, action: CHATBOX}```" -julia> clean_json_response(text) -"{thought: Hello, action: CHATBOX}" -``` -""" -function clean_json_response(text::String) - text = replace(text, '{' => "") - text = replace(text, '}' => "") - text = replace(text, "```" => "") - text = replace(text, "json" => "") - text = '{' * text * '}' - return text -end diff --git a/src/llmUtil.jl b/src/llmUtil.jl index 7c11afd..344ddeb 100644 --- a/src/llmUtil.jl +++ b/src/llmUtil.jl @@ -1,6 +1,7 @@ module llmUtil -export formatLLMtext, formatLLMtext_llama3instruct, jsoncorrection, deFormatLLMtext, extractthink +export formatLLMtext, formatLLMtext_llama3instruct, jsoncorrection, deFormatLLMtext, extractthink, + checkAgentResponse_JSON, clean_json_response using UUIDs, JSON, Dates using GeneralUtils @@ -440,6 +441,118 @@ end +""" Validate that an agent's JSON response contains all required keys and no extra keys. + +The function checks if `responsedict` contains exactly the keys specified in `requiredKeys` +with no duplicates and no missing keys. It is designed to validate structured agent responses +against an expected schema. + +# Arguments +- `responsedict::Dict` + A dictionary containing the agent's JSON response. Must be a plain `Dict` or + dictionary-like object with String keys. +- `requiredKeys::T` where `T<:Array{String}` + An array of required key names that must be present in `responsedict`. + +# Return +- `Tuple{Bool, Union{String, Nothing}}` + A tuple where the first element indicates whether validation passed (`true`) or failed (`false`), + and the second element contains an error message if validation failed, or `nothing` if it passed. + +# Details +The validation logic checks: +1. **Duplicate keys**: If `responsedict` contains more keys than `requiredKeys`, validation fails + because the agent included extra/unexpected keys. +2. **Missing keys**: If any key in `requiredKeys` is absent from `responsedict`, validation fails + and the specific missing keys are listed in the error message. +3. **Valid response**: If all required keys are present and no extra keys exist, validation passes. + +# Example + +```julia +julia> using YiemAgent +julia> requiredKeys = ["wine_name", "price", "rating"] +julia> response = Dict("wine_name"=>"Château Margaux", "price"=>250.0, "rating"=>98) +julia> YiemAgent.checkAgentResponse_JSON(response, requiredKeys) +(true, nothing) + +julia> response_missing = Dict("wine_name"=>"Château Margaux", "price"=>250.0) +julia> YiemAgent.checkAgentResponse_JSON(response_missing, requiredKeys) +(false, "rating are missing from your previous response") + +julia> response_extra = Dict("wine_name"=>"Château Margaux", "price"=>250.0, "rating"=>98, "extra_field"=>"data") +julia> YiemAgent.checkAgentResponse_JSON(response_extra, requiredKeys) +(false, "Your previous attempt has duplicated points according to the required response format") +``` +""" +function checkAgentResponse_JSON(responsedict::Dict, requiredKeys::T + )::Tuple where {T<:Array{String}} + _responsedictKey = keys(responsedict) + responsedictKey = [i for i in _responsedictKey] # convert into a list + is_requiredKeys_in_responsedictKey = [i ∈ responsedictKey for i in requiredKeys] + ispass = false + errormsg = nothing + if length(is_requiredKeys_in_responsedictKey) > length(requiredKeys) + errormsg = "Your previous attempt has duplicated points according to the required response format" + ispass = false + elseif !all(is_requiredKeys_in_responsedictKey) + zeroind = findall(x -> x == 0, is_requiredKeys_in_responsedictKey) + missingkeys = [requiredKeys[i] for i in zeroind] + errormsg = "$missingkeys are missing from your previous response" + ispass = false + else + ispass = true + end + return (ispass, errormsg) +end + +""" Convert a plain text string containing key-value pairs into a JSON-formatted string. + +This function takes text containing key-value pairs (typically extracted from LLM responses) +and wraps them in proper JSON braces to create a valid JSON string. It cleans the input +by removing common formatting artifacts like braces, code block markers, and language +specifiers before wrapping the content. + +# Arguments +- `text::String` + A string containing key-value pairs, typically in the format `key: value, key: value`. + May contain leading/trailing braces, code block markers (```), or language specifiers + (e.g., `json`) that will be removed. + +# Return +- `String` + A JSON-formatted string with the key-value pairs wrapped in `{}` braces. + +# Notes +- The function removes `{`, `}`, `````, and `json` from the input before wrapping. +- The output is always wrapped in curly braces to create valid JSON structure. +- This is typically used to sanitize LLM responses that contain key-value data + but may include formatting artifacts. + +# Examples +```jldoctest +julia> text = "thought: Hello, action: CHATBOX, input: How can I help?" +julia> clean_json_response(text) +"{thought: Hello, action: CHATBOX, input: How can I help?}" + +julia> text = "{thought: Hello, action: CHATBOX}" +julia> clean_json_response(text) +"{thought: Hello, action: CHATBOX}" + +julia> text = "```json{thought: Hello, action: CHATBOX}```" +julia> clean_json_response(text) +"{thought: Hello, action: CHATBOX}" +``` +""" +function clean_json_response(text::String) + text = replace(text, '{' => "") + text = replace(text, '}' => "") + text = replace(text, "```" => "") + text = replace(text, "json" => "") + text = '{' * text * '}' + return text +end +