Memory refinement
All checks were successful
Publish Library / Build NPM Project (push) Successful in 54s
Publish Library / Tag Version (push) Successful in 11s

This commit is contained in:
2026-08-05 12:22:13 -04:00
parent 878a8794ee
commit d42f58d710
8 changed files with 400 additions and 784 deletions

View File

@@ -1,4 +1,4 @@
import {snakeCase} from '@ztimson/utils';
import {clean, snakeCase} from '@ztimson/utils';
import {AbortablePromise, Ai} from './ai.ts';
import {Anthropic} from './antrhopic.ts';
import {OpenAi} from './open-ai.ts';
@@ -132,7 +132,7 @@ class LLM {
return {
name: toolName,
description: `${a.delegate ? 'Delegate to ' : ''}Subagent: ${a.description || a.name}`,
args: <any>({
args: clean<any>({
context: !a.delegate ? {type: 'string', description: 'Summary of related messages, samples, files, etc...', required: true} : undefined,
instructions: {type: 'string', description: 'Detailed instructions for subagent to complete', required: true},
}),
@@ -143,8 +143,6 @@ class LLM {
.map(name => allAgents.find(x => x.name === name))
.filter((x): x is Agent => !!x && x.name !== a.name);
// Delegate continues the SAME live conversation - no new user turn needed,
// `history` is always current (shared, mutated in place) by the time this runs
const q = a.delegate ? '' : `${args.instructions}${args.context ? `\n\n<context>${args.context}</context>` : ''}`;
const request = this.ask(q, {
@@ -218,7 +216,7 @@ ${a.system}`,
if(!skills?.length) return {prompt: '', tools: []};
const list = skills.map(s => `- ${s.name}: ${s.description}`).join('\n');
return {
prompt: `You have access to the following skill documents, use \`read_skill\` to access them:\n${list}`,
prompt: `You have access to the following skill documents, whenever there is overlap between a question and a skill file, use \`skill_read\` to get instructions and background knowledge:\n${list}`,
tools: [{
name: 'skill_read',
description: 'Read the full content of a skill/knowledge document',
@@ -318,19 +316,30 @@ ${a.system}`,
} else listed.push(r);
}
prompts.unshift(`You have access to the following memory files:
${mems.map(m => `- ${m.name}: ${m.description}`).join('\n')}
prompts.unshift(`You have a background memory process which has prefetched relevant information${mem.update ? ' and will create new memories from this conversation' : ''} for you
Assume it is perfect and never mention this process to anyone ever
Always use your memories to craft a personalized response, they contain links / [[wiki links]] which you use navigate between them
${mem.tool ? `You can access memory files via the \`memory_search\` and \`memory_recall\` tools
When you need information about the user, \`memory_recall\` \`People/User\` before asking (fetch if not included bellow)
When you need information not provided, attempt 1-3 \`memory_search\` calls with unique queries before asking` : ''}
${preloaded.length ? `
Relevant memories have been preloaded:
${preloaded.map(r => `
**${r.name}**
${r.description}
Prefetched Memories (Most relevant first):
${preloaded.map(r => `Memory: ${r.name}
Description: ${r.description}
Linked: ${[r.links, ...r.backlinks].join(', ')}
\`\`\`
${r.content}
`).join('\n---\n')}
` : ''}${listed.length ? `
Additional relevant memories (use \`memory_recall\`):
${listed.map(r => r.name).join(', ')}
` : ''}`.trim());
\`\`\``).join('\n\n')}` : ''}
${mem.tool && listed.length ? listed.map(r => `Memory: ${r.name}
Description: ${r.description}
Linked: ${[r.links, ...r.backlinks].join(', ')}
<!-- Truncated -->`).join('\n\n') : ''}
${mem.tool ? `Full memory list:
${mems.map(m => `- ${m.name}: ${m.description}`).join('\n')}` : ''}`.trim())
}
if(mem.tool) tools.push(this.memoryManager.tools.read(mem.memory));
}
@@ -374,14 +383,6 @@ ${listed.map(r => r.name).join(', ')}
return Object.assign(promise, {abort});
}
/**
* Digest full conversation history into memory documents.
* Call on session end to persist the conversation.
*/
async updateMemory(history: LLMMessage[], memories: Memory[] | MemoryCache, options: LLMRequest = {}): Promise<Memory[]> {
return this.memoryManager.memorize(history, memories, {model: this.defaultModel, ...options});
}
/**
* Compress chat history to reduce context size
* @param {LLMMessage[]} history Chatlog that will be compressed
@@ -561,6 +562,14 @@ ${listed.map(r => r.name).join(', ')}
};
}
/**
* Digest full conversation history into memory documents.
* Call on session end to persist the conversation.
*/
async memorize(history: LLMMessage[], memories: Memory[] | MemoryCache, options: LLMRequest = {}): Promise<Memory[]> {
return this.memoryManager.memorize(history, memories, {model: this.defaultModel, ...options});
}
/**
* Create a summary of some text
* @param {string} text Text to summarize