Skip to content

Commit

Permalink
Merge pull request #180 from MyLife-Services/179-version-003-updates
Browse files Browse the repository at this point in the history
20240429 Weekly Sprint Maht Update
  • Loading branch information
Mookse authored Apr 29, 2024
2 parents ccea581 + c0a56e3 commit 4d70b2c
Show file tree
Hide file tree
Showing 17 changed files with 1,380 additions and 436 deletions.
41 changes: 35 additions & 6 deletions inc/js/functions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ async function alerts(ctx){
}
}
async function bots(ctx){
const _bot = ctx.request.body
const bot = ctx.request.body
switch(ctx.method){
case 'POST':
ctx.body = await ctx.state.avatar.setBot(_bot)
case 'POST': // create new bot
ctx.body = await ctx.state.avatar.setBot(bot)
break
case 'PUT':
if(ctx.params.bid!==_bot.id) throw new Error('invalid bot data')
ctx.body = await ctx.state.avatar.setBot(_bot)
case 'PUT': // update bot
if(ctx.params.bid!==bot.id)
throw new Error('invalid bot data')
ctx.body = await ctx.state.avatar.setBot(bot)
break
case 'GET':
default:
Expand Down Expand Up @@ -77,6 +78,9 @@ async function chat(ctx){
const _response = await ctx.state.avatar.chatRequest(ctx)
ctx.body = _response // return message_member_chat
}
async function collections(ctx){
ctx.body = await ctx.state.avatar.collections(ctx.params.type)
}
/**
* Manage delivery and receipt of contributions(s).
* @async
Expand All @@ -91,6 +95,20 @@ async function contributions(ctx){
: mSetContributions(ctx)
)
}
/**
* Delete an item from collection via the member's avatar.
* @async
* @public
* @requires ctx.state.avatar - The avatar object for the member.
* @param {object} ctx - Koa Context object
* @returns {boolean} - Under `ctx.body`, status of deletion.
*/
async function deleteItem(ctx){
const { iid, } = ctx.params
if(!iid?.length)
ctx.throw(400, `missing item id`)
ctx.body = await ctx.state.avatar.deleteItem(iid)
}
/**
* Index page for the application.
* @async
Expand Down Expand Up @@ -148,6 +166,14 @@ async function members(ctx){ // members home
ctx.state.subtitle = `Welcome Agent ${ctx.state.member.agentName}`
await ctx.render('members')
}
async function passphraseReset(ctx){
if(ctx.state.avatar.isMyLife)
ctx.throw(400, `cannot reset system passphrase`)
const { passphrase } = ctx.request.body
if(!passphrase?.length)
ctx.throw(400, `passphrase required for reset`)
ctx.body = await ctx.state.avatar.resetPassphrase(passphrase)
}
async function privacyPolicy(ctx){
ctx.state.title = `MyLife Privacy Policy`
ctx.state.subtitle = `Effective Date: 2024-01-01`
Expand Down Expand Up @@ -262,13 +288,16 @@ export {
category,
challenge,
chat,
collections,
contributions,
deleteItem,
index,
interfaceMode,
login,
logout,
loginSelect,
members,
passphraseReset,
privacyPolicy,
signup,
upload,
Expand Down
32 changes: 31 additions & 1 deletion inc/js/mylife-agent-factory.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import MylifeMemberSession from './session.mjs'
import chalk from 'chalk'
/* modular constants */
// global object keys to exclude from class creations [apparently fastest way in js to lookup items, as they are hash tables]
const { MYLIFE_SERVER_MBR_ID: mPartitionId, } = process.env
const mBotInstructions = {}
const mPartitionId = process.env.MYLIFE_SERVER_MBR_ID
const mDataservices = await new Dataservices(mPartitionId).init()
const mDefaultBotType = 'personal-avatar'
const mExtensionFunctions = {
Expand Down Expand Up @@ -173,11 +173,29 @@ class BotFactory extends EventEmitter{
)
return _bots
}
/**
* Get member collection items.
* @param {string} type - The type of collection to retrieve, `false`-y = all.
* @returns {array} - The collection items with no wrapper.
*/
async collections(type){
return await this.dataservices.collections(type)
}
async createBot(bot={ type: mDefaultBotType }){
bot.id = this.newGuid
const _bot = await mCreateBot(this.#llmServices, this, bot, this.avatarId)
return _bot
}
/**
* Delete an item from member container.
* @param {Guid} id - The id of the item to delete.
* @returns {boolean} - true if item deleted successfully.
*/
async deleteItem(id){
if(this.isMyLife)
throw new Error('MyLife avatar cannot delete items.')
return await this.dataservices.deleteItem(id)
}
/**
* Gets array of member `experiences` from database. When placed here, it allows for a bot to be spawned who has access to this information, which would make sense for a mini-avatar whose aim is to report what experiences a member has endured.
* @public
Expand Down Expand Up @@ -267,6 +285,18 @@ class BotFactory extends EventEmitter{
}
return _updatedLibrary
}
/**
* Allows member to reset passphrase.
* @param {string} passphrase
* @returns {boolean} - true if passphrase reset successful.
*/
async resetPassphrase(passphrase){
if(this.isMyLife)
throw new Error('MyLife avatar cannot reset passphrase.')
if(!passphrase?.length)
throw new Error('Passphrase required for reset.')
return await this.dataservices.resetPassphrase(passphrase)
}
/**
* Adds or updates a bot.
* @public
Expand Down
91 changes: 67 additions & 24 deletions inc/js/mylife-avatar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { EvolutionAssistant } from './agents/system/evolution-assistant.mjs'
import LLMServices from './mylife-llm-services.mjs'
/* modular constants */
const { MYLIFE_DB_ALLOW_SAVE, OPENAI_MAHT_GPT_OVERRIDE, } = process.env
const allowSave = JSON.parse(MYLIFE_DB_ALLOW_SAVE ?? 'false')
const mAllowSave = JSON.parse(MYLIFE_DB_ALLOW_SAVE ?? 'false')
const mAvailableModes = ['standard', 'admin', 'evolution', 'experience', 'restoration']
const botIdOverride = OPENAI_MAHT_GPT_OVERRIDE
const mBotIdOverride = OPENAI_MAHT_GPT_OVERRIDE
/**
* @class
* @extends EventEmitter
Expand Down Expand Up @@ -72,7 +72,7 @@ class Avatar extends EventEmitter {
let activeBot = this.avatarBot
if(!this.isMyLife){
if(!activeBot?.id){ // create: but do not want to call setBot() to activate
activeBot = await mBot(this.#llmServices, this.#factory, this, { type: 'personal-avatar' })
activeBot = await mBot(this.#factory, this, { type: 'personal-avatar' })
this.#bots.unshift(activeBot)
}
this.activeBotId = activeBot.id
Expand All @@ -85,7 +85,7 @@ class Avatar extends EventEmitter {
} else { // Q-specific, leave as `else` as is near always false
// @todo - something doesn't smell right in how session would handle conversations - investigate logic; fine if new Avatar instance is spawned for each session, which might be true
this.activeBotId = activeBot.id
activeBot.bot_id = botIdOverride ?? activeBot.bot_id
activeBot.bot_id = mBotIdOverride ?? activeBot.bot_id
this.#llmServices.botId = activeBot.bot_id
const conversation = await this.createConversation()
activeBot.thread_id = conversation.threadId
Expand Down Expand Up @@ -123,7 +123,7 @@ class Avatar extends EventEmitter {
conversation.botId = this.activeBot.bot_id // pass in via quickly mutating conversation (or independently if preferred in end), versus llmServices which are global
const messages = await mCallLLM(this.#llmServices, conversation, prompt)
conversation.addMessages(messages)
if(allowSave)
if(mAllowSave)
conversation.save()
else
console.log('chatRequest::BYPASS-SAVE', conversation.message)
Expand Down Expand Up @@ -154,12 +154,33 @@ class Avatar extends EventEmitter {
})
return chat
}
/**
* Get member collection items.
* @param {string} type - The type of collection to retrieve, `false`-y = all.
* @returns {array} - The collection items with no wrapper.
*/
async collections(type){
const collections = await this.factory.collections(type)
return collections
}
async createConversation(type='chat'){
const thread = await this.#llmServices.thread()
const conversation = new (this.#factory.conversation)({ mbr_id: this.mbr_id, type: type }, this.#factory, thread, this.activeBotId) // guid only
this.#conversations.push(conversation)
return conversation
}
/**
* Delete an item from member container.
* @async
* @public
* @param {Guid} id - The id of the item to delete.
* @returns {boolean} - true if item deleted successfully.
*/
async deleteItem(id){
if(this.isMyLife)
throw new Error('MyLife avatar cannot delete items.')
return await this.factory.deleteItem(id)
}
/**
* Ends an experience.
* @todo - save living experience to cosmos, no need to await
Expand Down Expand Up @@ -249,6 +270,18 @@ class Avatar extends EventEmitter {
return this.#conversations
.find(_=>_.thread?.id===thread_id)
}
/**
* Allows member to reset passphrase.
* @param {string} passphrase
* @returns {boolean} - true if passphrase reset successful.
*/
async resetPassphrase(passphrase){
if(this.isMyLife)
throw new Error('MyLife avatar cannot reset passphrase.')
if(!passphrase?.length)
throw new Error('Passphrase required for reset.')
return await this.#factory.resetPassphrase(passphrase)
}
/**
* Processes and executes incoming category set request.
* @todo - deprecate if possible.
Expand All @@ -264,13 +297,18 @@ class Avatar extends EventEmitter {
}
/**
* Add or update bot, and identifies as activated, unless otherwise specified.
* @todo - strip protected bot data/create class?.
* @param {object} bot - Bot-data to set.
* @param {boolean} activate - Whether to activate bot, default=`true`.
* @returns {object} - The updated bot.
*/
async setBot(bot, activate=true){
bot = await mBot(this.#llmServices, this.#factory, this, bot)
/* add bot to avatar */
bot = await mBot(this.#factory, this, bot)
/* add/update bot */
if(!this.#bots.some(_bot => _bot.id === bot.id))
this.#bots.push(bot)
else
this.#bots = this.#bots.map(_bot=>_bot.id===bot.id ? bot : _bot)
/* activation */
if(activate)
this.activeBotId = bot.id
Expand Down Expand Up @@ -741,37 +779,42 @@ function mAssignGenericExperienceVariables(experienceVariables, avatar){
* Updates or creates bot (defaults to new personal-avatar) in Cosmos and returns successful `bot` object, complete with conversation (including thread/thread_id in avatar) and gpt-assistant intelligence.
* @todo Fix occasions where there will be no object_id property to use, as it was created through a hydration method based on API usage, so will be attached to mbr_id, but NOT avatar.id
* @modular
* @param {LLMServices} llm - OpenAI object
* @param {AgentFactory} factory - Agent Factory object
* @param {Avatar} avatar - Avatar object that will govern bot
* @param {object} bot - Bot object
* @returns {object} - Bot object
*/
async function mBot(llm, factory, avatar, bot){
async function mBot(factory, avatar, bot){
/* validation */
const { bots, id: avatarId, } = avatar
const { mbr_id, } = factory
const { bot_id, id: botId, mbr_id: botMbr_id, thread_id, type, } = bot
/* set required bot super-properties */
bot.mbr_id = bot.botMbr_id ?? factory.mbr_id
bot.type = bot.type ?? mDefaultBotType
bot.object_id = bot.object_id ?? avatarId
bot.id = botId ?? factory.newGuid // **note**: _this_ is a Cosmos id, not an openAI id
const { bots, id: avatarId, isMyLife, mbr_id, } = avatar
if(isMyLife)
throw new Error('MyLife system avatar may not create or alter its associated bots.')
const { newGuid, } = factory
const { id: botId=newGuid, object_id: objectId, type: botType, } = bot
/* set/reset required bot super-properties */
bot.mbr_id = mbr_id
bot.object_id = objectId ?? avatarId /* all your bots belong to me */
bot.id = botId // **note**: _this_ is a Cosmos id, not an openAI id
if(botType?.length) /* `bot.type` mutable? */
bot.type = botType
let _bot = bots.find(oBot=>oBot.id===bot.id)
?? await factory.createBot(bot)
/* update bot */
_bot = {..._bot, ...bot}
/* create or update bot properties */
if(!_bot.thread_id?.length){
const conversation = await avatar.createConversation()
_bot.thread_id = conversation.thread_id
/* create or update bot special properties */
const { thread_id, type, } = _bot
if(!thread_id?.length){
const excludeTypes = ['library',]
if(!excludeTypes.includes(type)){
const conversation = await avatar.createConversation()
_bot.thread_id = conversation.thread_id
}
}
// update Cosmos (no need async)
factory.setBot(_bot)
factory.setBot(_bot) // update Cosmos (no need async)
return _bot
}
/**
* Makes call to LLM and to return response(s) to prompt.\
* Makes call to LLM and to return response(s) to prompt.
* @todo - create actor-bot for internal chat? Concern is that API-assistants are only a storage vehicle, ergo not an embedded fine tune as I thought (i.e., there still may be room for new fine-tuning exercise); i.e., micro-instructionsets need to be developed for most. Unclear if direct thread/message instructions override or ADD, could check documentation or gpt, but...
* @todo - address disconnect between conversations held in memory in avatar and those in openAI threads; use `addLLMMessages` to post internally
* @modular
Expand Down
Loading

0 comments on commit 4d70b2c

Please sign in to comment.