diff --git a/src/interface.jl b/src/interface.jl index 5dad97d..39f1446 100755 --- a/src/interface.jl +++ b/src/interface.jl @@ -503,7 +503,7 @@ function work(a::T, prompt::String, maxround::Int=3) where {T<:agent} if a.thinkinground == 1 try respond = split(respond, "Obs:")[1] - headerToDetect = ["Question:", "Plan:", "Thought:", "Act:", "ActInput:", "Obs:", "...", "Answer:", + headerToDetect = ["Question:", "Plan:", "Thought:", "Act:", "Actinput:", "Obs:", "...", "Answer:", "Conclusion:", "Summary:"] catch end @@ -512,7 +512,7 @@ function work(a::T, prompt::String, maxround::Int=3) where {T<:agent} respond = split(respond, "Obs $(a.thinkinground):")[1] headerToDetect = ["Question $(a.thinkinground):", "Plan $(a.thinkinground):", "Thought $(a.thinkinground):", "Act $(a.thinkinground):", - "ActInput $(a.thinkinground):", "Obs $(a.thinkinground):", + "Actinput $(a.thinkinground):", "Obs $(a.thinkinground):", "...", "Answer:", "Conclusion:", "Summary:"] catch @@ -541,10 +541,10 @@ function work(a::T, prompt::String, maxround::Int=3) where {T<:agent} ActInd = findDetectedCharacter(headers, ActHeader)[1] toolname = toolNameBeingCalled(chunkedtext[ActInd][:body], a.tools) end - ActInputHeader = a.thinkinground == 1 ? "ActInput:" : "ActInput $(a.thinkinground):" - if length(findDetectedCharacter(headers, ActInputHeader)) != 0 # check whether there is ActInput: in a respond - ActInputInd = findDetectedCharacter(headers, ActInputHeader)[1] - toolinput = chunkedtext[ActInputInd][:body] + ActinputHeader = a.thinkinground == 1 ? "Actinput:" : "Actinput $(a.thinkinground):" + if length(findDetectedCharacter(headers, ActinputHeader)) != 0 # check whether there is Actinput: in a respond + ActinputInd = findDetectedCharacter(headers, ActinputHeader)[1] + toolinput = chunkedtext[ActinputInd][:body] end # clean up @@ -688,7 +688,7 @@ function work(a::agentReflex, usermsg::String) @show formulatedRespond a.memory[:shortterm]["Respond $(a.attempt):"] = respond - a.memory[:log]["Respond $mark:"] = respond + a.memory[:log]["Respond $(a.attempt):"] = respond # evaluate. if score < 8/10 try again. guideline = writeEvaluationGuideline(a, a.memory[:shortterm]["user:"]) @@ -705,7 +705,11 @@ function work(a::agentReflex, usermsg::String) @show analysis lessonwithcontext = selfReflext(a, analysis) @show lessonwithcontext - a.memory[:shortterm] = OrderedDict{String, Any}() + + newdict = OrderedDict() + + a.memory[:shortterm] = keepOnlyKeys(a.memory[:shortterm], ["user:"]) + #TODO add lesson and context into longterm memory headerToDetect = ["Lesson:", "Context:", ] headers = detectCharacters(lessonwithcontext, headerToDetect) @@ -775,6 +779,7 @@ function actor(a::agentReflex) 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)") elseif decision == "formulateUserRespond" actorState = "formulateUserRespond" @@ -802,7 +807,7 @@ function actor(a::agentReflex) end headerToDetect = ["Question:", "Plan:", "Thought:", - "Act:", "ActInput:", "Obs:", "...", + "Act:", "Actinput:", "Obs:", "...", "Answer:", "Conclusion:", "Summary:"] # replace headers with headers with correct attempt and step number @@ -817,7 +822,7 @@ function actor(a::agentReflex) headerToDetect = ["Plan $(a.attempt):", "Thought $(a.step):", "Act $(a.step):", - "ActInput $(a.step):", + "Actinput $(a.step):", "Obs $(a.step):", "Check $(a.step):",] headers = detectCharacters(respond, headerToDetect) @@ -826,9 +831,10 @@ function actor(a::agentReflex) # add to memory a.memory[:shortterm] = addShortMem!(a.memory[:shortterm], chunkedtext) + a.memory[:log] = addShortMem!(a.memory[:log], chunkedtext) toolname = toolNameBeingCalled(chunkedtext["Act $(a.step):"], a.tools) - toolinput = chunkedtext["ActInput $(a.step):"] + toolinput = chunkedtext["Actinput $(a.step):"] @show toolname @show toolinput @@ -845,6 +851,7 @@ function actor(a::agentReflex) toolresult = f(a, toolinput) @show toolresult a.memory[:shortterm]["Obs $(a.step):"] = toolresult + a.memory[:log]["Obs $(a.step):"] = toolresult end else #TODO finish all steps actorState = "all steps done" @@ -919,10 +926,10 @@ julia> shorttermMemory = OrderedDict{String, Any}( "user" => "What's the latest AMD GPU?", "Plan 1:" => " To answer this question, I will need to search for the latest AMD GPU using the wikisearch tool.\n", "Act 1:" => " wikisearch\n", - "ActInput 1:" => " amd gpu latest\n", + "Actinput 1:" => " amd gpu latest\n", "Obs 1:" => "No info available for your search query.", "Act 2:" => " wikisearch\n", - "ActInput 2:" => " amd graphics card latest\n", + "Actinput 2:" => " amd graphics card latest\n", "Obs 2:" => "No info available for your search query.") julia> guideline = "\nEvaluation Guideline:\n1. Check if the user's question has been understood correctly.\n2. Evaluate the steps taken to provide the information requested by the user.\n3. Assess whether the correct tools were used for the task.\n4. Determine if the user's request was successfully fulfilled.\n5. Identify any potential improvements or alternative approaches that could be used in the future.\n\nThe respond should include:\n1. A clear understanding of the user's question.\n2. The steps taken to provide the information requested by the user.\n3. An evaluation of whether the correct tools were used for the task.\n4. A confirmation or explanation if the user's request was successfully fulfilled.\n5. Any potential improvements or alternative approaches that could be used in the future." julia> score = grading(agent, guideline, shorttermMemory) @@ -984,10 +991,10 @@ julia> shorttermMemory = OrderedDict{String, Any}( "user:" => "What's the latest AMD GPU?", "Plan 1:" => " To answer this question, I will need to search for the latest AMD GPU using the wikisearch tool.\n", "Act 1:" => " wikisearch\n", - "ActInput 1:" => " amd gpu latest\n", + "Actinput 1:" => " amd gpu latest\n", "Obs 1:" => "No info available for your search query.", "Act 2:" => " wikisearch\n", - "ActInput 2:" => " amd graphics card latest\n", + "Actinput 2:" => " amd graphics card latest\n", "Obs 2:" => "No info available for your search query.") julia> report = analyze(agent, shorttermMemory) ``` @@ -1004,21 +1011,23 @@ function analyze(a) Your work: $shorttermMemory - Do each of the following steps in detail to analize your work. + You job is to do each of the following steps in detail to analize your work. 1. What happened? - 2. List all relationships, each with cause and effect . + 2. List all relationships, each with cause and effect. 3. Look at each relationship, figure out why it behaved that way. 4. What could you do to improve the respond? <|im_end|> + <|im_start|>assistant + """ - respond = sendReceivePrompt(a, prompt, max_tokens=2048) + respond = sendReceivePrompt(a, prompt, max_tokens=1024, timeout=180) println("") analyze_prompt = prompt @show analyze_prompt - println("") + println(">>>") analyze_respond = respond @show analyze_respond @@ -1096,10 +1105,10 @@ julia> shorttermMemory = OrderedDict{String, Any}( "user:" => "What's the latest AMD GPU?", "Plan 1:" => " To answer this question, I will need to search for the latest AMD GPU using the wikisearch tool.\n", "Act 1:" => " wikisearch\n", - "ActInput 1:" => " amd gpu latest\n", + "Actinput 1:" => " amd gpu latest\n", "Obs 1:" => "No info available for your search query.", "Act 2:" => " wikisearch\n", - "ActInput 2:" => " amd graphics card latest\n", + "Actinput 2:" => " amd graphics card latest\n", "Obs 2:" => "No info available for your search query.") julia> report = formulateUserRespond(agent, shorttermMemory) @@ -1118,7 +1127,7 @@ function formulateUserRespond(a) Plan: a plan Thought: your thought Act: the action you took - ActInput: the input to the action + Actinput: the input to the action Obs: the result of the action Stimulus: @@ -1153,10 +1162,10 @@ julia> shorttermMemory = OrderedDict{String, Any}( "user:" => "What's the latest AMD GPU?", "Plan 1:" => " To answer this question, I will need to search for the latest AMD GPU using the wikisearch tool.\n", "Act 1:" => " wikisearch\n", - "ActInput 1:" => " amd gpu latest\n", + "Actinput 1:" => " amd gpu latest\n", "Obs 1:" => "No info available for your search query.", "Act 2:" => " wikisearch\n", - "ActInput 2:" => " amd graphics card latest\n", + "Actinput 2:" => " amd graphics card latest\n", "Obs 2:" => "No info available for your search query.") julia> decision = goNogo(agent) @@ -1175,7 +1184,7 @@ function goNogo(a) # Plan: a plan # Thought: your thought # Act: the action you took - # ActInput: the input to the action + # Actinput: the input to the action # Obs: the result of the action # Stimulus: @@ -1199,7 +1208,7 @@ function goNogo(a) Plan: a plan Thought: your thought Act: the action you took - ActInput: the input to the action + Actinput: the input to the action Obs: the result of the action Stimulus: diff --git a/src/type.jl b/src/type.jl index c8d1f11..577f091 100644 --- a/src/type.jl +++ b/src/type.jl @@ -92,9 +92,9 @@ function agentReflex( Plan: first you should always think about the question and the info you have thoroughly then extract and devise a complete plan to find the answer (pay attention to variables and their corresponding numerals). Thought: ask yourself do you have all the info you need? And what to do according to the plan (pay attention to correct numeral calculation and commonsense). Act: the tool that match your thought, should be one of {toolnames} - ActInput: the input to the action (pay attention to the tool's input) + Actinput: the input to the action (pay attention to the tool's input) Obs: the result of the action - ... (this Plan/Thought/Act/ActInput/Obs can repeat N times until you know the answer.) + ... (this Plan/Thought/Act/Actinput/Obs can repeat N times until you know the answer.) Thought: I think I know the answer Answer: Answer of the original question @@ -111,7 +111,7 @@ function agentReflex( Use the following format: Thought: you should always think about what to do according to step {step} of the plan and the info you have (pay attention to correct numeral calculation and commonsense). Act: the action to take that match your thought, should be one of [{toolnames}] - ActInput: the input to the action (pay attention to the tool's input) + Actinput: the input to the action (pay attention to the tool's input) Obs: the result of the action """, ), @@ -241,9 +241,9 @@ function agentReact( Plan: first you should always think about the question and the info you have thoroughly then extract and devise a complete plan to find the answer (pay attention to variables and their corresponding numerals). Thought: ask yourself do you have all the info you need? And what to do according to the plan (pay attention to correct numeral calculation and commonsense). Act: the tool that match your thought, should be one of {toolnames} - ActInput: the input to the action (pay attention to the tool's input) + Actinput: the input to the action (pay attention to the tool's input) Obs: the result of the action - ... (this Plan/Thought/Act/ActInput/Obs can repeat N times until you know the answer.) + ... (this Plan/Thought/Act/Actinput/Obs can repeat N times until you know the answer.) Thought: I think I know the answer Answer: Answer of the original question diff --git a/src/utils.jl b/src/utils.jl index 00fc20b..2a3084e 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -3,7 +3,7 @@ module utils export makeSummary, sendReceivePrompt, chunktext, extractStepFromPlan, checkTotalStepInPlan, detectCharacters, findDetectedCharacter, extract_number, toolNameBeingCalled, chooseThinkingMode, conversationSummary, checkReasonableness, replaceHeaders, - addShortMem!, splittext, shortMemoryToString, removeHeaders + addShortMem!, splittext, shortMemoryToString, removeHeaders, keepOnlyKeys using UUIDs, Dates, DataStructures using CommUtils, GeneralUtils @@ -181,7 +181,7 @@ end julia> chunkedtext = ChatAgent.chunktext(text, headers) OrderedDict{String, String} with 3 entries: "Act 1:" => " wikisearch" - "ActInput 1:" => " latest AMD GPU" + "Actinput 1:" => " latest AMD GPU" "Thought 1:" => " I should always think about..." ``` """ @@ -515,13 +515,13 @@ Return: no return julia> chunkedtext = OrderedDict{String, String}( "Thought 1:" => " I should always think about...", "Act 1:" => " wikisearch", - "ActInput 1:" => " latest AMD GPU",) + "Actinput 1:" => " latest AMD GPU",) julia> shortMem = OrderedDict{String, Any}() julia> addShortMem!(shortMem, chunkedtext) OrderedDict{String, Any} with 3 entries: "Thought 1:" => " I should always think about..." "Act 1:" => " wikisearch" -"ActInput 1:" => " latest AMD GPU" +"Actinput 1:" => " latest AMD GPU" ``` """ function addShortMem!(shortMem::OrderedDict{String, Any}, chunkedtext::T) where {T<:AbstractDict} @@ -634,12 +634,12 @@ julia> shortMemory = OrderedDict( "user:" => "Umm", "Thought 1:" => "I like it.", "Act 1:" => "chatbox", - "ActInput 1:" => "I get this one.", + "Actinput 1:" => "I get this one.", ) julia> headers = ["user:"] julia> shortMemoryToString(shortMemory, headers) -"Thought 1: I like it.\nAct 1: chatbox\nActInput 1: I get this one.\n" +"Thought 1: I like it.\nAct 1: chatbox\nActinput 1: I get this one.\n" ``` """ function shortMemoryToString(shortMemory::OrderedDict, @@ -677,11 +677,11 @@ julia> shortMemory = OrderedDict( "Plan 1:" => "testing a small portion of icecream", "Thought 1:" => "I like it.", "Act 1:" => "chatbox", - "ActInput 1:" => "I get this one.", + "Actinput 1:" => "I get this one.", "Plan 2:" => "I'm meeting my wife this afternoon", "Thought 2:" => "I also want it for my wife", "Act 2:" => "chatbox", - "ActInput 2:" => "I would like to get 2 more", + "Actinput 2:" => "I would like to get 2 more", ) julia> skipHeaders = ["Plan"] julia> step = 2 @@ -691,7 +691,7 @@ OrderedDict( "Plan 1:" => "testing a small portion of icecream", "Thought 1:" => "I like it.", "Act 1:" => "chatbox", - "ActInput 1:" => "I get this one.", + "Actinput 1:" => "I get this one.", "Plan 2:" => "I'm meeting my wife this afternoon", ) ``` @@ -725,10 +725,44 @@ end +""" Keep only specified keys in a dictionary. All non-specified keys will be removed. +Args: + dict = a dictionary + keys = keys you want to keep in a dict +Return: + a dict with all non-specified keys removed - +# Example +```jldoctest +julia> dict = OrderedDict( + "user:" => "May I try this one?", + "Plan 1:" => "testing a small portion of icecream", + "Thought 1:" => "I like it.", + "Act 1:" => "chatbox", + "Actinput 1:" => "I get this one.", + "Plan 2:" => "I'm meeting my wife this afternoon", + "Thought 2:" => "I also want it for my wife", + "Act 2:" => "chatbox", + "Actinput 2:" => "I would like to get 2 more", + ) +julia> keys = ["user:"] +julia> keepOnlyKeys(dict, keys) +OrderedDict( + "user:" => "May I try this one?", + ) +``` +""" +function keepOnlyKeys(dict::T1, keys::T2) where {T1<:AbstractDict, T2<:AbstractVector} + newdict = similar(dict) + for (k, v) in dict + if k ∈ keys + newdict[k] = v + end + end + return newdict +end