mindcraft/src/agent/history.js

124 lines
4.3 KiB
JavaScript
Raw Normal View History

import { writeFileSync, readFileSync, mkdirSync } from 'fs';
2024-03-05 12:05:46 -08:00
import { NPCData } from './npc/data.js';
import settings from '../../settings.js';
2023-11-12 14:53:23 -08:00
export class History {
2023-12-21 20:42:01 -07:00
constructor(agent) {
this.agent = agent;
2023-11-12 14:53:23 -08:00
this.name = agent.name;
this.memory_fp = `./bots/${this.name}/memory.json`;
this.full_history_fp = undefined;
mkdirSync(`./bots/${this.name}/histories`, { recursive: true });
2023-11-15 13:18:38 -08:00
this.turns = [];
2023-11-12 14:53:23 -08:00
// Natural language memory as a summary of recent messages + previous memory
2023-11-12 14:53:23 -08:00
this.memory = '';
// Maximum number of messages to keep in context before saving chunk to memory
this.max_messages = settings.max_messages;
// Number of messages to remove from current history and save into memory
this.summary_chunk_size = 5;
// chunking reduces expensive calls to promptMemSaving and appendFullHistory
}
2023-08-15 23:39:02 -07:00
getHistory() { // expects an Examples object
return JSON.parse(JSON.stringify(this.turns));
2023-11-13 20:33:34 -08:00
}
2023-11-12 14:53:23 -08:00
async summarizeMemories(turns) {
console.log("Storing memories...");
this.memory = await this.agent.prompter.promptMemSaving(turns);
console.log("Memory updated to: ", this.memory);
2023-11-15 13:18:38 -08:00
}
appendFullHistory(to_store) {
if (this.full_history_fp === undefined) {
const string_timestamp = new Date().toLocaleString().replace(/[/:]/g, '-').replace(/ /g, '').replace(/,/g, '_');
this.full_history_fp = `./bots/${this.name}/histories/${string_timestamp}.json`;
writeFileSync(this.full_history_fp, '[]', 'utf8');
}
try {
const data = readFileSync(this.full_history_fp, 'utf8');
let full_history = JSON.parse(data);
full_history.push(...to_store);
writeFileSync(this.full_history_fp, JSON.stringify(full_history, null, 4), 'utf8');
} catch (err) {
console.error(`Error reading ${this.name}'s full history file: ${err.message}`);
}
}
2023-11-12 14:53:23 -08:00
async add(name, content) {
let role = 'assistant';
if (name === 'system') {
role = 'system';
}
2023-11-13 20:33:34 -08:00
else if (name !== this.name) {
role = 'user';
content = `${name}: ${content}`;
2023-08-17 00:00:57 -07:00
}
this.turns.push({role, content});
2023-11-12 14:53:23 -08:00
if (this.turns.length >= this.max_messages) {
let chunk = this.turns.splice(0, this.summary_chunk_size);
2023-12-04 23:26:21 -08:00
while (this.turns[0].role != 'user' && this.turns.length > 1)
chunk.push(this.turns.shift()); // first message must be user message
await this.summarizeMemories(chunk);
this.appendFullHistory(chunk);
2023-11-12 14:53:23 -08:00
}
}
2024-05-10 12:18:47 -05:00
save() {
2023-11-12 14:53:23 -08:00
// save history object to json file
2023-11-15 13:18:38 -08:00
let data = {
'name': this.name,
'memory': this.memory,
'turns': this.turns
};
2024-03-05 12:05:46 -08:00
if (this.agent.npc.data !== null)
data.npc = this.agent.npc.data.toObject();
2024-04-20 22:18:26 -05:00
const modes = this.agent.bot.modes.getJson();
if (modes !== null)
data.modes = modes;
const memory_bank = this.agent.memory_bank.getJson();
if (memory_bank !== null)
data.memory_bank = memory_bank;
if (this.agent.self_prompter.on) {
data.self_prompt = this.agent.self_prompter.prompt;
}
2023-11-15 13:18:38 -08:00
const json_data = JSON.stringify(data, null, 4);
writeFileSync(this.memory_fp, json_data, (err) => {
2023-11-12 14:53:23 -08:00
if (err) {
throw err;
}
console.log("JSON data is saved.");
});
}
load() {
2023-11-12 14:53:23 -08:00
try {
// load history object from json file
const data = readFileSync(this.memory_fp, 'utf8');
2023-11-12 14:53:23 -08:00
const obj = JSON.parse(data);
this.memory = obj.memory;
2024-03-05 12:05:46 -08:00
this.agent.npc.data = NPCData.fromObject(obj.npc);
2024-04-20 22:18:26 -05:00
if (obj.modes)
this.agent.bot.modes.loadJson(obj.modes);
if (obj.memory_bank)
this.agent.memory_bank.loadJson(obj.memory_bank);
2023-12-04 23:26:21 -08:00
this.turns = obj.turns;
return obj;
2023-11-12 14:53:23 -08:00
} catch (err) {
2024-04-20 22:18:26 -05:00
console.error(`Error reading ${this.name}'s memory file: ${err.message}`);
2023-11-12 14:53:23 -08:00
}
return null;
2023-08-17 00:00:57 -07:00
}
clear() {
this.turns = [];
this.memory = '';
}
}