From 9de820808c179a1f51345006fa68e644c3af5fdf Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 9 Feb 2024 19:39:04 +0700 Subject: [PATCH] update --- src/interface.jl | 308 ++++++++++++++++++++++++++++----------------- src/llmfunction.jl | 49 ++++---- src/type.jl | 2 +- 3 files changed, 216 insertions(+), 143 deletions(-) diff --git a/src/interface.jl b/src/interface.jl index 2c5e2b7..8f02f6b 100755 --- a/src/interface.jl +++ b/src/interface.jl @@ -308,100 +308,6 @@ function updatePlan(a::agentReflex) end -# function selfAwareness(a::agentReflex) - -# getonlykeys = ["Actinput", "Obs"] -# worknoplan = similar(a.memory[:shortterm]) -# for (k, v) in a.memory[:shortterm] -# count = 0 -# for i in getonlykeys -# if occursin(i, k) -# count += 1 -# end -# end -# if count != 0 -# worknoplan[k] = v -# end -# end - -# work = dictToString(worknoplan) - -# aboutYourself = -# """ -# Your name is $(a.agentName) -# $(a.roles[a.role]) - -# """ - -# prompt = -# """ -# <|system|> -# -# $aboutYourself -# $(a.roleSpecificInstruction[a.role]) -# -# -# $work -# -# -# $(JSON3.write(a.memory[:keyword])) -# -# -# Use the following format strictly: -# Info extraction: repeat all important info from the latest observed result thoroughly -# Info mapping: based on extracted info, explicitly state what each info could match which keyword memory's key -# Info matching: using JSON format, what key in my memory matches which info -# - -# -# -# The user wants to buy an electric SUV car under 20000 dollars. -# -# -# {"car type": null, "color": null, "financing": null} -# -# Info extraction: -# - The user is buying an electric SUV car. -# Info mapping: -# - SUV could matches "car type" key -# - electric could matches "engine type" key -# Info matching: {"car type": "SUV", "engine type": "electric motor", "color": null, "financing": null} -# -# -# <|assistant|> -# Info extraction: -# """ -# response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.2, timeout=180, -# stopword=["/n/n", "END", "End", "Obs", "<|", " @@ -514,6 +420,189 @@ function selfAwareness(a::agentReflex) return response end +function sentenceToKeywordMemory(a::agentReflex) + + getonlykeys = ["Actinput", "Obs"] + worknoplan = similar(a.memory[:shortterm]) + worklength = length(a.memory[:shortterm]) + for (i, (k, v)) in enumerate(a.memory[:shortterm]) + if i >= worklength - 1 + count = 0 + for i in getonlykeys + if occursin(i, k) + count += 1 + end + end + if count != 0 + worknoplan[k] = v + end + end + end + + println("") + @show worknoplan + + work = dictToString(worknoplan) + + aboutYourself = + """ + Your name is $(a.agentName) + $(a.roles[a.role]) + + """ + + prompt = + """ + + <|system|> + + $aboutYourself + $(a.roleSpecificInstruction[a.role]) + + + Use the following format strictly: + Info extraction: repeat all important info from the latest observed result thoroughly + Info mapping: based on extracted info, explicitly state what each info could match which keyword memory's key + Info matching: using JSON format, what key in my memory matches which info + + + + + The user wants to buy an electric SUV car under 20000 dollars. + + + {\"car type\": null, \"engine type\": null, \"price\": null, \"color\": null, \"financing\": null} + + <|assistant|> + Info extraction: + - The user is buying an electric SUV car. + - price is under 20000 dollars + Info mapping: + - "SUV" could matches "car type" key + - "electric" could matches "engine type" key + - "under 20000 dollars" could match "price" key + Info matching: {\"car type\": \"SUV\", \"engine type\": \"electric motor\", \"price\": \"under 20000\", \"color\": null, \"financing\": null} + + + + + $work + + + $(JSON3.write(a.memory[:keyword])) + + <|assistant|> + Info extraction: + """ + response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.2, timeout=180, + stopword=["/n/n", "END", "End", "Obs", "<|", "")[1] + response = "Info extraction:" * response + + println("") + @show selfaware_1 = response + + headerToDetect = ["Info extraction:", "Info mapping:", "Info matching:", "Actinput"] + headers = detectCharacters(response, headerToDetect) + + # headers[1:2] is for when LLM generate more than a paire of "Info extraction" and "Info matching", discard the rest + chunkedtext = chunktext(response, headers[1:3]) + println("") + _infomatch = chunkedtext["Info matching:"] + _infomatch = GeneralUtils.getStringBetweenCharacters(_infomatch, '{', '}', endCharLocation="end") + infomatch = GeneralUtils.JSON3read_stringKey(_infomatch) + # infomatch = copy(JSON3.read(_infomatch)) + + println("") + @show chunkedtext + + println("") + @show infomatch + + keywordMemoryUpdate!(a.memory[:keyword], infomatch) +end + +function keywordMemoryToPlanMatching(a::agentReflex) + + aboutYourself = + """ + Your name is $(a.agentName) + $(a.roles[a.role]) + + """ + + prompt = + """ + + <|system|> + + $aboutYourself + $(a.roleSpecificInstruction[a.role]) + + + Use the following format strictly: + Info mapping: explicitly state what each step of the plan could match which keyword memory's key + Info matching: using JSON format, what key in my memory matches which info + + + + + 1. ask the user for car type, + 2. ask the user for color + + + {\"car type\": "SUV", \"color\": null} + + <|assistant|> + Info mapping: + -In step 1 of the plan, I need to ask the user about the car type. From user info, the car type is "SUV". Therefore this step is done. + -In step 2 of the plan, I need to ask the user about the color . From user info, the color is null. Therefore this step is not done yet and I'll need to do this step. + + + + + $work + + + $(JSON3.write(a.memory[:keyword])) + + <|assistant|> + Info mapping: + """ + response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.2, timeout=180, + stopword=["/n/n", "END", "End", "Obs", "<|", "")[1] + response = "Info mapping:" * response + + println("") + @show keywordMemoryToPlanMatching = response + + error(1111) + + headerToDetect = ["Info extraction:", "Info mapping:", "Info matching:", "Actinput"] + headers = detectCharacters(response, headerToDetect) + + # headers[1:2] is for when LLM generate more than a paire of "Info extraction" and "Info matching", discard the rest + chunkedtext = chunktext(response, headers[1:3]) + println("") + _infomatch = chunkedtext["Info matching:"] + _infomatch = GeneralUtils.getStringBetweenCharacters(_infomatch, '{', '}', endCharLocation="end") + infomatch = GeneralUtils.JSON3read_stringKey(_infomatch) + # infomatch = copy(JSON3.read(_infomatch)) + + println("") + @show chunkedtext + + println("") + @show infomatch + + keywordMemoryUpdate!(a.memory[:keyword], infomatch) +end + # function actor_mistral_openorca(a::agentReflex, selfaware=nothing) # getonlykeys = ["Actinput", "Obs"] # worknoplan = similar(a.memory[:shortterm]) @@ -844,37 +933,19 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing) Use the following format: - Thought: based on what you know about the user, where are you at according to the plan? what to do next?. (PS. 1. let's think only one thing at a time. 2. pay attention to correct numeral calculation and commonsense.) + Thought: based on your user info, think about what to do to next according to the plan. (PS. 1. let's think only one thing at a time. 2. pay attention to correct numeral calculation and commonsense.) Act: based on your thought what action to choose?, must be one of [{toolnames}]. Actinput: your input to the action using JSON format (pay attention to the tool's input) Obs: observed result of the action - - - I'll ask the user for car type, brand, price, color, financing method and luxury level before I'll give them any advice. - - - - Car type is SUV - - Brand is Lexus - - Price is 20k dollar - - No info on the car color yet - - No info on the financing method yet - - Luxury level is high - - <|assistant|> - Thought: after checking what I know about the user against my plan, I still don't know the color and financing method yet. Next, I need to know what color the user like. - Act: askbox - Actinput: - - $(a.memory[:shortterm]["Plan 1:"]) - - $keywordmemory) - + + $keywordmemory + <|assistant|> Thought: """ @@ -890,7 +961,7 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing) while true # while Thought or Act is empty, run actor again - response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.4, timeout=300, + response = sendReceivePrompt(a, prompt, max_tokens=1024, temperature=0.0, timeout=300, stopword=["Thought:", "Obs:", "<|system|>", "", "<|end|>"], seed=rand(1000000:2000000)) println("") @@ -1246,6 +1317,7 @@ function actor(a::agentReflex) selfaware = nothing if length(a.memory[:shortterm]) > 2 # must have User:, Plan:, Thought:, Act:, Actinput: already selfaware = selfAwareness(a) + # result = keywordMemoryToPlanMatching(a) end actorResult = actor_mistral_openorca(a, selfaware) diff --git a/src/llmfunction.jl b/src/llmfunction.jl index f041c99..6108ecf 100644 --- a/src/llmfunction.jl +++ b/src/llmfunction.jl @@ -174,29 +174,29 @@ function winestock(a::agentReflex, input::NamedTuple) Dessert = table for wine type "dessert" Fortified = table for wine type "fortified" Intensity level: - intensity = 1, light bodied - intensity = 2, semi-light bodied - intensity = 3, medium bodied - intensity = 4, semi-full bodied - intensity = 5, full bodied + light bodied = 1 + semi-light bodied = 2 + medium bodied = 3 + semi-full bodied = 4 + full bodied = 5 Sweetness level: - sweetness = 1, dry - sweetness = 2, off-dry - sweetness = 3, semi-sweet - sweetness = 4, sweet - sweetness = 5, very sweet + dry = 1 + off-dry = 2 + semi-sweet = 3 + sweet = 4 + very sweet = 5 Tannin level: - tannin = 1, low tannin - tannin = 2, semi-low tannin - tannin = 3, medium tannin - tannin = 4, semi-high tannin - tannin = 5, high tannin + low tannin = 1 + semi-low tannin = 2 + medium tannin = 3 + semi-high tannin = 4 + high tannin = 4 Acidity level: - acidity = 1, low acidity - acidity = 2, semi-low acidity - acidity = 3, medium acidity - acidity = 4, semi-high acidity - acidity = 5, high acidity + low acidity = 1 + semi-low acidity = 2 + medium acidity = 3 + semi-high acidity = 4 + high acidity = 5 Write a specific SQL command from a query using a conversion table @@ -270,15 +270,13 @@ function winestock(a::agentReflex, input::NamedTuple) body = newsql uri = URI(scheme="http", host="192.168.88.12", port="9010", path="/sql", userinfo="root:root") r = HTTP.request("POST", uri, ["Accept" => "application/json", "NS"=>"yiem", "DB"=>"Blossom_wines"], body) - println("") - @show r + a.memory[:r] = r result = copy(JSON3.read(r.body)) wines = shuffle(result[1][:result]) # shuffle in case there are more than 1 result - println("") - @show wines + # choose only 2 wines if length(wines) > 2 @@ -286,6 +284,9 @@ function winestock(a::agentReflex, input::NamedTuple) wines = wines[1:2] end + println("") + @show wines + result = nothing if length(wines) == 0 result = diff --git a/src/type.jl b/src/type.jl index 12d8e6f..87e35ef 100644 --- a/src/type.jl +++ b/src/type.jl @@ -152,7 +152,7 @@ function agentReflex( """ Request the user’s input for the following info initially, and use alternative sources of information only if they are unable to provide it: - wine price range: ask the user - - wine type (Rose, White, Red, Rose, Sparkling, Dessert) + - wine type (rose, white, red, sparkling, dessert) - food type that will be served with wine - wine sweetness level (dry to very sweet) - wine intensity level (light to full bodied)