Skip to content

Commit

Permalink
Version 0.0.26 -> PROD (#430)
Browse files Browse the repository at this point in the history
* 20241017 @Mookse
- version

* 20241027 @Mookse
- Bot Greetings #276
- validateRegistration

* 20241027 @Mookse
- Greeting Pipeline #293
- wip stable
- all but db instructions

* 20241027 @Mookse
- intelligence commenting

* 20241028 @Mookse
- onCreate Greetings

* 20241028 @Mookse
- incorporate ajax version for memberValidation

* 20241028 @Mookse
- Version 0.0.26 #420
- alerts()
- globals Datamanager (internal)
- cosmetic

* 20241028 @Mookse
- Version 0.0.26 #420
- alerts()
- greetings()

* 20241028 @Mookse
- mFetchHostedMembers
- mSubmitPasspharse
- mSubmitSignup

* 20241028 @Mookse
- Version 0.0.26 #420
- `members.mjs`
- obscure()
- summary()
- mSubmitChat

* 20241028 @Mookse
- Version 0.0.26 #420
- `bots.mjs`
- fetchBots()
- fetchCollections()
- fetchTeams()
- botActivate()
- mBotVersionUpdate
- botCreate
- itemDelete
- mFetchShadows => shadows()
- logout()
- help()
- uploadFiles()
- mRetireBot => botRetire()
- mRetireChat => chatRetire()
- mSetBot => botUpdate()
- mSetCollectionItem => itemUpdate()
- mSetCollectionItemTitle => itemUpdateTitle()
- mStory DELETE
- mSubmitPassphrase => passphraseUpdate()
- mReliveMemoryRequest => reliveMemory()
- mReliveMemoryRequestStop => reliveMemoryEnd()

* 20241028 @Mookse
- timeout to login

* 20241029 @Mookse
- Version 0.0.26 #420
- experience.mjs -> datamanager

* 20241029 @Mookse
- Version 0.0.26 #420
- Unable to edit memory title via pop up window header #389
- Double click on Active should allow user to edit the title of the memory #379

* 20241030 @Mookse
- Save memory without AI intervention #424
- Copy Bar Updates #311

* 20241031 @Mookse
- Enhance Memory Save Feedback and User Guidance #401
- crude but working

* 20241031 @Mookse
- Memory deletion confirmation message #423
- Enhance Memory Save Feedback and User Guidance #401

* 20241031 @Mookse
- "Sticky" Memory Refresh #395

* 20241031 @Mookse
- Selecting bots needs codification and revamp #286

* 20241101 @Mookse
- Print Memory Functionality #429
- backend

* 20241105 @Mookse
- Print Memory Functionality #429
- frontend
- wip stable
  • Loading branch information
Mookse authored Nov 7, 2024
1 parent a10c100 commit dee1297
Show file tree
Hide file tree
Showing 42 changed files with 2,124 additions and 1,857 deletions.
210 changes: 142 additions & 68 deletions inc/js/agents/system/bot-agent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
const mBot_idOverride = process.env.OPENAI_MAHT_GPT_OVERRIDE
const mDefaultBotTypeArray = ['personal-avatar', 'avatar']
const mDefaultBotType = mDefaultBotTypeArray[0]
const mDefaultGreetings = []
const mDefaultGreeting = 'Hello! If you need to know how to get started, just ask!'
const mDefaultGreetings = ['Welcome to MyLife! I am here to help you!']
const mDefaultTeam = 'memory'
const mRequiredBotTypes = ['personal-avatar']
const mTeams = [
Expand All @@ -28,16 +29,22 @@ class Bot {
#collectionsAgent
#conversation
#factory
#feedback
#initialGreeting
#greetings
#instructionNodes = new Set()
#llm
#type
constructor(botData, llm, factory){
const { id=factory.newGuid, type=mDefaultBotType, } = botData
console.log(`bot pre-created`, this.feedback)
this.#factory = factory
this.#llm = llm
botData = this.globals.sanitize(botData)
Object.assign(this, botData)
this.id = id
this.type = type
const { feedback=[], greeting=mDefaultGreeting, greetings=mDefaultGreetings, type=mDefaultBotType, ..._botData } = botData
this.#feedback = feedback
this.#greetings = greetings
this.#initialGreeting = greeting
this.#type = type
Object.assign(this, this.globals.sanitize(_botData))
switch(type){
case 'diary':
case 'journal':
Expand Down Expand Up @@ -94,6 +101,29 @@ class Bot {
const collections = ( await this.#factory.collections(type) )
return collections
}
/**
* Submits message content and id feedback to bot.
* @param {String} message_id - LLM message id
* @param {Boolean} isPositive - Positive or negative feedback, defaults to `true`
* @param {String} message - Message content (optional)
* @returns {Object} - The feedback object
*/
async feedback(message_id, isPositive=true, message=''){
if(!message_id?.length)
console.log('feedback message_id required')
this.#feedback.push(isPositive)
const botData = { feedback: this.#feedback, }
const botOptions = { instructions: false, }
this.update(botData, botOptions) // no `await`
if(message.length)
console.log(`feedback regarding agent message`, message)
const response = {
message,
message_id,
success: true,
}
return response
}
/**
* Retrieves `this` Bot instance.
* @returns {Bot} - The Bot instance
Expand All @@ -117,13 +147,17 @@ class Bot {
/**
* Retrieves a greeting message from the active bot.
* @param {Boolean} dynamic - Whether to use dynamic greetings (`true`) or static (`false`)
* @param {LLMServices} llm - OpenAI object
* @param {AgentFactory} factory - Agent Factory object
* @returns {Array} - The greeting message(s) string array in order of display
* @param {String} greetingPrompt - The prompt for the dynamic greeting
* @returns {String} - The greeting message string
*/
async getGreeting(dynamic=false, llm, factory){
const greetings = await mBotGreeting(dynamic, this, llm, factory)
return greetings
async greeting(dynamic=false, greetingPrompt='Greet me and tell me briefly what we did last'){
if(!this.llm_id)
throw new Error('Bot initialized incorrectly: missing `llm_id` from database')
const greetings = dynamic
? await mBotGreetings(this.thread_id, this.llm_id, greetingPrompt, this.#llm, this.#factory)
: this.greetings
const greeting = greetings[Math.floor(Math.random() * greetings.length)]
return greeting
}
/**
* Migrates Conversation from an old thread to a newly-created destination thread, observable in `this.Conversation`.
Expand Down Expand Up @@ -153,7 +187,7 @@ class Bot {
/* execute request */
botOptions.instructions = botOptions.instructions
?? Object.keys(botData).some(key => this.#instructionNodes.has(key))
const { id, mbr_id, type, ...updatedNodes } = await mBotUpdate(botData, botOptions, this, this.#llm, this.#factory)
const { feedback, id, mbr_id, type, ...updatedNodes } = await mBotUpdate(botData, botOptions, this, this.#llm, this.#factory)
Object.assign(this, updatedNodes)
/* respond request */
return this
Expand Down Expand Up @@ -199,6 +233,9 @@ class Bot {
get globals(){
return this.#factory.globals
}
get greetings(){
return this.#greetings
}
get instructionNodes(){
return this.#instructionNodes
}
Expand Down Expand Up @@ -239,6 +276,9 @@ class Bot {
}
return microBot
}
get type(){
return this.#type
}
}
/**
* @class - Team
Expand Down Expand Up @@ -345,14 +385,29 @@ class BotAgent {
const Conversation = await mConversationStart(type, form, bot_id, null, llm_id, this.#llm, this.#factory, prompt)
return Conversation
}
/**
* Gets the correct bot for the item type and form.
* @todo - deprecate
* @param {String} itemForm - The item form
* @param {String} itemType - The item type
* @returns {String} - The assistant type
*/
getAssistantType(itemForm='biographer', itemType='memory'){
if(itemType.toLowerCase()==='memory')
return 'biographer'
if(itemType.toLowerCase()==='entry')
return itemForm.toLowerCase()==='diary'
? 'diary'
: 'journaler'
}
/**
* Get a static or dynamic greeting from active bot.
* @param {boolean} dynamic - Whether to use LLM for greeting
* @returns {Messages[]} - The greeting message(s) string array in order of display
* @returns {String} - The greeting message from the active Bot
*/
async greeting(dynamic=false){
const greetings = await this.activeBot.getGreeting(dynamic, this.#llm, this.#factory)
return greetings
const greeting = await this.activeBot.greeting(dynamic)
return greeting
}
/**
* Begins or continues a living memory conversation.
Expand Down Expand Up @@ -414,13 +469,38 @@ class BotAgent {
}
/**
* Sets the active bot for the BotAgent.
* @async
* @param {Guid} bot_id - The Bot id
* @returns {void}
* @param {Boolean} dynamic - Whether to use dynamic greetings, defaults to `false`
* @returns {object} - Activated Response object: { bot_id, greeting, success, version, versionUpdate, }
*/
setActiveBot(bot_id=this.avatar?.id){
async setActiveBot(bot_id=this.avatar?.id, dynamic=false){
let greeting,
success=false,
version=0.0,
versionUpdate=0.0
const Bot = this.#bots.find(bot=>bot.id===bot_id)
if(Bot)
this.#activeBot = Bot
success = !!Bot
if(!success)
return
this.#activeBot = Bot
dynamic = dynamic && !this.#factory.isMyLife
if(this.#factory.isMyLife)
bot_id = null
else {
const { id, type, version: versionCurrent, } = Bot
bot_id = id
version = versionCurrent
versionUpdate = this.#factory.botInstructionsVersion(type)
}
greeting = await Bot.greeting(dynamic, `Greet member while thanking them for selecting you`)
return {
bot_id,
greeting,
success,
version,
versionUpdate,
}
}
/**
* Sets the active team for the BotAgent if `teamId` valid.
Expand Down Expand Up @@ -566,6 +646,9 @@ class BotAgent {
get globals(){
return this.#factory.globals
}
get greetings(){
return this.#activeBot.greetings
}
/**
* Returns whether BotAgent is employed by MyLife (`true`) or Member (`false`).
* @getter
Expand Down Expand Up @@ -622,7 +705,7 @@ async function mBotCreate(avatarId, vectorstore_id, botData, llm, factory){
const { type, } = botData
if(!avatarId?.length || !type?.length)
throw new Error('avatar id and type required to create bot')
const { instructions, version=1.0, } = mBotInstructions(factory, botData)
const { greeting, greetings, instructions, version=1.0, } = mBotInstructions(factory, botData)
const model = process.env.OPENAI_MODEL_CORE_BOT
?? process.env.OPENAI_MODEL_CORE_AVATAR
?? 'gpt-4o'
Expand All @@ -637,6 +720,8 @@ async function mBotCreate(avatarId, vectorstore_id, botData, llm, factory){
being: 'bot',
bot_name,
description,
greeting,
greetings,
id,
instructions,
metadata: {
Expand All @@ -655,11 +740,11 @@ async function mBotCreate(avatarId, vectorstore_id, botData, llm, factory){
version,
}
/* create in LLM */
const { id: bot_id, thread_id, } = await mBotCreateLLM(validBotData, llm)
if(!bot_id?.length)
const { id: llm_id, thread_id, } = await mBotCreateLLM(validBotData, llm)
if(!llm_id?.length)
throw new Error('bot creation failed')
/* create in MyLife datastore */
validBotData.bot_id = bot_id
validBotData.llm_id = llm_id
validBotData.thread_id = thread_id
botData = await factory.createBot(validBotData) // repurposed incoming botData
const _Bot = new Bot(botData, llm, factory)
Expand Down Expand Up @@ -709,41 +794,20 @@ async function mBotDelete(bot_id, BotAgent, llm, factory){
return true
}
/**
* Returns set of Greeting messages, dynamic or static
* @param {boolean} dynamic - Whether to use dynamic greetings
* @param {Bot} Bot - The bot instance
* Returns set of dynamically generated Greeting messages.
* @module
* @param {String} thread_id - The thread id
* @param {Guid} llm_id - The bot id
* @param {String} greetingPrompt - The prompt for the greeting
* @param {LLMServices} llm - OpenAI object
* @param {AgentFactory} factory - Agent Factory object
* @returns {Promise<Message[]>} - The array of messages to respond with
* @returns {Promise<Array>} - The array of string messages to respond with
*/
async function mBotGreeting(dynamic=false, Bot, llm, factory){
const { bot_id, bot_name, id, greetings=[], greeting, thread_id, } = Bot
const failGreetings = [
`Hello! I'm concerned that there is something wrong with my instruction-set, as I was unable to find my greetings, but let's see if I can get back online.`,
`How can I be of help today?`
]
const greetingPrompt = factory.isMyLife
? `Greet this new visitor and let them know that you are here to help them understand MyLife and the MyLife platform. Begin by asking them about something that's important to them so I can demonstrate how MyLife will assist.`
: `Where did we leave off, or how do we start?`
const botGreetings = greetings?.length
? greetings
: greeting
? [greeting]
: failGreetings
let messages = !dynamic
? botGreetings
: await llm.getLLMResponse(thread_id, bot_id, greetingPrompt, factory)
if(!messages?.length)
messages = failGreetings
messages = messages
.map(message=>new (factory.message)({
being: 'message',
content: message,
thread_id,
role: 'assistant',
type: 'greeting'
}))
return messages
async function mBotGreetings(thread_id, llm_id, greetingPrompt=`Greet me enthusiastically`, llm, factory){
let responses = await llm.getLLMResponse(thread_id, llm_id, greetingPrompt, factory)
?? [mDefaultGreetings]
responses = llm.extractResponses(responses)
return responses
}
/**
* Returns MyLife-version of bot instructions.
Expand All @@ -755,6 +819,8 @@ async function mBotGreeting(dynamic=false, Bot, llm, factory){
function mBotInstructions(factory, botData={}){
const { type=mDefaultBotType, } = botData
let {
greeting,
greetings,
instructions,
limit=8000,
version,
Expand All @@ -774,29 +840,35 @@ function mBotInstructions(factory, botData={}){
} = instructions
/* compile instructions */
switch(type){
case 'diary':
instructions = purpose
+ preamble
+ prefix
+ general
+ suffix
+ voice
break
case 'avatar':
case 'personal-avatar':
instructions = preamble
+ general
break
case 'biographer':
case 'journaler':
case 'personal-biographer':
instructions = preamble
+ purpose
+ prefix
+ general
+ voice
break
case 'diary':
instructions = purpose
+ preamble
+ prefix
+ general
+ suffix
+ voice
break
default:
instructions = general
break
}
/* greetings */
greetings = greetings
?? [greeting]
/* apply replacements */
replacements.forEach(replacement=>{
const placeholderRegExp = factory.globals.getRegExp(replacement.name, true)
Expand All @@ -806,6 +878,7 @@ function mBotInstructions(factory, botData={}){
?? replacement?.default
?? '`unknown-value`'
instructions = instructions.replace(placeholderRegExp, _=>replacementText)
greetings = greetings.map(greeting=>greeting.replace(placeholderRegExp, _=>replacementText))
})
/* apply references */
references.forEach(_reference=>{
Expand Down Expand Up @@ -842,6 +915,7 @@ function mBotInstructions(factory, botData={}){
}
})
const response = {
greetings,
instructions,
version,
}
Expand All @@ -863,7 +937,7 @@ async function mBotUpdate(botData, options={}, Bot, llm, factory){
throw new Error('Bot instance required to update bot')
const { bot_id, id, llm_id, metadata={}, type, vectorstoreId: bot_vectorstore_id, } = Bot
const _llm_id = llm_id
?? bot_id // @stub - deprecate bot_id
?? bot_id // @stub - deprecate bot_id
const {
instructions: discardInstructions,
mbr_id, // no modifications allowed
Expand Down Expand Up @@ -1023,7 +1097,7 @@ function mGetAIFunctions(type, globals, vectorstoreId){
tools.push(
globals.getGPTJavascriptFunction('changeTitle'),
globals.getGPTJavascriptFunction('getSummary'),
globals.getGPTJavascriptFunction('storySummary'),
globals.getGPTJavascriptFunction('itemSummary'),
globals.getGPTJavascriptFunction('updateSummary'),
)
includeSearch = true
Expand All @@ -1035,8 +1109,8 @@ function mGetAIFunctions(type, globals, vectorstoreId){
case 'journaler':
tools.push(
globals.getGPTJavascriptFunction('changeTitle'),
globals.getGPTJavascriptFunction('entrySummary'),
globals.getGPTJavascriptFunction('getSummary'),
globals.getGPTJavascriptFunction('itemSummary'),
globals.getGPTJavascriptFunction('obscure'),
globals.getGPTJavascriptFunction('updateSummary'),
)
Expand Down Expand Up @@ -1097,7 +1171,7 @@ function mGetGPTResources(globals, toolName, vectorstoreId){
async function mInit(BotAgent, bots, factory, llm){
const { avatarId, vectorstoreId, } = BotAgent
bots.push(...await mInitBots(avatarId, vectorstoreId, factory, llm))
BotAgent.setActiveBot()
BotAgent.setActiveBot(null, false)
}
/**
* Initializes active bots based upon criteria.
Expand Down
Loading

0 comments on commit dee1297

Please sign in to comment.