update
This commit is contained in:
244
src/interface.jl
244
src/interface.jl
@@ -3,7 +3,7 @@ module interface
|
||||
|
||||
export agentReact, agentReflex,
|
||||
addNewMessage, clearMessage, removeLatestMsg, conversation, directconversation,
|
||||
writeEvaluationGuideline, grading, analyze, selfReflext, actor_mistral_openorca2,
|
||||
writeEvaluationGuideline, grading, analyze, selfReflext,
|
||||
formulateUserresponse, extractinfo, updateEnvState, chat_mistral_openorca
|
||||
|
||||
using JSON3, DataStructures, Dates, UUIDs, HTTP
|
||||
@@ -178,7 +178,7 @@ function planner_mistral_openorca(a::agentReflex)
|
||||
end
|
||||
|
||||
# skip objective and plan because LLM is going to generate new plan
|
||||
shorttermMemory = dictToString(a.memory[:shortterm], skiplist=["Objective:", "Plan 0:"])
|
||||
shorttermMemory = dictToString(a.memory[:shortterm], skiplist=["Objective:", "Plan 1:"])
|
||||
|
||||
assistant_plan_prompt =
|
||||
"""
|
||||
@@ -187,7 +187,8 @@ function planner_mistral_openorca(a::agentReflex)
|
||||
The required info you need for wine recommendation:
|
||||
- type of food: ask the user
|
||||
- occasion: ask the user
|
||||
- user's personal taste of wine: ask the user
|
||||
- type of wine (red, white, rose, sparkling, etc): ask the user
|
||||
- user's personal taste of wine characteristic (sweetness, acidity, etc): ask the user
|
||||
- wine price range: ask the user
|
||||
- ambient temperature at the serving location: ask the user
|
||||
- wines we have in stock
|
||||
@@ -255,7 +256,7 @@ end
|
||||
# end
|
||||
|
||||
# # skip objective and plan because LLM is going to generate new plan
|
||||
# shorttermMemory = dictToString(a.memory[:shortterm], skiplist=["Objective:", "Plan 0:"])
|
||||
# shorttermMemory = dictToString(a.memory[:shortterm], skiplist=["Objective:", "Plan 1:"])
|
||||
|
||||
# assistant_plan_prompt =
|
||||
# """
|
||||
@@ -348,7 +349,7 @@ function updatePlan(a::agentReflex)
|
||||
|
||||
result = sendReceivePrompt(a, prompt, max_tokens=512, temperature=0.1)
|
||||
@show updatedPlan = result
|
||||
a.memory[:shortterm]["Plan 0:"] = result
|
||||
a.memory[:shortterm]["Plan 1:"] = result
|
||||
|
||||
end
|
||||
|
||||
@@ -428,9 +429,9 @@ function actor_mistral_openorca(a::agentReflex)
|
||||
response = splittext(response, ["Obs", "<|im_end|>"])
|
||||
|
||||
if !occursin("Thought", response)
|
||||
response = "Thought: " * response
|
||||
response = "Thought $(a.step): " * response
|
||||
end
|
||||
|
||||
@show response_actor1 = response
|
||||
headerToDetect = ["Question:", "Plan:", "Thought:",
|
||||
"Act:", "Actinput:", "Obs:", "...",
|
||||
"Answer:", "Conclusion:", "Summary:"]
|
||||
@@ -442,7 +443,7 @@ function actor_mistral_openorca(a::agentReflex)
|
||||
headers = detectCharacters(response, headerToDetect)
|
||||
|
||||
println("")
|
||||
@show response_actor = response
|
||||
@show response_actor2 = response
|
||||
|
||||
headerToDetect = ["Plan $(a.attempt):",
|
||||
"Thought $(a.step):",
|
||||
@@ -465,14 +466,14 @@ function actor_mistral_openorca(a::agentReflex)
|
||||
toolinput = chunkedtext["Actinput $(a.step):"]
|
||||
|
||||
# change trailing number to continue a.memory[:shortterm]
|
||||
_latest_step = keys(a.memory[:shortterm])
|
||||
_latest_step = [i for i in _latest_step]
|
||||
_latest_step = _latest_step[end]
|
||||
latest_step = parse(Int, _latest_step[end-2:end-1])
|
||||
_latestStep = keys(a.memory[:shortterm])
|
||||
_latestStep = [i for i in _latestStep]
|
||||
_latestStep = _latestStep[end]
|
||||
latestStep = parse(Int, _latestStep[end-2:end-1])
|
||||
headerToDetect = ["Question:", "Plan:", "Thought:",
|
||||
"Act:", "Actinput:", "Obs:", "...",
|
||||
"Answer:", "Conclusion:", "Summary:"]
|
||||
nextstep = latest_step+1 # next step in short term memory
|
||||
nextstep = latestStep+1 # next step in short term memory
|
||||
response = replaceHeaders(response, headerToDetect, nextstep)
|
||||
headerToDetect = ["Plan $(a.attempt):",
|
||||
"Thought $nextstep:",
|
||||
@@ -535,12 +536,12 @@ function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3)
|
||||
|
||||
# a.earlierConversation = conversationSummary(a)
|
||||
_ = addNewMessage(a, "user", usermsg)
|
||||
isusetools = isUseTools(a)
|
||||
isuseplan = isUsePlans(a)
|
||||
# newinfo = extractinfo(a, usermsg)
|
||||
# a.env = newinfo !== nothing ? updateEnvState(a, newinfo) : a.env
|
||||
@show isusetools
|
||||
@show isuseplan
|
||||
|
||||
if isusetools # use tools before responseing
|
||||
if isuseplan # use plan before responding
|
||||
workstate, response = work(a)
|
||||
end
|
||||
|
||||
@@ -557,21 +558,6 @@ function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3)
|
||||
return response
|
||||
end
|
||||
|
||||
""" Direct conversation is not an agent, messages does not pass through logic loop
|
||||
but goes directly to LLM.
|
||||
|
||||
"""
|
||||
function directconversation(a::agentReflex, usermsg::String)
|
||||
response = nothing
|
||||
|
||||
_ = addNewMessage(a, "user", usermsg)
|
||||
|
||||
response = chat_mistral_openorca(a)
|
||||
response = removeTrailingCharacters(response)
|
||||
_ = addNewMessage(a, "assistant", response)
|
||||
return response
|
||||
end
|
||||
|
||||
"""
|
||||
Continuously run llm functions except when llm is getting Answer: or chatbox.
|
||||
There are many work() depend on thinking mode.
|
||||
@@ -582,10 +568,10 @@ function work(a::agentReflex)
|
||||
|
||||
# user answering LLM -> Obs
|
||||
if length(a.memory[:shortterm]) != 0
|
||||
latest_step = dictLatestStep(a.memory[:shortterm])
|
||||
if haskey(a.memory[:shortterm], "Act $latest_step:")
|
||||
if occursin("chatbox", a.memory[:shortterm]["Act $latest_step:"])
|
||||
a.memory[:shortterm]["Obs $latest_step:"] = a.messages[end][:content]
|
||||
latestStep = shortMemLatestStep(a.memory[:shortterm])
|
||||
if haskey(a.memory[:shortterm], "Act $latestStep:")
|
||||
if occursin("chatbox", a.memory[:shortterm]["Act $latestStep:"])
|
||||
a.memory[:shortterm]["Obs $latestStep:"] = a.messages[end][:content]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -601,7 +587,7 @@ function work(a::agentReflex)
|
||||
plan = planner_mistral_openorca(a)
|
||||
a.memory[:shortterm]["Plan $(a.attempt):"] = plan
|
||||
a.memory[:log]["Plan $(a.attempt):"] = plan
|
||||
a.step = 0 # reset because new plan is created
|
||||
a.step = 1 # reset because new plan is created
|
||||
|
||||
println("")
|
||||
@show plan
|
||||
@@ -706,30 +692,15 @@ function actor(a::agentReflex)
|
||||
totalsteps = checkTotalStepInPlan(a)
|
||||
|
||||
while true # Actor loop
|
||||
|
||||
# decide whether to repeat step or do the next step
|
||||
decision = "Yes" # yes because a.step start at 0
|
||||
if a.step != 0
|
||||
decision, reason = goNogo(a)
|
||||
end
|
||||
|
||||
if decision == "Yes" # in case there is a cancel, go straight to evaluation
|
||||
a.step += 1
|
||||
elseif decision == "No" # repeat the latest step
|
||||
a.memory[:shortterm] = removeHeaders(a.memory[:shortterm], a.step, ["Plan"])
|
||||
a.memory[:log] = removeHeaders(a.memory[:log], a.step, ["Plan"])
|
||||
println("repeating step $(a.step)")
|
||||
else
|
||||
error("undefined condition decision = $decision $(@__LINE__)")
|
||||
end
|
||||
@show a.step
|
||||
#WORKING checkStepCompletion
|
||||
iscomplete = checkStepCompletion(a::agentReflex)
|
||||
# if iscomplete
|
||||
|
||||
if a.step < totalsteps # the last step of the plan is responding, let work() do this part
|
||||
# check whether the current step is completed
|
||||
iscomplete, reason = checkStepCompletion(a)
|
||||
@show stepcompletecheck = iscomplete
|
||||
|
||||
if !iscomplete # not yet done
|
||||
# work
|
||||
toolname, toolinput = actor_mistral_openorca(a)
|
||||
println("")
|
||||
@show toolname
|
||||
@show toolinput
|
||||
|
||||
@@ -747,11 +718,35 @@ function actor(a::agentReflex)
|
||||
a.memory[:shortterm]["Obs $(a.step):"] = toolresult
|
||||
a.memory[:log]["Obs $(a.step):"] = toolresult
|
||||
end
|
||||
else
|
||||
actorState = "all steps done"
|
||||
msgToUser = nothing
|
||||
break
|
||||
else # already done
|
||||
a.step +=1
|
||||
# if not add to memory yet. Add
|
||||
|
||||
# step +1
|
||||
|
||||
#TODO may be let LLM call finalResponse()
|
||||
# if a.step > totalsteps # the last step of the plan is responding, let work() do this part
|
||||
# actorState = "all steps done"
|
||||
# msgToUser = nothing
|
||||
# break
|
||||
# end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# elseif decision == "No" # repeat the latest step
|
||||
# a.memory[:shortterm] = removeHeaders(a.memory[:shortterm], a.step, ["Plan"])
|
||||
# a.memory[:log] = removeHeaders(a.memory[:log], a.step, ["Plan"])
|
||||
# println("repeating step $(a.step)")
|
||||
# else
|
||||
# error("undefined condition decision = $decision $(@__LINE__)")
|
||||
# end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
return actorState, msgToUser
|
||||
@@ -1144,14 +1139,14 @@ julia> shorttermMemory = OrderedDict{String, Any}(
|
||||
"Actinput 2:" => " amd graphics card latest\n",
|
||||
"Obs 2:" => "No info available for your search query.")
|
||||
|
||||
julia> decision = goNogo(agent)
|
||||
julia> decision = checkStepCompletion(agent)
|
||||
"Yes"
|
||||
```
|
||||
"""
|
||||
function goNogo(a)
|
||||
function checkStepCompletion(a)
|
||||
# stimulus = a.memory[:shortterm]["user:"]
|
||||
work = dictToString(a.memory[:shortterm])
|
||||
|
||||
#WORKING
|
||||
prompt =
|
||||
"""
|
||||
<|system|>
|
||||
@@ -1165,76 +1160,91 @@ function goNogo(a)
|
||||
Your earlier work:
|
||||
$work
|
||||
|
||||
|
||||
Your job is to check whether step $(a.step) of your work is completed according to the plan.
|
||||
So for instance the following:
|
||||
|
||||
step 2 of the plan: Ask user about the occasion type. But you can't find any relevant info of occasion type in your work.
|
||||
assistant: Step 2 isn't done yet. {No}
|
||||
step 5 of the plan: Ask user if they have any preference for the style of wine. And you found relevant info in your work such as the user like full-bodied wine.
|
||||
assistant: Step 5 is done. {Yes}
|
||||
Step 2 of the plan: Ask user about their preferred taste in white wine.
|
||||
Your interpretation of step 2 of the plan: My understanding of this step is that I need info about their preferred taste in white wine e.g. dryness, sweetness and etc. But I can't find any relevant info that the user tell me their preferred taste in white wine according to Obs.
|
||||
assistant: Thus, step 2 isn't done yet. Answer: {Not done}
|
||||
|
||||
Step 5 of the plan: Ask user if they have any preferred type of wine.
|
||||
Your interpretation of step 5 of the plan: My understanding of this step is that I need info about user preferred wine type. And I found relevant info such as the user like full-bodied wine according to Obs.
|
||||
assistant: Step 5 is done. Answer: {done}
|
||||
Let's think step by step.
|
||||
</s|>
|
||||
<|assistant|>
|
||||
"""
|
||||
|
||||
response = sendReceivePrompt(a, prompt)
|
||||
@show goNogo_response = response
|
||||
response = sendReceivePrompt(a, prompt, max_tokens=512)
|
||||
@show checkStepCompletion_response = response
|
||||
|
||||
decision = nothing
|
||||
reason = nothing
|
||||
if occursin("Yes", response)
|
||||
decision = "Yes"
|
||||
elseif occursin("No", response)
|
||||
decision = "No"
|
||||
if occursin("Not done", response)
|
||||
decision = false
|
||||
elseif occursin("done", response)
|
||||
decision = true
|
||||
else
|
||||
error("undefied condition, decision $decision $(@__LINE__)")
|
||||
end
|
||||
|
||||
startInd = findfirst(decision, response)[end] +2
|
||||
|
||||
if occursin(":", response[startInd:end]) # check for ":" after decision cha
|
||||
startInd2 = findnext(":", response, startInd)[end]+1
|
||||
reason = response[startInd2:end]
|
||||
else
|
||||
reason = response[startInd:end]
|
||||
end
|
||||
|
||||
return decision, reason
|
||||
return decision, response
|
||||
end
|
||||
# function checkStepCompletion(a)
|
||||
# # stimulus = a.memory[:shortterm]["user:"]
|
||||
# work = dictToString(a.memory[:shortterm])
|
||||
|
||||
# prompt =
|
||||
# """
|
||||
# <|system|>
|
||||
# Symbol meaning:
|
||||
# Plan: a plan
|
||||
# Thought: your thought
|
||||
# Act: the action you took
|
||||
# Actinput: the input to the action
|
||||
# Obs: the result of the action
|
||||
|
||||
|
||||
function checkStepCompletion(a::agentReflex)
|
||||
result = false
|
||||
#WORKING I need current step of the plan
|
||||
plan = "Plan $(a.attempt):"
|
||||
plan = a.memory[:shortterm][plan]
|
||||
|
||||
prompt =
|
||||
"""
|
||||
<|system|>
|
||||
Symbol meaning:
|
||||
Plan: a plan
|
||||
Thought: your thought
|
||||
Act: the action you took
|
||||
Actinput: the input to the action
|
||||
Obs: the result of the action
|
||||
|
||||
Your plan:
|
||||
$plan
|
||||
# Your earlier work:
|
||||
# $work
|
||||
|
||||
What is step $(a.step) of the plan?
|
||||
<|/s|>
|
||||
<|assistant|>
|
||||
|
||||
"""
|
||||
# Your job is to check whether step $(a.step) of your work is completed according to the plan.
|
||||
# So for instance the following:
|
||||
# step 2 of the plan: Ask user about the occasion type. But you can't find any relevant info about occasion type in your work.
|
||||
# assistant: Step 2 isn't done yet. Answer {Not done}
|
||||
# step 5 of the plan: Ask user if they have any preference for the style of wine. And you found relevant info in your work such as the user like full-bodied wine.
|
||||
# assistant: Step 5 is done. Answer {done}
|
||||
# Let's think step by step.
|
||||
# </s|>
|
||||
# <|assistant|>
|
||||
# """
|
||||
|
||||
response = sendReceivePrompt(a, prompt)
|
||||
|
||||
response = split(response, "<|im_end|>")[1]
|
||||
# response = sendReceivePrompt(a, prompt)
|
||||
# @show checkStepCompletion_response = response
|
||||
|
||||
|
||||
|
||||
return result
|
||||
# decision = nothing
|
||||
# if occursin("Not done", response)
|
||||
# decision = false
|
||||
# elseif occursin("done", response)
|
||||
# decision = true
|
||||
# else
|
||||
# error("undefied condition, decision $decision $(@__LINE__)")
|
||||
# end
|
||||
|
||||
# return decision, response
|
||||
# end
|
||||
|
||||
""" Direct conversation is not an agent, messages does not pass through logic loop
|
||||
but goes directly to LLM.
|
||||
"""
|
||||
function directconversation(a::agentReflex, usermsg::String)
|
||||
response = nothing
|
||||
|
||||
_ = addNewMessage(a, "user", usermsg)
|
||||
|
||||
response = chat_mistral_openorca(a)
|
||||
response = removeTrailingCharacters(response)
|
||||
_ = addNewMessage(a, "assistant", response)
|
||||
return response
|
||||
end
|
||||
|
||||
|
||||
@@ -1285,10 +1295,6 @@ end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -94,8 +94,8 @@ julia> agent = ChatAgent.agentReflex(
|
||||
tools::Union{Dict, Nothing} = nothing
|
||||
newplan::Bool = false # if true, new plan will be generated
|
||||
attemptlimit::Int = 5 # thinking round limit
|
||||
attempt::Int = 0 # attempted number
|
||||
step::Int = 0 # step number
|
||||
attempt::Int = 1 # attempted number
|
||||
step::Int = 1 # step number
|
||||
env::AbstractString = "N/A"
|
||||
thinkingFormat::Union{Dict, Nothing} = nothing
|
||||
memory::Dict = Dict(
|
||||
@@ -167,7 +167,7 @@ function agentReflex(
|
||||
:actor=>
|
||||
"""
|
||||
Use the following format:
|
||||
Thought: you should always think about what to do according to step {step} of the plan (pay attention to correct numeral calculation and commonsense).
|
||||
Thought: you should always think about what to do to achieve step {step} of the plan (pay attention to correct numeral calculation and commonsense).
|
||||
Act: the action to take that align with your thought, should be one of [{toolnames}]
|
||||
Actinput: your input to the action you chose (pay attention to the tool's input)
|
||||
Obs: the result of the action
|
||||
|
||||
29
src/utils.jl
29
src/utils.jl
@@ -2,9 +2,9 @@ module utils
|
||||
|
||||
export makeSummary, sendReceivePrompt, chunktext, extractStepFromPlan, checkTotalStepInPlan,
|
||||
detectCharacters, findDetectedCharacter, extract_number, toolNameBeingCalled,
|
||||
isUseTools, conversationSummary, checkReasonableness, replaceHeaders,
|
||||
isUsePlans, conversationSummary, checkReasonableness, replaceHeaders,
|
||||
addShortMem!, splittext, dictToString, removeHeaders, keepOnlyKeys, experience,
|
||||
messagesToString, messagesToString_nomark, removeTrailingCharacters, dictLatestStep
|
||||
messagesToString, messagesToString_nomark, removeTrailingCharacters, shortMemLatestStep
|
||||
|
||||
using UUIDs, Dates, DataStructures
|
||||
using CommUtils, GeneralUtils
|
||||
@@ -375,7 +375,7 @@ Return:
|
||||
1. true/false # is LLM going to use tools
|
||||
2. objective # what LLM going to do
|
||||
"""
|
||||
function isUseTools(a::agentReflex)
|
||||
function isUsePlans(a::agentReflex)
|
||||
toollines = ""
|
||||
for (toolname, v) in a.tools
|
||||
if toolname ∉ ["chatbox"] # LLM will always use chatbox
|
||||
@@ -405,26 +405,26 @@ function isUseTools(a::agentReflex)
|
||||
"""
|
||||
|
||||
# if LLM mentions any tools, use Plan/Thought/Act loop
|
||||
isusetool = false
|
||||
isuseplan = false
|
||||
response = sendReceivePrompt(a, prompt, temperature=0.2, max_tokens=64)
|
||||
response = split(response, "<|assistant|>")[1]
|
||||
response = split(response, "<|user|>")[1]
|
||||
@show response
|
||||
|
||||
for (toolname, v) in a.tools
|
||||
if occursin("Yes", String(response))
|
||||
isusetool = true
|
||||
isuseplan = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if length(a.memory[:shortterm]) != 0
|
||||
isusetool = true
|
||||
isuseplan = true
|
||||
end
|
||||
return isusetool
|
||||
return isuseplan
|
||||
end
|
||||
|
||||
|
||||
# function isUseTools(a::agentReflex)
|
||||
# function isUsePlans(a::agentReflex)
|
||||
# toollines = ""
|
||||
# for (toolname, v) in a.tools
|
||||
# if toolname ∉ ["chatbox"] # LLM will always use chatbox
|
||||
@@ -451,21 +451,21 @@ end
|
||||
# """
|
||||
|
||||
# # if LLM mentions any tools, use Plan/Thought/Act loop
|
||||
# isusetool = false
|
||||
# isuseplan = false
|
||||
# response = sendReceivePrompt(a, prompt, temperature=0.0)
|
||||
# response = split(response, "<|im_end|>")[1]
|
||||
# for (toolname, v) in a.tools
|
||||
# if occursin(toolname, String(response))
|
||||
# isusetool = true
|
||||
# isuseplan = true
|
||||
# break
|
||||
# end
|
||||
# end
|
||||
|
||||
# if length(a.memory[:shortterm]) != 0
|
||||
# isusetool = true
|
||||
# isuseplan = true
|
||||
# end
|
||||
|
||||
# return isusetool
|
||||
# return isuseplan
|
||||
# end
|
||||
|
||||
|
||||
@@ -1016,8 +1016,7 @@ function experience(dict::T) where {T<:AbstractDict}
|
||||
end
|
||||
|
||||
|
||||
function dictLatestStep(dict::T) where {T<:AbstractDict}
|
||||
@show dict
|
||||
function shortMemLatestStep(dict::T) where {T<:AbstractDict}
|
||||
_latest_step = keys(dict)
|
||||
_latest_step = [i for i in _latest_step]
|
||||
_latest_step = _latest_step[end]
|
||||
|
||||
Reference in New Issue
Block a user