diff --git a/src/interface.jl b/src/interface.jl
index 7cc276c..d9cce19 100644
--- a/src/interface.jl
+++ b/src/interface.jl
@@ -33,6 +33,17 @@ using ..type, ..util, ..llmfunction, ..mcts
# ---------------------------------------------- 100 --------------------------------------------- #
+macro executeStringFunction(functionStr, args...)
+ # Parse the function string into an expression
+ func_expr = Meta.parse(functionStr)
+
+ # Create a new function with the parsed expression
+ function_to_call = eval(Expr(:function, Expr(:call, func_expr, args...), func_expr.args[2:end]...))
+
+ # Call the newly created function with the provided arguments
+ function_to_call(args...)
+end
+
""" Think and choose action
# Arguments
@@ -97,9 +108,9 @@ function decisionMaker(a::T1, state::T2)::String where {T1<:agent, T2<:AbstractD
You should only respond with interleaving step-by-step Thought, Action, Observation steps.
Thought can reason about the current situation, and Action can be three types:
- 1) Chatbox[text], which you can use to interact with the user.
- 2) Winestock[query], which you can use to find wine in your inventory.
- 3) Finish[answer], which returns your wine reccommendation to the user.
+ 1) winestock[query], which you can use to find wine in your inventory.
+ 2) chatbox[text], which you can use to interact with the user.
+ 3) finish[answer], which returns your wine reccommendation to the user.
You should only respond in JSON format as describe below:
{
@@ -115,15 +126,15 @@ function decisionMaker(a::T1, state::T2)::String where {T1<:agent, T2<:AbstractD
{
"Question": "I would like to buy a sedan.",
"Thought_1": "I have many cars in my inventory suitable for several usage scenarios.",
- "Thought_2": "It would be better if I knew what the user intends to do with his car."1,
+ "Thought_2": "It would be better if I knew what the user intends to do with his car.",
"Thought_3": "I will ask the user what is the intended usecase",
- "Action_1": {"action": "Chatbox", "input": "What will you use it for?"}
+ "Action_1": {"action": "chatbox", "input": "What will you use it for?"}
}
{
"Question": "I'm looking for a sedan.",
"Thought_1": "I have many types of sedans in my inventory, each with diverse features.",
"Thought_2": "It would be easier to make a recommendation if I knew what feature the user is looking for. I should ask the user.",
- "Action_1": {"action": "Chatbox", "input": "Do you have any specific feature in mind?"}
+ "Action_1": {"action": "chatbox", "input": "Do you have any specific feature in mind?"}
}
$reflect
@@ -157,25 +168,20 @@ end
"""
- Arguments\n
- -----
-
- Return\n
- -----
+# Arguments
+
+# Return
- Example\n
- -----
- ```jldoctest
- julia>
- ```
+# Example
+```jldoctest
+julia>
+```
- TODO\n
- -----
- [] update docstring
- [] implement the function
+# TODO
+ - [] update docstring
+ - [] implement the function
- Signature\n
- -----
+# Signature
"""
function stateValueEstimator()
@@ -184,25 +190,20 @@ end
"""
- Arguments\n
- -----
-
- Return\n
- -----
+# Arguments
+
+# Return
- Example\n
- -----
- ```jldoctest
- julia>
- ```
+# Example
+```jldoctest
+julia>
+```
- TODO\n
- -----
- [] update docstring
- [] implement the function
+# TODO
+ - [] update docstring
+ - [] implement the function
- Signature\n
- -----
+# Signature
"""
function reflector()
@@ -211,91 +212,80 @@ end
"""
- Arguments\n
- -----
-
- Return\n
- -----
+# Arguments
+
+# Return
- Example\n
- -----
- ```jldoctest
- julia>
- ```
+# Example
+```jldoctest
+julia>
+```
- TODO\n
- -----
- [] update docstring
- [] implement the function
- [] implement RAG to pull similar experience
+# TODO
+ - [] update docstring
+ - [] implement the function
- Signature\n
- -----
+# Signature
"""
function isterminal()
end
-
-
""" Chat with llm.
- Arguments\n
- -----
- a::agent
- an agent
-
- Return\n
- -----
- None
+# Arguments
+ `a::agent`
+ an agent
+
+# Return
+ None
- Example\n
- -----
- ```jldoctest
- julia> using JSON3, UUIDs, Dates, FileIO, MQTTClient, ChatAgent
- julia> const mqttBroker = "mqtt.yiem.cc"
- julia> mqttclient, connection = MakeConnection(mqttBroker, 1883)
- julia> tools=Dict( # update input format
- "askbox"=>Dict(
- :description => "Useful for when you need to ask the user for more context. Do not ask the user their own question.",
- :input => "Input is a text in JSON format.{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}",
- :output => "" ,
- :func => nothing,
- ),
- )
- julia> msgMeta = Dict(
- :msgPurpose=> "updateStatus",
- :from=> "agent",
- :to=> "llmAI",
- :requestresponse=> "request",
- :sendto=> "", # destination topic
- :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())",
- )
- julia> a = ChatAgent.agentReflex(
- "Jene",
- mqttclient,
- msgMeta,
- agentConfigTopic, # I need a function to send msg to config topic to get load balancer
- role=:sommelier,
- tools=tools
- )
- julia> newAgent = ChatAgent.agentReact(agent)
- julia> response = ChatAgent.conversation(newAgent, "Hi! how are you?")
- ```
+# Example
+```jldoctest
+julia> using JSON3, UUIDs, Dates, FileIO, MQTTClient, ChatAgent
+julia> const mqttBroker = "mqtt.yiem.cc"
+julia> mqttclient, connection = MakeConnection(mqttBroker, 1883)
+julia> tools=Dict( # update input format
+ "askbox"=>Dict(
+ :description => "Useful for when you need to ask the user for more context. Do not ask the user their own question.",
+ :input => "Input is a text in JSON format.{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}",
+ :output => "" ,
+ :func => nothing,
+ ),
+ )
+julia> msgMeta = Dict(
+ :msgPurpose=> "updateStatus",
+ :from=> "agent",
+ :to=> "llmAI",
+ :requestresponse=> "request",
+ :sendto=> "", # destination topic
+ :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())",
+)
+julia> a = ChatAgent.agentReflex(
+ "Jene",
+ mqttclient,
+ msgMeta,
+ agentConfigTopic, # I need a function to send msg to config topic to get load balancer
+ role=:sommelier,
+ tools=tools
+ )
+julia> newAgent = ChatAgent.agentReact(agent)
+julia> response = ChatAgent.conversation(newAgent, "Hi! how are you?")
+```
- Signature\n
- -----
+# TODO
+- [] update docstring
+- [PENDING] MCTS() for planning
+
+# Signature
"""
function conversation(a::T, userinput::Dict) where {T<:agent}
- """
- [] update document
- [PENDING] MCTS() for planning
- """
+
# "newtopic" command to delete chat history
if userinput[:text] == "newtopic"
clearhistory(a)
diff --git a/src/llmfunction.jl b/src/llmfunction.jl
index d90968f..ee30e5c 100644
--- a/src/llmfunction.jl
+++ b/src/llmfunction.jl
@@ -8,6 +8,286 @@ using ..type, ..util
# ---------------------------------------------- 100 --------------------------------------------- #
+"""
+
+# Arguments
+
+# Return
+
+# Example
+```jldoctest
+julia>
+```
+
+# TODO
+ - [] update docstring
+ - [] implement the function
+
+# Signature
+"""
+function chatbox(input::T) where {T<:AbstractString}
+ # put in model format
+end
+
+""" Search wine in stock.
+
+ Arguments\n
+ a : one of ChatAgent's agent.
+ Return\n
+ A JSON string of available wine
+
+ Example\n
+ ```jldoctest
+ julia> using ChatAgent
+ julia> agent = ChatAgent.agentReflex("Jene")
+ julia> input = "{\"food\": \"pizza\", \"occasion\": \"anniversary\"}"
+ julia> result = winestock(agent, input)
+ "{"wine 1": {\"Winery\": \"Pichon Baron\", \"wine name\": \"Pauillac (Grand Cru Classé)\", \"grape variety\": \"Cabernet Sauvignon\", \"year\": 2010, \"price\": \"125 USD\", \"stock ID\": \"ar-17\"}, }"
+ ```
+"""
+# function winestock(a::agentReflex, input::NamedTuple)
+# println("")
+# @show input
+
+# wineSearchCriteria = GeneralUtils.JSON3read_stringKey(input[:toolinput])
+# newDict = Dict{String,Any}()
+# for (k,v) in wineSearchCriteria
+# println("k $k v $v")
+# newDict[string(k)] = v
+# end
+
+# #TODO temporary delete key "food pairing from a dict
+# newDict = deepcopy(a.memory[:keyword])
+# delete!(newDict, "food pairing")
+
+# query = JSON3.write(newDict)
+
+# println("")
+# @show query
+
+# # prompt =
+# # """
+# # <|system|>
+# #
+# # Your are a helpful assistant.
+# #
+# #
+# # Database table name by wine type:
+# # Red = table for wine type "red"
+# # White = table for wine type "white"
+# # Sparkling = table for wine type "sparkling"
+# # Rose = table for wine type "rose"
+# # 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
+# # Sweetness level:
+# # sweetness = 1, dry
+# # sweetness = 2, off-dry
+# # sweetness = 3, semi-sweet
+# # sweetness = 4, sweet
+# # sweetness = 5, very sweet
+# # Tannin level:
+# # tannin = 1, low tannin
+# # tannin = 2, semi-low tannin
+# # tannin = 3, medium tannin
+# # tannin = 4, semi-high tannin
+# # tannin = 5, high tannin
+# # Acidity level:
+# # acidity = 1, low acidity
+# # acidity = 2, semi-low acidity
+# # acidity = 3, medium acidity
+# # acidity = 4, semi-high acidity
+# # acidity = 5, high acidity
+# #
+# #
+# # Consult the conversion table then write a specific SQL command using only available info from a JSON-format query.
+# # List of keywords not allowed in SQL: ["BETWEEN", "--", "WHEN", "IN"]
+
+# # Use the following format:
+# # Info map: based on conversion table, map the info in query to appropriate variables
+# # SQL: write a specific SQL command
+# #
+# #
+# # query: {\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | low to medium tannin\", \"price\": {\"max\": \"50\"}}
+# # Think: 1) low to medium tannin is not explicitly stated, but assuming it falls within the range of low-medium tannin.
+# # Info map: {\"wine type\": \"white\", \"intensity\": 5, \"sweetness\": 2, \"tannin\": 2, \"acidity\": 1, \"price\": 50}
+# # SQL: SELECT * FROM White WHERE intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 2 AND price <= 50;
+# #
+# #
+# # query: {\"wine characteristics\":\"low-bodied | a little sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
+# # Think: 1) medium sweet is not explicitly stated, but assuming it falls within the range of dry and off-dry.
+# # Info map: {\"wine type\": \"Rose\", \"intensity\": 1, \"sweetness\": 3, \"tannin\": 2, \"acidity\": 3, \"price\": 22, \"food\":\"American dishes\"}
+# # SQL: SELECT * FROM Rose WHERE intensity = 1 AND tannin = 2 AND (sweetness = 1 OR sweetness = 2) AND price <= 22 AND food = American;
+# #
+# #
+# # <|query|>
+# # $query
+# #
+# # <|assistant|>
+# # """
+
+# prompt =
+# """
+#
+# <|system|>
+#
+# Your are a helpful assistant.
+#
+#
+# Database table name by wine type:
+# Red = table for wine type "red"
+# White = table for wine type "white"
+# Sparkling = table for wine type "sparkling"
+# Rose = table for wine type "rose"
+# Dessert = table for wine type "dessert"
+# Fortified = table for wine type "fortified"
+# Intensity level:
+# light bodied = 1
+# semi-light bodied = 2
+# medium bodied = 3
+# semi-full bodied = 4
+# full bodied = 5
+# Sweetness level:
+# dry or low = 1
+# off-dry or semi-low = 2
+# semi-sweet = 3
+# sweet = 4
+# very sweet = 5
+# Tannin level:
+# low tannin = 1
+# semi-low tannin = 2
+# medium tannin = 3
+# semi-high tannin = 4
+# high tannin = 4
+# Acidity level:
+# 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
+# List of keywords not allowed the command: ["BETWEEN", "--", "WHEN", "IN"]
+
+# Use the following format:
+# Info map: based on conversion table, map the info in query to appropriate variables
+# SQL: write a specific SQL command
+#
+# |system|>
+#
+#
+# {\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | low to medium tannin\", \"price\": {\"max\": \"50\"}}
+#
+# <|assistant|>
+# Think: 1) low to medium tannin is not explicitly stated, but assuming it falls within the range of low-medium tannin.
+# Info map: {\"wine type\": \"white\", \"intensity\": 5, \"sweetness\": 2, \"tannin\": 2, \"acidity\": 1, \"price\": 50}
+# SQL: SELECT * FROM wines WHERE wine_type = "red" AND intensity = 5 AND sweetness = 2 AND acidity = 1 AND tannin = 2 AND price <= 50;
+# |assistant|>
+#
+#
+#
+# {\"wine characteristics\":\"low-bodied | a little sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
+#
+# <|assistant|>
+# Think: 1) medium sweet is not explicitly stated, but assuming it falls within the range of dry and off-dry.
+# Info map: {\"wine type\": \"Rose\", \"intensity\": 1, \"sweetness\": 3, \"tannin\": 2, \"acidity\": 3, \"price\": 22, \"food\":\"American dishes\"}
+# SQL: SELECT * FROM wines WHERE wine_type = "white" AND intensity = 1 AND tannin = 2 AND (sweetness = 1 OR sweetness = 2) AND price <= 22 AND food = American;
+# |assistant|>
+#
+#
+#
+# $query
+#
+# <|assistant|>
+# """
+
+# println("")
+# @show db_prompt = prompt
+# _sql = nothing
+# while true
+# _sql = sendReceivePrompt(a, prompt, a.config[:text2text][:mqtttopic],
+# max_tokens=1024, temperature=0.4, timeout=180,
+# stopword=["Thought:", "Obs:", "<|system|>", "", "<|end|>", "<|user|>"])
+# _sql = split(_sql, ";")[1] * ";"
+# @show _sql
+# # check for valid SQL command
+# check_1 = occursin("BETWEEN", _sql)
+# check_2 = occursin("--", _sql)
+# check_3 = occursin("IN", _sql)
+
+# if check_1 == false && check_2 == false && check_3 == false
+# break
+# end
+# println("invalid SQL command")
+# end
+
+# _sql = split(_sql, "SQL:")[end]
+# println("")
+# @show db_sql = replace(_sql, '\n'=>"")
+
+# # remove any blank character in front of a string
+# newsql = nothing
+# for i in eachindex(db_sql)
+# if db_sql[i] != ' '
+# newsql = db_sql[i:end]
+# break
+# end
+# end
+
+
+# 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"=>"wines"], body)
+
+# # a.memory[:r] = r
+# result = copy(JSON3.read(r.body))
+
+
+# wines = shuffle(result[1][:result]) # shuffle in case there are more than 1 result
+
+
+# # choose only 2 wines
+# if length(wines) > 2
+# println("$(length(wines)) wines found")
+# wines = wines[1:2]
+# end
+
+# println("")
+# @show wines
+
+# result = nothing
+# if length(wines) == 0
+# result =
+# """
+# No wine match my search query.
+# """
+# else
+# # write wines dictionary in to string
+# wines_str = ""
+# for (i, wine) in enumerate(wines)
+# winename = wine[:wine_name]
+# wines_str *= "$i: $(JSON3.write(wines[i])),"
+# end
+
+# result =
+# """
+# I found the following wines in our stock:
+# {
+# $wines_str
+# }
+# """
+# end
+
+# @show result
+
+# return result
+# end
diff --git a/src/mcts.jl b/src/mcts.jl
index 154bb35..b4e568f 100644
--- a/src/mcts.jl
+++ b/src/mcts.jl
@@ -9,7 +9,7 @@ export MCTSNode, runMCTS
using Dates, UUIDs, DataStructures, JSON3, Random
using GeneralUtils
-using ..type
+using ..type, ..llmfunction
# ---------------------------------------------- 100 --------------------------------------------- #
@@ -232,8 +232,19 @@ julia>
"""
function transition(a::T1, state::T2, action::T3,
actioninput::T3) where {T1<:agent, T2<:AbstractDict, T3<:AbstractString}
+error("--> transition")
- error("--> transition")
+ # map action and input() to llm function
+ # result =
+ # if action == "chatbox"
+ # chatbox(input)
+ # elseif
+
+ # else
+
+ # end
+
+
end
"""
diff --git a/test/runtest.jl b/test/runtest.jl
index 56759dd..d425e83 100644
--- a/test/runtest.jl
+++ b/test/runtest.jl
@@ -6,7 +6,7 @@ using Base.Threads
config = copy(JSON3.read("config.json"))
-instanceInternalTopic = config[:serviceInternalTopic][:value] * "/1"
+instanceInternalTopic = config[:serviceInternalTopic][:mqtttopic] * "/1"
client, connection = MakeConnection(config[:mqttServerInfo][:value][:broker],
config[:mqttServerInfo][:value][:port])