update
This commit is contained in:
295
src/interface.jl
295
src/interface.jl
@@ -8,6 +8,7 @@ export agentReact, agentReflex,
|
||||
|
||||
using JSON3, DataStructures, Dates, UUIDs, HTTP
|
||||
using CommUtils, GeneralUtils
|
||||
using ..type
|
||||
|
||||
# ---------------------------------------------------------------------------- #
|
||||
# pythoncall setting #
|
||||
@@ -34,281 +35,6 @@ using CommUtils, GeneralUtils
|
||||
|
||||
#------------------------------------------------------------------------------------------------100
|
||||
|
||||
abstract type agent end
|
||||
|
||||
@kwdef mutable struct agentReact <: agent
|
||||
availableRole::AbstractVector = ["system", "user", "assistant"]
|
||||
agentName::String = "assistant"
|
||||
maxUserMsg::Int = 10
|
||||
earlierConversation::String = "" # summary of earlier conversation
|
||||
mqttClient::Union{mqttClient, Nothing} = nothing
|
||||
msgMeta::Union{Dict, Nothing} = nothing
|
||||
|
||||
""" Dict(Role=> Content) ; Role can be system, user, assistant
|
||||
Example:
|
||||
messages=[
|
||||
Dict(:role=>"system", :content=> "You are a helpful assistant."),
|
||||
Dict(:role=>"assistant", :content=> "How may I help you"),
|
||||
Dict(:role=>"user", :content=> "Hello, how are you"),
|
||||
]
|
||||
"""
|
||||
role::Symbol = :assistant
|
||||
roles::Dict = Dict(:assistant => "You are a helpful assistant.",)
|
||||
|
||||
# Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
|
||||
# messages= [Dict(:role=>"system", :content=> "", :timestamp=> Dates.now()),]
|
||||
messages = Vector{Dict{Symbol, Any}}()
|
||||
context::String = "nothing" # internal thinking area
|
||||
tools::Union{Dict, Nothing} = nothing
|
||||
thought::String = "nothing" # contain unfinished thoughts for ReAct agent only
|
||||
thinkinground::Int = 0 # no. of thinking round
|
||||
thinkingroundlimit::Int = 5 # thinking round limit
|
||||
thinkingMode::Union{Dict, Nothing} = nothing
|
||||
end
|
||||
|
||||
function agentReact(
|
||||
agentName::String,
|
||||
mqttClientSpec::NamedTuple;
|
||||
role::Symbol=:assistant,
|
||||
roles::Dict=Dict(
|
||||
:assistant =>
|
||||
"""
|
||||
You are a helpful assistant who answer the user's questions as best you can.
|
||||
""",
|
||||
:sommelier =>
|
||||
"""
|
||||
You are a helpful sommelier at an online wine reseller who always ask user for wine relevant info before you could help them choosing wine.
|
||||
You provide a personalized recommendation of up to two wines based on the user's preference, and you describe the benefits of each wine in detail.
|
||||
You don't know other people personal info previously.
|
||||
|
||||
Info used to select wine:
|
||||
- type of food
|
||||
- occasion
|
||||
- user's personal taste of wine
|
||||
- wine price range
|
||||
- temperature at the serving location
|
||||
- wine we have in stock
|
||||
""",
|
||||
),
|
||||
thinkingMode::Dict=Dict(
|
||||
:no_thinking=> "",
|
||||
:thinking=>
|
||||
"""Use the following format:
|
||||
Question: the input question your user is asking and you must answer
|
||||
Plan: first you should always think about the question and the info you have thoroughly then extract and devise a complete plan to find the answer (pay attention to variables and their corresponding numerals).
|
||||
Thought: ask yourself do you have all the info you need? And what to do according to the plan (pay attention to correct numeral calculation and commonsense).
|
||||
Act: the tool that match your thought, should be one of {toolnames}
|
||||
ActInput: the input to the action (pay attention to the tool's input)
|
||||
Obs: the result of the action
|
||||
... (this Plan/Thought/Act/ActInput/Obs can repeat N times until you know the answer.)
|
||||
Thought: I think I know the answer
|
||||
Answer: Answer of the original question
|
||||
|
||||
Begin!""",
|
||||
),
|
||||
tools::Dict=Dict(
|
||||
:wikisearch=>Dict(
|
||||
:name => "wikisearch",
|
||||
:description => "Useful for when you need to search an encyclopedia",
|
||||
:input => "Input is keywords and not a question.",
|
||||
:output => "",
|
||||
:func => wikisearch, # put function here
|
||||
),
|
||||
:chatbox=>Dict(
|
||||
:name => "chatbox",
|
||||
:description => "Useful for when you need to ask a customer for more context.",
|
||||
:input => "Input should be a conversation to customer.",
|
||||
:output => "" ,
|
||||
:func => nothing,
|
||||
),
|
||||
# :wineStock=>Dict(
|
||||
# :name => "wineStock",
|
||||
# :description => "useful for when you need to search for wine by your description, price, name or ID.",
|
||||
# :input => "Input should be a search query with as much details as possible.",
|
||||
# :output => "" ,
|
||||
# :func => nothing,
|
||||
# ),
|
||||
# :NTHING=>Dict(
|
||||
# :name => "NTHING",
|
||||
# :description => "useful for when you don't need to use tools or actions",
|
||||
# :input => "No input is needed",
|
||||
# :output => "" ,
|
||||
# :func => nothing,
|
||||
# ),
|
||||
),
|
||||
msgMeta::Dict=Dict(
|
||||
:msgPurpose=> "updateStatus",
|
||||
:from=> "chatbothub",
|
||||
:to=> "llmAI",
|
||||
:requestrespond=> "request",
|
||||
:sendto=> "", # destination topic
|
||||
:replyTo=> "chatbothub/llm/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())",
|
||||
),
|
||||
availableRole::AbstractArray=["system", "user", "assistant"],
|
||||
maxUserMsg::Int=10,)
|
||||
|
||||
newAgent = agentReact()
|
||||
newAgent.availableRole = availableRole
|
||||
newAgent.maxUserMsg = maxUserMsg
|
||||
newAgent.mqttClient = CommUtils.mqttClient(mqttClientSpec)
|
||||
newAgent.msgMeta = msgMeta
|
||||
newAgent.tools = tools
|
||||
newAgent.role = role
|
||||
newAgent.roles = roles
|
||||
newAgent.thinkingMode = thinkingMode
|
||||
|
||||
return newAgent
|
||||
end
|
||||
|
||||
|
||||
@kwdef mutable struct agentReflex <: agent
|
||||
availableRole::AbstractVector = ["system", "user", "assistant"]
|
||||
agentName::String = "assistant"
|
||||
maxUserMsg::Int = 10
|
||||
earlierConversation::String = "" # summary of earlier conversation
|
||||
mqttClient::Union{mqttClient, Nothing} = nothing
|
||||
msgMeta::Union{Dict, Nothing} = nothing
|
||||
|
||||
""" Dict(Role=> Content) ; Role can be system, user, assistant
|
||||
Example:
|
||||
messages=[
|
||||
Dict(:role=>"system", :content=> "You are a helpful assistant."),
|
||||
Dict(:role=>"assistant", :content=> "How may I help you"),
|
||||
Dict(:role=>"user", :content=> "Hello, how are you"),
|
||||
]
|
||||
"""
|
||||
role::Symbol = :assistant
|
||||
roles::Dict = Dict(:assistant => "You are a helpful assistant.",)
|
||||
|
||||
# Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3
|
||||
# messages= [Dict(:role=>"system", :content=> "", :timestamp=> Dates.now()),]
|
||||
messages = Vector{Dict{Symbol, Any}}()
|
||||
context::String = "nothing" # internal thinking area
|
||||
tools::Union{Dict, Nothing} = nothing
|
||||
thought::String = "nothing" # contain unfinished thoughts for ReAct agent only
|
||||
thinkinground::Int = 0 # no. of thinking round
|
||||
thinkingroundlimit::Int = 5 # thinking round limit
|
||||
thinkingMode::Union{Dict, Nothing} = nothing
|
||||
memory::Dict = Dict(
|
||||
:shortterm=> "",
|
||||
:longterm=>""
|
||||
)
|
||||
end
|
||||
|
||||
function agentReflex(
|
||||
agentName::String,
|
||||
mqttClientSpec::NamedTuple;
|
||||
role::Symbol=:assistant,
|
||||
roles::Dict=Dict(
|
||||
:assistant =>
|
||||
"""
|
||||
You are a helpful assistant who answer the user's questions as best you can.
|
||||
""",
|
||||
:sommelier =>
|
||||
"""
|
||||
You are a sommelier at an online wine reseller who always ask user for wine relevant info before you could help them choosing wine.
|
||||
You provide a personalized recommendation of up to two wines based on the user's preference, and you describe the benefits of each wine in detail.
|
||||
You don't know other people personal info previously.
|
||||
|
||||
Info used to select wine:
|
||||
- type of food
|
||||
- occasion
|
||||
- user's personal taste of wine
|
||||
- wine price range
|
||||
- temperature at the serving location
|
||||
- wine we have in stock
|
||||
""",
|
||||
),
|
||||
thinkingFormat::Dict=Dict(
|
||||
:react=>
|
||||
"""Use the following format:
|
||||
Question: the input question your user is asking and you must answer
|
||||
Plan: first you should always think about the question and the info you have thoroughly then extract and devise a complete plan to find the answer (pay attention to variables and their corresponding numerals).
|
||||
Thought: ask yourself do you have all the info you need? And what to do according to the plan (pay attention to correct numeral calculation and commonsense).
|
||||
Act: the tool that match your thought, should be one of {toolnames}
|
||||
ActInput: the input to the action (pay attention to the tool's input)
|
||||
Obs: the result of the action
|
||||
... (this Plan/Thought/Act/ActInput/Obs can repeat N times until you know the answer.)
|
||||
Thought: I think I know the answer
|
||||
Answer: Answer of the original question
|
||||
|
||||
Begin!""",
|
||||
:plan=>
|
||||
"""Use the following format:
|
||||
Question: the input question your user is asking and you must answer
|
||||
Plan: first you should always think about the question and the info you have thoroughly then extract and devise a complete plan to find the answer (pay attention to variables and their corresponding numerals).
|
||||
|
||||
Begin!""",
|
||||
:qta=>
|
||||
"""Use the following format:
|
||||
Question: the input question your user is asking and you must answer
|
||||
Thought: ask yourself do you have all the info you need? And what to do according to the plan (pay attention to correct numeral calculation and commonsense).
|
||||
Act: the tool that match your thought, should be one of {toolnames}
|
||||
ActInput: the input to the action (pay attention to the tool's input)
|
||||
|
||||
Begin!""",
|
||||
),
|
||||
tools::Dict=Dict(
|
||||
:wikisearch=>Dict(
|
||||
:name => "wikisearch",
|
||||
:description => "Useful for when you need to search an encyclopedia",
|
||||
:input => "Input is keywords and not a question.",
|
||||
:output => "",
|
||||
:func => wikisearch, # put function here
|
||||
),
|
||||
:chatbox=>Dict(
|
||||
:name => "chatbox",
|
||||
:description => "Useful for when you need to ask a customer for more context.",
|
||||
:input => "Input should be a conversation to customer.",
|
||||
:output => "" ,
|
||||
:func => nothing,
|
||||
),
|
||||
# :wineStock=>Dict(
|
||||
# :name => "wineStock",
|
||||
# :description => "useful for when you need to search for wine by your description, price, name or ID.",
|
||||
# :input => "Input should be a search query with as much details as possible.",
|
||||
# :output => "" ,
|
||||
# :func => nothing,
|
||||
# ),
|
||||
# :NTHING=>Dict(
|
||||
# :name => "NTHING",
|
||||
# :description => "useful for when you don't need to use tools or actions",
|
||||
# :input => "No input is needed",
|
||||
# :output => "" ,
|
||||
# :func => nothing,
|
||||
# ),
|
||||
),
|
||||
msgMeta::Dict=Dict(
|
||||
:msgPurpose=> "updateStatus",
|
||||
:from=> "chatbothub",
|
||||
:to=> "llmAI",
|
||||
:requestrespond=> "request",
|
||||
:sendto=> "", # destination topic
|
||||
:replyTo=> "chatbothub/llm/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())",
|
||||
),
|
||||
availableRole::AbstractArray=["system", "user", "assistant"],
|
||||
maxUserMsg::Int=10,)
|
||||
|
||||
newAgent = agentReact()
|
||||
newAgent.availableRole = availableRole
|
||||
newAgent.maxUserMsg = maxUserMsg
|
||||
newAgent.mqttClient = CommUtils.mqttClient(mqttClientSpec)
|
||||
newAgent.msgMeta = msgMeta
|
||||
newAgent.tools = tools
|
||||
newAgent.role = role
|
||||
newAgent.roles = roles
|
||||
|
||||
return newAgent
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
add new message to agent
|
||||
@@ -779,9 +505,9 @@ function conversation(a::agentReflex, usermsg::String; thinkingroundlimit::Int=3
|
||||
respond = nothing
|
||||
|
||||
# determine thinking mode
|
||||
a.thinkingMode = chooseThinkingMode(a, usermsg)
|
||||
a.thinkingmode = chooseThinkingMode(a, usermsg)
|
||||
|
||||
if a.thinkingMode == :no_thinking
|
||||
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 = genPrompt_mistral_openorca(a, usermsg) #TODO rewrite this function
|
||||
@@ -800,10 +526,11 @@ end
|
||||
|
||||
#WORKING
|
||||
function work(a::agentReflex, usermsg::String)
|
||||
if a.thinkingMode == :new_thinking
|
||||
error("work done")
|
||||
if a.thinkingmode == :new_thinking
|
||||
a.earlierConversation = conversationSummary(a)
|
||||
_ = addNewMessage(a, "user", usermsg)
|
||||
elseif a.thinkingMode == :continue_thinking
|
||||
elseif a.thinkingmode == :continue_thinking
|
||||
_ = addNewMessage(a, "user", usermsg)
|
||||
a.thought *= "Obs $(a.thinkinground): $usermsg\n"
|
||||
else
|
||||
@@ -823,6 +550,8 @@ function work(a::agentReflex, usermsg::String)
|
||||
# end
|
||||
# evaluate
|
||||
#
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -982,9 +711,9 @@ function chooseThinkingMode(a::T, usermsg::String) where {T<:agent}
|
||||
end
|
||||
|
||||
function chooseThinkingMode(a::agentReflex, usermsg::String)
|
||||
thinkingMode = nothing
|
||||
thinkingmode = nothing
|
||||
if a.thought != "nothing"
|
||||
thinkingMode = :continue_thinking
|
||||
thinkingmode = :continue_thinking
|
||||
else
|
||||
prompt =
|
||||
"""
|
||||
@@ -1017,10 +746,10 @@ function chooseThinkingMode(a::agentReflex, usermsg::String)
|
||||
prompt = replace(prompt, "{input}" => usermsg)
|
||||
result = sendReceivePrompt(a, prompt)
|
||||
willusetools = GeneralUtils.getStringBetweenCharacters(result, "{", "}")
|
||||
thinkingMode = willusetools == "yes" ? :new_thinking : :no_thinking
|
||||
thinkingmode = willusetools == "yes" ? :new_thinking : :no_thinking
|
||||
end
|
||||
|
||||
return thinkingMode
|
||||
return thinkingmode
|
||||
end
|
||||
|
||||
function identifyUserIntention(a::T, usermsg::String) where {T<:agent}
|
||||
|
||||
Reference in New Issue
Block a user