Skip to content

Commit 021d174

Browse files
authored
Merge pull request #452 from MyLife-Services/azure-deploy-prod
Azure deploy prod
2 parents 3f234b7 + 272c799 commit 021d174

25 files changed

+854
-293
lines changed

inc/js/agents/system/bot-agent.mjs

Lines changed: 92 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
const mBot_idOverride = process.env.OPENAI_MAHT_GPT_OVERRIDE
33
const mDefaultBotTypeArray = ['personal-avatar', 'avatar']
44
const mDefaultBotType = mDefaultBotTypeArray[0]
5-
const mDefaultGreeting = 'Hello! If you need to know how to get started, just ask!'
5+
const mDefaultGreeting = 'avatar' // greeting routine
66
const mDefaultGreetings = ['Welcome to MyLife! I am here to help you!']
77
const mDefaultTeam = 'memory'
88
const mRequiredBotTypes = ['personal-avatar']
@@ -28,20 +28,24 @@ const mTeams = [
2828
class Bot {
2929
#collectionsAgent
3030
#conversation
31+
#documentName
3132
#factory
3233
#feedback
33-
#initialGreeting
34+
#firstAccess=false
35+
#greetingRoutine
3436
#greetings
3537
#instructionNodes = new Set()
3638
#llm
3739
#type
3840
constructor(botData, llm, factory){
3941
this.#factory = factory
4042
this.#llm = llm
41-
const { feedback=[], greeting=mDefaultGreeting, greetings=mDefaultGreetings, type=mDefaultBotType, ..._botData } = botData
43+
const { feedback=[], greeting=mDefaultGreeting, greetings=mDefaultGreetings, name, unaccessed, type=mDefaultBotType, ..._botData } = botData
44+
this.#documentName = name
4245
this.#feedback = feedback
46+
this.#firstAccess = unaccessed
4347
this.#greetings = greetings
44-
this.#initialGreeting = greeting
48+
this.#greetingRoutine = type.split('-').pop()
4549
this.#type = type
4650
Object.assign(this, this.globals.sanitize(_botData))
4751
switch(type){
@@ -75,7 +79,7 @@ class Bot {
7579
Conversation.prompt = message
7680
Conversation.originalPrompt = originalMessage
7781
await mCallLLM(Conversation, allowSave, this.#llm, this.#factory, avatar) // mutates Conversation
78-
/* frontend mutations */
82+
this.accessed = true
7983
return Conversation
8084
}
8185
/**
@@ -153,17 +157,27 @@ class Bot {
153157
/**
154158
* Retrieves a greeting message from the active bot.
155159
* @param {Boolean} dynamic - Whether to use dynamic greetings (`true`) or static (`false`)
156-
* @param {String} greetingPrompt - The prompt for the dynamic greeting
157-
* @returns {String} - The greeting message string
160+
* @param {string} greetingPrompt - The prompt for the dynamic greeting
161+
* @returns {object} - The Response object { responses, routine, success, }
158162
*/
159163
async greeting(dynamic=false, greetingPrompt='Greet me and tell me briefly what we did last'){
160164
if(!this.llm_id)
161165
throw new Error('Bot initialized incorrectly: missing `llm_id` from database')
162-
const greetings = dynamic
163-
? await mBotGreetings(this.thread_id, this.llm_id, greetingPrompt, this.#llm, this.#factory)
164-
: this.greetings
165-
const greeting = greetings[Math.floor(Math.random() * greetings.length)]
166-
return greeting
166+
let greeting,
167+
responses=[],
168+
routine
169+
if(!this.#firstAccess){
170+
const greetings = dynamic
171+
? await mBotGreetings(this.thread_id, this.llm_id, greetingPrompt, this.#llm, this.#factory)
172+
: [this.greetings[Math.floor(Math.random() * this.greetings.length)]]
173+
responses.push(...greetings)
174+
} else
175+
routine = this.#greetingRoutine
176+
return {
177+
responses,
178+
routine,
179+
success: true,
180+
}
167181
}
168182
/**
169183
* Migrates Conversation from an old thread to a newly-created destination thread, observable in `this.Conversation`.
@@ -215,12 +229,23 @@ class Bot {
215229
await this.#factory.updateBot(bot)
216230
}
217231
/* getters/setters */
232+
get accessed(){
233+
return !this.unaccessed
234+
}
235+
set accessed(accessed=true){
236+
if(accessed){
237+
this.update({
238+
unaccessed: false,
239+
})
240+
this.#firstAccess = false
241+
}
242+
}
218243
/**
219244
* Gets the frontend bot object.
220245
* @getter
221246
*/
222247
get bot() {
223-
const { bot_name: name, description, flags, id, interests, purpose, type, version } = this
248+
const { description, flags, id, interests, name, purpose, type, version } = this
224249
const bot = {
225250
description,
226251
flags,
@@ -263,24 +288,11 @@ class Bot {
263288
get isMyLife(){
264289
return this.#factory.isMyLife
265290
}
266-
get micro(){
267-
const {
268-
bot_name,
269-
id,
270-
name,
271-
provider,
272-
type,
273-
version,
274-
} = this
275-
const microBot = {
276-
bot_name,
277-
id,
278-
name,
279-
provider,
280-
type,
281-
version,
282-
}
283-
return microBot
291+
get name(){
292+
return this.bot_name
293+
}
294+
set name(name){
295+
this.bot_name = name
284296
}
285297
get type(){
286298
return this.#type
@@ -298,7 +310,7 @@ class Bot {
298310
class BotAgent {
299311
#activeBot
300312
#activeTeam = mDefaultTeam
301-
#avatarId
313+
#avatar
302314
#bots
303315
#factory
304316
#fileConversation
@@ -311,19 +323,19 @@ class BotAgent {
311323
/**
312324
* Initializes the BotAgent instance.
313325
* @async
314-
* @param {Guid} avatarId - The Avatar id
326+
* @param {Guid} Avatar - The Avatar instance
315327
* @param {string} vectorstoreId - The Vectorstore id
316328
* @returns {Promise<BotAgent>} - The BotAgent instance
317329
*/
318-
async init(avatarId, vectorstoreId){
330+
async init(Avatar){
319331
/* validate request */
320-
if(!avatarId?.length)
321-
throw new Error('AvatarId required')
322-
this.#avatarId = avatarId
332+
if(!Avatar)
333+
throw new Error('Avatar required')
334+
this.#avatar = Avatar
323335
this.#bots = []
324-
this.#vectorstoreId = vectorstoreId
336+
this.#vectorstoreId = Avatar.vectorstoreId
325337
/* execute request */
326-
await mInit(this, this.#bots, this.#factory, this.#llm)
338+
await mInit(this, this.#bots, this.#avatar, this.#factory, this.#llm)
327339
return this
328340
}
329341
/* public functions */
@@ -346,7 +358,7 @@ class BotAgent {
346358
* @returns {Bot} - The created Bot instance
347359
*/
348360
async botCreate(botData){
349-
const Bot = await mBotCreate(this.#avatarId, this.#vectorstoreId, botData, this.#llm, this.#factory)
361+
const Bot = await mBotCreate(this.avatarId, this.#vectorstoreId, botData, this.#llm, this.#factory)
350362
this.#bots.push(Bot)
351363
this.setActiveBot(Bot.id)
352364
return Bot
@@ -509,10 +521,11 @@ class BotAgent {
509521
version = versionCurrent
510522
versionUpdate = this.#factory.botInstructionsVersion(type)
511523
}
512-
greeting = await Bot.greeting(dynamic, `Greet member while thanking them for selecting you`)
524+
const { responses, routine, success: greetingSuccess, } = await Bot.greeting(dynamic, `Greet member while thanking them for selecting you`)
513525
return {
514526
bot_id,
515-
greeting,
527+
responses,
528+
routine,
516529
success,
517530
version,
518531
versionUpdate,
@@ -634,7 +647,7 @@ class BotAgent {
634647
* @returns {String} - The Avatar id
635648
*/
636649
get avatarId(){
637-
return this.#avatarId
650+
return this.#avatar?.id
638651
}
639652
/**
640653
* Gets the Biographer bot for the BotAgent.
@@ -726,15 +739,17 @@ async function mBotCreate(avatarId, vectorstore_id, botData, llm, factory){
726739
?? 'gpt-4o'
727740
const { tools, tool_resources, } = mGetAIFunctions(type, factory.globals, vectorstore_id)
728741
const id = factory.newGuid
742+
const typeShort = type.split('-').pop()
729743
let {
730-
bot_name = `My ${type}`,
731-
description = `I am a ${type} for ${factory.memberName}`,
732-
name = `bot_${type}_${avatarId}`,
744+
bot_name=`My ${ typeShort }`,
745+
description=`I am a ${ typeShort } for ${ factory.memberName }`,
746+
name=`bot_${ type }_${ avatarId }`,
733747
} = botData
734748
const validBotData = {
735-
being: 'bot',
749+
being: 'bot', // intentionally hard-coded
736750
bot_name,
737751
description,
752+
unaccessed: true,
738753
greeting,
739754
greetings,
740755
id,
@@ -751,6 +766,7 @@ async function mBotCreate(avatarId, vectorstore_id, botData, llm, factory){
751766
tools,
752767
tool_resources,
753768
type,
769+
unaccessed: true, // removed after first chat
754770
vectorstore_id,
755771
version,
756772
}
@@ -763,7 +779,7 @@ async function mBotCreate(avatarId, vectorstore_id, botData, llm, factory){
763779
validBotData.thread_id = thread_id
764780
botData = await factory.createBot(validBotData) // repurposed incoming botData
765781
const _Bot = new Bot(botData, llm, factory)
766-
console.log(`bot created::${ type }`, _Bot.thread_id, _Bot.id, _Bot.bot_id, _Bot.bot_name )
782+
console.log(`bot created::${ type }`, _Bot.thread_id, _Bot.id, _Bot.llm_id, _Bot.bot_name )
767783
return _Bot
768784
}
769785
/**
@@ -1183,30 +1199,50 @@ function mGetGPTResources(globals, toolName, vectorstoreId){
11831199
* @module
11841200
* @param {BotAgent} BotAgent - The BotAgent to initialize
11851201
* @param {Bot[]} bots - The array of bots (empty on init)
1202+
* @param {Avatar} Avatar - The Avatar instance
11861203
* @param {AgentFactory} factory - The factory instance
11871204
* @param {LLMServices} llm - The LLMServices instance
11881205
* @returns {void}
11891206
*/
1190-
async function mInit(BotAgent, bots, factory, llm){
1191-
const { avatarId, vectorstoreId, } = BotAgent
1192-
bots.push(...await mInitBots(avatarId, vectorstoreId, factory, llm))
1207+
async function mInit(BotAgent, bots, Avatar, factory, llm){
1208+
const { vectorstoreId, } = BotAgent
1209+
bots.push(...await mInitBots(vectorstoreId, Avatar, factory, llm))
11931210
BotAgent.setActiveBot(null, false)
11941211
}
11951212
/**
11961213
* Initializes active bots based upon criteria.
1197-
* @param {Guid} avatarId - The Avatar id
11981214
* @param {String} vectorstore_id - The Vectorstore id
1215+
* @param {Avatar} Avatar - The Avatar instance
11991216
* @param {AgentFactory} factory - The MyLife factory instance
12001217
* @param {LLMServices} llm - The LLMServices instance
12011218
* @returns {Bot[]} - The array of activated and available bots
12021219
*/
1203-
async function mInitBots(avatarId, vectorstore_id, factory, llm){
1204-
const bots = ( await factory.bots(avatarId) )
1205-
.map(botData=>{
1220+
async function mInitBots(vectorstore_id, Avatar, factory, llm){
1221+
let bots = await factory.bots(Avatar?.id)
1222+
if(bots?.length){
1223+
bots = bots.map(botData=>{
12061224
botData.vectorstore_id = vectorstore_id
1207-
botData.object_id = avatarId
1225+
botData.object_id = Avatar.id
12081226
return new Bot(botData, llm, factory)
12091227
})
1228+
} else {
1229+
if(factory.isMyLife)
1230+
throw new Error('MyLife bots not yet implemented')
1231+
const botTypes = mGetBotTypes(factory.isMyLife)
1232+
bots = await Promise.all(
1233+
botTypes.map(async type=>{
1234+
const botData = {
1235+
object_id: Avatar.id,
1236+
type,
1237+
}
1238+
if(type.includes('avatar'))
1239+
botData.bot_name = Avatar.nickname
1240+
const Bot = await mBotCreate(Avatar.id, vectorstore_id, botData, llm, factory)
1241+
return Bot
1242+
})
1243+
)
1244+
Avatar.setupComplete = true
1245+
}
12101246
return bots
12111247
}
12121248
/**

inc/js/functions.mjs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
/* imports */
2-
import fs from 'fs/promises'
3-
import path from 'path'
4-
import { fileURLToPath } from 'url'
52
import {
63
upload as apiUpload,
74
} from './api-functions.mjs'
8-
/* variables */
9-
const __filename = fileURLToPath(import.meta.url)
10-
const __dirname = path.dirname(__filename)
115
/* module export functions */
126
/**
137
* Renders the about page for the application. Visitors see the rendered page, members see the page as responses from their Avatar.
@@ -20,9 +14,7 @@ async function about(ctx){
2014
await ctx.render('about')
2115
} else {
2216
const { avatar: Avatar, } = ctx.state
23-
const aboutFilePath = path.resolve(__dirname, '../..', 'views/assets/html/_about.html')
24-
const html = await fs.readFile(aboutFilePath, 'utf-8')
25-
const response = await Avatar.renderContent(html)
17+
const response = await Avatar.routine('about')
2618
ctx.body = response
2719
}
2820
}
@@ -307,9 +299,7 @@ async function privacyPolicy(ctx){
307299
await ctx.render('privacy-policy')
308300
} else {
309301
const { avatar: Avatar, } = ctx.state
310-
const aboutFilePath = path.resolve(__dirname, '../..', 'views/assets/html/_privacy-policy.html')
311-
const html = await fs.readFile(aboutFilePath, 'utf-8')
312-
const response = await Avatar.renderContent(html)
302+
const response = await Avatar.routine('privacy')
313303
ctx.body = response
314304
}
315305
}
@@ -326,11 +316,21 @@ async function retireBot(ctx){
326316
* @param {Koa} ctx - Koa Context object
327317
*/
328318
async function retireChat(ctx){
329-
const { avatar, } = ctx.state
319+
const { avatar: Avatar, } = ctx.state
330320
const { bid, } = ctx.params
331321
if(!bid?.length)
332322
ctx.throw(400, `missing bot id`)
333-
const response = await avatar.retireChat(bid)
323+
const response = await Avatar.retireChat(bid)
324+
ctx.body = response
325+
}
326+
/**
327+
* Routines are pre-composed scripts that can be run on-demand. They animate HTML content formatted by <section>.
328+
* @param {Koa} ctx - Koa Context object
329+
*/
330+
async function routine(ctx){
331+
const { rid, } = ctx.params
332+
const { avatar: Avatar, } = ctx.state
333+
const response = await Avatar.routine(rid)
334334
ctx.body = response
335335
}
336336
/**
@@ -465,6 +465,7 @@ export {
465465
privacyPolicy,
466466
retireBot,
467467
retireChat,
468+
routine,
468469
shadows,
469470
signup,
470471
summarize,

inc/js/menu.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ class Menu {
77
return this.#menu
88
}
99
#setMenu(){
10+
/* **note**: clicks need connector between window element and datamanager call, even when genericized with an intermediary */
1011
this.#menu = [
11-
{ display: `About`, icon: 'about', memberClick: 'about()', memberRoute: 'javascript:void(0)', route: '/about', },
12+
{ display: `About`, icon: 'about', click: 'about()', route: 'javascript:void(0)', },
1213
{ display: `Walkthrough`, route: 'https://medium.com/@ewbj/mylife-we-save-your-life-480a80956a24', icon: 'gear', },
1314
{ display: `Donate`, route: 'https://gofund.me/65013d6e', icon: 'donate', },
1415
]

0 commit comments

Comments
 (0)