refactor(memory,gui): Streamline memory archtiecture and terminology

- Short term memory/ recent events are collectively now Cognitive Buffer (Tier 1)

- Long term memory/ memory ledgers are just Memory Ledger (Tier 2)

- Dossiers stay Dossiers (Tier 3)
This commit is contained in:
2026-07-18 15:50:12 +05:30
parent c6b32bb546
commit b4bf70dbae
13 changed files with 70 additions and 69 deletions

View File

@@ -33,17 +33,17 @@ export type ActorResponse = z.infer<typeof ActorResponseSchema>;
*
* The prompt is strictly epistemically bounded: the entity only sees what
* it is allowed to see (public attributes + private attributes explicitly
* ACL'd to it), its own recent memory buffer, and the entities co-located
* ACL'd to it), its own Cognitive Buffer, and the entities co-located
* with it. System UUIDs are surfaced as subjective aliases.
*/
export class ActorPromptBuilder {
/**
* @param bufferRepo Used to fetch the actor's recent memory. Optional —
* @param bufferRepo Used to fetch the actor's Cognitive Buffer. Optional —
* if absent, the memory section is omitted.
* @param ledgerRepo Used to fetch long-term memories. Optional.
* @param memoryLimit Maximum number of recent buffer entries to inject.
* @param ledgerRepo Used to fetch Memory Ledger entries. Optional.
* @param memoryLimit Maximum number of recent Cognitive Buffer entries to inject.
* Defaults to 20.
* @param ledgerLimit Maximum number of long-term memories to retrieve.
* @param ledgerLimit Maximum number of Memory Ledger entries to retrieve.
* Defaults to 5.
*/
constructor(
@@ -111,13 +111,13 @@ Guidelines:
}
}
// --- Recent memory ---
// --- Cognitive Buffer ---
const memorySection = this.buildMemorySection(entity, recentEntries, now);
if (memorySection) {
sections.push(memorySection);
}
// --- Recalled Long-Term memory ---
// --- Recalled Memory Ledger ---
const ledgerSection = this.buildLedgerSection(
worldState,
entity,
@@ -139,7 +139,7 @@ Guidelines:
if (!this.bufferRepo) return null;
if (entries.length === 0) {
return `=== RECENT EVENTS ===\n(No recent events recorded.)`;
return `=== COGNITIVE BUFFER ===\n(No recent events recorded.)`;
}
const recent = entries.slice(-this.memoryLimit);
@@ -159,7 +159,7 @@ Guidelines:
groupedLines.push(` - ${serialized}`);
}
return `=== RECENT EVENTS ===\n${groupedLines.join("\n")}`;
return `=== COGNITIVE BUFFER ===\n${groupedLines.join("\n")}`;
}
private buildLedgerSection(
@@ -263,6 +263,6 @@ Guidelines:
}
}
return `=== YOUR MEMORIES ===\n${groupedLines.join("\n")}`;
return `=== MEMORY LEDGER ===\n${groupedLines.join("\n")}`;
}
}

View File

