Skip to content

Commit 6eeef0f

Browse files
authored
351 version 0021 updates (#366)
- [x] entries appearing in story? Saved as being=story - [x] #354 - [x] deleteMemory failing
1 parent ec50749 commit 6eeef0f

14 files changed

+827
-264
lines changed

inc/js/api-functions.mjs

+69-43
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,31 @@ async function availableExperiences(ctx){
2020
mbr_id,
2121
}
2222
}
23+
async function entry(ctx){
24+
await mAPIKeyValidation(ctx)
25+
const { assistantType, mbr_id } = ctx.state
26+
if(!ctx.request.body?.summary?.length)
27+
throw new Error('No entry summary provided. Use `summary` field.')
28+
console.log(chalk.yellowBright('entry()::entry attempted:'), ctx.request.body)
29+
const summary = {
30+
...ctx.request.body,
31+
assistantType,
32+
mbr_id,
33+
}
34+
const entry = await ctx.MyLife.entry(summary)
35+
console.log(chalk.yellowBright('entry()::entry submitted:'), entry, summary)
36+
ctx.status = 200
37+
ctx.body = {
38+
id: entry.id,
39+
message: 'entry submitted successfully.',
40+
success: true,
41+
}
42+
43+
}
2344
// @todo implement builder functionality, allowing for interface creation of experiences by members
2445
// @todo implement access to exposed member experiences using `mbr_key` as parameter to `factory.getItem()`
2546
async function experienceBuilder(ctx){
26-
mAPIKeyValidation(ctx)
47+
await mAPIKeyValidation(ctx)
2748
const { assistantType, mbr_id } = ctx.state
2849
const { eid, sid } = ctx.params
2950
const { experience } = ctx.request.body?.experience
@@ -54,7 +75,7 @@ async function experienceCast(ctx){
5475
* @property {object} scene - Scene data, regardless if "current" or new.
5576
*/
5677
async function experience(ctx){
57-
mAPIKeyValidation(ctx)
78+
await mAPIKeyValidation(ctx)
5879
const { MemberSession, } = ctx.state
5980
const { eid, } = ctx.params
6081
const { memberInput, } = ctx.request.body
@@ -66,8 +87,8 @@ async function experience(ctx){
6687
* @returns {Object} - Represents `ctx.body` object with following `experience` properties.
6788
* @property {boolean} success - Success status, true/false.
6889
*/
69-
function experienceEnd(ctx){
70-
mAPIKeyValidation(ctx)
90+
async function experienceEnd(ctx){
91+
await mAPIKeyValidation(ctx)
7192
const { MemberSession, } = ctx.state
7293
const { eid, } = ctx.params
7394
ctx.body = MemberSession.experienceEnd(eid)
@@ -80,17 +101,17 @@ function experienceEnd(ctx){
80101
* @property {Array} cast - Experience cast array.
81102
* @property {Object} navigation - Navigation object (optional - for interactive display purposes only).
82103
*/
83-
function experienceManifest(ctx){
84-
mAPIKeyValidation(ctx)
104+
async function experienceManifest(ctx){
105+
await mAPIKeyValidation(ctx)
85106
const { avatar, } = ctx.state
86107
ctx.body = avatar.manifest
87108
return
88109
}
89110
/**
90111
* Navigation array of scenes for experience.
91112
*/
92-
function experienceNavigation(ctx){
93-
mAPIKeyValidation(ctx)
113+
async function experienceNavigation(ctx){
114+
await mAPIKeyValidation(ctx)
94115
const { avatar, } = ctx.state
95116
ctx.body = avatar.navigation
96117
return
@@ -103,18 +124,26 @@ function experienceNavigation(ctx){
103124
* @property {array} experiences - Array of Experience shorthand objects.
104125
*/
105126
async function experiences(ctx){
106-
mAPIKeyValidation(ctx)
127+
await mAPIKeyValidation(ctx)
107128
const { MemberSession, } = ctx.state
108129
// limit one mandatory experience (others could be highlighted in alerts) per session
109130
const experiencesObject = await MemberSession.experiences()
110131
ctx.body = experiencesObject
111132
}
112133
async function experiencesLived(ctx){
113-
mAPIKeyValidation(ctx)
134+
await mAPIKeyValidation(ctx)
114135
const { MemberSession, } = ctx.state
115136
ctx.body = MemberSession.experiencesLived
116137
}
117-
async function keyValidation(ctx){ // from openAI
138+
/**
139+
* Validates member key and returns member data. Leverages the key validation structure to ensure payload is liegimate. Currently in use by OpenAI GPT and local Postman instance.
140+
* @param {Koa} ctx - Koa Context object
141+
* @returns {object} - Object with following properties.
142+
* @property {boolean} success - Success status.
143+
* @property {string} message - Message to querying intelligence.
144+
* @property {object} data - Consented Member data.
145+
*/
146+
async function keyValidation(ctx){
118147
await mAPIKeyValidation(ctx)
119148
ctx.status = 200 // OK
120149
if(ctx.method === 'HEAD') return
@@ -137,10 +166,10 @@ async function keyValidation(ctx){ // from openAI
137166
?? names?.[0].split(' ')[0]
138167
?? '',
139168
}
140-
console.log(chalk.yellowBright(`keyValidation():${memberCoreData.mbr_id}`), memberCoreData.fullName)
169+
console.log(chalk.yellowBright(`keyValidation()::`), chalk.redBright(`success::`), chalk.redBright(memberCoreData.mbr_id))
141170
ctx.body = {
142171
success: true,
143-
message: 'Valid member.',
172+
message: 'Valid Member',
144173
data: memberCoreData,
145174
}
146175
}
@@ -195,21 +224,25 @@ async function register(ctx){
195224
/**
196225
* Functionality around story contributions.
197226
* @param {Koa} ctx - Koa Context object
198-
* @returns {Koa} Koa Context object
199227
*/
200-
async function story(ctx){
228+
async function memory(ctx){
201229
await mAPIKeyValidation(ctx) // sets ctx.state.mbr_id and more
202230
const { assistantType, mbr_id } = ctx.state
203-
const { storySummary } = ctx.request?.body??{}
204-
if(!storySummary?.length)
205-
ctx.throw(400, 'No story summary provided. Use `storySummary` field.')
206-
// write to cosmos db
207-
const _story = await ctx.MyLife.story(mbr_id, assistantType, storySummary) // @todo: remove await
208-
console.log(chalk.yellowBright('story submitted:'), _story)
209-
ctx.status = 200 // OK
231+
if(!ctx.request.body?.summary?.length)
232+
throw new Error('No memory summary provided. Use `summary` field.')
233+
console.log(chalk.yellowBright('memory()::memory attempted:'), ctx.request.body)
234+
const summary = {
235+
...ctx.request.body,
236+
assistantType,
237+
mbr_id,
238+
}
239+
const memory = await ctx.MyLife.memory(summary)
240+
console.log(chalk.yellowBright('memory()::memory submitted:'), memory, summary)
241+
ctx.status = 200
210242
ctx.body = {
243+
id: memory.id,
244+
message: 'memory submitted successfully.',
211245
success: true,
212-
message: 'Story submitted successfully.',
213246
}
214247
}
215248
/**
@@ -220,21 +253,21 @@ async function story(ctx){
220253
* @param {function} next Koa next function
221254
* @returns {function} Koa next function
222255
*/
223-
async function tokenValidation(ctx, next) {
256+
async function tokenValidation(ctx, next){
224257
try {
225258
const authHeader = ctx.request.headers['authorization']
226259
if(!authHeader){
227260
ctx.status = 401
228261
ctx.body = { error: 'Authorization header is missing' }
229262
return
230263
}
231-
const _token = authHeader.split(' ')[1] // Bearer TOKEN_VALUE
232-
if(!mTokenValidation(_token)){
264+
const token = authHeader.split(' ')[1] // Bearer TOKEN_VALUE
265+
if(!mTokenValidation(token)){
233266
ctx.status = 401
234267
ctx.body = { error: 'Authorization token failure' }
235268
return
236269
}
237-
ctx.state.token = _token // **note:** keep first, as it is used in mTokenType()
270+
ctx.state.token = token // **note:** keep first, as it is used in mTokenType()
238271
ctx.state.assistantType = mTokenType(ctx)
239272
await next()
240273
} catch (error) {
@@ -283,19 +316,11 @@ async function mAPIKeyValidation(ctx){ // transforms ctx.state
283316
ctx.throw(400, 'Missing member key.')
284317
else // unlocked, providing passphrase
285318
return
286-
let isValidated
287-
if(!ctx.state.locked || ctx.session?.isAPIValidated){
288-
isValidated = true
289-
} else {
290-
const serverHostedMembers = JSON.parse(process.env.MYLIFE_HOSTED_MBR_ID ?? '[]')
291-
const localHostedMembers = [
292-
'system-one|4e6e2f26-174b-43e4-851f-7cf9cdf056df',
293-
].filter(member=>serverHostedMembers.includes(member)) // none currently
294-
serverHostedMembers.push(...localHostedMembers)
295-
if(serverHostedMembers.includes(memberId))
296-
isValidated = await ctx.MyLife.testPartitionKey(memberId)
297-
}
298-
if(isValidated){
319+
if( // validated
320+
!ctx.state.locked
321+
|| ( ctx.session.isAPIValidated ?? false )
322+
|| await ctx.MyLife.isMemberHosted(memberId)
323+
){
299324
ctx.state.isValidated = true
300325
ctx.state.mbr_id = memberId
301326
ctx.state.assistantType = mTokenType(ctx)
@@ -308,12 +333,13 @@ function mTokenType(ctx){
308333
const assistantType = mBotSecrets?.[token] ?? 'personal-avatar'
309334
return assistantType
310335
}
311-
function mTokenValidation(_token){
312-
return mBotSecrets?.[_token]?.length??false
336+
function mTokenValidation(token){
337+
return mBotSecrets?.[token]?.length??false
313338
}
314339
/* exports */
315340
export {
316341
availableExperiences,
342+
entry,
317343
experience,
318344
experienceCast,
319345
experienceEnd,
@@ -323,8 +349,8 @@ export {
323349
experiencesLived,
324350
keyValidation,
325351
logout,
352+
memory,
326353
register,
327-
story,
328354
tokenValidation,
329355
upload,
330356
}

inc/js/core.mjs

+68-16
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ class MyLife extends Organization { // form=server
241241
this.#avatar = await this.factory.getAvatar()
242242
return await super.init(this.#avatar)
243243
}
244+
/* public functions */
244245
/**
245246
* Retrieves all public experiences (i.e., owned by MyLife).
246247
* @returns {Object[]} - An array of the currently available public experiences.
@@ -262,7 +263,22 @@ class MyLife extends Organization { // form=server
262263
if(!_mbr_id || _mbr_id===this.mbr_id) throw new Error('datacore cannot be accessed')
263264
return await this.factory.datacore(_mbr_id)
264265
}
265-
/* public functions */
266+
/**
267+
* Submits and returns the journal or diary entry to MyLife via API.
268+
* @public
269+
* @todo - consent check-in with spawned Member Avatar
270+
* @param {object} summary - Object with story summary and metadata
271+
* @returns {object} - The story document from Cosmos.
272+
*/
273+
async entry(summary){
274+
if(!summary.mbr_id?.length)
275+
throw new Error('entry `mbr_id` required')
276+
if(!summary.summary?.length)
277+
throw new Error('entry `summary` required')
278+
summary.being = 'entry'
279+
summary.form = summary.form ?? 'journal'
280+
return await this.summary(summary)
281+
}
266282
/**
267283
* Server MyLife _Maht instantiation uses this function to populate the most current alerts in the modular factory memoryspace. Currently only applicable to system types, but since this is implemented at the `core.mjs` scope, we can account
268284
* @public
@@ -274,6 +290,10 @@ class MyLife extends Organization { // form=server
274290
async getMyLifeSession(){
275291
return await this.factory.getMyLifeSession()
276292
}
293+
async hostedMemberList(){
294+
let members = await this.hostedMembers()
295+
return members.map(member=>member.mbr_id)
296+
}
277297
/**
278298
* Returns Array of hosted members based on validation requirements.
279299
* @param {Array} validations - Array of validation strings to filter membership.
@@ -282,6 +302,20 @@ class MyLife extends Organization { // form=server
282302
async hostedMembers(validations){
283303
return await this.factory.hostedMembers(validations)
284304
}
305+
/**
306+
* Returns whether a specified member id is hosted on this instance.
307+
* @param {string} memberId - Member id
308+
* @returns {boolean} - Returns true if member is hosted
309+
*/
310+
async isMemberHosted(memberId){
311+
const hostedMembers = await this.hostedMemberList()
312+
const isHosted = hostedMembers.includes(memberId)
313+
let isValidated = false
314+
if(isHosted)
315+
isValidated = await this.testPartitionKey(memberId)
316+
console.log('isMemberHosted:', isHosted, isValidated, memberId)
317+
return isValidated
318+
}
285319
/**
286320
* Registers a new candidate to MyLife membership
287321
* @public
@@ -291,26 +325,44 @@ class MyLife extends Organization { // form=server
291325
return await this.factory.registerCandidate(candidate)
292326
}
293327
/**
294-
* Submits a story to MyLife via API. Unclear if can be dual-purposed for internal, or if internal still instantiates API context.
328+
* Submits and returns the memory to MyLife via API.
295329
* @public
296-
* @param {string} _mbr_id - Member id
297-
* @param {string} _assistantType - String name of assistant type
298-
* @param {string} _summary - String summary of story
330+
* @todo - consent check-in with spawned Member Avatar
331+
* @param {object} summary - Object with story summary and metadata
332+
* @returns {object} - The story document from Cosmos.
333+
*/
334+
async memory(summary){
335+
if(!summary.mbr_id?.length)
336+
throw new Error('story `mbr_id` required')
337+
if(!summary.summary?.length)
338+
throw new Error('story `summary` required')
339+
summary.being = 'story'
340+
summary.form = 'memory'
341+
return await this.summary(summary) // @todo - convert modular
342+
}
343+
/**
344+
* Submits and returns a summary to MyLife via API.
345+
* @param {object} summary - Object with story summary and metadata
299346
* @returns {object} - The story document from Cosmos.
300347
*/
301-
async story(_mbr_id, _assistantType, storySummary){
302-
const id = this.globals.newGuid
303-
const _story = {
304-
assistantType: _assistantType,
305-
being: 'story',
306-
form: _assistantType,
348+
async summary(summary){
349+
const {
350+
being='story',
351+
form='story',
352+
id=this.globals.newGuid,
353+
mbr_id,
354+
title=`untitled ${ form }`,
355+
} = summary
356+
const story = {
357+
...summary,
358+
being,
359+
form,
307360
id,
308-
mbr_id: _mbr_id,
309-
name: `story_${_assistantType}_${_mbr_id}`,
310-
summary: storySummary,
361+
mbr_id,
362+
name: `${ being }_${ title.substring(0,64) }_${ mbr_id }`,
311363
}
312-
const _storyCosmos = await this.factory.story(_story)
313-
return this.globals.stripCosmosFields(_storyCosmos)
364+
const savedStory = this.globals.stripCosmosFields(await this.factory.summary(story))
365+
return savedStory
314366
}
315367
/**
316368
* Tests partition key for member

inc/js/factory-class-extenders/class-conversation-functions.mjs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
async function mSaveConversation(_factory, _conversation){
2-
const { thread, messages, ..._retainedProperties} = _conversation.inspect(true)
3-
_retainedProperties.thread = _conversation.thread
4-
_retainedProperties.messages = [] // populated separately as unshifted array to cosmos
5-
await _factory.dataservices.pushItem(_retainedProperties)
1+
async function mSaveConversation(factory, conversation){
2+
const { thread, messages, ...properties} = conversation.inspect(true)
3+
properties.thread = conversation.thread
4+
properties.messages = [] // populated separately as unshifted array to cosmos
5+
const savedConversation = await factory.dataservices.pushItem(properties)
6+
console.log('mSaveConversation', savedConversation)
67
}
78
export {
89
mSaveConversation,

0 commit comments

Comments
 (0)