This commit is contained in:
2026-06-27 08:00:41 +07:00
parent 299a485e4e
commit e63dd7d898
8 changed files with 534 additions and 508 deletions
+128 -421
View File
@@ -122,21 +122,21 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
# """
# end
recentevents_ind = GeneralUtils.recentElementsIndex(
length(a.memory["events"]), recentevents; includelatest=true)
# recentevents_ind = GeneralUtils.recentElementsIndex(
# length(a.memory["events"]), recentevents; includelatest=true)
requiredKeys = ["plan", "actionname", "actioninput"]
context =
"""
<internal_context_for_assistant>
$(a.memory["scratchpad"])
$(a.memory["shortmem"]["scratchpad"])
</internal_context_for_assistant>
"""
#WORKING add context to text of the latest message (in the front).
# add context to text of the latest message (in the front).
# use for loop because in openai format, each msg may contain both text and image.
for d in enumerate(a.chathistory[end]["content"])
for d in a.chathistory[end]["content"]
if d["type"] == "text"
d["text"] = context * d["text"]
break
@@ -145,28 +145,27 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
errornote = "N/A"
response = nothing # placeholder for show when error msg show up
for attempt in 1:maxattempt
if attempt > 1
println("\nYiemAgent decisionMaker() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
end
openai_msg = Dict(
"model" => "gemma-4-E4B-it-UD-Q4_K_XL",
"messages" => a.chathistory,
"temperature" => 0.7
)
response = a.context.text2textInstructLLM(prompt; senderId=a.id)
response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
response = a.context.text2textInstructLLM(a.id, openai_msg)
# response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
response = GeneralUtils.remove_french_accents(response)
think, response = GeneralUtils.extractthink(response)
response = String(split(response, ", observation")[1]) # in case LLM generate observation key which it isn't supposed to
response = strip(response)
responsedict = nothing
try
responsedict = copy(JSON.parsefile(response))
_responsedict = JSON.parse(response)
responsedict = GeneralUtils.dictify(_responsedict, keytype=String)
catch
println("\nERROR YiemAgent decisionMaker() failed to parse response: $response", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
@@ -179,21 +178,6 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)> $responsedict", @__FILE__, ":", @__LINE__, " $(Dates.now())\n")
continue
end
# _responsedictKey = keys(responsedict)
# responsedictKey = [i for i in _responsedictKey] # convert into a list
# is_requiredKeys_in_responsedictKey = [i ∈ responsedictKey for i in requiredKeys]
# if length(is_requiredKeys_in_responsedictKey) > length(requiredKeys)
# errornote = "Your previous attempt has more key points than answer's required key points."
# println("\nERROR YiemAgent decisionMaker() $errornote ----(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# elseif !all(is_requiredKeys_in_responsedictKey)
# zeroind = findall(x -> x == 0, is_requiredKeys_in_responsedictKey)
# missingkeys = [requiredKeys[i] for i in zeroind]
# errornote = "$missingkeys are missing from your previous response"
# println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# end
if responsedict["actionname"] ["CHATBOX", "CHECKWINE", "PRESENTBOX", "ENDCONVERSATION"]
errornote = "Your previous attempt didn't use the given functions"
@@ -204,64 +188,64 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
println("\nYiem decisionMaker() ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
pprintln(Dict(responsedict))
# check whether an agent recommend wines before checking inventory or recommend wines
# outside its inventory
# ask LLM whether there are any winery mentioned in the response
mentioned_winery = detectWineryName(a, response)
if mentioned_winery != "None"
mentioned_winery = String.(strip.(split(mentioned_winery, ",")))
# # check whether an agent recommend wines before checking inventory or recommend wines
# # outside its inventory
# # ask LLM whether there are any winery mentioned in the response
# mentioned_winery = detectWineryName(a, response)
# if mentioned_winery != "None"
# mentioned_winery = String.(strip.(split(mentioned_winery, ",")))
# check whether the wine is in event
isWineInEvent = false
for winename in mentioned_winery
for event in a.memory["events"]
if event["observation"] !== nothing && occursin(winename, event["observation"])
isWineInEvent = true
break
end
end
end
# # check whether the wine is in event
# isWineInEvent = false
# for winename in mentioned_winery
# for event in a.memory["events"]
# if event["observation"] !== nothing && occursin(winename, event["observation"])
# isWineInEvent = true
# break
# end
# end
# end
# then the agent is not supposed to recommend the wine
if isWineInEvent == false
errornote = "You recommended wines that are not in your inventory before. Please only recommend wines that you have previously found in your inventory."
println("\nERROR YiemAgent decisionMaker() $errornote $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
end
# # then the agent is not supposed to recommend the wine
# if isWineInEvent == false
# errornote = "You recommended wines that are not in your inventory before. Please only recommend wines that you have previously found in your inventory."
# println("\nERROR YiemAgent decisionMaker() $errornote $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# end
# end
delete!(responsedict, :mentioned_winery)
# delete!(responsedict, :mentioned_winery)
# check whether responsedict["actioninput"] is the same as previous dialogue
if !isempty(a.chathistory) && responsedict["actioninput"] == a.chathistory[end]["text"]
errornote = "In your previous attempt, you repeated the previous dialogue. Please try again."
println("\nERROR YiemAgent decisionMaker() $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# if !isempty(a.chathistory) && responsedict["actioninput"] == a.chathistory[end]["text"]
# errornote = "In your previous attempt, you repeated the previous dialogue. Please try again."
# println("\nERROR YiemAgent decisionMaker() $response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# end
evaluationdict = evaluator(a, timeline, responsedict, context)
if evaluationdict[:approval] == "no"
mentor_comment = evaluationdict[:suggestion]
errornote = "Your previous attempt was not good enough. Please try again. Here is the mentor's suggestion: $mentor_comment"
println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> \n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# evaluationdict = evaluator(a, timeline, responsedict, context)
# if evaluationdict[:approval] == "no"
# mentor_comment = evaluationdict[:suggestion]
# errornote = "Your previous attempt was not good enough. Please try again. Here is the mentor's suggestion: $mentor_comment"
# println("\nERROR YiemAgent decisionMaker() $errornote --(not qualify response)--> \n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# continue
# end
# store for later training
responsedict["system"] = systemmsg
responsedict["unformatPrompt"] = unformatPrompt
responsedict["prompt"] = prompt
responsedict["context"] = context
responsedict["think"] = think
responsedict["response"] = response
# responsedict["QandA"] = QandA
# # store for later training
# responsedict["system"] = systemmsg
# responsedict["unformatPrompt"] = unformatPrompt
# responsedict["prompt"] = prompt
# responsedict["context"] = context
# responsedict["think"] = think
# responsedict["response"] = response
# # responsedict["QandA"] = QandA
# check whether there is a file path exists before writing to it
if !haskey(a.memory["shortmem"], "decisionlog")
a.memory["shortmem"]["decisionlog"] = [responsedict]
else
push!(a.memory["shortmem"]["decisionlog"], responsedict)
end
# # check whether there is a file path exists before writing to it
# if !haskey(a.memory["shortmem"], "decisionlog")
# a.memory["shortmem"]["decisionlog"] = [responsedict]
# else
# push!(a.memory["shortmem"]["decisionlog"], responsedict)
# end
# # save to filename ./log/decisionlog.txt
# println("\nsaving YiemAgent decisionMaker() to disk ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
@@ -286,7 +270,7 @@ function decisionMaker(a::T; recentevents::Integer=20, maxattempt=10
# println("\nYiemAgent decisionMaker() saved to disk is done. agent $(a.id)")
responsedict["prompt"] = prompt
# responsedict["prompt"] = prompt
return responsedict
end
error("DecisionMaker failed to generate a thought ", response)
@@ -468,7 +452,7 @@ base64_string = base64encode(image_bytes)
# 2. Match the MIME type according to your file extension (e.g., png, jpeg)
mime_type = "image/png"
data_uri = "data:$(mime_type);base64,$(base64_string)"
data1_uri = "data:<mime_type>;base64,<image1_base64_string>"
# 3. Construct payload with the Data URI
message => Dict(
@@ -483,33 +467,31 @@ message => Dict(
)
# ---------------------------------------------- 100 --------------------------------------------- #
""" #WORKING
function conversation(a::sommelier; userinput::Union{Dict{String, Any}, JSON.Object{String, Any}}, maximumMsg=50)
"""
function conversation(a::sommelier; userinput::Union{Dict{String, Any}, JSON.Object{String, Any}},
maximumMsg=50)
userinput = GeneralUtils.dictify(userinput; keytype=String)
# find text in usermsg
usertext = nothing
text_position = nothing
for (i, d) in enumerate(userinput["content"])
if d["type"] == "text"
usertext = d["text"]
text_position = i
end
end
# place holder
actionname = nothing
result = nothing
chatresponse = nothing
if userinput === nothing
# thinking loop until AI wants to communicate with the user
chatresponse = nothing
while chatresponse === nothing
actionname, result = think(a)
if actionname ["CHATBOX", "PRESENTBOX", "ENDCONVERSATION"]
chatresponse = result
end
end
addNewMessage(a, "assistant", chatresponse; maximumMsg=maximumMsg)
return chatresponse
elseif user_text_input == "newtopic"
if usertext == "newtopic"
clearhistory(a)
return "Okay. What shall we talk about?"
else
userinput["content"][text_position] = GeneralUtils.remove_french_accents(user_text_input)
userinput["content"][text_position]["text"] = GeneralUtils.remove_french_accents(usertext)
# add usermsg to a.chathistory but how do I handle images?
addNewMessage(a, "user", userinput; maximumMsg=maximumMsg)
@@ -521,7 +503,11 @@ function conversation(a::sommelier; userinput::Union{Dict{String, Any}, JSON.Obj
chatresponse = result
end
end
addNewMessage(a, "assistant", chatresponse; maximumMsg=maximumMsg)
assistant_response = Dict{String, Any}(
"role" => "assistant",
"content" => [Dict("type" => "text", "text" => chatresponse),]
)
addNewMessage(a, "assistant", assistant_response; maximumMsg=maximumMsg)
return chatresponse
end
@@ -568,7 +554,6 @@ function conversation(a::Union{companion, virtualcustomer}, userinput::Dict;
end
"""
# Arguments
# Return
@@ -578,92 +563,49 @@ end
julia>
```
""" # WORKING
function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} where {T<:agent}
"""
function think(a::T)::NamedTuple{(:actionname, :result),Tuple{String,String}} where {T<:agent}
# a.memory[:recap] = generateSituationReport(a, a.context["text"2textInstructLLM]; skiprecent=0)
thoughtDict = decisionMaker(a)
actionname = thoughtDict["actionname"]
actioninput = thoughtDict["actioninput"]
# # map action and input() to llm function
# response =
# if thoughtDict["actionname"] == "CHATBOX" || thoughtDict["actionname"] == "ENDCONVERSATION"
# (result=thoughtDict["plan"], errormsg=nothing, success=true)
# elseif thoughtDict["actionname"] == "CHECKWINE"
# checkwine(a, thoughtDict["actioninput"])
# elseif thoughtDict["actionname"] == "PRESENTBOX"
# (result=thoughtDict["actioninput"], errormsg=nothing, success=true)
# else
# error("undefined LLM function. Requesting $(thoughtDict["actionname"])")
# end
# map action and input() to llm function
response =
if actionname == "CHATBOX" || actionname == "ENDCONVERSATION"
(result=thoughtDict["plan"], errormsg=nothing, success=true)
elseif actionname == "CHECKWINE"
checkwine(a, actioninput)
elseif actionname == "PRESENTBOX"
(result=actioninput, errormsg=nothing, success=true)
# elseif actionname == "ENDCONVERSATION"
# x = "Conclude the conversation, thanks the user then goodbye and inviting them to return next time."
# (result=actioninput, errormsg=nothing, success=true)
else
error("undefined LLM function. Requesting $actionname")
end
# # this section allow LLM functions above to have different return values.
# result = haskey(response, "result") ? response["result"] : nothing
# rawresponse = haskey(response, "rawresponse") ? response["rawresponse"] : nothing
# select = haskey(response, "select") ? response["select"] : nothing
# reward::Integer = haskey(response, "reward") ? response["reward"] : 0
# isterminal::Bool = haskey(response, "isterminal") ? response["isterminal"] : false
# errormsg::Union{AbstractString,Nothing} = haskey(response, "errormsg") ? response["errormsg"] : nothing
# success::Bool = haskey(response, "success") ? response["success"] : false
# this section allow LLM functions above to have different return values.
result = haskey(response, "result") ? response["result"] : nothing
rawresponse = haskey(response, "rawresponse") ? response["rawresponse"] : nothing
select = haskey(response, "select") ? response["select"] : nothing
reward::Integer = haskey(response, "reward") ? response["reward"] : 0
isterminal::Bool = haskey(response, "isterminal") ? response["isterminal"] : false
errormsg::Union{AbstractString,Nothing} = haskey(response, "errormsg") ? response["errormsg"] : nothing
success::Bool = haskey(response, "success") ? response["success"] : false
result = nothing
if thoughtDict["actionname"] ["CHATBOX"]
result = thoughtDict["actioninput"]
elseif thoughtDict["actionname"] ["ENDCONVERSATION"]
# WORKING add ENDCONVERSATION guideline in to scratchpad
guideline =
"""
To end conversation with the user
"""
# # manage memory (pass msg to generatechat)
# if actionname ∈ ["CHATBOX", "PRESENTBOX", "ENDCONVERSATION"]
# chatresponse = generatechat(a, thoughtDict)
# push!(a.memory["events"],
# eventdict(;
# event_description="the assistant talks to the user.",
# timestamp=Dates.now(),
# subject="assistant",
# thought=thoughtDict,
# actionname=actionname,
# actioninput=actioninput,
# )
# )
# result = chatresponse
if actionname ["CHATBOX"]
push!(a.memory["events"],
eventdict(;
event_description="an assistant talks to the user.",
timestamp=Dates.now(),
subject="assistant",
thought=thoughtDict,
actionname=actionname,
actioninput=actioninput,
)
)
result = actioninput
elseif actionname ["ENDCONVERSATION"]
chatresponse = generatechat(a, thoughtDict)
push!(a.memory["events"],
eventdict(;
event_description="an assistant talks to the user to end conversation.",
timestamp=Dates.now(),
subject="assistant",
thought=thoughtDict,
actionname=actionname,
actioninput=chatresponse,
)
)
a.memory["shortmem"]["scratchpad"] =
result = chatresponse
elseif actionname ["PRESENTBOX"]
chatresponse = presentbox(a, thoughtDict)
push!(a.memory["events"],
eventdict(;
event_description="the assistant presents wines to the user.",
timestamp=Dates.now(),
subject="assistant",
thought=thoughtDict,
actionname=actionname,
actioninput=chatresponse,
)
)
elseif thoughtDict["actionname"] ["PRESENTBOX"]
chatresponse = presentbox(a, thoughtDict) #PENDING
result = chatresponse
elseif actionname == "CHECKWINE"
elseif thoughtDict["actionname"] == "CHECKWINE"
if rawresponse !== nothing
vd = GeneralUtils.dfToVectorDict(rawresponse) # comes in dataframe format
# a.memory["shortmem"]["found_wine"] = vd # used by decisionMaker() as a short note
@@ -689,24 +631,11 @@ function think(a::T)::namedTuple{(:actionname, :result),Tuple{String,String}} wh
# </database_search_result>
# """
end
push!(a.memory["events"],
eventdict(;
event_description= "the assistant searched the database.",
timestamp= Dates.now(),
subject= "assistant",
thought=thoughtDict,
actionname=actionname,
actioninput= "I search the database with this search term: $actioninput",
observation= "This is what I found:, $result"
)
)
else
error("condition is not defined ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
end
return (actionname=actionname, result=result)
return (actionname=thoughtDict["actionname"], result=result)
end
@@ -866,94 +795,22 @@ function presentbox(a::sommelier, thoughtDict; maxtattempt::Integer=10, recentev
error("presentbox() failed to generate a response")
end
"""
# Arguments
- `a::T1`
one of ChatAgent's agent.
- `input::T2`
# Return
A JSON string of available wine
# Example
```jldoctest
julia>
```
# TODO
- [] update docs
# Signature
"""
function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10)
systemmsg =
function endconversation(a::sommelier, thoughtDict; maxattempt::Integer=10)
text =
"""
Your role:
Your name is $(a.name). You are a helpful English-speaking assistant, acting as a polite, website-based sommelier for $(a.retailername)'s wine store.
Situation:
You have some thinking in mind while you are talking with the user.
Your mission:
Concentrate on your thoughts and articulate them clearly. Keep the conversation engaging.
Your responsibility does NOT includes:
- Requesting the user to place an order, make a purchase, or confirm the order. These are the job of our sales team at the store.
- Processing sales orders or engaging in any other sales-related activities. These are the job of our sales team at the store.
- Answering questions or offering additional services beyond those related to your store's wine recommendations such as discounts, quantity, rewards programs, promotions, delivery options, shipping, boxes, gift wrapping, packaging, personalized messages or something similar. These are the job of our sales team at the store.
At each round of conversation, you will be given the following:
Your ongoing conversation with the user: ...
Your thoughts: Your current thoughts in your mind
You must follow the following guidelines:
- Do not offer additional services you didn't think
You should follow the following guidelines:
- Focus on the latest conversation
- If the user interrupts, prioritize the user
- Be honest
You should then respond to the user with:
dialogue: what you want to say to the user
You should only respond in JSON format as described below:
{
"dialogue": "..."
}
Here are some examples:
Your ongoing conversation with the user: "user> hello, I need a new car\n"
Your thoughts: "I should recommend the car we have found in our inventory to the user."
{"dialogue": "We have a variety of cars available, including the Toyota Camry 2020, the Honda Civic 2021, and the Ford Mustang 2022. Which one would you like to see?"}
Let's begin!
---
"""
requiredKeys = [:dialogue]
requiredKeys = ["dialogue"]
# a.memory["shortmem"]["available_wine"] is a vector of dictionary
# context =
# if length(a.memory["shortmem"]["available_wine"]) != 0
# "Wines previously found in your inventory: $(availableWineToText(a.memory["shortmem"]["available_wine"]))"
# else
# "N/A"
# end
chathistory = chatHistoryToText(a.chathistory)
errornote = "N/A"
response = nothing # placeholder for show when error msg show up
yourthought = thoughtDict["plan"]
# yourthought1 = nothing
system_msg = Dict(
"role" => "system",
"content" => [
Dict("type" => "text", "text" => systemmsg),
]
)
for attempt in 1:maxattempt
# if attempt > 1 # use to prevent LLM generate the same respond over and over
# println("\nYiemAgent generatchat() attempt $attempt/10 ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# yourthought1 = paraphrase(a.context["text"2textInstructLLM], yourthought)
# else
# yourthought1 = yourthought
# end
context =
"""
<context>
Your ongoing conversation with the user: $chathistory
Your thoughts: $yourthought
P.S. $errornote
</context>
"""
unformatPrompt =
[
@@ -1036,156 +893,6 @@ function generatechat(a::sommelier, thoughtDict; maxattempt::Integer=10)
end
function generatechat(a::companion; recentevents::Integer=10,
converPartnerName::Union{String, Nothing}=nothing, maxattempt=10)
recentchat_ind = GeneralUtils.recentElementsIndex(length(a.chathistory), recentevents;
includelatest=true);
recentchat = createChatLog(a.chathistory; index=recentchat_ind)
response = nothing # placeholder for show when error msg show up
errornote = "N/A"
for attempt in 1:maxattempt
if attempt > 1
println("\nYiemAgent generatechat() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
end
context =
"""
<context>
P.S. $errornote
</context>
"""
unformatPrompt =
[
Dict("name" => "system", "text" => a.systemmsg),
]
unformatPrompt = vcat(unformatPrompt, recentchat)
# put in model format
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
# add info
prompt = prompt * context
# replace user and assistant with partner name
prompt = replace(_prompt, "|>user"=>"|>$(converPartnerName)")
prompt = replace(prompt, "|>assistant"=>"|>$(a.name)")
response = a.context.text2textInstructLLM(prompt; llmkwargs=llmkwargs, senderId=a.id)
response = replace(response, "<|im_start|>"=> "")
response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
think, response = GeneralUtils.extractthink(response)
# check whether LLM just repeat the previous dialogue
for msg in a.chathistory
if msg["text"] == response
errornote = "In your previous attempt, you repeated the previous dialogue. Please try again."
println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
end
return response
end
error("generatechat failed to generate a response")
end
# modify it to work with customer object
function generatechat(a::virtualcustomer;
converPartnerName::Union{String, Nothing}=nothing, maxattempt=10, recentEventNum=10
)
recent_ind = GeneralUtils.recentElementsIndex(length(a.memory["events"]), recentEventNum; includelatest=true)
recentEventsDict = createEventsLog(a.memory["events"]; index=recent_ind)
response = nothing # placeholder for show when error msg show up
errornote = "N/A"
header = ["Dialogue:", "Role:"]
dictkey = ["dialogue", "role"]
llmkwargs=Dict(
"num_ctx" => 32768,
"temperature" => 0.5,
)
for attempt in 1:maxattempt
if attempt > 1
println("\nYiemAgent generatechat() attempt $attempt/$maxattempt ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
end
context =
"""
<context>
P.S. $errornote
</context>
"""
unformatPrompt =
[
Dict("name" => "system", "text" => a.systemmsg),
]
unformatPrompt = vcat(unformatPrompt, recentEventsDict)
# put in model format
prompt = GeneralUtils.formatLLMtext(unformatPrompt, a.llmFormatName)
# add info
prompt = prompt * context
response = a.context.text2textInstructLLM(prompt; llmkwargs=llmkwargs, senderId=a.id)
response = replace(response, "<|im_start|>"=> "")
response = GeneralUtils.deFormatLLMtext(response, a.llmFormatName)
think, response = GeneralUtils.extractthink(response)
# check whether response has all header
detected_kw = GeneralUtils.detectKeywordVariation(header, response)
missingkeys = [k for (k, v) in detected_kw if v === nothing]
if !isempty(missingkeys)
errornote = "$missingkeys are missing from your previous response"
println("\nERROR YiemAgent rolegenerator() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
elseif sum([length(i) for i in values(detected_kw)]) > length(header)
errornote = "\nYour previous attempt has duplicated points according to the required response format"
println("\nERROR YiemAgent rolegenerator() $errornote ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
responsedict = GeneralUtils.textToDict(response, header;
dictKey=dictkey, symbolkey=true)
if responsedict["role"] == "no"
errornote = "In your previous attempt you said $(responsedict["dialogue"]) which you, as a customer of a wine store, are not supposed to speak."
println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# check if the dialogue is the same as the previous one
if length(responsedict["dialogue"]) != 0 && responsedict["dialogue"] == a.chathistory[end]["text"]
errornote = "In your previous attempt you said $(responsedict["dialogue"]) which was the same as the previous one."
println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
continue
end
# check whether LLM just repeat the previous dialogue
dublicate = false
for msg in a.chathistory
if msg["text"] == responsedict["dialogue"]
errornote = "In your previous attempt, you repeated the earlier dialogue. Please try again."
println("\nYiemAgent generatechat() $errornote:\n$response ", @__FILE__, ":", @__LINE__, " $(Dates.now())")
dublicate = true
break
end
end
if dublicate
continue
end
# println("\n$prompt", @__FILE__, ":", @__LINE__, " $(Dates.now())")
# println("\n $response")
return responsedict["dialogue"]
end
error("generatechat failed to generate a response")
end
function generatequestion(a, text2textInstructLLM::Function, timeline)::String
systemmsg =
"""