@@ -4,7 +4,7 @@ import { WorldState, Entity } from "@omnia/core";
import { BufferRepository, LedgerRepository } from "@omnia/memory";
import { ActorPromptBuilder } from "../src/actor-prompt-builder";
describe("ActorPromptBuilder with Long-Term Memory Integration", () => {
describe("ActorPromptBuilder with Memory Ledger Integration", () => {
let db: Database.Database;
let bufferRepo: BufferRepository;
let ledgerRepo: LedgerRepository;
@@ -31,7 +31,7 @@ describe("ActorPromptBuilder with Long-Term Memory Integration", () => {
db.close();
});
it("should inject both recent memory and recalled long-term memory with subjective aliases resolved", () => {
it("should inject both Cognitive Buffer and recalled Memory Ledger entries with subjective aliases resolved", () => {
const world = new WorldState(
"world-123",
new Date("2024-01-10T12:00:00.000Z"),
@@ -60,7 +60,7 @@ describe("ActorPromptBuilder with Long-Term Memory Integration", () => {
},
});
// 2. Populate ledger repository (long-term memory)
// 2. Populate ledger repository (Memory Ledger)
ledgerRepo.save({
id: "ledger1",
ownerId: "alice",
@@ -76,12 +76,12 @@ describe("ActorPromptBuilder with Long-Term Memory Integration", () => {
const builder = new ActorPromptBuilder(bufferRepo, ledgerRepo, 20, 5);
const { userContext } = builder.build(world, alice);
// Check recent memory exists
expect(userContext).toContain("=== RECENT EVENTS ===");
// Check Cognitive Buffer exists
expect(userContext).toContain("=== COGNITIVE BUFFER ===");
expect(userContext).toContain("Alice greets Bob");
// Check long-term memory exists
expect(userContext).toContain("=== YOUR MEMORIES ===");
// Check Memory Ledger exists
expect(userContext).toContain("=== MEMORY LEDGER ===");
// Bob should be resolved to Strider in the ledger content
expect(userContext).toContain("alice met Strider at the tavern.");
expect(userContext).toContain('Quote: "I am a ranger."');
@@ -98,7 +98,7 @@ describe("ActorPromptBuilder with Long-Term Memory Integration", () => {
const builder = new ActorPromptBuilder(bufferRepo, ledgerRepo, 20, 5);
const { userContext } = builder.build(world, alice);
expect(userContext).toContain("=== RECENT EVENTS ===");
expect(userContext).not.toContain("=== YOUR MEMORIES ===");
expect(userContext).toContain("=== COGNITIVE BUFFER ===");
expect(userContext).not.toContain("=== MEMORY LEDGER ===");
});
});

View File

@@ -33,7 +33,7 @@ export function getMemorySectionLength(
now: Date,
): number {
if (entries.length === 0) {
return `=== RECENT EVENTS ===\n(No recent events recorded.)`.length;
return `=== COGNITIVE BUFFER ===\n(No recent events recorded.)`.length;
}
const groupedLines: string[] = [];
@@ -52,7 +52,7 @@ export function getMemorySectionLength(
groupedLines.push(` - ${serialized}`);
}
return `=== RECENT EVENTS ===\n${groupedLines.join("\n")}`.length;
return `=== COGNITIVE BUFFER ===\n${groupedLines.join("\n")}`.length;
}
function checkSceneExit(entity: Entity, bufferEntries: BufferEntry[]): boolean {
@@ -227,7 +227,7 @@ export class HandoffEngine {
.join("\n---\n");
const systemPrompt = `
You are the memory Handoff Engine. Your task is to process a list of recent working memory buffer entries for an entity and select which memories to promote to the long-term Ledger, and which to forget or summarize.
You are the memory Handoff Engine. Your task is to process a list of Cognitive Buffer entries for an entity and select which memories to promote to the Memory Ledger, and which to forget or summarize.
Instructions:
1. **Cluster** related consecutive buffer entries into high-level narrative beats or events (e.g. physical action and its outcome or trivial actions). Combine them into a single chunk.
@@ -237,7 +237,7 @@ Instructions:
4. **Determine Importance**: Assign an importance score from 1 (trivial, e.g. waking up) to 10 (life-altering, e.g. witnessing a crime).
4. Discard small body movements like looking around, sighing, etc that do not contextually hold any meaning after it is done.
5. **Involved Entities**: Identify all entity IDs involved in the memories in this chunk.
6. **Retain in Buffer (Pinning)**: If a beat represents an unresolved high-stakes situation (e.g. a standing threat, an unanswered accusation, an ongoing chase or conflict), set "retainInBuffer" to true so it remains in the working memory buffer for immediate context. Otherwise, set it to false so it is safely pruned from the buffer.
6. **Retain in Cognitive Buffer (Pinning)**: If a beat represents an unresolved high-stakes situation (e.g. a standing threat, an unanswered accusation, an ongoing chase or conflict), set "retainInBuffer" to true so it remains in the Cognitive Buffer for immediate context. Otherwise, set it to false so it is safely pruned from the Cognitive Buffer.
7. **Exclude stage business**: Glances, sighs, ambient noticing, and irrelevant sensory details should be ignored and not included in any promoted chunk. They will be forgotten.
8. **Forget by omission**: Any buffer entry ID that you do not include in any chunk's "sourceEntryIds" will be permanently deleted and forgotten.
`.trim();