This commit is contained in:
narawat lamaiin
2024-05-05 22:51:53 +07:00
parent e43caf4919
commit 9e3ab1333b
5 changed files with 310 additions and 287 deletions

View File

@@ -1,6 +1,6 @@
module YiemAgent module YiemAgent
# export agent, addNewMessage, clearMessage # export agent
""" Order by dependencies of each file. The 1st included file must not depend on any other """ Order by dependencies of each file. The 1st included file must not depend on any other

View File

@@ -127,7 +127,7 @@ function decisionMaker(a::T1, state::T2)::Dict{Symbol, Any} where {T1<:agent, T2
Thought can reason about the current situation, and Action can be three types: Thought can reason about the current situation, and Action can be three types:
1) winestock[query], which you can use to find wine in your inventory. The more input data the better. 1) winestock[query], which you can use to find wine in your inventory. The more input data the better.
2) chatbox[text], which you can use to interact with the user. 2) chatbox[text], which you can use to interact with the user.
3) recommendation[answer], which returns your wine reccommendation to the user. 3) reccommendbox[answer], which returns your wine reccommendation to the user.
$responseformat $responseformat
@@ -186,9 +186,18 @@ function decisionMaker(a::T1, state::T2)::Dict{Symbol, Any} where {T1<:agent, T2
_response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg) _response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
_thoughtJsonStr = _response[:response][:text] _thoughtJsonStr = _response[:response][:text]
thoughtJsonStr = jsoncorrection(a, _thoughtJsonStr, responseformat) expectedJsonExample =
"""
Here is an expected JSON format:
{
"Thought": "...",
"Action": {"name": "...", "input": "..."},
"Observation": "..."
}
"""
thoughtJsonStr = jsoncorrection(a, _thoughtJsonStr, expectedJsonExample)
thoughtDict = copy(JSON3.read(thoughtJsonStr)) thoughtDict = copy(JSON3.read(thoughtJsonStr))
pprint(thoughtDict)
return thoughtDict return thoughtDict
end end
@@ -219,10 +228,7 @@ function progressValueEstimator(a::T1, state::T2)::Tuple{String, Integer} where
""" """
You should only respond in JSON format as describe below: You should only respond in JSON format as describe below:
{ {
"Thought_1": "reasoning 1", "Evaluation": {"evaluation": "your evaluation", "score": your evaluation score}
"Action_1": {"name": "action to take", "input": "Action input"},
"Observation_1": "result of the action",
"Evaluation_1": {"evaluation": "your evaluation", "score": your evaluation score}
} }
""" """
@@ -233,7 +239,7 @@ function progressValueEstimator(a::T1, state::T2)::Tuple{String, Integer} where
the current situation and actions that can be three types: the current situation and actions that can be three types:
1) winestock[query], which you can use to find wine in your inventory. 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. 2) chatbox[text], which you can use to interact with the user.
3) finish[answer], which returns your wine reccommendation to the user. 3) reccommendbox[answer], which returns your wine reccommendation to the user.
Given a question and a trajectory, evaluate its correctness and provide your reasoning and Given a question and a trajectory, evaluate its correctness and provide your reasoning and
analysis in detail. Focus on the latest thought, action, and observation. Incomplete trajectories analysis in detail. Focus on the latest thought, action, and observation. Incomplete trajectories
@@ -250,14 +256,17 @@ function progressValueEstimator(a::T1, state::T2)::Tuple{String, Integer} where
"Thought_2": "But there is only 1 model that has the feature customer wanted.", "Thought_2": "But there is only 1 model that has the feature customer wanted.",
"Thought_3": "I should check our inventory first to see if we have it.", "Thought_3": "I should check our inventory first to see if we have it.",
"Action_1": {"name": "inventory", "input": "Yiem model A"}, "Action_1": {"name": "inventory", "input": "Yiem model A"},
"Observation_1": "Yiem model A is in stock.", "Observation_1": "Yiem model A is in stock."
"Evaluation_1": {"evaluation": "This trajectory is correct as it is reasonable to check an inventory for info provided in the question. }
{
"Evaluation": {"evaluation": "This trajectory is correct as it is reasonable to check an inventory for info provided in the question.
It is also better to have simple searches corresponding to a single entity, making this the best action.", It is also better to have simple searches corresponding to a single entity, making this the best action.",
"score": 10} "score": 10}
} }
Let's begin!: Let's begin!:
$(JSON3.write(state[:thoughtHistory])) $(JSON3.write(state[:thoughtHistory]))
{Evaluation
""" """
# apply LLM specific instruct format # apply LLM specific instruct format
@@ -292,11 +301,16 @@ function progressValueEstimator(a::T1, state::T2)::Tuple{String, Integer} where
_response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg) _response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
_thoughtJsonStr = _response[:response][:text] _thoughtJsonStr = _response[:response][:text]
thoughtJsonStr = jsoncorrection(a, _thoughtJsonStr, responseformat) expectedJsonExample =
"""
Here is an expected JSON format:
{
"Evaluation": {"evaluation": "...", "score": ...}
}
"""
thoughtJsonStr = jsoncorrection(a, _thoughtJsonStr, expectedJsonExample)
thoughtDict = copy(JSON3.read(thoughtJsonStr)) thoughtDict = copy(JSON3.read(thoughtJsonStr))
latestEvaluationKey, _ = evaluation = thoughtDict[:Evaluation]
GeneralUtils.findHighestIndexKey(thoughtDict, "Evaluation")
evaluation = thoughtDict[latestEvaluationKey]
return evaluation[:evaluation], evaluation[:score] return evaluation[:evaluation], evaluation[:score]
end end

