Skip to content

Commit 91f1187

Browse files
committed
Merge branch 'azure-deploy-prod' into base
version 0.0.18
2 parents c1db5e1 + 9f68074 commit 91f1187

File tree

13 files changed

+264
-102
lines changed

13 files changed

+264
-102
lines changed

inc/js/core.mjs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// imports
22
import EventEmitter from 'events'
3-
import chalk from 'chalk'
43
// server-specific imports
54
import initRouter from './routes.mjs'
65
// define export Classes for Members and MyLife
@@ -234,6 +233,7 @@ class Organization extends Member { // form=organization
234233
}
235234
class MyLife extends Organization { // form=server
236235
#avatar // MyLife's private class avatar, _same_ object reference as Member Class's `#avatar`
236+
#version = '0.0.0' // indicates error
237237
constructor(factory){ // no session presumed to exist
238238
super(factory)
239239
}
@@ -365,6 +365,14 @@ class MyLife extends Organization { // form=server
365365
get being(){
366366
return 'MyLife'
367367
}
368+
get version(){
369+
return this.#version
370+
}
371+
set version(_version){
372+
if(!this.globals.isValidVersion(_version))
373+
throw new Error('Invalid version number')
374+
this.#version = _version
375+
}
368376
}
369377
/* exports */
370378
export {

inc/js/functions.mjs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,17 @@ async function challenge(ctx){
9393
* @param {Koa} ctx - Koa Context object
9494
*/
9595
async function chat(ctx){
96-
const { botId, message, role, } = ctx.request.body
97-
?? {} /* body nodes sent by fe */
96+
const { botId, itemId, message, shadowId, } = ctx.request.body ?? {} /* body nodes sent by fe */
9897
if(!message?.length)
9998
ctx.throw(400, 'missing `message` content')
10099
const { avatar, MemberSession, } = ctx.state
101100
const { isMyLife, thread_id, } = MemberSession
101+
let conversation
102102
if(isMyLife && !thread_id?.length){
103-
const conversation = await avatar.createConversation('system', undefined, botId, true) // pushes to this.#conversations in Avatar
103+
conversation = await avatar.createConversation('system', undefined, botId, true) // pushes to this.#conversations in Avatar
104104
MemberSession.thread_id = conversation.thread_id
105105
}
106-
const response = await avatar.chatRequest(botId, MemberSession.thread_id, message)
106+
const response = await avatar.chatRequest(message, botId, MemberSession.thread_id, itemId, shadowId, conversation)
107107
ctx.body = response
108108
}
109109
async function collections(ctx){
@@ -234,15 +234,6 @@ async function privacyPolicy(ctx){
234234
ctx.state.subtitle = `Effective Date: 2024-01-01`
235235
await ctx.render('privacy-policy') // privacy-policy
236236
}
237-
async function shadow(ctx){
238-
const { avatar, } = ctx.state
239-
const { active=true, botId, itemId, message, role, threadId, shadowId, title, } = ctx.request.body // necessary to flip active bot, or just presume to use the creator of the shadow?
240-
if(!itemId?.length)
241-
ctx.throw(400, `missing item id`)
242-
if(!active) // @stub - redirect to normal chat?
243-
ctx.throw(400, `shadow must be active`)
244-
ctx.body = await avatar.shadow(shadowId, itemId, title, message)
245-
}
246237
/**
247238
* Gets the list of shadows.
248239
* @returns {Object[]} - Array of shadow objects.
@@ -370,7 +361,6 @@ export {
370361
members,
371362
passphraseReset,
372363
privacyPolicy,
373-
shadow,
374364
shadows,
375365
signup,
376366
summarize,

inc/js/globals.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ class Globals extends EventEmitter {
244244
isValidGuid(text){
245245
return typeof text === 'string' && mGuidRegex.test(text)
246246
}
247+
isValidVersion(version) {
248+
const regex = /^\d+\.\d+\.\d+$/
249+
return typeof version === 'string' && regex.test(version)
250+
}
247251
stripCosmosFields(object){
248252
return Object.fromEntries(Object.entries(object).filter(([k, v]) => !k.startsWith('_')))
249253
}

inc/js/mylife-avatar.mjs

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -81,32 +81,40 @@ class Avatar extends EventEmitter {
8181
}
8282
/**
8383
* Processes and executes incoming chat request.
84-
* @todo - cleanup/streamline frontend communication as it really gets limited to Q&A... other events would fire API calls on the same same session, so don't need to be in chat or conversation streams
8584
* @public
85+
* @param {string} message - The chat message content.
8686
* @param {string} activeBotId - The active bot id.
8787
* @param {string} threadId - The openai thread id.
88-
* @param {string} chatMessage - The chat message content.
88+
* @param {Guid} itemId - The active collection-item id (optional).
89+
* @param {Guid} shadowId - The active Shadow Id (optional).
8990
* @param {Conversation} conversation - The conversation object.
9091
* @param {number} processStartTime - The start time of the process.
9192
* @returns {object} - The response(s) to the chat request.
9293
*/
93-
async chatRequest(activeBotId, threadId, chatMessage, conversation, processStartTime=Date.now()){
94-
if(!chatMessage)
94+
async chatRequest(message, activeBotId, threadId, itemId, shadowId, conversation, processStartTime=Date.now()){
95+
if(!message)
9596
throw new Error('No message provided in context')
9697
if(!activeBotId)
9798
throw new Error('Parameter `activeBotId` required.')
9899
const { activeBot, factory } = this
99100
const { id: botId, thread_id, } = activeBot
100101
if(botId!==activeBotId)
101102
throw new Error(`Invalid bot id: ${ activeBotId }, active bot id: ${ botId }`)
102-
// @stub - clean up conversation alterations - Q is immune
103103
conversation = conversation
104104
?? this.getConversation(threadId ?? thread_id)
105105
?? await this.createConversation('chat', threadId ?? thread_id, activeBotId)
106106
if(!conversation)
107107
throw new Error('No conversation found for thread id and could not be created.')
108108
conversation.bot_id = activeBot.bot_id // pass in via quickly mutating conversation (or independently if preferred in end), versus llmServices which are global
109-
const messages = await mCallLLM(this.#llmServices, conversation, chatMessage, factory, this)
109+
let messages
110+
if(shadowId)
111+
messages = await this.shadow(shadowId, itemId, message)
112+
else {
113+
// @stub - one weakness in teh chain might also be the fact that I am not including in instructions how to create integrated summary and left it primarily to the JSON description of function
114+
if(itemId)
115+
message = `update-memory-request: itemId=${ itemId }\n` + message
116+
messages = await mCallLLM(this.#llmServices, conversation, message, factory, this)
117+
}
110118
conversation.addMessages(messages)
111119
if(mAllowSave)
112120
conversation.save()
@@ -116,12 +124,12 @@ class Avatar extends EventEmitter {
116124
const { activeBot: bot } = this
117125
// current fe will loop through messages in reverse chronological order
118126
const chat = conversation.messages
119-
.filter(message=>{ // limit to current chat response(s); usually one, perhaps faithfully in future [or could be managed in LLM]
120-
return messages.find(_message=>_message.id===message.id)
121-
&& message.type==='chat'
122-
&& message.role!=='user'
127+
.filter(_message=>{ // limit to current chat response(s); usually one, perhaps faithfully in future [or could be managed in LLM]
128+
return messages.find(__message=>__message.id===_message.id)
129+
&& _message.type==='chat'
130+
&& _message.role!=='user'
123131
})
124-
.map(message=>mPruneMessage(bot, message, 'chat', processStartTime))
132+
.map(_message=>mPruneMessage(bot, _message, 'chat', processStartTime))
125133
return chat
126134
}
127135
/**
@@ -472,14 +480,13 @@ class Avatar extends EventEmitter {
472480
return await this.#factory.resetPassphrase(passphrase)
473481
}
474482
/**
475-
* Takes a shadow message and sends it to the appropriate bot for response.
483+
* Takes a shadow message and sends it to the appropriate bot for response, returning the standard array of bot responses.
476484
* @param {Guid} shadowId - The shadow id.
477485
* @param {Guid} itemId - The item id.
478-
* @param {string} title - The title of the original summary.
479486
* @param {string} message - The member (interacting with shadow) message content.
480-
* @returns {Object} - The response object { error, itemId, messages, processingBotId, success, }
487+
* @returns {Object[]} - The array of bot responses.
481488
*/
482-
async shadow(shadowId, itemId, title, message){
489+
async shadow(shadowId, itemId, message){
483490
const processingStartTime = Date.now()
484491
const shadows = await this.shadows()
485492
const shadow = shadows.find(shadow=>shadow.id===shadowId)
@@ -515,12 +522,7 @@ class Avatar extends EventEmitter {
515522
messages = messages.map(message=>mPruneMessage(bot, message, 'shadow', processingStartTime))
516523
if(tailgate?.length)
517524
messages.push(mPruneMessage(bot, tailgate, 'system'))
518-
return {
519-
itemId,
520-
messages,
521-
processingBotId: bot.id,
522-
success: true,
523-
}
525+
return messages
524526
}
525527
/**
526528
* Gets the list of shadows.
@@ -1150,25 +1152,29 @@ class Q extends Avatar {
11501152
/* overloaded methods */
11511153
/**
11521154
* Processes and executes incoming chat request.
1153-
* @todo - cleanup/streamline frontend communication as it really gets limited to Q&A... other events would fire API calls on the same same session, so don't need to be in chat or conversation streams
11541155
* @public
1156+
* @param {string} message - The chat message content.
11551157
* @param {string} activeBotId - The active bot id.
11561158
* @param {string} threadId - The openai thread id.
1157-
* @param {string} chatMessage - The chat message content.
1158-
* @param {number} processStartTime - The process start time.
1159+
* @param {Guid} itemId - The active collection-item id (optional).
1160+
* @param {Guid} shadowId - The active Shadow Id (optional).
1161+
* @param {Conversation} conversation - The conversation object.
1162+
* @param {number} processStartTime - The start time of the process.
11591163
* @returns {object} - The response(s) to the chat request.
11601164
*/
1161-
async chatRequest(activeBotId=this.activeBotId, threadId, chatMessage, processStartTime=Date.now()){
1162-
let conversation = this.getConversation(threadId)
1165+
async chatRequest(message, activeBotId, threadId, itemId, shadowId, conversation, processStartTime=Date.now()){
1166+
conversation = conversation
1167+
?? this.getConversation(threadId)
11631168
if(!conversation)
11641169
throw new Error('Conversation cannot be found')
11651170
this.activeBot.bot_id = mBot_idOverride
11661171
?? this.activeBot.bot_id
11671172
if(this.isValidating) // trigger confirmation until session (or vld) ends
1168-
chatMessage = `CONFIRM REGISTRATION PHASE: registrationId=${ this.registrationId }\n${ chatMessage }`
1173+
message = `CONFIRM REGISTRATION PHASE: registrationId=${ this.registrationId }\n${ message }`
11691174
if(this.isCreatingAccount)
1170-
chatMessage = `CREATE ACCOUNT PHASE: ${ chatMessage }`
1171-
return super.chatRequest(activeBotId, threadId, chatMessage, conversation, processStartTime)
1175+
message = `CREATE ACCOUNT PHASE: ${ message }`
1176+
activeBotId = this.activeBotId
1177+
return super.chatRequest(message, activeBotId, threadId, itemId, shadowId, conversation, processStartTime)
11721178
}
11731179
upload(){
11741180
throw new Error('MyLife avatar cannot upload files.')

inc/js/routes.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
members,
2222
passphraseReset,
2323
privacyPolicy,
24-
shadow,
2524
shadows,
2625
signup,
2726
summarize,
@@ -120,7 +119,6 @@ _memberRouter.post('/bots/activate/:bid', activateBot)
120119
_memberRouter.post('/category', category)
121120
_memberRouter.post('/mode', interfaceMode)
122121
_memberRouter.post('/passphrase', passphraseReset)
123-
_memberRouter.post('/shadow', shadow)
124122
_memberRouter.post('/summarize', summarize)
125123
_memberRouter.post('/teams/:tid', team)
126124
_memberRouter.post('/upload', upload)

sample.env

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,5 @@ MYLIFE_HOSTED_MBR_ID=[] # array of ids hosted on your server--OR--remove or leav
2222
MYLIFE_SESSION_KEY=0.0.15 # random string for resetting sessions
2323
MYLIFE_SESSION_TIMEOUT_MS=900000
2424
MYLIFE_SYSTEM_ALERT_CHECK_INTERVAL=120000 # how often to check for alerts in ms
25-
MYLIFE_VERSION=0.0.15
2625
MYLIFE_REGISTRATION_DB_CONTAINER_NAME= # get from admin
2726
MYLIFE_SYSTEM_DB_CONTAINER_NAME= # get from admin

server.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ import chalk from 'chalk'
1515
import MyLife from './inc/js/mylife-agent-factory.mjs'
1616
// constants/variables
1717
// @todo - parse environment variables in Globals and then have them available via as values
18+
const version = '0.0.18'
1819
const app = new Koa()
1920
const port = JSON.parse(process.env.PORT ?? '3000')
2021
const __filename = fileURLToPath(import.meta.url)
2122
const __dirname = path.dirname(__filename)
2223
const _Maht = await MyLife // Mylife is the pre-instantiated exported version of organization with very unique properties. MyLife class can protect fields that others cannot, #factory as first refactor will request
2324
if(!process.env.MYLIFE_HOSTING_KEY || process.env.MYLIFE_HOSTING_KEY !== _Maht.avatar.hosting_key)
2425
throw new Error('Invalid hosting key. Server will not start.')
26+
_Maht.version = version
27+
console.log(chalk.bgBlue('created-core-entity:'), _Maht.version)
2528
const MemoryStore = new session.MemoryStore()
2629
const mimeTypesToExtensions = {
2730
// Text Formats

views/assets/css/chat.css

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,43 @@
2828
.await-button-spinner {
2929
margin-right: 0.5em;
3030
}
31+
.chat-active-items {
32+
align-items: center;
33+
display: flex;
34+
flex: 1 0 auto;
35+
flex-direction: column;
36+
padding-left: 3rem;
37+
margin-bottom: 0.5rem;
38+
max-width: 100%;
39+
}
40+
.chat-active-item {
41+
background-color: #007BFF;
42+
border: solid thin aliceblue;
43+
border-radius: 0.6rem;
44+
display: none;
45+
flex: 1 0 auto;
46+
flex-direction: row;
47+
padding: 0.3rem;
48+
width: 100%;
49+
}
50+
.chat-active-item-close {
51+
align-self: top;
52+
color: maroon;
53+
cursor: pointer;
54+
font-size: 1.25rem;
55+
margin-left: 2rem;
56+
}
57+
.chat-active-item-icon {
58+
color: #e9eb5c;
59+
font-size: 1.25rem;
60+
margin-right: 0.5em;
61+
}
62+
.chat-active-item-text {
63+
color: aliceblue;
64+
display: flex;
65+
flex: 1 0 auto;
66+
max-width: 80%;
67+
}
3168
.chat-bubble {
3269
background-color: #3427ec; /* Assuming a dark bubble color */
3370
border-radius: 0.8rem;
@@ -97,15 +134,21 @@
97134
}
98135
.chat-member,
99136
.chat-user {
100-
align-items: center;
137+
align-items: flex-start;
101138
display: flex;
102139
flex: 1 1 auto;
103-
flex-direction: row;
140+
flex-direction: column;
104141
flex-wrap: wrap;
105142
margin: 0.5em 0;
106143
max-height: 60%;
107144
width: 100%;
108145
}
146+
.chat-member-container,
147+
.chat-user-container {
148+
display: flex;
149+
flex-direction: row;
150+
width: 100%;
151+
}
109152
.chat-message-container {
110153
display: flex;
111154
position: relative;

0 commit comments

Comments
 (0)