module interface export agentReact, agentReflex, addNewMessage, clearMessage, removeLatestMsg, conversation, writeEvaluationGuideline, grading, analyze, selfReflext using JSON3, DataStructures, Dates, UUIDs, HTTP using CommUtils, GeneralUtils using ..type, ..utils # ---------------------------------------------------------------------------- # # pythoncall setting # # ---------------------------------------------------------------------------- # # Ref: https://github.com/JuliaPy/PythonCall.jl/issues/252 # by setting the following variables, PythonCall will use system python or conda python and # packages installed by system or conda # if these setting are not set (comment out), PythonCall will use its own python and package that # installed by CondaPkg (from env_preparation.jl) # ENV["JULIA_CONDAPKG_BACKEND"] = "Null" # systemPython = split(read(`which python`, String), "\n")[1] # ENV["JULIA_PYTHONCALL_EXE"] = systemPython # find python location with $> which python ex. raw"/root/conda/bin/python" # using PythonCall # const py_agents = PythonCall.pynew() # const py_llms = PythonCall.pynew() # function __init__() # # PythonCall.pycopy!(py_cv2, pyimport("cv2")) # # equivalent to from urllib.request import urlopen in python # PythonCall.pycopy!(py_agents, pyimport("langchain.agents")) # PythonCall.pycopy!(py_llms, pyimport("langchain.llms")) # end #------------------------------------------------------------------------------------------------100 """ Add new message to agent. Args: Return: ```jldoctest julia> addNewMessage(agent1, "user", "Where should I go to buy snacks") ```` """ function addNewMessage(a::T1, role::String, content::T2) where {T1<:agent, T2<:AbstractString} if role ∉ a.availableRole # guard against typo error("role is not in agent.availableRole $(@__LINE__)") end # check whether user messages exceed limit userMsg = 0 for i in a.messages if i[:role] == "user" userMsg += 1 end end messageleft = 0 if userMsg > a.maxUserMsg # delete all conversation clearMessage(a) messageleft = a.maxUserMsg else userMsg += 1 d = Dict(:role=> role, :content=> content, :timestamp=> Dates.now()) push!(a.messages, d) messageleft = a.maxUserMsg - userMsg end return messageleft end function clearMessage(a::T) where {T<:agent} for i in eachindex(a.messages) if length(a.messages) > 1 # system instruction will NOT be deleted pop!(a.messages) else break end end a.thought = "nothing" end function removeLatestMsg(a::T) where {T<:agent} if length(a.messages) > 1 pop!(a.messages) end end # function generatePrompt_mistral_openorca(a::T, usermsg::String, role::Symbol) where {T<:agent} # prompt = # """ # <|im_start|>system # {systemMsg} # <|im_end|> # Here are the context for the question: # {context} # """ # prompt = replace(prompt, "{systemMsg}" => a.roles[role]) # toolnames = "" # toollines = "" # for (toolname, v) in a.tools # toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" # toollines *= toolline # toolnames *= "$toolname," # end # prompt = replace(prompt, "{toolnames}" => toolnames) # prompt = replace(prompt, "{tools}" => toollines) # prompt = replace(prompt, "{context}" => a.context) # prompt *= "<|im_start|>user\n" * usermsg * "\n<|im_end|>\n" # prompt *= "<|im_start|>assistant\n" # return prompt # end # function generatePrompt_mistral_openorca(a::T, usermsg::String, # thinkingMode::Symbol=:nothinking) where {T<:agent} # prompt = # """ # <|im_start|>system # {systemMsg} # You have access to the following tools: # {tools} # {thinkingMode} # <|im_end|> # Here are the context for the question: # {context} # """ # prompt = replace(prompt, "{systemMsg}" => a.roles[a.role]) # prompt = replace(prompt, "{thinkingMode}" => a.thinkingMode[thinkingMode]) # toolnames = "" # toollines = "" # for (toolname, v) in a.tools # toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" # toollines *= toolline # toolnames *= "$toolname," # end # prompt = replace(prompt, "{toolnames}" => toolnames) # prompt = replace(prompt, "{tools}" => toollines) # prompt = replace(prompt, "{context}" => a.context) # prompt *= "<|im_start|>user\nQuestion: " * usermsg * "\n<|im_end|>\n" # prompt *= "<|im_start|>assistant\n" # return prompt # end function generatePrompt_mistral_openorca(a::T, usermsg::String, thinkingMode::Symbol=:nothinking) where {T<:agent} prompt = """ <|im_start|>system {systemMsg} {tools} {thinkingMode} <|im_end|> Here are the context for the stimulus: {context} """ prompt = replace(prompt, "{systemMsg}" => a.roles[a.role]) prompt = replace(prompt, "{thinkingMode}" => a.thinkingMode[thinkingMode]) toolnames = "" toollines = "" for (toolname, v) in a.tools toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" toollines *= toolline toolnames *= "$toolname," end prompt = replace(prompt, "{toolnames}" => toolnames) prompt = replace(prompt, "{context}" => a.context) prompt *= "<|im_start|>user\nStimulus: " * usermsg * "\n<|im_end|>\n" prompt *= "<|im_start|>assistant\n" return prompt end function chat_mistral_openorca(a::agentReflex, usermsg::String) """ general prompt format: " <|im_start|>system {role} {tools} {thinkingFormat} <|im_end|> {context} <|im_start|>user {usermsg} <|im_end|> <|im_start|>assistant " Note: {context} = " {earlierConversation} {env state} {shortterm memory} {longterm memory} " """ prompt = """ <|im_start|>system {role} {thinkingFormat} <|im_end|> {context} <|im_start|>user {usermsg} <|im_end|> <|im_start|>assistant """ prompt = replace(prompt, "{role}" => a.roles[a.role]) prompt = replace(prompt, "{thinkingFormat}" => "") context = """ {earlierConversation} {env state} {longterm memory} """ context = replace(context, "{earlierConversation}" => "My earlier talk with the user:\n$(a.earlierConversation)") context = replace(context, "{env state}" => "") context = replace(context, "{longterm memory}" => "") prompt = replace(prompt, "{context}" => context) prompt = replace(prompt, "{usermsg}" => "Stimulus: $usermsg") return prompt end function planner_mistral_openorca(a::agentReflex, usermsg::String) """ general prompt format: " <|im_start|>system {role} {tools} {thinkingFormat} <|im_end|> {context} <|im_start|>user {usermsg} <|im_end|> <|im_start|>assistant " Note: {context} = " {earlierConversation} {env state} {shortterm memory} {longterm memory} " """ prompt = """ <|im_start|>system {role} {tools} {thinkingFormat} <|im_end|> {context} <|im_start|>user {usermsg} <|im_end|> <|im_start|>assistant """ prompt = replace(prompt, "{role}" => a.roles[a.role]) prompt = replace(prompt, "{thinkingFormat}" => a.thinkingFormat[:planner]) toolnames = "" toollines = "" for (toolname, v) in a.tools toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" toollines *= toolline toolnames *= "$toolname," end prompt = replace(prompt, "{toolnames}" => toolnames) prompt = replace(prompt, "{tools}" => "You have access to the following tools:\n$toollines") context = """ {earlierConversation} {env state} {longterm memory} """ context = replace(context, "{earlierConversation}" => "My earlier talk with the user:\n$(a.earlierConversation)") context = replace(context, "{env state}" => "") context = replace(context, "{longterm memory}" => "") prompt = replace(prompt, "{context}" => context) prompt = replace(prompt, "{usermsg}" => "Stimulus: $usermsg") return prompt end function actor_mistral_openorca(a::agentReflex, usermsg::T) where {T<:AbstractString} """ general prompt format: " <|im_start|>system {role} {tools} {thinkingFormat} <|im_end|> {context} <|im_start|>user {usermsg} <|im_end|> <|im_start|>assistant " Note: {context} = " {earlierConversation} {env state} {shortterm memory} {longterm memory} " """ prompt = """ <|im_start|>system {role} {tools} {thinkingFormat} <|im_end|> {context} <|im_start|>user {usermsg} <|im_end|> <|im_start|>assistant """ prompt = replace(prompt, "{role}" => a.roles[a.role]) prompt = replace(prompt, "{thinkingFormat}" => a.thinkingFormat[:actor]) toolnames = "" toollines = "" for (toolname, v) in a.tools toolline = "$toolname: $(v[:description]) $(v[:input]) $(v[:output])\n" toollines *= toolline toolnames *= "$toolname, " end prompt = replace(prompt, "{toolnames}" => toolnames) prompt = replace(prompt, "{tools}" => "You have access to the following tools:\n$toollines") context = """ {env state} {longterm memory} """ # context = replace(context, "{earlierConversation}" => "My earlier talk with the user:\n$(a.earlierConversation)") context = replace(context, "{env state}" => "") context = replace(context, "{longterm memory}" => "") prompt = replace(prompt, "{context}" => context) prompt = replace(prompt, "{usermsg}" => "Stimulus: $usermsg") return prompt end """ Chat with llm. ```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, role=:assistant_react, msgMeta=msgMeta ) julia> respond = ChatAgent.conversation(newAgent, "Hi! how are you?") ``` """ function conversation(a::T, usermsg::String) where {T<:agent} respond = nothing if a.thought != "nothing" # continue thought _ = addNewMessage(a, "user", usermsg) a.thought *= "Obs $(a.thinkinground): $usermsg\n" prompt = a.thought respond = work(a, prompt) else # new thought thinkingmode = chooseThinkingMode(a, usermsg) @show thinkingmode if thinkingmode == :no_thinking a.context = conversationSummary(a) #TODO should be long conversation before use summary because it leaves out details _ = addNewMessage(a, "user", usermsg) prompt = generatePrompt_mistral_openorca(a, usermsg, thinkingmode) @show prompt respond = sendReceivePrompt(a, prompt) respond = split(respond, "<|im_end|>")[1] respond = replace(respond, "\n" => "") _ = addNewMessage(a, "assistant", respond) @show respond elseif thinkingmode == :thinking a.context = conversationSummary(a) _ = addNewMessage(a, "user", usermsg) prompt = generatePrompt_mistral_openorca(a, usermsg, thinkingmode) respond = work(a, prompt) else error("undefined condition thinkingmode = $thinkingmode $(@__LINE__)") end end return respond end """ Continuously run llm functions except when llm is getting Answer: or chatbox. There are many work() depend on thinking mode. """ function work(a::T, prompt::String, maxround::Int=3) where {T<:agent} respond = nothing while true a.thinkinground += 1 @show a.thinkinground toolname = nothing toolinput = nothing if a.thinkinground > a.thinkingroundlimit a.thought *= "Thought $(a.thinkinground): I think I know the answer." prompt = a.thought end @show prompt respond = sendReceivePrompt(a, prompt) headerToDetect = nothing if a.thinkinground == 1 try respond = split(respond, "Obs:")[1] headerToDetect = ["Question:", "Plan:", "Thought:", "Act:", "ActInput:", "Obs:", "...", "Answer:", "Conclusion:", "Summary:"] catch end else try 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):", "...", "Answer:", "Conclusion:", "Summary:"] catch end end @show respond headers = detectCharacters(respond, headerToDetect) chunkedtext = chunktext(respond, headers) Answer = findDetectedCharacter(headers, "Answer:") AnswerInd = length(Answer) != 0 ? Answer[1] : nothing Act = findDetectedCharacter(headers, "Act $(a.thinkinground):") if length(Answer) == 1 && length(Act) == 0 a.thought = "nothing" # assignment finished, no more thought a.context = "nothing" a.thinkinground = 0 respond = chunkedtext[AnswerInd][:body] respond = replace(respond, "<|im_end|>"=>"") _ = addNewMessage(a, "assistant", respond) break else # check for tool being called ActHeader = a.thinkinground == 1 ? "Act:" : "Act $(a.thinkinground):" if length(findDetectedCharacter(headers, ActHeader)) != 0 # check whether there is Act: in a respond 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] end # clean up if occursin(" \"", toolinput) toolinput = GeneralUtils.getStringBetweenCharacters(toolinput, " \"", "\"\n") else toolinput = GeneralUtils.getStringBetweenCharacters(toolinput, " ", "\n") end @show toolname @show toolinput if toolname === nothing || toolinput === nothing println("toolname $toolname toolinput $toolinput retry thinking") a.thinkinground -= 1 continue end if a.thought == "nothing" thought = "" for i in chunkedtext header = i[:header] header = replace(header, ":"=>" $(a.thinkinground):") # add number so that llm not confused body = i[:body] thought *= "$header $body" end a.thought = prompt * thought else a.thought *= respond end if toolname == "chatbox" # chat with user a.thought *= toolinput respond = toolinput _ = addNewMessage(a, "assistant", respond) break else # function call f = a.tools[Symbol(toolname)][:func] _result = f(toolinput) if _result != "No info available." #TODO for use with wikisearch(). Not good for other tools _result = makeSummary(a, _result) end result = "Obs $(a.thinkinground): $_result\n" a.thought *= result prompt = a.thought end end end @show respond return respond end function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3) a.attemptlimit = attemptlimit respond = nothing # determine thinking mode a.thinkingmode = chooseThinkingMode(a, usermsg) @show a.thinkingmode if a.thinkingmode == :no_thinking a.earlierConversation = conversationSummary(a) #TODO should be long conversation before use summary because it leaves out details _ = addNewMessage(a, "user", usermsg) prompt = chat_mistral_openorca(a, usermsg) @show prompt respond = sendReceivePrompt(a, prompt) respond = split(respond, "<|im_end|>")[1] respond = replace(respond, "\n" => "") _ = addNewMessage(a, "assistant", respond) @show respond else respond = work(a, usermsg) end return respond end function work(a::agentReflex, usermsg::String) respond = nothing if a.thinkingmode == :new_thinking a.earlierConversation = conversationSummary(a) _ = addNewMessage(a, "user", usermsg) a.thoughtlog = "user: $usermsg\n" elseif a.thinkingmode == :continue_thinking #TODO error("continue_thinking $(@__LINE__)") _ = addNewMessage(a, "user", usermsg) a.thought *= "Obs $(a.attempt): $usermsg\n" else error("undefined condition thinkingmode = $thinkingmode $(@__LINE__)") end while true # Work loop # plan a.attempt += 1 @show a.attempt @show usermsg if a.attempt <= a.attemptlimit logmsg = "user: $usermsg\n" a.memory[:shortterm] *= logmsg toolname = nothing toolinput = nothing prompt = planner_mistral_openorca(a, usermsg) @show prompt respond = sendReceivePrompt(a, prompt) plan = split(respond, "<|im_end|>")[1] plan = split(plan, "Response:")[1] _plan = replace(plan, "Plan:"=>"Plan $(a.attempt):") logmsg = "assistant: $_plan\n" a.memory[:shortterm] *= logmsg a.thoughtlog *= logmsg actorstate, msgToUser = actor(a, plan) if actorstate == "chatbox" respond = msgToUser break elseif actorstate == "all steps done" println("all steps done") #WORKING give answer to the question respond = formulateRespond(a, a.memory[:shortterm]) a.memory[:shortterm] *= "Respond: $respond\n" #TODO evaluate. if score < 8/10 try again. headerToDetect = ["user:", "assistant:", ] headers = detectCharacters(a.memory[:shortterm], headerToDetect) chunkedtext = chunktext(a.memory[:shortterm], headers) stimulus = chunkedtext["user:"] guideline = writeEvaluationGuideline(a, stimulus) @show guideline score = grading(a, guideline, respond) @show score if score >= 8 # good enough answer @show a.memory[:shortterm] a.memory[:shortterm] = "" a.thoughtlog = "" break else # self evaluate and reflect then try again report = analyze(a, a.memory[:shortterm]) @show report lessonwithcontext = selfReflext(a, report) @show lessonwithcontext a.memory[:shortterm] = "" #TODO add lesson and context into longterm memory headerToDetect = ["Lesson:", "Context:", ] headers = detectCharacters(lessonwithcontext, headerToDetect) chunkedtext = chunktext(lessonwithcontext, headers) @show chunkedtext push!(a.memory[:longterm], Dict(:context=>chunkedtext["Context:"], :lesson=>chunkedtext["Lesson:"])) error(">>>>>>>>>>") end else error("undefied condition, actorstate $actorstate $(@__LINE__)") break end else #TODO attempt limit reached, force AI to answer error("attempt limit reach") break end end # good enough answer # communicates with user _ = addNewMessage(a, "assistant", respond) return respond end function evaluate() end """ Actor function. Args: a, one of ChatAgent's agent. plan, a step by step plan to respond Return: case 1) if actor complete the plan successfully. actorState = "all steps done" inidicates that all step in plan were done. msgToUser = nothing. case 2) if actor needs to talk to user for more context actorState = "chatbox" msgToUser = "message from assistant to user" """ function actor(a::agentReflex, plan::T) where {T<:AbstractString} actorState = nothing msgToUser = nothing @show plan totalsteps = checkTotalStepInPlan(a, plan) a.step = 0 while true # Actor loop a.step += 1 @show a.step if a.step <= totalsteps stepdetail = extractStepFromPlan(a, plan, a.step) prompt = actor_mistral_openorca(a, stepdetail) @show prompt respond = sendReceivePrompt(a, prompt) respond = split(respond, "<|im_end|>")[1] @show respond headerToDetect = ["Question:", "Plan:", "Thought:", "Act:", "ActInput:", "Obs:", "...", "Answer:", "Conclusion:", "Summary:"] headers = detectCharacters(respond, headerToDetect) # add to memory _respond = addStepNumber(respond, headers, a.step) a.memory[:shortterm] *= _respond a.thoughtlog *= _respond chunkedtext = chunktext(respond, headers) toolname = toolNameBeingCalled(chunkedtext["Act:"], a.tools) toolinput = chunkedtext["ActInput:"] @show toolname @show toolinput if toolname == "chatbox" # chat with user respond = toolinput msgToUser = respond actorState = toolname break else # function call f = a.tools[Symbol(toolname)][:func] result = f(a, toolinput) _result = "\nObs $(a.step): $result\n" a.memory[:shortterm] *= _result a.thoughtlog *= _result msgToUser = result end else #TODO finish all steps actorState = "all steps done" msgToUser = nothing break end end return actorState, msgToUser end """ Write evaluation guideline. Args: a, one of ChatAgent's agent. usermsg, stimulus e.g. question, task and etc. Return: An evaluation guideline used to guage AI's work. # Example ```jldoctest julia> using ChatAgent, CommUtils julia> agent = ChatAgent.agentReflex("Jene") julia> usermsg = "What's AMD latest product?" " julia> evaluationGuideLine = writeEvaluationGuideline(agent, usermsg) ``` """ function writeEvaluationGuideline(a::agentReflex, usermsg::T) where {T<:AbstractString} prompt = """ <|im_start|>system You have access to the following tools: chatbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer. wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question. Your work: $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. <|im_end|> """ respond = sendReceivePrompt(a, prompt) return respond end """ Determine a score out of 10 according to evaluation guideline. Args: a, one of ChatAgent's agent. guidelines, an evaluation guideline. shorttermMemory, a short term memory that logs what happened. Return: A score out of 10 based on guideline. # Example ```jldoctest julia> using ChatAgent, CommUtils julia> agent = ChatAgent.agentReflex("Jene") julia> shorttermMemory = " user: What's AMD latest product? assistant: Plan 1: To provide the user with information about AMD's latest product, I will search for the most recent product release from AMD. 1. Search for \"AMD latest product\" using wikisearch tool. 2. Identify the most recent product release mentioned in the search results. 3. Provide the user with the name of the latest product. Thought 1: The user wants to know about the latest AMD products, so I should use the wikisearch tool to find information on this topic. Act 1: wikisearch ActInput 1: \"AMD latest product\" Obs 1: No info available." 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) 2 ``` """ function grading(a, guideline::T, text::T) where {T<:AbstractString} prompt = """ <|im_start|>system You have access to the following tools: chatbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer. wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question. $guideline Your respond: $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. Use the following format to answer: {Evaluation} Score {}/10. <|im_end|> """ println("prompt 11 ", prompt) respond = sendReceivePrompt(a, prompt) println("grading respond 11 = $respond") _score = split(respond[end-5:end], "/")[1] _score = split(_score, " ")[end] score = parse(Int, _score) return score end """ Analize work. Args: a, one of ChatAgent's agent. Return: A report of analized work. # Example ```jldoctest julia> using ChatAgent, CommUtils julia> agent = ChatAgent.agentReflex("Jene") julia> shorttermMemory = " user: What's AMD latest product? assistant: Plan 1: To provide the user with information about AMD's latest product, I will search for the most recent product release from AMD. 1. Search for \"AMD latest product\" using wikisearch tool. 2. Identify the most recent product release mentioned in the search results. 3. Provide the user with the name of the latest product. Thought 1: The user wants to know about the latest AMD products, so I should use the wikisearch tool to find information on this topic. Act 1: wikisearch ActInput 1: \"AMD latest product\" Obs 1: No info available." julia> report = analyze(agent, shorttermMemory) ``` """ function analyze(a, shorttermMemory::T) where {T<:AbstractString} prompt = """ <|im_start|>system You have access to the following tools: chatbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer. wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question. Your work: $shorttermMemory Do each of the following steps in detail to analize your work. 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. Do relationships behaved differently than your expectation? If yes, why? 5. What could you do to improve the respond? <|im_end|> """ respond = sendReceivePrompt(a, prompt, max_tokens=2048) return respond end """ Write a lesson drawn from evaluation. Args: a, one of ChatAgent's agent. report, a report resulted from analyzing shorttermMemory Return: A lesson. # Example ```jldoctest julia> using ChatAgent, CommUtils julia> agent = ChatAgent.agentReflex("Jene") julia> report = "What happened: I tried to search for AMD's latest product using the wikisearch tool, but no information was available in the search results. Cause and effect relationships: 1. Searching \"AMD latest product\" -> No info available. 2. Searching \"most recent product release\" -> No info available. 3. Searching \"latest product\" -> No info available. Analysis of each relationship: 1. The search for \"AMD latest product\" did not provide any information because the wikisearch tool could not find relevant results for that query. 2. The search for \"most recent product release\" also did not yield any results, indicating that there might be no recent product releases available or that the information is not accessible through the wikisearch tool. 3. The search for \"latest product\" similarly resulted in no information being found, suggesting that either the latest product is not listed on the encyclopedia or it is not easily identifiable using the wikisearch tool. Improvements: To improve the response, I could try searching for AMD's products on a different source or search engine to find the most recent product release. Additionally, I could ask the user for more context or clarify their question to better understand what they are looking for." julia> lesson = selfReflext(agent, report) ``` """ function selfReflext(a, report::T) where {T<:AbstractString} prompt = """ <|im_start|>system You have access to the following tools: chatbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer. wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question. Your report: $report Your job are: 1. Lesson: what lesson could you learn from your report?. 2. Context: what is the context this lesson could apply to? <|im_end|> """ respond = sendReceivePrompt(a, prompt, max_tokens=2048) return respond end """ Formulate a respond from work for user's stimulus. Args: a, one of ChatAgent's agent. Return: A respond for user's stimulus. # Example ```jldoctest julia> using ChatAgent, CommUtils julia> agent = ChatAgent.agentReflex("Jene") julia> shorttermMemory = " user: What's AMD latest product? assistant: Plan 1: To provide the user with information about AMD's latest product, I will search for the most recent product release from AMD. 1. Search for \"AMD latest product\" using wikisearch tool. 2. Identify the most recent product release mentioned in the search results. 3. Provide the user with the name of the latest product. Thought 1: The user wants to know about the latest AMD products, so I should use the wikisearch tool to find information on this topic. Act 1: wikisearch ActInput 1: \"AMD latest product\" Obs 1: No info available." julia> report = formulateRespond(agent, shorttermMemory) ``` """ function formulateRespond(a, shorttermMemory::T) where {T<:AbstractString} prompt = """ <|im_start|>system You have access to the following tools: chatbox: Useful for when you need to ask a customer for more context. Input should be a conversation to customer. wikisearch: Useful for when you need to search an encyclopedia Input is keywords and not a question. Symbol: Stimulus: the input user gives to you and you must respond Plan: a plan Thought: your thought Act: the action you took ActInput: the input to the action Obs: the result of the action Your work: $shorttermMemory From your work, formulate a respond for user's stimulus. <|im_end|> """ respond = sendReceivePrompt(a, prompt) return respond end end # module