View File

@@ -1,6 +1,7 @@
module llmfunction module llmfunction
export virtualWineCustomerChatbox, jsoncorrection export virtualWineCustomerChatbox, jsoncorrection, winestock,
virtualWineCustomerReccommendbox
using HTTP, JSON3, URIs, Random using HTTP, JSON3, URIs, Random
using GeneralUtils using GeneralUtils
@@ -46,6 +47,67 @@ function chatbox(a::T1, input::T2) where {T1<:agent, T2<:AbstractString}
end end
""" Chatbox for chatting with virtual wine customer.
# Arguments
- `a::T1`
one of Yiem's agent
- `input::T2`
text to be send to virtual wine customer
# Return
- `response::String`
response of virtual wine customer
# Example
```jldoctest
julia>
```
# TODO
- [] update docstring
- [] add reccommend() to compare wine
# Signature
"""
function virtualWineCustomerReccommendbox(a::T1, input::T2)::String where {T1<:agent, T2<:AbstractString}
input = "I reccomment Zeno crown vista"
# put in model format
virtualWineCustomer = a.config[:externalservice][:virtualWineCustomer_1]
llminfo = virtualWineCustomer[:llminfo]
prompt =
if llminfo[:name] == "llama3instruct"
formatLLMtext_llama3instruct("assistant", input)
else
error("llm model name is not defied yet $(@__LINE__)")
end
# send formatted input to user using GeneralUtils.sendReceiveMqttMsg
msgMeta = GeneralUtils.generate_msgMeta(
virtualWineCustomer[:mqtttopic],
senderName= "virtualWineCustomerReccommendbox",
senderId= a.id,
receiverName= "virtualWineCustomer",
mqttBroker= a.config[:mqttServerInfo][:broker],
mqttBrokerPort= a.config[:mqttServerInfo][:port],
msgId = "dummyid" #CHANGE remove after testing finished
)
outgoingMsg = Dict(
:msgMeta=> msgMeta,
:payload=> Dict(
:text=> prompt,
)
)
@show outgoingMsg
result = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
response = result[:response][:text]
return response
end
""" Chatbox for chatting with virtual wine customer. """ Chatbox for chatting with virtual wine customer.
@@ -104,263 +166,43 @@ end
""" Search wine in stock. """ Search wine in stock.
Arguments\n # Arguments
a : one of ChatAgent's agent. - `a::T1`
Return\n one of ChatAgent's agent.
- `input::T2`
# Return
A JSON string of available wine A JSON string of available wine
Example\n # Example
```jldoctest ```jldoctest
julia> using ChatAgent julia> using ChatAgent
julia> agent = ChatAgent.agentReflex("Jene") julia> agent = ChatAgent.agentReflex("Jene")
julia> input = "{\"food\": \"pizza\", \"occasion\": \"anniversary\"}" julia> input = "{\"food\": \"pizza\", \"occasion\": \"anniversary\"}"
julia> result = winestock(agent, input) 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\"}, }" "{"wine 1": {\"Winery\": \"Pichon Baron\", \"wine name\": \"Pauillac (Grand Cru Classé)\", \"grape variety\": \"Cabernet Sauvignon\", \"year\": 2010, \"price\": \"125 USD\", \"stock ID\": \"ar-17\"}, }"
``` ```
# TODO
[] update docs
[] implement the function
# Signature
""" """
# function winestock(a::agentReflex, input::NamedTuple) function winestock(a::T1, input::T2) where {T1<:agent, T2<:AbstractString}
# println("") winesStr =
# @show input """
1: El Enemigo Cabernet Franc 2019
# wineSearchCriteria = GeneralUtils.JSON3read_stringKey(input[:toolinput]) 2: Tantara Chardonnay 2017
# newDict = Dict{String,Any}() """
# for (k,v) in wineSearchCriteria result =
# println("k $k v $v") """
# newDict[string(k)] = v I found the following wines in our stock:
# end {
$winesStr
# #TODO temporary delete key "food pairing from a dict }
# newDict = deepcopy(a.memory[:keyword]) """
# delete!(newDict, "food pairing") return result
end
# query = JSON3.write(newDict)
# println("")
# @show query
# # prompt =
# # """
# # <|system|>
# # <About yourself>
# # Your are a helpful assistant.
# # </About yourself>
# # <You have the following conversion table>
# # 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
# # </You have the following conversion table>
# # <Your job>
# # 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
# # </Your job>
# # <Example 1>
# # 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;
# # </Example 1>
# # <Example 2>
# # 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;
# # </Example 2>
# # </s>
# # <|query|>
# # $query
# # </s>
# # <|assistant|>
# # """
# prompt =
# """
# <s>
# <|system|>
# <About yourself>
# Your are a helpful assistant.
# </About yourself>
# <You have the following conversion table>
# 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
# </You have the following conversion table>
# <Your job>
# 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
# </Your job>
# </|system|>
# <Example 1>
# <query>
# {\"wine type\": \"white\", \"wine characteristics\": \"full-bodied | off-dry | low acidity | low to medium tannin\", \"price\": {\"max\": \"50\"}}
# </query>
# <|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|>
# </Example 1>
# <Example 2>
# <query>
# {\"wine characteristics\":\"low-bodied | a little sweet | low-medium tannin\",\"price\":\"22 USD\",\"occasion\":\"anniversary\",\"wine type\":\"Rose\",\"food\":\"American dishes\"}
# </query>
# <|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|>
# </Example 2>
# </s>
# <query>
# $query
# </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|>", "</s>", "<|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
""" Attemp to correct LLM response's incorrect JSON response. """ Attemp to correct LLM response's incorrect JSON response.
@@ -389,26 +231,30 @@ function jsoncorrection(a::T1, input::T2,
correctJsonExample::T3) where {T1<:agent, T2<:AbstractString, T3<:AbstractString} correctJsonExample::T3) where {T1<:agent, T2<:AbstractString, T3<:AbstractString}
attemptround = 0 attemptround = 0
incorrectjson = input incorrectjson = deepcopy(input)
correctjson = nothing correctjson = nothing
while true while true
attemptround += 1 attemptround += 1
if attemptround <= 5 if attemptround <= 5
try try
JSON3.read(incorrectjson) d = copy(JSON3.read(incorrectjson))
correctjson = incorrectjson correctjson = incorrectjson
break break
catch catch e
@warn "Attempting correct JSON string. $attemptround" @warn "Attempting correct JSON string. $attemptround"
incorrectjson = deepcopy(input)
_prompt = _prompt =
""" """
Your goal is to correct a given incorrect JSON string. Your goal are:
1) Use the info why the given JSON string failed to load and provide a corrected version that can be loaded by Python's json.load function.
2) The user need Corrected JSON string only. Do not provide any other info.
$correctJsonExample $correctJsonExample
Incorrect JSON: Let's begin!
$incorrectjson Given JSON string: $incorrectjson
Corrention: The given JSON string failed to load previously because: $e
Corrected JSON string:
""" """
# apply LLM specific instruct format # apply LLM specific instruct format
@@ -449,10 +295,77 @@ function jsoncorrection(a::T1, input::T2,
break break
end end
end end
@show correctjson
return correctjson return correctjson
end end
# function jsoncorrection(a::T1, input::T2,
# correctJsonExample::T3) where {T1<:agent, T2<:AbstractString, T3<:AbstractString}
# attemptround = 0
# incorrectjson = deepcopy(input)
# correctjson = nothing
# while true
# attemptround += 1
# if attemptround <= 5
# try
# JSON3.read(incorrectjson)
# correctjson = incorrectjson
# break
# catch
# @warn "Attempting correct JSON string. $attemptround"
# incorrectjson = deepcopy(input)
# _prompt =
# """
# Your goal is to correct a given incorrect JSON format while retaining original content.
# $correctJsonExample
# Incorrect JSON:
# $incorrectjson
# Corrention:
# """
# # apply LLM specific instruct format
# externalService = a.config[:externalservice][:text2textinstruct]
# llminfo = externalService[:llminfo]
# prompt =
# if llminfo[:name] == "llama3instruct"
# formatLLMtext_llama3instruct("system", _prompt)
# else
# error("llm model name is not defied yet $(@__LINE__)")
# end
# # send formatted input to user using GeneralUtils.sendReceiveMqttMsg
# msgMeta = GeneralUtils.generate_msgMeta(
# externalService[:mqtttopic],
# senderName= "jsoncorrection",
# senderId= a.id,
# receiverName= "text2textinstruct",
# mqttBroker= a.config[:mqttServerInfo][:broker],
# mqttBrokerPort= a.config[:mqttServerInfo][:port],
# )
# outgoingMsg = Dict(
# :msgMeta=> msgMeta,
# :payload=> Dict(
# :text=> prompt,
# :kwargs=> Dict(
# :max_tokens=> 512,
# :stop=> ["<|eot_id|>"],
# )
# )
# )
# result = GeneralUtils.sendReceiveMqttMsg(outgoingMsg)
# incorrectjson = result[:response][:text]
# end
# else
# error("Can't fix JSON string")
# break
# end
# end
# return correctjson
# end

View File

@@ -47,7 +47,7 @@ julia> state = Dict(
# Signature # Signature
""" """
struct MCTSNode{T<:AbstractDict} mutable struct MCTSNode{T<:AbstractDict}
nodekey::String nodekey::String
state::T state::T
visits::Integer visits::Integer
@@ -272,14 +272,14 @@ julia> thoughtDict = Dict(
``` ```
# TODO # TODO
- [PENDING] add other actions - [x] add other actions
- [] add embedding of newstate and store in newstate[:embedding] - [] add embedding of newstate and store in newstate[:embedding]
# Signature # Signature
""" """
function MCTStransition(a::T1, state::T2, thoughtDict::T3, isterminal::Function function MCTStransition(a::T1, state::T2, thoughtDict::T3, isterminal::Function
)::Tuple{String, Dict{Symbol, <:Any}, Bool, <:Number} where {T1<:agent, T2<:AbstractDict, T3<:AbstractDict} )::Tuple{String, Dict{Symbol, <:Any}, Bool, <:Number} where {T1<:agent, T2<:AbstractDict, T3<:AbstractDict}
pprint(thoughtDict)
actionname = thoughtDict[:Action][:name] actionname = thoughtDict[:Action][:name]
actioninput = thoughtDict[:Action][:input] actioninput = thoughtDict[:Action][:input]
@@ -288,11 +288,11 @@ function MCTStransition(a::T1, state::T2, thoughtDict::T3, isterminal::Function
if actionname == "chatbox" if actionname == "chatbox"
virtualWineCustomerChatbox(a, actioninput) # virtual customer virtualWineCustomerChatbox(a, actioninput) # virtual customer
elseif actionname == "winestock" elseif actionname == "winestock"
winestock(a, actioninput)
elseif actionname == "finish" elseif actionname == "reccommendbox"
virtualWineCustomerReccommendbox(a, actioninput)
else else
error("undefined LLM function. Requesting $actionname")
end end
latestThoughtKey, latestThoughtIndice = GeneralUtils.findHighestIndexKey(state[:thoughtHistory], latestThoughtKey, latestThoughtIndice = GeneralUtils.findHighestIndexKey(state[:thoughtHistory],

96
test/prompttest_1.jl Normal file
View File

@@ -0,0 +1,96 @@
using Revise # remove when this package is completed
using YiemAgent, GeneralUtils, JSON3, MQTTClient, Dates, UUIDs
using Base.Threads
# ---------------------------------------------- 100 --------------------------------------------- #
config = copy(JSON3.read("config.json"))
instanceInternalTopic = config[:serviceInternalTopic][:mqtttopic] * "/1"
client, connection = MakeConnection(config[:mqttServerInfo][:broker],
config[:mqttServerInfo][:port])
receiveUserMsgChannel = Channel{Dict}(4)
receiveInternalMsgChannel = Channel{Dict}(4)
msgMeta = GeneralUtils.generate_msgMeta(
"N/A",
replyTopic = config[:servicetopic][:mqtttopic] # ask frontend reply to this instance_chat_topic
)
agentConfig = Dict(
:mqttServerInfo=> config[:mqttServerInfo],
:receivemsg=> Dict(
:prompt=> config[:servicetopic][:mqtttopic], # topic to receive prompt i.e. frontend send msg to this topic
:internal=> instanceInternalTopic,
),
:externalservice=> config[:externalservice],
)
# Instantiate an agent
tools=Dict( # update input format
"askbox"=> Dict(
:description => "<askbox tool description>Useful for when you need to ask the user for more context. Do not ask the user their own question.</askbox tool description>",
:input => """<input>Input is a text in JSON format.</input><input example>{\"Q1\": \"How are you doing?\", \"Q2\": \"How may I help you?\"}</input example>""",
:output => "" ,
:func => nothing,
),
# "winestock"=> Dict(
# :description => "<winestock tool description>A handy tool for searching wine in your inventory that match the user preferences.</winestock tool description>",
# :input => """<input>Input is a JSON-formatted string that contains a detailed and precise search query.</input><input example>{\"wine type\": \"rose\", \"price\": \"max 35\", \"sweetness level\": \"sweet\", \"intensity level\": \"light bodied\", \"Tannin level\": \"low\", \"Acidity level\": \"low\"}</input example>""",
# :output => """<output>Output are wines that match the search query in JSON format.""",
# :func => ChatAgent.winestock,
# ),
"finalanswer"=> Dict(
:description => "<tool description>Useful for when you are ready to recommend wines to the user.</tool description>",
:input => """<input format>{\"finalanswer\": \"some text\"}.</input format><input example>{\"finalanswer\": \"I recommend Zena Crown Vista\"}</input example>""",
:output => "" ,
:func => nothing,
),
)
a = YiemAgent.sommelier(
receiveUserMsgChannel,
receiveInternalMsgChannel,
agentConfig,
name= "assistant",
id= "testingSessionID", # agent instance id
tools=tools,
)
input =
"""
{\n\"Evaluation\": {\n\"evaluation\": \"This trajectory is partially correct as it's attempting to gather more information about the user's needs. However, asking what occasion might not be the most effective way to determine the type of wine to recommend.\",\n\"score\": 7\n}
"""
expectedJsonExample =
"""
Here is an expected JSON format:
{
"Evaluation": {"evaluation": "...", "score": ...}
}
"""
result = YiemAgent.jsoncorrection(a, input, correctJsonExample)