module type export agent, sommelier using Dates, UUIDs, DataStructures, JSON3 using GeneralUtils # ---------------------------------------------- 100 --------------------------------------------- # abstract type agent end """ A sommelier agent. # Arguments - `mqttClient::Client` MQTTClient's client - `msgMeta::Dict{Symbol, Any}` A dict contain info about a message. - `config::Dict{Symbol, Any}` Config info for an agent. Contain mqtt topic for internal use and other info. # Keyword Arguments - `name::String` Agent's name - `id::String` Agent's ID - `tools::Dict{Symbol, Any}` Agent's tools - `maxHistoryMsg::Integer` max history message # Return - `nothing` # Example ```jldoctest julia> using YiemAgent, MQTTClient, GeneralUtils julia> msgMeta = GeneralUtils.generate_msgMeta( "N/A", replyTopic = "/testtopic/prompt" ) julia> tools= Dict( :chatbox=>Dict( :name => "chatbox", :description => "Useful only for when you need to ask the user for more info or context. Do not ask the user their own question.", :input => "Input should be a text.", :output => "" , :func => nothing, ), ) julia> agentConfig = Dict( :receiveprompt=>Dict( :mqtttopic=> "/testtopic/prompt", # topic to receive prompt i.e. frontend send msg to this topic ), :receiveinternal=>Dict( :mqtttopic=> "/testtopic/internal", # receive topic for model's internal ), :text2text=>Dict( :mqtttopic=> "/text2text/receive", ), ) julia> client, connection = MakeConnection("test.mosquitto.org", 1883) julia> agent = YiemAgent.bsommelier( client, msgMeta, agentConfig, name= "assistant", id= "555", # agent instance id tools=tools, ) ``` # TODO - [] update docstring - [x] implement the function # Signature """ @kwdef mutable struct sommelier <: agent name::String # agent name id::String # agent id config::Dict # agent config tools::Dict thinkinglimit::Integer # thinking round limit thinkingcount::Integer # used to count attempted round of a task """ Memory Ref: Chat prompt format https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/discussions/3 NO "system" message in chathistory because I want to add it at the inference time chathistory= [ Dict(:name=>"user", :text=> "Wassup!", :timestamp=> Dates.now()), Dict(:name=>"assistant", :text=> "Hi I'm your assistant.", :timestamp=> Dates.now()), ] """ chathistory::Vector{Dict{Symbol, Any}} = Vector{Dict{Symbol, Any}}() maxHistoryMsg::Integer # 31th and earlier messages will get summarized keywordinfo::Dict{Symbol, Any} = Dict{Symbol, Any}( :customerinfo => Dict{Symbol, Any}(), :storeinfo => Dict{Symbol, Any}(), ) mctstree::Dict{Symbol, Any} = Dict{Symbol, Any}() # 1-historyPoint is in Dict{Symbol, Any} and compose of: # state, statevalue, thought, action, observation plan::Dict{Symbol, Any} = Dict{Symbol, Any}( # store 3 to 5 best plan AI frequently used to avoid having to search MCTS all the time # each plan is in [historyPoint_1, historyPoint_2, ...] format :existingplan => Vector(), :activeplan => Vector{Dict{Symbol, Any}}(), # current using plan :currenttrajectory=> Vector{Dict{Symbol, Any}}(), # store ) # put incoming message here. waiting for further processing receiveUserMsgChannel::Channel{Dict} = Channel{Dict}(8) # for incoming user communication receiveInternalMsgChannel::Channel{Dict} = Channel{Dict}(8) # for internal communication end function sommelier( receiveUserMsgChannel::Channel, receiveInternalMsgChannel::Channel, config::Dict = Dict( :mqttServerInfo=> Dict( :broker=> nothing, :port=> nothing, ), :receivemsg=> Dict( :prompt=> nothing, # topic to receive prompt i.e. frontend send msg to this topic :internal=> nothing, ), :thirdPartyService=> Dict( :text2textinstruct=> nothing, :text2textchat=> nothing, ), ) ; name::String= "Assistant", id::String= string(uuid4()), tools::Dict= Dict( :chatbox=> Dict( :name => "chatbox", :description => "Useful for when you need to communicate with the user.", :input => "Input should be a conversation to the user.", :output => "" , :func => nothing, ), ), maxHistoryMsg::Integer= 20, thinkinglimit::Integer= 5, thinkingcount::Integer= 0, ) #[NEXTVERSION] publish to a.config[:configtopic] to get a config. #[NEXTVERSION] get a config message in a.mqttMsg_internal #[NEXTVERSION] set agent according to config newAgent = sommelier( receiveUserMsgChannel= receiveUserMsgChannel, receiveInternalMsgChannel= receiveInternalMsgChannel, name= name, id= id, config= config, maxHistoryMsg= maxHistoryMsg, tools= tools, thinkinglimit= thinkinglimit, thinkingcount= thinkingcount, ) return newAgent end end # module type