450 lines
10 KiB
Julia
450 lines
10 KiB
Julia
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 |