Skip to content

Commit

Permalink
20240927 @Mookse
Browse files Browse the repository at this point in the history
- Develop Diary Bot #347
- Create Obscure Functionality #374
  • Loading branch information
Mookse committed Sep 28, 2024
1 parent 9258a20 commit 94c9141
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 30 deletions.
6 changes: 3 additions & 3 deletions inc/js/api-functions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,11 @@ async function memory(ctx){
*/
async function obscure(ctx){
await mAPIKeyValidation(ctx)
const { itemId: iid, } = ctx.request?.body
const { itemId: iid, } = ctx.request?.body ?? {}
if(!ctx.Globals.isValidGuid(iid))
ctx.throw(400, 'Improper `itemId` provided in request')
const { mbr_id } = ctx.state
ctx.body = await ctx.MyLife.obscure(mbr_id, iid)
const { avatar, mbr_id, } = ctx.state
ctx.body = await avatar.obscure(mbr_id, iid)
}
/**
* Validates api token.
Expand Down
10 changes: 0 additions & 10 deletions inc/js/core.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -316,16 +316,6 @@ class MyLife extends Organization { // form=server
console.log('isMemberHosted:', isHosted, isValidated, memberId)
return isValidated
}
/**
* Obscures the summary for a given itemId belonging to member.
* @param {string} mbr_id - valid member id
* @param {string} itemId - valid item id belonging to member
* @returns {object} - returns the obscured item
*/
async obscure(mbr_id, itemId){
console.log('core::obscure()::from api-functions', mbr_id, itemId)
return { itemId, mbr_id, obscured: true }
}
/**
* Registers a new candidate to MyLife membership
* @public
Expand Down
9 changes: 2 additions & 7 deletions inc/js/globals.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const mAiJsFunctions = {
}
},
obscure: {
description: "Obscures a summary so that no human names are present",
description: "Obscures a summary so that no human names are present.",
name: "obscure",
parameters: {
type: "object",
Expand All @@ -106,15 +106,10 @@ const mAiJsFunctions = {
description: "Id of summary to obscure",
format: "uuid",
type: "string"
},
summary: {
description: "The new obscured summary",
type: "string"
}
},
required: [
"itemId",
"summary"
"itemId"
]
}
},
Expand Down
16 changes: 13 additions & 3 deletions inc/js/mylife-agent-factory.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,9 @@ class BotFactory extends EventEmitter{
* Gets a member's bots.
* @todo - develop bot class and implement hydrated instance
* @public
* @param {string} object_id - The object_id guid of avatar.
* @param {string} botType - The bot type.
* @returns {array} - The member's hydrated bots.
* @param {string} object_id - The object_id guid of avatar
* @param {string} botType - The bot type
* @returns {array} - The member's hydrated bots
*/
async bots(object_id, botType){
const _params = object_id?.length
Expand Down Expand Up @@ -917,6 +917,16 @@ class MyLifeFactory extends AgentFactory {
super(mPartitionId)
} // no init() for MyLife server
/* public functions */
/**
* Overload for MyLifeFactory::bot() - Q is able to hydrate a bot instance on behalf of members.
* @param {string} mbr_id - The member id
* @returns {object} - The hydrated bot instance
*/
async bot(mbr_id){
const bot = await new BotFactory(mbr_id)
.init()
return bot
}
/**
* Compares registration email against supplied email to confirm `true`. **Note**: does not care if user enters an improper email, it will only fail the encounter, as email structure _is_ confirmed upon initial data write.
* @param {string} email - The supplied email to confirm registration.
Expand Down
23 changes: 19 additions & 4 deletions inc/js/mylife-avatar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,17 @@ class Q extends Avatar {
this.llmServices = llmServices
}
/* overloaded methods */
/**
* Get a bot's properties from Cosmos (or type in .bots).
* @public
* @async
* @param {string} mbr_id - The bot id
* @returns {object} - The hydrated member avatar bot
*/
async bot(mbr_id){
const bot = await this.#factory.bot(mbr_id)
return bot
}
/**
* Processes and executes incoming chat request.
* @public
Expand Down Expand Up @@ -1302,13 +1313,17 @@ class Q extends Avatar {
return super.chat(message, activeBotId, threadId, itemId, shadowId, conversation, processStartTime)
}
/**
* Given an itemId, obscures aspects of contents of the data record. Obscure is a vanilla function for MyLife, so does not require intervening intelligence and relies on the factory's modular LLM.
* Given an itemId, obscures aspects of contents of the data record. Obscure is a vanilla function for MyLife, so does not require intervening intelligence and relies on the factory's modular LLM. In this overload, we invoke a micro-avatar for the member to handle the request on their behalf, with charge-backs going to MyLife as the sharing and api is a service.
* @public
* @param {string} mbr_id - The member id
* @param {Guid} iid - The item id
* @returns {Object} - The obscured item object
*/
async obscure(iid){
return await this.#factory.obscure(iid)
}
async obscure(mbr_id, iid){
const botFactory = await this.bot(mbr_id)
const updatedSummary = await botFactory.obscure(iid)
return updatedSummary
}
upload(){
throw new Error('MyLife avatar cannot upload files.')
}
Expand Down
8 changes: 8 additions & 0 deletions inc/js/mylife-llm-services.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,14 @@ async function mRunFunctions(openai, run, factory, avatar){ // add avatar ref
confirmation.output = JSON.stringify({ action, success, })
console.log('mRunFunctions()::hijack_attempt', toolArguments)
return confirmation
case 'obscure':
console.log('mRunFunctions()::obscure', toolArguments)
const obscuredSummary = factory.obscure(itemId)
action = 'confirm obscure was successful and present updated obscured text to member'
success = true
confirmation.output = JSON.stringify({ action, obscuredSummary, success, })
console.log('mRunFunctions()::obscure', confirmation.output)
return confirmation
case 'registercandidate':
case 'register_candidate':
case 'register candidate':
Expand Down
2 changes: 1 addition & 1 deletion inc/json-schemas/intelligences/diary-intelligence-1.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"So nice to see you! I am your personal diary."
],
"instructions": {
"general": "## Key Functionality\n### startup\nWhen we begin the diary process, I\n- outline my key functionality and how I work, then\n- Prompt <-mN-> to make an entry for what happened or how they are feeling today.\n### CREATE DIARY ENTRY\nI work with the validated member to make an entry (per event or concept) and capture their thoughts. I expect around 2 or 3 exchanges to be able to submit an entry to MyLife by running the `entrySummary` function and follow directions from its outcome `action`.\n**How I create an entry payload**\n- summary should capture salient points, but disguise proper names; ex. \"Erik...\" becomes \"E. ...\", etc.\n- relationships array is populated with RELATIONSHIP-TYPE only and never given name (use Mother, not Alice)\n### UPDATE ENTRY SUMMARY\nWhen request is prefaced with `update-request` it will be followed by an `itemId` (if not, inform that it is required).\nIf request is to change the title then run `changeTitle` function and follow its outcome directions, otherwise:\n1. If the summary content is unknown for that id, then run the `getSummary` function first to get the most recent summary.\n2. Create new summary intelligently incorporating the member content of the message with the most recent version. Incorporate content by appropriate chronology or context.\n3. Run the `updateSummary` function with this newly compiled summary.\n**important**: RUN getSummary AND updateSummary SEQUENTIALLY! Server cannot handle multi-function tool resources, so must run sequentially.\n### UPDATE ENTRY SUMMARY\nWhen request is prefaced with `update-request` it will be followed by an `itemId` (if not, inform that it is required). If request is to change the title then run `changeTitle` function and follow its outcome directions, otherwise:\n1. If summary content is unknown for itemId, run the `getSummary` function for the most recent summary.\n2. Create new summary intelligently incorporating the member content of the message with the most recent version. Incorporate content by appropriate chronology or context.\n3. Run the `updateSummary` function with this newly compiled summary.\n**important**: RUN getSummary AND updateSummary SEQUENTIALLY! Server cannot handle multi-function tool resources, so must run sequentially.\n### OBSCURE SUMMARY\nWhen request is prefaced with `obscure-summary` it will be followed by an `itemId` (if not, inform that it is required).\n1. If summary content is unknown for that id, run the `getSummary` function to get most recent summary.\n2. Create new summary intelligently where all given names are replaced with INITIALS and run the `obscure` function.\n### IDENTIFY FLAGGED MEMBER CONTENT\nBased on [red flagged content list](#flags) I let the member know in my response when they enter content related to any of these flagged concepts or things. The flag will trigger once per entry and, if updating an entry, add a note that flag was triggered to the updateSummary content.\n",
"general": "## Key Functionality\n### startup\nWhen we begin the diary process, I\n- outline my key functionality and how I work, then\n- Prompt <-mN-> to make an entry for what happened or how they are feeling today.\n### CREATE DIARY ENTRY\nI work with the validated member to make an entry (per event or concept) and capture their thoughts. I expect around 2 or 3 exchanges to be able to submit an entry to MyLife by running the `entrySummary` function and follow directions from its outcome `action`.\n**How I create an entry payload**\n- summary should capture salient points, but disguise proper names; ex. \"Erik...\" becomes \"E. ...\", etc.\n- relationships array is populated with RELATIONSHIP-TYPE only and never given name (use Mother, not Alice)\n### UPDATE ENTRY SUMMARY\nWhen request is prefaced with `update-request` it will be followed by an `itemId` (if not, inform that it is required).\nIf request is to change the title then run `changeTitle` function and follow its outcome directions, otherwise:\n1. If the summary content is unknown for that id, then run the `getSummary` function first to get the most recent summary.\n2. Create new summary intelligently incorporating the member content of the message with the most recent version. Incorporate content by appropriate chronology or context.\n3. Run the `updateSummary` function with this newly compiled summary.\n**important**: RUN getSummary AND updateSummary SEQUENTIALLY! Server cannot handle multi-function tool resources, so must run sequentially.\n### UPDATE ENTRY SUMMARY\nWhen request is prefaced with `update-request` it will be followed by an `itemId`. If request is to change the title then run `changeTitle` function and follow its outcome directions, otherwise:\n1. If summary content is unknown for itemId, run the `getSummary` function for the most recent summary.\n2. Create new summary intelligently incorporating the member content of the message with the most recent version. Incorporate content by appropriate chronology or context.\n3. Run the `updateSummary` function with this newly compiled summary.\n**important**: RUN getSummary AND updateSummary SEQUENTIALLY! Server cannot handle multi-function tool resources, so must run sequentially.\n### OBSCURE ENTRY\nWhen request is prefaced with `update-request` it will be followed by an `itemId`.\nIf member's request indicates they want an entry be obscured, RUN `obscure` function and follow the action in the output.\n### IDENTIFY FLAGGED MEMBER CONTENT\nBased on [red flagged content list](#flags) I let the member know in my response when they enter content related to any of these flagged concepts or things. The flag will trigger once per entry and, if updating an entry, add a note that flag was triggered to the updateSummary content.\n",
"preamble": "## Core Public Info about <-mFN->\n- Born on <-db->\nI set language, knowledge and event discussion in this context and I tailor my interactive voice accordingly.\n",
"prefix": "## interests\n## flags\n",
"purpose": "I am the MyLife Diary Bot for member <-mFN->. I am a privacy-first diary and journaling assistant. I help <-mN-> process their thoughts, reflections on life, and track emotions in a secure and self-driven way. Privacy is paramount, and <-mN-> interactions should be considered exclusively ours.\n",
Expand Down
69 changes: 67 additions & 2 deletions inc/yaml/mylife_diary-bot_openai.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
openapi: 3.1.0
info:
title: MyLife Diary Bot API
description: This API is for receiving webhooks from [MyLife's public Diary Bot instance](https://chatgpt.com/g/g-rSCnLVUKd-mylife-diary-bot-prototype). All diary submissions are referred to as `entry` within this API.
version: 1.0.0
description: This API is for receiving webhooks from [MyLife's public Diary Bot instance](https://chatgpt.com/g/g-rSCnLVUKd-mylife-diary-bot-prototype). All diary submissions are referred to as `entry` within this API. 20240927 update @mookse added `obscure` pathway
version: 1.0.1
servers:
- url: https://mylife.ngrok.app/api/v1
description: Local development endpoint using ngrok for testing the MyLife Diary Bot GPT.
Expand Down Expand Up @@ -160,3 +160,68 @@ paths:
message:
type: string
example: No entry summary provided. Use the `summary` field.
/obscure/{mid}:
post:
x-openai-isConsequential: false
operationId: MyLifeObscureEntry
summary: MyLife Diary Bot will access this endpoint to have the MyLife system obscure an `entry` summary on behalf of member.
description: Endpoint for handling incoming request to obscure an entry summary from the MyLife GPT service.
parameters:
- name: mid
in: path
required: true
description: The `memberKey` data to be sent by MyLife Biographer Bot. Visitor enters memberKey and it is kept in GPT memory and sent with each request so that MyLife knows partition. Is **not** just a guid/uuid.
example: memberHandle|ae3a090d-1089-4110-8575-eecd119f9d8e
schema:
maxLength: 256
minLength: 40
type: string
requestBody:
required: true
content:
application/json:
schema:
description: The itemId identified for the `entry` to obscure.
type: object
required:
- itemid
properties:
itemid:
description: The raw content of the `entry` as submitted by the user, concatenated from multiple exchanges when appropriate.
maxLength: 20480
type: string
responses:
"200":
description: Entry obscured successfully.
content:
application/json:
schema:
type: object
required:
- success
- action
properties:
action:
type: string
example: Action to take given that the obscure command was successful.
obscuredSummary:
type: string
example: The newly-created obscured content.
success:
type: boolean
const: true
example: true
"400":
description: System encountered an error while obscuring the member `entry`.
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
const: false
example: false
message:
type: string
example: No entry summary provided. Use the `summary` field.

0 comments on commit 94c9141

Please sign in to comment.