update
This commit is contained in:
111
src/interface.jl
111
src/interface.jl
@@ -85,8 +85,8 @@ function clearMessage(a::T) where {T<:agent}
|
||||
|
||||
a.memory = newAgentMemory()
|
||||
|
||||
@show a.messages
|
||||
@show a.memory
|
||||
# @show a.messages
|
||||
# @show a.memory
|
||||
end
|
||||
|
||||
function removeLatestMsg(a::T) where {T<:agent}
|
||||
@@ -1165,77 +1165,6 @@ function actor_mistral_openorca(a::agentReflex, selfaware=nothing)
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Chat with llm.
|
||||
|
||||
```jldoctest
|
||||
julia> using JSON3, UUIDs, Dates, FileIO, ChatAgent
|
||||
julia> mqttClientSpec = (
|
||||
clientName= "someclient", # name of this client
|
||||
clientID= "$(uuid4())",
|
||||
broker= "mqtt.yiem.cc",
|
||||
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/response",
|
||||
txtAI="agent/api/v0.1.0/txt/response"),
|
||||
keepalive= 30,
|
||||
)
|
||||
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> newAgent = ChatAgent.agentReact(
|
||||
"Jene",
|
||||
mqttClientSpec,
|
||||
role=:assistant_react,
|
||||
msgMeta=msgMeta
|
||||
)
|
||||
julia> response = ChatAgent.conversation(newAgent, "Hi! how are you?")
|
||||
```
|
||||
"""
|
||||
function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3)
|
||||
a.attemptlimit = attemptlimit
|
||||
workstate = nothing
|
||||
response = nothing
|
||||
|
||||
_ = addNewMessage(a, "user", usermsg)
|
||||
isuseplan = isUsePlans(a)
|
||||
# newinfo = extractinfo(a, usermsg)
|
||||
# a.env = newinfo !== nothing ? updateEnvState(a, newinfo) : a.env
|
||||
@show isuseplan
|
||||
|
||||
if isuseplan # use plan before responding
|
||||
if haskey(a.memory[:shortterm], "User:") == false #TODO should change role if user want to buy wine.
|
||||
a.memory[:shortterm]["User:"] = usermsg
|
||||
end
|
||||
workstate, response = work(a)
|
||||
end
|
||||
|
||||
# if LLM using askbox, use returning msg form askbox as conversation response
|
||||
if workstate == "askbox" || workstate == "formulatedUserResponse"
|
||||
#TODO paraphrase msg so that it is human friendlier word.
|
||||
else
|
||||
response = chat_mistral_openorca(a)
|
||||
response = split(response, "\n\n")[1]
|
||||
response = split(response, "\n\n")[1]
|
||||
end
|
||||
|
||||
response = removeTrailingCharacters(response)
|
||||
_ = addNewMessage(a, "assistant", response)
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
|
||||
|
||||
""" Chat with llm.
|
||||
|
||||
Arguments\n
|
||||
@@ -1288,6 +1217,42 @@ end
|
||||
Signature\n
|
||||
-----
|
||||
"""
|
||||
function conversation(a::agentReflex, usermsg::String; attemptlimit::Int=3)
|
||||
a.attemptlimit = attemptlimit
|
||||
workstate = nothing
|
||||
response = nothing
|
||||
|
||||
_ = addNewMessage(a, "user", usermsg)
|
||||
isuseplan = isUsePlans(a)
|
||||
# newinfo = extractinfo(a, usermsg)
|
||||
# a.env = newinfo !== nothing ? updateEnvState(a, newinfo) : a.env
|
||||
@show isuseplan
|
||||
|
||||
if isuseplan # use plan before responding
|
||||
if haskey(a.memory[:shortterm], "User:") == false #TODO should change role if user want to buy wine.
|
||||
a.memory[:shortterm]["User:"] = usermsg
|
||||
end
|
||||
workstate, response = work(a)
|
||||
end
|
||||
|
||||
# if LLM using askbox, use returning msg form askbox as conversation response
|
||||
if workstate == "askbox" || workstate == "formulatedUserResponse"
|
||||
#TODO paraphrase msg so that it is human friendlier word.
|
||||
else
|
||||
response = chat_mistral_openorca(a)
|
||||
response = split(response, "\n\n")[1]
|
||||
response = split(response, "\n\n")[1]
|
||||
end
|
||||
|
||||
response = removeTrailingCharacters(response)
|
||||
_ = addNewMessage(a, "assistant", response)
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
110
src/type.jl
110
src/type.jl
@@ -4,7 +4,7 @@ export agent, agentReflex, newAgentMemory
|
||||
|
||||
using Dates, UUIDs, DataStructures
|
||||
|
||||
#------------------------------------------------------------------------------------------------100
|
||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||
|
||||
function newAgentMemory()
|
||||
memory::Dict{Any, Any} = Dict(
|
||||
@@ -79,9 +79,10 @@ julia> agent = ChatAgent.agentReflex(
|
||||
```
|
||||
"""
|
||||
@kwdef mutable struct agentReflex <: agent
|
||||
agentName::String = "Jene" # ex. Jene
|
||||
name::String
|
||||
id::String
|
||||
availableRole::AbstractVector
|
||||
|
||||
availableRole::AbstractVector = ["system", "user", "assistant"]
|
||||
""" Dict(Role=> Content) ; Role can be system, user, assistant
|
||||
Example:
|
||||
messages=[
|
||||
@@ -90,13 +91,12 @@ julia> agent = ChatAgent.agentReflex(
|
||||
Dict(:role=>"user", :content=> "Hello, how are you"),
|
||||
]
|
||||
"""
|
||||
role::Symbol = :assistant
|
||||
roles::Dict = Dict(:assistant => "You are a helpful assistant.",)
|
||||
roleSpecificInstruction::Union{Dict, Nothing} = nothing
|
||||
thinkingFormat::Union{Dict, Nothing} = nothing
|
||||
role::Symbol
|
||||
roles::Dict{Symbol, String}
|
||||
roleSpecificInstruction::Dict{Symbol, String}
|
||||
config::Dict
|
||||
|
||||
tools::Union{Dict, Nothing} = nothing
|
||||
newplan::Bool = false # if true, new plan will be generated
|
||||
attemptlimit::Int = 5 # thinking round limit
|
||||
attempt::Int = 1 # attempted number
|
||||
task::Int = 1 # task number
|
||||
@@ -110,22 +110,31 @@ julia> agent = ChatAgent.agentReflex(
|
||||
earlierConversation::String = "N/A" # summary of earlier conversation
|
||||
|
||||
# communication
|
||||
configTopic::String="" # store mqtt topic where an agent can get configuration
|
||||
mqttClient::Any=nothing # store mqtt client for use in various internal functions
|
||||
msgMeta::Union{Dict, Nothing} = nothing # a template for msgMeta
|
||||
mqttMsg_chat::Vector{Dict} = Vector{Dict}() # store incoming mqtt chat msg
|
||||
mqttMsg_internal::Dict = Dict() # store incoming mqtt internal use msg
|
||||
mqttMsg_internal::Channel{Dict} = Channel{Dict}(32)
|
||||
|
||||
# LLM function related
|
||||
winestockResult = ""
|
||||
end
|
||||
|
||||
function agentReflex(
|
||||
agentName::String,
|
||||
mqttClient,
|
||||
msgMeta::Dict,
|
||||
configTopic::String,
|
||||
config::Dict = Dict(
|
||||
:frontend=>Dict(
|
||||
:mqtttopic=> nothing
|
||||
),
|
||||
:internal=>Dict(
|
||||
:mqtttopic=> nothing
|
||||
),
|
||||
:text2text=>Dict(
|
||||
:mqtttopic=> "txt2text/api/v1/prompt/gpu",
|
||||
),
|
||||
),
|
||||
;
|
||||
name::String="Assistant",
|
||||
id::String=string(uuid4()),
|
||||
role::Symbol=:assistant,
|
||||
roles::Dict=Dict(
|
||||
:assistant =>
|
||||
@@ -168,51 +177,6 @@ function agentReflex(
|
||||
</Required wine info>
|
||||
"""
|
||||
),
|
||||
|
||||
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!""",
|
||||
:planner=>
|
||||
"""
|
||||
Use the following format:
|
||||
Stimulus: the input user gives to you and you must respond
|
||||
Plan: first you should always think about the stimulus, the info you need and the info you have thoroughly then extract and devise a step by step plan (pay attention to correct numeral calculation and commonsense).
|
||||
P.S.1 each step should be a single action.
|
||||
""",
|
||||
:actor=>
|
||||
"""
|
||||
<Your job>
|
||||
Use the following format:
|
||||
Thought: based on the plan and the recap of the plan, what to do? (pay attention to correct numeral calculation and commonsense).
|
||||
Act: an action to take based on your thought, must be one of [{toolnames}]
|
||||
Actinput: your input to the action based on your thought (pay attention to the tool's input)
|
||||
Obs: observed result of the action
|
||||
|
||||
P.S.1 ask the user one by one question.
|
||||
P.S.2 ask the user what you want to know if you didn't ask yet.
|
||||
</Your job>
|
||||
""",
|
||||
:actorOriginal=>
|
||||
"""
|
||||
Use the following format:
|
||||
Thought: you should always think about do you have all the required info and what to do according to step {step} of the plan and the info you have (pay attention to correct numeral calculation and commonsense).
|
||||
Act: the action to take 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
|
||||
""",
|
||||
),
|
||||
tools::Dict=Dict(
|
||||
:chatbox=>Dict(
|
||||
:name => "chatbox",
|
||||
@@ -247,19 +211,23 @@ function agentReflex(
|
||||
maxUserMsg::Int=10,
|
||||
)
|
||||
|
||||
newAgent = agentReflex()
|
||||
newAgent.agentName = agentName
|
||||
newAgent.mqttClient = mqttClient
|
||||
newAgent.msgMeta = msgMeta
|
||||
newAgent.configTopic = configTopic
|
||||
newAgent.availableRole = availableRole
|
||||
newAgent.maxUserMsg = maxUserMsg
|
||||
newAgent.msgMeta = msgMeta
|
||||
newAgent.tools = tools
|
||||
newAgent.role = role
|
||||
newAgent.roles = roles
|
||||
newAgent.thinkingFormat = thinkingFormat
|
||||
newAgent.roleSpecificInstruction = roleSpecificInstruction
|
||||
#NEXTVERSION publish to agentConfigTopic to get a config.
|
||||
#NEXTVERSION get a config message in a.mqttMsgList
|
||||
#NEXTVERSION set agent according to config
|
||||
|
||||
newAgent = agentReflex(
|
||||
name = name,
|
||||
id = id,
|
||||
config = config,
|
||||
mqttClient = mqttClient,
|
||||
msgMeta = msgMeta,
|
||||
availableRole = availableRole,
|
||||
maxUserMsg = maxUserMsg,
|
||||
tools = tools,
|
||||
role = role,
|
||||
roles = roles,
|
||||
roleSpecificInstruction = roleSpecificInstruction,
|
||||
)
|
||||
|
||||
|
||||
return newAgent
|
||||
|
||||
144
src/utils.jl
144
src/utils.jl
@@ -11,17 +11,92 @@ using UUIDs, Dates, DataStructures, HTTP, MQTTClient
|
||||
using GeneralUtils
|
||||
using ..type
|
||||
|
||||
#------------------------------------------------------------------------------------------------100
|
||||
# ---------------------------------------------- 100 --------------------------------------------- #
|
||||
|
||||
#WORKING
|
||||
function sendReceivePrompt(message::AbstractDict, mqttclient, pubtopic::String)
|
||||
""" Send message to receiver then wait for reply.
|
||||
|
||||
Arguments\n
|
||||
-----
|
||||
a::agent
|
||||
an agent
|
||||
prompt::String
|
||||
prompt to be sent
|
||||
sendtopic::String
|
||||
topic the sender sends to e.g. "/agent/wine/api/v1/prompt"
|
||||
|
||||
Keyword Arguments\n
|
||||
-----
|
||||
max_tokens::Integer
|
||||
maximum number of tokens to be generated
|
||||
timeout::Integer
|
||||
timeout in seconds
|
||||
temperature::AbstractFloat
|
||||
range 0.0-1.0
|
||||
stopword::Vector{<:AbstractString}
|
||||
list of stopword to stop text generation
|
||||
|
||||
Return\n
|
||||
-----
|
||||
inferenced text
|
||||
|
||||
Example\n
|
||||
-----
|
||||
```jldoctest
|
||||
julia> using GeneralUtils
|
||||
julia> msgMeta = generate_msgMeta("/agent/frontend/wine/chat/api/v1/txt/receive")
|
||||
Dict{Symbol, Union{Nothing, String}} with 13 entries:
|
||||
:msgPurpose => nothing
|
||||
:requestresponse => nothing
|
||||
:timestamp => "2024-03-15T08:10:23.909"
|
||||
:replyToMsgId => nothing
|
||||
:receiverId => nothing
|
||||
:getpost => nothing
|
||||
:msgId => "e3467028-1dc1-4678-a6f1-a074696ca07c"
|
||||
:acknowledgestatus => nothing
|
||||
:sendTopic => "/agent/frontend/wine/chat/api/v1/txt/receive"
|
||||
:receiverName => nothing
|
||||
:replyTopic => nothing
|
||||
:senderName => nothing
|
||||
:senderId => nothing
|
||||
```
|
||||
|
||||
Signature\n
|
||||
-----
|
||||
"""
|
||||
function sendReceivePrompt(a::T1, prompt::String, sendtopic::String;
|
||||
max_tokens::Integer=256, timeout::Integer=120, temperature::AbstractFloat=0.2,
|
||||
stopword::T2=["nostopwordyet"],
|
||||
seed=nothing) where {T1<:agent, T2<:Vector{<:AbstractString}}
|
||||
|
||||
sendto = a.config[:text2text][:mqtttopic]
|
||||
msgMeta = deepcopy(a.msgMeta)
|
||||
msgMeta[:sendTopic] = #WORKING assign value
|
||||
|
||||
sendto,
|
||||
senderName = "agent-wine-backend",
|
||||
receiverName = "text2text-llm",
|
||||
replyTopic = a.config[:frontend][:mqtttopic],
|
||||
msgId = string(uuid4())
|
||||
|
||||
|
||||
a.msgMeta[:msgId] = "$(uuid4())" # new msg id for each msg
|
||||
msg = Dict(
|
||||
:msgMeta=> a.msgMeta,
|
||||
:txt=> prompt,
|
||||
:max_tokens=> max_tokens,
|
||||
:temperature=> temperature,
|
||||
:stopword=> stopword,
|
||||
:seed=> seed,
|
||||
)
|
||||
|
||||
# send prompt
|
||||
CommUtils.request(a.mqttClient, msg)
|
||||
starttime = Dates.now()
|
||||
result = nothing
|
||||
|
||||
while true
|
||||
timepass = (Dates.now() - starttime).value / 1000.0
|
||||
#WORKING get payload form mqtt or rest
|
||||
if isready(payloadChannel)
|
||||
if isready(mqttMsg_internal)
|
||||
topic, payload = take!(payloadChannel)
|
||||
if payload[:msgMeta][:repondToMsgId] == msg[:msgMeta][:msgId]
|
||||
result = haskey(payload, :txt) ? payload[:txt] : nothing
|
||||
@@ -37,68 +112,11 @@ function sendReceivePrompt(message::AbstractDict, mqttclient, pubtopic::String)
|
||||
error("undefined condition. timepass=$timepass timeout=$timeout $(@__LINE__)")
|
||||
end
|
||||
end
|
||||
sleep(0.1) # allow other threads to run
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function sendReceivePrompt(message::AbstractDict, endpoint::String)
|
||||
|
||||
end
|
||||
|
||||
"""
|
||||
Send a msg to registered mqtt topic within mqttClient.
|
||||
|
||||
```jldoctest
|
||||
julia> using JSON3, UUIDs, Dates, FileIO, ChatAgent
|
||||
julia> newAgent = ChatAgent.agentReact(
|
||||
"Jene",
|
||||
mqttClientSpec,
|
||||
role=:assistant_react,
|
||||
msgMeta=msgMeta
|
||||
)
|
||||
```
|
||||
"""
|
||||
# function sendReceivePrompt(a::T, prompt::String; max_tokens=256, timeout::Int=120,
|
||||
# temperature::AbstractFloat=0.2, stopword=[], seed=nothing) where {T<:agent}
|
||||
# a.msgMeta[:msgId] = "$(uuid4())" # new msg id for each msg
|
||||
# msg = Dict(
|
||||
# :msgMeta=> a.msgMeta,
|
||||
# :txt=> prompt,
|
||||
# :max_tokens=> max_tokens,
|
||||
# :temperature=> temperature,
|
||||
# :stopword=> stopword,
|
||||
# :seed=> seed,
|
||||
# )
|
||||
# payloadChannel = Channel(1)
|
||||
|
||||
# #WORKING send prompt using mqtt or Rest
|
||||
|
||||
# starttime = Dates.now()
|
||||
# result = nothing
|
||||
|
||||
# while true
|
||||
# timepass = (Dates.now() - starttime).value / 1000.0
|
||||
# #WORKING get payload form mqtt or rest
|
||||
# if isready(payloadChannel)
|
||||
# topic, payload = take!(payloadChannel)
|
||||
# if payload[:msgMeta][:repondToMsgId] == msg[:msgMeta][:msgId]
|
||||
# result = haskey(payload, :txt) ? payload[:txt] : nothing
|
||||
# break
|
||||
# end
|
||||
# elseif timepass <= timeout
|
||||
# # skip, within waiting period
|
||||
# elseif timepass > timeout
|
||||
# println("sendReceivePrompt timeout $timepass/$timeout")
|
||||
# result = nothing
|
||||
# break
|
||||
# else
|
||||
# error("undefined condition. timepass=$timepass timeout=$timeout $(@__LINE__)")
|
||||
# end
|
||||
# end
|
||||
|
||||
# return result
|
||||
# end
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user