module util export clearhistory, addNewMessage, vectorOfDictToText, eventdict, noises using UUIDs, Dates, DataStructures, HTTP, MQTTClient, JSON3 using GeneralUtils using ..type # ---------------------------------------------- 100 --------------------------------------------- # """ Clear agent chat history. # Arguments - `a::agent` an agent # Return - nothing # Example ```jldoctest julia> using YiemAgent, MQTTClient, GeneralUtils julia> client, connection = MakeConnection("test.mosquitto.org", 1883) julia> connect(client, connection) julia> msgMeta = GeneralUtils.generate_msgMeta("testtopic") julia> agentConfig = Dict( :receiveprompt=>Dict( :mqtttopic=> "testtopic/receive", ), :receiveinternal=>Dict( :mqtttopic=> "testtopic/internal", ), :text2text=>Dict( :mqtttopic=> "testtopic/text2text", ), ) julia> a = YiemAgent.sommelier( client, msgMeta, agentConfig, ) julia> YiemAgent.addNewMessage(a, "user", "hello") julia> YiemAgent.clearhistory(a) ``` # TODO - [PENDING] clear memory # Signature """ function clearhistory(a::T) where {T<:agent} empty!(a.chathistory) empty!(a.memory[:shortmem]) empty!(a.memory[:events]) a.memory[:chatbox] = "" end """ Add new message to agent. Arguments\n ----- a::agent an agent role::String message sender role i.e. system, user or assistant text::String message text Return\n ----- nothing Example\n ----- ```jldoctest julia> using YiemAgent, MQTTClient, GeneralUtils julia> client, connection = MakeConnection("test.mosquitto.org", 1883) julia> connect(client, connection) julia> msgMeta = GeneralUtils.generate_msgMeta("testtopic") julia> agentConfig = Dict( :receiveprompt=>Dict( :mqtttopic=> "testtopic/receive", ), :receiveinternal=>Dict( :mqtttopic=> "testtopic/internal", ), :text2text=>Dict( :mqtttopic=> "testtopic/text2text", ), ) julia> a = YiemAgent.sommelier( client, msgMeta, agentConfig, ) julia> YiemAgent.addNewMessage(a, "user", "hello") ``` Signature\n ----- """ function addNewMessage(a::T1, name::String, text::T2; maximumMsg::Integer=20) where {T1<:agent, T2<:AbstractString} if name ∉ ["system", "user", "assistant"] # guard against typo error("name is not in agent.availableRole $(@__LINE__)") end #[] summarize the oldest 10 message if length(a.chathistory) > maximumMsg summarize(a.chathistory) else d = Dict(:name=> name, :text=> text, :timestamp=> Dates.now()) push!(a.chathistory, d) end end """ # Arguments - `v::Integer` dummy variable # Return # Example ```jldoctest julia> ``` # TODO - [] update docstring - [x] implement the function # Signature """ function vectorOfDictToText(vecd::Vector; withkey=true) text = "" if withkey for d in vecd name = d[:name] _text = d[:text] text *= "$name> $_text \n" end else for d in vecd for (k, v) in d text *= "$v \n" end end end return text end function eventdict(; event_description::Union{String, Nothing}=nothing, timestamp::Union{DateTime, Nothing}=nothing, subject::Union{String, Nothing}=nothing, action_or_dialogue::Union{String, Nothing}=nothing, location::Union{String, Nothing}=nothing, equipment_used::Union{String, Nothing}=nothing, material_used::Union{String, Nothing}=nothing, outcome::Union{String, Nothing}=nothing, note::Union{String, Nothing}=nothing, ) return Dict{Symbol, Any}( :event_description=> event_description, :timestamp=> timestamp, :subject=> subject, :action_or_dialogue=> action_or_dialogue, :location=> location, :equipment_used=> equipment_used, :material_used=> material_used, :outcome=> outcome, :note=> note, ) end noise(n::Integer) = String(rand('a':'z', n)) function noises(totalword::Integer, wordlength::Integer) noises = "" for i in 1:totalword noises *= noise(wordlength) * " " end noises = strip(noises) return noises end # """ Convert a single chat dictionary into LLM model instruct format. # # Llama 3 instruct format example # <|system|> # You are a helpful AI assistant.<|end|> # <|user|> # I am going to Paris, what should I see?<|end|> # <|assistant|> # Paris, the capital of France, is known for its stunning architecture, art museums."<|end|> # <|user|> # What is so great about #1?<|end|> # <|assistant|> # # Arguments # - `name::T` # message owner name e.f. "system", "user" or "assistant" # - `text::T` # # Return # - `formattedtext::String` # text formatted to model format # # Example # ```jldoctest # julia> using Revise # julia> using YiemAgent # julia> d = Dict(:name=> "system",:text=> "You are a helpful, respectful and honest assistant.",) # julia> formattedtext = YiemAgent.formatLLMtext_phi3instruct(d[:name], d[:text]) # ``` # Signature # """ # function formatLLMtext_phi3instruct(name::T, text::T) where {T<:AbstractString} # formattedtext = # """ # <|$name|> # $text<|end|>\n # """ # return formattedtext # end # """ Convert a single chat dictionary into LLM model instruct format. # # Llama 3 instruct format example # <|begin_of_text|> # <|start_header_id|>system<|end_header_id|> # You are a helpful assistant. # <|eot_id|> # <|start_header_id|>user<|end_header_id|> # Get me an icecream. # <|eot_id|> # <|start_header_id|>assistant<|end_header_id|> # Go buy it yourself at 7-11. # <|eot_id|> # # Arguments # - `name::T` # message owner name e.f. "system", "user" or "assistant" # - `text::T` # # Return # - `formattedtext::String` # text formatted to model format # # Example # ```jldoctest # julia> using Revise # julia> using YiemAgent # julia> d = Dict(:name=> "system",:text=> "You are a helpful, respectful and honest assistant.",) # julia> formattedtext = YiemAgent.formatLLMtext_llama3instruct(d[:name], d[:text]) # "<|begin_of_text|>\n <|start_header_id|>system<|end_header_id|>\n You are a helpful, respectful and honest assistant.\n <|eot_id|>\n" # ``` # Signature # """ # function formatLLMtext_llama3instruct(name::T, text::T) where {T<:AbstractString} # formattedtext = # if name == "system" # """ # <|begin_of_text|> # <|start_header_id|>$name<|end_header_id|> # $text # <|eot_id|> # """ # else # """ # <|start_header_id|>$name<|end_header_id|> # $text # <|eot_id|> # """ # end # return formattedtext # end # """ Convert a chat messages in vector of dictionary into LLM model instruct format. # # Arguments # - `messages::Vector{Dict{Symbol, T}}` # message owner name e.f. "system", "user" or "assistant" # - `formatname::T` # format name to be used # # Return # - `formattedtext::String` # text formatted to model format # # Example # ```jldoctest # julia> using Revise # julia> using YiemAgent # julia> chatmessage = [ # Dict(:name=> "system",:text=> "You are a helpful, respectful and honest assistant.",), # Dict(:name=> "user",:text=> "list me all planets in our solar system.",), # Dict(:name=> "assistant",:text=> "I'm sorry. I don't know. You tell me.",), # ] # julia> formattedtext = YiemAgent.formatLLMtext(chatmessage, "llama3instruct") # "<|begin_of_text|>\n <|start_header_id|>system<|end_header_id|>\n You are a helpful, respectful and honest assistant.\n <|eot_id|>\n <|start_header_id|>user<|end_header_id|>\n list me all planets in our solar system.\n <|eot_id|>\n <|start_header_id|>assistant<|end_header_id|>\n I'm sorry. I don't know. You tell me.\n <|eot_id|>\n" # ``` # # Signature # """ # function formatLLMtext(messages::Vector{Dict{Symbol, T}}, # formatname::String="llama3instruct") where {T<:Any} # f = if formatname == "llama3instruct" # formatLLMtext_llama3instruct # elseif formatname == "mistral" # # not define yet # elseif formatname == "phi3instruct" # formatLLMtext_phi3instruct # else # error("$formatname template not define yet") # end # str = "" # for t in messages # str *= f(t[:name], t[:text]) # end # # add <|assistant|> so that the model don't generate it and I don't need to clean it up later # if formatname == "phi3instruct" # str *= "<|assistant|>\n" # end # return str # end # """ # Arguments\n # ----- # Return\n # ----- # Example\n # ----- # ```jldoctest # julia> # ``` # TODO\n # ----- # [] update docstring # [PENDING] implement the function # Signature\n # ----- # """ # function iterativeprompting(a::T, prompt::String, verification::Function) where {T<:agent} # msgMeta = GeneralUtils.generate_msgMeta( # a.config[:externalService][:text2textinstruct], # senderName= "iterativeprompting", # senderId= a.id, # receiverName= "text2textinstruct", # ) # outgoingMsg = Dict( # :msgMeta=> msgMeta, # :payload=> Dict( # :text=> prompt, # ) # ) # success = nothing # result = nothing # critique = "" # # iteration loop # while true # # send prompt to LLM # response = GeneralUtils.sendReceiveMqttMsg(outgoingMsg) # error("--> iterativeprompting") # # check for correctness and get feedback # success, _critique = verification(response) # if success # result = response # break # else # # add critique to prompt # critique *= _critique * "\n" # replace!(prompt, "Critique: ..." => "Critique: $critique") # end # end # return (success=success, result=result) # end end # module util