mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-07-21 15:35:18 +02:00
119 lines
No EOL
4.1 KiB
JavaScript
119 lines
No EOL
4.1 KiB
JavaScript
import { writeFileSync, readFileSync, mkdirSync, existsSync } from 'fs';
|
|
import { NPCData } from './npc/data.js';
|
|
import settings from '../../settings.js';
|
|
|
|
|
|
export class History {
|
|
constructor(agent) {
|
|
this.agent = agent;
|
|
this.name = agent.name;
|
|
this.memory_fp = `./bots/${this.name}/memory.json`;
|
|
this.full_history_fp = undefined;
|
|
|
|
mkdirSync(`./bots/${this.name}/histories`, { recursive: true });
|
|
|
|
this.turns = [];
|
|
|
|
// Natural language memory as a summary of recent messages + previous memory
|
|
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
|
|
// and improves the quality of the memory summary
|
|
}
|
|
|
|
getHistory() { // expects an Examples object
|
|
return JSON.parse(JSON.stringify(this.turns));
|
|
}
|
|
|
|
async summarizeMemories(turns) {
|
|
console.log("Storing memories...");
|
|
this.memory = await this.agent.prompter.promptMemSaving(turns);
|
|
|
|
if (this.memory.length > 500) {
|
|
this.memory = this.memory.slice(0, 500);
|
|
this.memory += '...(Memory truncated to 500 chars. Compress it more next time)';
|
|
}
|
|
|
|
console.log("Memory updated to: ", this.memory);
|
|
}
|
|
|
|
async 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}`);
|
|
}
|
|
}
|
|
|
|
async add(name, content) {
|
|
let role = 'assistant';
|
|
if (name === 'system') {
|
|
role = 'system';
|
|
}
|
|
else if (name !== this.name) {
|
|
role = 'user';
|
|
content = `${name}: ${content}`;
|
|
}
|
|
this.turns.push({role, content});
|
|
|
|
if (this.turns.length >= this.max_messages) {
|
|
let chunk = this.turns.splice(0, this.summary_chunk_size);
|
|
while (this.turns.length > 0 && this.turns[0].role === 'assistant')
|
|
chunk.push(this.turns.shift()); // remove until turns starts with system/user message
|
|
|
|
await this.summarizeMemories(chunk);
|
|
await this.appendFullHistory(chunk);
|
|
}
|
|
}
|
|
|
|
async save() {
|
|
try {
|
|
const data = {
|
|
memory: this.memory,
|
|
turns: this.turns,
|
|
self_prompt: this.agent.self_prompter.on ? this.agent.self_prompter.prompt : null,
|
|
last_sender: this.agent.last_sender
|
|
};
|
|
writeFileSync(this.memory_fp, JSON.stringify(data, null, 2));
|
|
console.log('Saved memory to:', this.memory_fp);
|
|
} catch (error) {
|
|
console.error('Failed to save history:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
load() {
|
|
try {
|
|
if (!existsSync(this.memory_fp)) {
|
|
console.log('No memory file found.');
|
|
return null;
|
|
}
|
|
const data = JSON.parse(readFileSync(this.memory_fp, 'utf8'));
|
|
this.memory = data.memory || '';
|
|
this.turns = data.turns || [];
|
|
console.log('Loaded memory:', this.memory);
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Failed to load history:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
clear() {
|
|
this.turns = [];
|
|
this.memory = '';
|
|
}
|
|
} |