From 2e559210740249752b03490f2fa5a2f424e70c7a Mon Sep 17 00:00:00 2001 From: tonaerospace Date: Mon, 11 Dec 2023 06:57:39 +0000 Subject: [PATCH] update --- src/interface.jl | 272 +++++++++++++++++++++++++++++++---------------- src/type.jl | 8 +- src/utils.jl | 44 ++------ 3 files changed, 191 insertions(+), 133 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index ccd52b7..05d6842 100755 --- a/src/interface.jl +++ b/src/interface.jl @@ -3,7 +3,7 @@ module interface export agentReact, agentReflex, addNewMessage, clearMessage, removeLatestMsg, conversation, writeEvaluationGuideline, - grading, analyze, selfReflext, actor_mistral_openorca2, formulateUserRespond, + grading, analyze, selfReflext, actor_mistral_openorca2, formulateUserresponse, extractinfo, updateEnvState using JSON3, DataStructures, Dates, UUIDs, HTTP @@ -424,18 +424,18 @@ end broker= "mqtt.yiem.ai", pubtopic= (imgAI="img/api/v0.0.1/gpu/request", txtAI="txt/api/v0.1.0/gpu/request"), - subtopic= (imgAI="agent/api/v0.1.0/img/respond", - txtAI="agent/api/v0.1.0/txt/respond"), + subtopic= (imgAI="agent/api/v0.1.0/img/response", + txtAI="agent/api/v0.1.0/txt/response"), keepalive= 30, ) julia> msgMeta = Dict( :msgPurpose=> "updateStatus", :from=> "agent", :to=> "llmAI", - :requestrespond=> "request", + :requestresponse=> "request", :sendto=> "", # destination topic - :replyTo=> "agent/api/v0.1.0/txt/respond", # requester ask responder to send reply to this topic - :repondToMsgId=> "", # responder is responding to this msg id + :replyTo=> "agent/api/v0.1.0/txt/response", # requester ask responseer to send reply to this topic + :repondToMsgId=> "", # responseer is responseing to this msg id :taskstatus=> "", # "complete", "fail", "waiting" or other status :timestamp=> Dates.now(), :msgId=> "$(uuid4())", @@ -446,34 +446,36 @@ end role=:assistant_react, msgMeta=msgMeta ) - julia> respond = ChatAgent.conversation(newAgent, "Hi! how are you?") + julia> response = ChatAgent.conversation(newAgent, "Hi! how are you?") ``` """ function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3) a.attemptlimit = attemptlimit - respond = nothing + response = nothing a.earlierConversation = conversationSummary(a) _ = addNewMessage(a, "user", usermsg) isusetools = isUseTools(a, usermsg) + newinfo = extractinfo(a, usermsg) + a.env = newinfo !== nothing ? updateEnvState(a, newinfo) #WORKING - if isusetools # use tools before responding - respond = work(a, usermsg) + if isusetools # use tools before responseing + response = work(a, usermsg) end #WORKING prompt = chat_mistral_openorca(a, usermsg) println("") @show prompt - respond = sendReceivePrompt(a, prompt) - respond = split(respond, "<|im_end|>")[1] - respond = replace(respond, "\n" => "") - _ = addNewMessage(a, "assistant", respond) + response = sendReceivePrompt(a, prompt) + response = split(response, "<|im_end|>")[1] + response = replace(response, "\n" => "") + _ = addNewMessage(a, "assistant", response) println("") - @show respond + @show response - return respond + return response end """ @@ -481,7 +483,7 @@ end There are many work() depend on thinking mode. """ function work(a::agentReflex, usermsg::String) - respond = nothing + response = nothing if a.thinkingmode == :new_thinking _ = addNewMessage(a, "user", usermsg) @@ -510,10 +512,10 @@ function work(a::agentReflex, usermsg::String) prompt_plan = planner_mistral_openorca(a) println("") @show prompt_plan - respond = sendReceivePrompt(a, prompt_plan, max_tokens=1024) + response = sendReceivePrompt(a, prompt_plan, max_tokens=1024) # sometimes LLM add not-need word I don't want - plan = splittext(respond, ["Step 1", "<|im_end|>", "Response", "Execution", + plan = splittext(response, ["Step 1", "<|im_end|>", "Response", "Execution", "Result", "Recommendation", "My response"]) # plan = replace(plan, "Plan:"=>"") println("") @@ -531,19 +533,19 @@ function work(a::agentReflex, usermsg::String) actorstate, msgToUser = actor(a) if actorstate == "chatbox" - respond = msgToUser + response = msgToUser break - elseif actorstate == "all steps done" || actorstate == "formulateUserRespond" + elseif actorstate == "all steps done" || actorstate == "formulateUserresponse" println("all steps done") - respond = formulateUserRespond(a) + response = formulateUserresponse(a) println("") - formulatedRespond = respond - @show formulatedRespond + formulatedresponse = response + @show formulatedresponse - a.memory[:shortterm]["Respond $(a.attempt):"] = respond - a.memory[:log]["Respond $(a.attempt):"] = respond + a.memory[:shortterm]["response $(a.attempt):"] = response + a.memory[:log]["response $(a.attempt):"] = response # evaluate. if score < 8/10 try again. guideline = writeEvaluationGuideline(a, a.memory[:shortterm]["user:"]) @@ -551,7 +553,7 @@ function work(a::agentReflex, usermsg::String) println("") @show guideline - score = grading(a, guideline, respond) + score = grading(a, guideline, response) @show score if score >= 6 # good enough answer break @@ -594,8 +596,8 @@ function work(a::agentReflex, usermsg::String) # communicates with user - _ = addNewMessage(a, "assistant", respond) - return respond + _ = addNewMessage(a, "assistant", response) + return response end @@ -610,7 +612,7 @@ end Arguments: a, one of ChatAgent's agent. - plan, a step by step plan to respond + plan, a step by step plan to response Return: case 1) if actor complete the plan successfully. @@ -643,8 +645,8 @@ function actor(a::agentReflex) 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" + elseif decision == "formulateUserresponse" + actorState = "formulateUserresponse" msgToUser = nothing break else @@ -661,11 +663,11 @@ function actor(a::agentReflex) println("") @show prompt_actor - respond = sendReceivePrompt(a, prompt_actor) - respond = splittext(respond, ["Obs", "<|im_end|>"]) + response = sendReceivePrompt(a, prompt_actor) + response = splittext(response, ["Obs", "<|im_end|>"]) - if !occursin("Thought", respond) - respond = "Thought: " * respond + if !occursin("Thought", response) + response = "Thought: " * response end headerToDetect = ["Question:", "Plan:", "Thought:", @@ -673,13 +675,13 @@ function actor(a::agentReflex) "Answer:", "Conclusion:", "Summary:"] # replace headers with headers with correct attempt and step number - respond = replaceHeaders(respond, headerToDetect, a.step) + response = replaceHeaders(response, headerToDetect, a.step) - headers = detectCharacters(respond, headerToDetect) + headers = detectCharacters(response, headerToDetect) println("") - respond_actor = respond - @show respond_actor + response_actor = response + @show response_actor headerToDetect = ["Plan $(a.attempt):", "Thought $(a.step):", @@ -687,8 +689,8 @@ function actor(a::agentReflex) "Actinput $(a.step):", "Obs $(a.step):", "Check $(a.step):",] - headers = detectCharacters(respond, headerToDetect) - chunkedtext = chunktext(respond, headers) + headers = detectCharacters(response, headerToDetect) + chunkedtext = chunktext(response, headers) # add to memory @@ -704,7 +706,7 @@ function actor(a::agentReflex) msgToUser = toolinput actorState = toolname break - elseif toolname == "formulateUserRespond" + elseif toolname == "formulateUserresponse" msgToUser = toolinput actorState = toolname break @@ -760,13 +762,13 @@ function writeEvaluationGuideline(a::agentReflex, usermsg::T) where {T<:Abstrac $usermsg Your job are: - 1. Write an evaluation guideline for your work in order to be able to evaluate your respond. - 2. An example of what the respond should be. + 1. Write an evaluation guideline for your work in order to be able to evaluate your response. + 2. An example of what the response should be. <|im_end|> """ - respond = sendReceivePrompt(a, prompt) - return respond + response = sendReceivePrompt(a, prompt) + return response end @@ -795,7 +797,7 @@ julia> shorttermMemory = OrderedDict{String, Any}( "Act 2:" => " wikisearch\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> 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 response 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) 2 ``` @@ -810,11 +812,11 @@ function grading(a, guideline::T, text::T) where {T<:AbstractString} $guideline - Your respond: $text + Your response: $text You job are: - 1. Evaluate your respond using the evaluation guideline and an example respond. - 2. Give yourself a score out of 10 for your respond. + 1. Evaluate your response using the evaluation guideline and an example response. + 2. Give yourself a score out of 10 for your response. Use the following format to answer: {Evaluation} Score {}/10. @@ -824,13 +826,13 @@ function grading(a, guideline::T, text::T) where {T<:AbstractString} prompt_grading = prompt @show prompt_grading - respond = sendReceivePrompt(a, prompt) + response = sendReceivePrompt(a, prompt) println("") - respond_grading = respond - @show respond_grading + response_grading = response + @show response_grading - _score = split(respond[end-5:end], "/")[1] + _score = split(response[end-5:end], "/")[1] _score = split(_score, " ")[end] score = parse(Int, _score) return score @@ -879,15 +881,15 @@ function analyze(a) 1. What happened? 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? + 4. What could you do to improve the response? <|im_end|> <|im_start|>assistant """ - respond = sendReceivePrompt(a, prompt, max_tokens=1024, timeout=180) + response = sendReceivePrompt(a, prompt, max_tokens=1024, timeout=180) - return respond + return response end @@ -940,18 +942,18 @@ function selfReflext(a, analysis::T) where {T<:AbstractString} <|im_end|> """ - respond = sendReceivePrompt(a, prompt, max_tokens=2048) - return respond + response = sendReceivePrompt(a, prompt, max_tokens=2048) + return response end -""" Formulate a respond from work for user's stimulus. +""" Formulate a response from work for user's stimulus. Arguments: a, one of ChatAgent's agent. Return: - A respond for user's stimulus. + A response for user's stimulus. # Example ```jldoctest @@ -967,10 +969,10 @@ julia> shorttermMemory = OrderedDict{String, Any}( "Actinput 2:" => " amd graphics card latest\n", "Obs 2:" => "No info available for your search query.") -julia> report = formulateUserRespond(agent, shorttermMemory) +julia> report = formulateUserresponse(agent, shorttermMemory) ``` """ -function formulateUserRespond(a) +function formulateUserresponse(a) stimulus = a.memory[:shortterm]["user:"] work = dictToString(a.memory[:shortterm], ["user:"]) @@ -979,7 +981,7 @@ function formulateUserRespond(a) """ <|im_start|>system Symbol: - Stimulus: the input user gives to you and you must respond + Stimulus: the input user gives to you and you must response Plan: a plan Thought: your thought Act: the action you took @@ -992,12 +994,12 @@ function formulateUserRespond(a) Your work: $work - From your work, formulate a respond for user's stimulus. + From your work, formulate a response for user's stimulus. <|im_end|> - Respond: + response: """ - respond = sendReceivePrompt(a, prompt) - return respond + response = sendReceivePrompt(a, prompt) + return response end @@ -1036,7 +1038,7 @@ function goNogo(a) # """ # <|im_start|>system # Symbol meaning: - # Stimulus: the input user gives to you and you must respond + # Stimulus: the input user gives to you and you must response # Plan: a plan # Thought: your thought # Act: the action you took @@ -1052,7 +1054,7 @@ function goNogo(a) # From your work, you job is to decide what to do next by choosing one of the following choices: # If you are ready to do the next step of the plan say, "{Yes}". And what is the rationale behind the decision? # If you need to repeat the latest step say, "{No}". And what is the rationale behind the decision? - # If you are ready to formulate a final respond to user original stimulus say, {formulateUserRespond}. And what is the rationale behind the decision? + # If you are ready to formulate a final response to user original stimulus say, {formulateUserresponse}. And what is the rationale behind the decision? # <|im_end|> # """ @@ -1060,7 +1062,7 @@ function goNogo(a) """ <|im_start|>system Symbol meaning: - Stimulus: the input user gives to you and you must respond + Stimulus: the input user gives to you and you must response Plan: a plan Thought: your thought Act: the action you took @@ -1081,36 +1083,36 @@ function goNogo(a) """ - respond = sendReceivePrompt(a, prompt) + response = sendReceivePrompt(a, prompt) decision = nothing reason = nothing - if occursin("Yes", respond) + if occursin("Yes", response) decision = "Yes" - elseif occursin("No", respond) + elseif occursin("No", response) decision = "No" - elseif occursin("formulateUserRespond", respond) - decision = "formulateUserRespond" + elseif occursin("formulateUserresponse", response) + decision = "formulateUserresponse" else error("undefied condition, decision $decision $(@__LINE__)") end - startInd = findfirst(decision, respond)[end] +2 + startInd = findfirst(decision, response)[end] +2 - if occursin(":", respond[startInd:end]) # check for ":" after decision cha - startInd2 = findnext(":", respond, startInd)[end]+1 - reason = respond[startInd2:end] + if occursin(":", response[startInd:end]) # check for ":" after decision cha + startInd2 = findnext(":", response, startInd)[end]+1 + reason = response[startInd2:end] else - reason = respond[startInd:end] + reason = response[startInd:end] end return decision, reason end -#WORKING + """ Extract important info from text into key-value pair text. Arguments: @@ -1118,7 +1120,7 @@ Arguments: text, a text you want to extract info Return: - a text with important info are in key-value format. + key-value pair text. # Example ```jldoctest @@ -1130,29 +1132,64 @@ julia> extract(agent, text) ``` """ function extractinfo(a, text::T) where {T<:AbstractString} - + # determine whether there are any important info in an input text prompt = """ <|im_start|>system - User message: + User's message: $text - Your job is to extract important info from user's message into keys and values using this format: key=value ,. - p.s.1 you can extract many key-value pairs. + Your job is determine whether there are important info in the user's message. Answer: {Yes/No/Not sure} <|im_end|> - + Answer: """ + response = sendReceivePrompt(a, prompt, temperature=0.0) + if occursin("Yes", response) + prompt = + """ + <|im_start|>system + User's message: + $text + + Your job is to extract important info from the user's message into keys and values using this format: key=value,. + p.s.1 you can extract many key-value pairs. + <|im_end|> - respond = sendReceivePrompt(a, prompt, temperature=0.0) -end + """ + + response = sendReceivePrompt(a, prompt, temperature=0.0) + return response + else + return nothing + end +end -function updateEnvState(a, currentinfo, newinfo) +""" Update important info from key-value pair text into another key-value pair text. + +Arguments: + a, one of ChatAgent's agent + text, a key-value pair text + +Return: + updated key-value pair text + +# Example +```jldoctest +julia> using ChatAgent +julia> agent = ChatAgent.agentReflex("Jene") +julia> currentinfo = "location=beach, event=wedding party" +julia> newinfo = "wine_type=full body, dry and medium tannin\nprice_range=50 dollars" +julia> updateEnvState(agent, currentinfo, newinfo) +" location=beach, event=wedding party, wine_type=full body, dry and medium tannin, price_range=50 dollars" +``` +""" +function updateEnvState(a, newinfo) prompt = """ <|im_start|>system Current state: - $currentinfo + $(a.env) New info: $newinfo @@ -1162,7 +1199,7 @@ function updateEnvState(a, currentinfo, newinfo) Updated Current State:\n """ - respond = sendReceivePrompt(a, prompt, temperature=0.0) + response = sendReceivePrompt(a, prompt, temperature=0.0) end @@ -1179,4 +1216,51 @@ end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + end # module \ No newline at end of file diff --git a/src/type.jl b/src/type.jl index 1aedebb..4fa1e74 100644 --- a/src/type.jl +++ b/src/type.jl @@ -20,9 +20,9 @@ julia> mqttClientSpec = ( clientID= "$(uuid4())", broker= "mqtt.yiem.ai", pubtopic= (imgAI="img/api/v0.0.1/gpu/request", - txtAI="txt/api/v0.1.0/gpu/request"), - subtopic= (imgAI="agent/api/v0.1.0/img/respond", - txtAI="agent/api/v0.1.0/txt/respond"), + txtAI="txt/api/v0.1.0/gpu/request"), # this is where LLM server located + subtopic= (imgAI="agent/api/v0.1.0/img/respond", + txtAI="agent/api/v0.1.0/txt/respond"), # this is where this agent located keepalive= 30, ) julia> msgMeta = Dict( @@ -96,7 +96,7 @@ julia> agent = ChatAgent.agentReflex( attemptlimit::Int = 5 # thinking round limit attempt::Int = 0 # attempted number step::Int = 0 # step number - env::Dict = Dict() + env::AbstractString = "" thinkingFormat::Union{Dict, Nothing} = nothing memory::Dict = Dict( :shortterm=> OrderedDict{String, Any}(), diff --git a/src/utils.jl b/src/utils.jl index d150730..4eae588 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -59,28 +59,6 @@ end ```jldoctest julia> using JSON3, UUIDs, Dates, FileIO, CommUtils, ChatAgent - julia> mqttClientSpec = ( - clientName= "someclient", # name of this client - clientID= "$(uuid4())", - broker= "mqtt.yiem.ai", - pubtopic= (imgAI="img/api/v0.0.1/gpu/request", - txtAI="txt/api/v0.1.0/gpu/request"), - subtopic= (imgAI="agent/api/v0.1.0/img/respond", - txtAI="agent/api/v0.1.0/txt/respond"), - keepalive= 30, - ) - julia> msgMeta = Dict( - :msgPurpose=> "updateStatus", - :from=> "agent", - :to=> "llmAI", - :requestrespond=> "request", - :sendto=> "", # destination topic - :replyTo=> "agent/api/v0.1.0/txt/respond", # requester ask responder to send reply to this topic - :repondToMsgId=> "", # responder is responding to this msg id - :taskstatus=> "", # "complete", "fail", "waiting" or other status - :timestamp=> Dates.now(), - :msgId=> "$(uuid4())", - ) julia> newAgent = ChatAgent.agentReact( "Jene", mqttClientSpec, @@ -226,9 +204,9 @@ function extractStepFromPlan(a::agent, plan::T, step::Int) where {T<:AbstractStr """ - respond = sendReceivePrompt(a, prompt) + response = sendReceivePrompt(a, prompt) - return respond + return response end function checkTotalStepInPlan(a::agent) @@ -265,8 +243,8 @@ function checkTotalStepInPlan(a::agent) <|im_start|>assistant """ - respond = sendReceivePrompt(a, prompt) - result = extract_number(respond) + response = sendReceivePrompt(a, prompt) + result = extract_number(response) return result end @@ -351,13 +329,13 @@ end # """ # <|im_start|>system # {systemMsg} -# You always use tools if there is a chance to impove your respond. +# You always use tools if there is a chance to impove your response. # You have access to the following tools: # {tools} -# Your job is to determine whether you will use tools or actions to respond. +# Your job is to determine whether you will use tools or actions to response. # Choose one of the following choices: -# Choice 1: If you don't need to use tools or actions to respond to the stimulus say, "{no}". +# Choice 1: If you don't need to use tools or actions to response to the stimulus say, "{no}". # Choice 2: If you think the user want to get wine say, "{yes}". # <|im_end|> @@ -393,11 +371,10 @@ function isUseTools(a::agentReflex, usermsg::String) You have access to the following tools: {tools} - User message: + User's message: {input} - Your job is to answer the following questions: - Question 1: From the user's message, Do you need to any tools before responding? Answer: {Yes/No/Not sure}. What will the you do? + From the user's message, Do you need to any tools before responseing? Answer: {Yes/No/Not sure}. What will the you do? <|im_end|> <|im_start|>assistant Answer: @@ -415,9 +392,6 @@ function isUseTools(a::agentReflex, usermsg::String) result = sendReceivePrompt(a, prompt, temperature=0.2) - # headers = detectCharacters(result, ["Question 1:", "Question 2:"]) - # chunkedtext = chunktext(result, headers) - if occursin("Yes", result) return true else