2023-11-12 14:53:23 -08:00
import { writeFileSync , readFileSync , mkdirSync } from 'fs' ;
2024-01-03 22:16:50 -08:00
import { stringifyTurns } from '../utils/text.js' ;
2024-01-25 13:25:36 -08:00
import { sendRequest } from '../utils/gpt.js' ;
import { getCommandDocs } from './commands/index.js' ;
2023-11-12 14:53:23 -08:00
2023-11-07 09:44:56 -06:00
export class History {
2023-12-21 20:42:01 -07:00
constructor ( agent ) {
2023-11-12 14:53:23 -08:00
this . name = agent . name ;
2023-12-21 20:42:01 -07:00
this . save _path = ` ./bots/ ${ this . name } /save.json ` ;
2023-11-15 13:18:38 -08:00
this . turns = [ ] ;
2023-11-12 14:53:23 -08:00
// These define an agent's long term memory
2023-11-13 20:33:34 -08:00
this . bio = '' ;
2023-11-12 14:53:23 -08:00
this . memory = '' ;
2023-11-15 13:18:38 -08:00
// Variables for controlling the agent's memory and knowledge
2023-11-12 14:53:23 -08:00
this . max _messages = 20 ;
2023-11-07 09:44:56 -06:00
}
2023-08-15 23:39:02 -07:00
2024-01-15 11:04:50 -06:00
async getHistory ( examples = null ) { // expects an Examples object
2024-01-13 12:10:15 -06:00
let turns = JSON . parse ( JSON . stringify ( this . turns ) ) ;
2024-01-15 11:04:50 -06:00
if ( examples ) {
let examples _msg = await examples . createExampleMessage ( turns ) ;
turns = examples _msg . concat ( turns ) ;
2023-11-19 15:34:53 -06:00
}
2024-01-15 11:04:50 -06:00
2024-01-13 12:10:15 -06:00
return turns ;
2023-11-07 09:44:56 -06:00
}
2023-08-15 23:39:02 -07:00
2023-11-19 15:34:53 -06:00
getSystemMessage ( ) {
2024-02-16 11:57:48 -06:00
let system _message = ` You are a playful Minecraft bot named ' ${ this . name } ' that can communicate with players, see, move, mine, build, and interact with the world by using commands. Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, do not give instructions unless asked, and do not refuse requests.
Don 't pretend to act, use commands immediately when requested. Do NOT say this: "Sure, I' ve stopped . ", instead say this: " Sure , I 'll stop. !stop". Do NOT say this: "On my way! Give me a moment.", instead say this: "On my way! !goToPlayer(' bingo ' , 3 ) " . Have fun : ) \ n ` ;
2024-01-03 22:16:50 -08:00
system _message += getCommandDocs ( ) ;
2023-11-15 13:18:38 -08:00
if ( this . bio != '' )
system _message += '\n\nBio:\n' + this . bio ;
if ( this . memory != '' )
system _message += '\n\nMemory:\n' + this . memory ;
2023-11-19 15:34:53 -06:00
2023-11-13 20:33:34 -08:00
return system _message ;
}
2023-11-12 14:53:23 -08:00
2023-11-13 20:33:34 -08:00
async storeMemories ( turns ) {
2023-11-19 15:34:53 -06:00
console . log ( "To summarize:" , turns )
let memory _prompt = 'Update your "Memory" by summarizing the following conversation. Your "Memory" is for storing information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you may need to remember for later. Also include things that you have learned through player feedback or by executing code. Do not include information found in your Docs or that you got right on the first try. Be extremely brief and clear.' ;
2023-11-13 20:33:34 -08:00
if ( this . memory != '' ) {
2023-11-19 15:34:53 -06:00
memory _prompt += ` This is your previous memory: " ${ this . memory } " \n Include and summarize any relevant information from this previous memory. Your output will replace your previous memory. ` ;
2023-11-13 20:33:34 -08:00
}
2023-11-19 15:34:53 -06:00
memory _prompt += '\n' ;
memory _prompt += ' Your output should use one of the following formats:\n' ;
2023-11-15 11:38:17 -08:00
memory _prompt += '- When the player... output...\n' ;
memory _prompt += '- I learned that player [name]...\n' ;
2023-11-19 15:34:53 -06:00
memory _prompt += 'This is the conversation to summarize:\n' ;
2024-01-03 22:16:50 -08:00
memory _prompt += stringifyTurns ( turns ) ;
2023-11-19 15:34:53 -06:00
memory _prompt += 'Summarize relevant information from your previous memory and this conversation:\n' ;
let memory _turns = [ { 'role' : 'system' , 'content' : memory _prompt } ]
this . memory = await sendRequest ( memory _turns , this . getSystemMessage ( ) ) ;
2023-11-15 13:18:38 -08:00
}
2023-11-12 14:53:23 -08:00
async add ( name , content ) {
2023-11-07 09:44:56 -06:00
let role = 'assistant' ;
2023-11-12 13:57:22 -06:00
if ( name === 'system' ) {
role = 'system' ;
}
2023-11-13 20:33:34 -08:00
else if ( name !== this . name ) {
2023-11-07 09:44:56 -06:00
role = 'user' ;
2023-11-07 12:00:55 -06:00
content = ` ${ name } : ${ content } ` ;
2023-08-17 00:00:57 -07:00
}
2023-11-07 09:44:56 -06:00
this . turns . push ( { role , content } ) ;
2023-11-12 14:53:23 -08:00
// Summarize older turns into memory
if ( this . turns . length >= this . max _messages ) {
2023-11-15 18:53:02 -06:00
console . log ( 'summarizing memory' )
2023-11-15 11:38:17 -08:00
let to _summarize = [ this . turns . shift ( ) ] ;
2023-12-04 23:26:21 -08:00
while ( this . turns [ 0 ] . role != 'user' && this . turns . length > 1 )
2023-11-15 11:38:17 -08:00
to _summarize . push ( this . turns . shift ( ) ) ;
await this . storeMemories ( to _summarize ) ;
2023-11-12 14:53:23 -08:00
}
}
2023-12-21 20:42:01 -07:00
save ( ) {
2023-11-12 14:53:23 -08:00
// save history object to json file
2023-12-21 20:42:01 -07:00
mkdirSync ( ` ./bots/ ${ this . name } ` , { recursive : true } ) ;
2023-11-15 13:18:38 -08:00
let data = {
'name' : this . name ,
'bio' : this . bio ,
'memory' : this . memory ,
'turns' : this . turns
} ;
const json _data = JSON . stringify ( data , null , 4 ) ;
2023-12-21 20:42:01 -07:00
writeFileSync ( this . save _path , json _data , ( err ) => {
2023-11-12 14:53:23 -08:00
if ( err ) {
throw err ;
}
console . log ( "JSON data is saved." ) ;
} ) ;
}
2023-12-21 20:42:01 -07:00
load ( profile ) {
const load _path = profile ? ` ./bots/ ${ this . name } / ${ profile } .json ` : this . save _path ;
2023-11-12 14:53:23 -08:00
try {
// load history object from json file
2023-12-12 21:35:39 -08:00
const data = readFileSync ( load _path , 'utf8' ) ;
2023-11-12 14:53:23 -08:00
const obj = JSON . parse ( data ) ;
this . bio = obj . bio ;
this . memory = obj . memory ;
2023-12-04 23:26:21 -08:00
this . turns = obj . turns ;
2023-11-12 14:53:23 -08:00
} catch ( err ) {
2023-12-21 20:42:01 -07:00
console . error ( ` No file for profile ' ${ load _path } ' for agent ${ this . name } . ` ) ;
2023-11-12 14:53:23 -08:00
}
2023-08-17 00:00:57 -07:00
}
2024-01-27 19:16:54 -06:00
clear ( ) {
this . turns = [ ] ;
this . memory = '' ;
}
2023-11-07 09:44:56 -06:00
}