diff --git a/README.md b/README.md index 048396f..cc33661 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ omnia/ intent/ intent types (dialogue/action/monologue) and the prose decoder architect/ World Architect: LLM validation plus time-delta generation actor/ actor agent: epistemically-bounded prompts, pluggable prose generators - memory/ verbatim buffer; later the vector archive, dossier, and affect vectors + memory/ Cognitive Buffer; Memory Ledger (vector archive), dossier, and affect vectors spatial/ location and POI graph, portal-based perception llm/ ILLMProvider interface plus Gemini and deterministic mock implementations scenario/ scenario JSON schema and loader (JSON → SQLite) diff --git a/apps/gui/src/components/play/PromptModal.tsx b/apps/gui/src/components/play/PromptModal.tsx index ea0cc90..eb46f93 100644 --- a/apps/gui/src/components/play/PromptModal.tsx +++ b/apps/gui/src/components/play/PromptModal.tsx @@ -61,7 +61,7 @@ export function PromptModal({ entry, onClose }: PromptModalProps) { { label: "Memory Ledger", type: "memories", - content: ledgerStr || "(No memory buffer entries.)", + content: ledgerStr || "(No memory ledger entries.)", }, ]; diff --git a/content/demo/scenarios/talking-room.json b/content/demo/scenarios/talking-room.json index bbec88d..8a65d53 100644 --- a/content/demo/scenarios/talking-room.json +++ b/content/demo/scenarios/talking-room.json @@ -72,7 +72,7 @@ ], "initialMemories": [ { - "id": "alpha-wake", + "id": "ab3f29d2-cf11-4111-9a99-b13c126d123e", "timestamp": "2026-07-09T07:58:00.000Z", "locationId": "white-room", "intent": { @@ -119,7 +119,7 @@ ], "initialMemories": [ { - "id": "beta-wake", + "id": "7c9b83b3-8cfb-4e89-8d77-626a5757d591", "timestamp": "2026-07-09T07:58:30.000Z", "locationId": "white-room", "intent": { diff --git a/docs b/docs index 51037cd..9f43cd9 120000 --- a/docs +++ b/docs @@ -1 +1 @@ -web/docs/src \ No newline at end of file +web/docs/src/content/docs \ No newline at end of file diff --git a/packages/actor/src/actor-prompt-builder.ts b/packages/actor/src/actor-prompt-builder.ts index 2bb252d..0387bee 100644 --- a/packages/actor/src/actor-prompt-builder.ts +++ b/packages/actor/src/actor-prompt-builder.ts @@ -139,7 +139,7 @@ Guidelines: if (!this.bufferRepo) return null; if (entries.length === 0) { - return `=== COGNITIVE BUFFER ===\n(No recent events recorded.)`; + return `=== COGNITIVE BUFFER ===\n(No entries recorded.)`; } const recent = entries.slice(-this.memoryLimit); diff --git a/packages/architect/src/architect.ts b/packages/architect/src/architect.ts index 56234fc..f5514cd 100644 --- a/packages/architect/src/architect.ts +++ b/packages/architect/src/architect.ts @@ -50,7 +50,7 @@ export class Architect { * "monologue" intents are internal thoughts — they bypass validation and * time-delta generation entirely: the clock does not advance, the world * state is not mutated or persisted. The caller is responsible for writing - * the monologue to the actor's memory buffer. + * the monologue to the actor's Cognitive Buffer. */ async processIntent( worldState: WorldState, diff --git a/packages/intent/src/intent.ts b/packages/intent/src/intent.ts index dc42974..705c67a 100644 --- a/packages/intent/src/intent.ts +++ b/packages/intent/src/intent.ts @@ -6,7 +6,7 @@ import { z } from "zod"; * - "action": A physical or logical action performed in the world. * - "monologue": An inner thought or internal monologue. Not perceivable by * any other entity. Bypasses the Architect/validators entirely and is - * written directly to the actor's memory buffer with no outcome. + * written directly to the actor's Cognitive Buffer with no outcome. */ export const IntentTypeSchema = z.enum(["dialogue", "action", "monologue"]); export type IntentType = z.infer; diff --git a/packages/memory/src/buffer.ts b/packages/memory/src/buffer.ts index 394cc56..733419b 100644 --- a/packages/memory/src/buffer.ts +++ b/packages/memory/src/buffer.ts @@ -4,7 +4,7 @@ import { Intent } from "@omnia/intent"; export interface BufferEntry { id: string; - ownerId: string; // Whose subjective memory buffer this lives in + ownerId: string; // Whose Cognitive Buffer this entry lives in timestamp: string; // WorldClock.get().toISOString() at write time locationId: string | null; // Actor's location when this happened diff --git a/packages/memory/src/handoff.ts b/packages/memory/src/handoff.ts index 6908bce..8eee51c 100644 --- a/packages/memory/src/handoff.ts +++ b/packages/memory/src/handoff.ts @@ -33,7 +33,7 @@ export function getMemorySectionLength( now: Date, ): number { if (entries.length === 0) { - return `=== COGNITIVE BUFFER ===\n(No recent events recorded.)`.length; + return `=== COGNITIVE BUFFER ===\n(No entries recorded.)`.length; } const groupedLines: string[] = []; @@ -246,7 +246,7 @@ Instructions: Subject Entity ID: ${entity.id} Current Time: ${now.toISOString()} -Working Memory Candidates for Handoff: +Cognitive Buffer Candidates for Handoff: ${candidatesList} `.trim(); diff --git a/tests/integration/actor-monologue.test.ts b/tests/integration/actor-monologue.test.ts index 4e877bd..9d32d0d 100644 --- a/tests/integration/actor-monologue.test.ts +++ b/tests/integration/actor-monologue.test.ts @@ -166,7 +166,7 @@ describe("Actor Agent + Monologue Intent Integration (Tier 2)", () => { const expectedTime = new Date(startTime.getTime() + 3 * 60_000); expect(world.clock.get().toISOString()).toBe(expectedTime.toISOString()); - // 7. All three intents persisted to Alice's memory buffer. + // 7. All three intents persisted to Alice's Cognitive Buffer. const aliceMemory = bufferRepo.listForOwner("alice"); expect(aliceMemory).toHaveLength(3); expect(aliceMemory[0].intent.type).toBe("monologue"); diff --git a/web/docs/src/assets/img/mem1.png b/web/docs/src/assets/img/mem1.png new file mode 100644 index 0000000..f5d037b Binary files /dev/null and b/web/docs/src/assets/img/mem1.png differ diff --git a/web/docs/src/assets/img/mem2.png b/web/docs/src/assets/img/mem2.png new file mode 100644 index 0000000..7529e7d Binary files /dev/null and b/web/docs/src/assets/img/mem2.png differ diff --git a/web/docs/src/content/docs/architecture/memory.md b/web/docs/src/content/docs/architecture/memory.md index 88707ea..c36633c 100644 --- a/web/docs/src/content/docs/architecture/memory.md +++ b/web/docs/src/content/docs/architecture/memory.md @@ -36,14 +36,14 @@ Entity aliases are persisted in the `objects` table via the `aliases_json TEXT` ## Subjective Buffer Entry -A subjective `BufferEntry` records a discrete event from the perspective of an entity (the `owner`). It wraps a structured `Intent` and appends execution metadata. +A subjective `BufferEntry` records a discrete event from the perspective of an entity (the `owner`). It wraps a structured `Intent` and appends execution metadata. These entries make up the entity's **Cognitive Buffer**. ### The Shape of a Buffer Entry ```typescript interface BufferEntry { id: string; - ownerId: string; // Whose subjective memory buffer this lives in + ownerId: string; // Whose Cognitive Buffer this entry lives in timestamp: string; // WorldClock.get().toISOString() at write time locationId: string | null; // Actor's location when this happened @@ -61,7 +61,7 @@ interface BufferEntry { ## Buffer Serialization (Epistemic Substitute) -To prevent leaking system IDs, buffer memories are serialized using `serializeSubjectiveBufferEntry` with the `resolveAlias` helper: +To prevent leaking system IDs, Cognitive Buffer entries are serialized using `serializeSubjectiveBufferEntry` with the `resolveAlias` helper: ```typescript export function resolveAlias(viewer: Entity, targetId: string): string { @@ -89,7 +89,7 @@ CREATE TABLE IF NOT EXISTS buffer_entries ( ``` - **JSON Storage**: `intent` and `outcome` are serialized/deserialized as raw JSON, validated by Zod at creation time. -- **Cascade Deletes**: Deleting an entity removes all associated subjective memory entries. +- **Cascade Deletes**: Deleting an entity removes all associated Cognitive Buffer entries. ## Time Naturalization diff --git a/web/docs/src/content/docs/architecture/overview.md b/web/docs/src/content/docs/architecture/overview.md index a18f9ec..a71a1fc 100644 --- a/web/docs/src/content/docs/architecture/overview.md +++ b/web/docs/src/content/docs/architecture/overview.md @@ -12,7 +12,7 @@ omnia/ intent/ intent types (dialogue/action/monologue) and the prose decoder architect/ World Architect: LLM validation plus time-delta generation actor/ actor agent: epistemically-bounded prompts, pluggable prose generators - memory/ verbatim buffer; later the vector archive, dossier, and affect vectors + memory/ Cognitive Buffer; Memory Ledger (vector archive), dossier, and affect vectors spatial/ location and POI graph, portal-based perception llm/ ILLMProvider interface plus Gemini and deterministic mock implementations scenario/ scenario JSON schema and loader (JSON → SQLite) diff --git a/web/docs/src/content/docs/diary/2_Finalizing_memory.md b/web/docs/src/content/docs/diary/2_Finalizing_memory.md new file mode 100644 index 0000000..36a2395 --- /dev/null +++ b/web/docs/src/content/docs/diary/2_Finalizing_memory.md @@ -0,0 +1,42 @@ +--- +title: I'm done with confusing memory jargon +author: sortedcord +time: 2026-07-18T16:12:00+05:30 +--- + +Memory has always been a core part of Omnia's architecture. I've always leaned towards a three tier system and it feels good to finally have a system frozen that's not subject to any more dramatic shifts. + +Up until now, I had been juggling terms like "short-term", "long-term", "buffer", "ledger" and memory quite randomly and interchagebly. Not just that, I think even [NLAVS](https://github.com/sortedcord/NLAVS) is also guilty of this. + +## How it was + +![A simple diagram showing three stacked horizontal boxes with orange outlines and text, labeled "Tier 1: Short Term" at the top, "Tier 2: Medium-ish long term?" in the middle, and "Tier 3: Long Term" at the bottom.](../../../assets/img/mem1.png) + +Notice how the tier 2 bar is the longest here. This made sense to me. You'd have a short term memory structure, ideally for events that are happening in real time and this would be small. At any given time you can't realistically carry a lot of information. And then at the bottom we have the long term tier. And just to make the graph complete, there's this intermediate layer which would contain most of the memories of an agent. + +Sounded right on markdown and looked cool in excali. But once you start talking about how they actually work, how does a unit of memory actually go between these layers is when all hell breaks loose. This wasn't something I paid much attention towards. + +## A colorful diagram that's a wanna be complex flowchart + +While developing [Handoff](../architecture/handoff.md); which is the mechanism for promoting "short term" memories to "long term" memories I realized that blindly modelling this after how humans are supposed to remember isn't a good approach to this, or rather, I'd say is a naiive solution to a data engineering problem. + +![A flow chart illustrating a three-tiered system where "Tier 1: Cognitive Buffer" flows into a "Handoff Call" box, which then connects to both the "Tier 2: Memory Ledger" and the "DossierDelta Generator"; simultaneously, both the "Tier 1: Cognitive Buffer" and the "Tier 2: Memory Ledger" also feed into the "DossierDelta Generator," which subsequently leads to "Tier 3: Dossiers," a large vertical box that also has a feedback loop returning to the "Tier 2: Memory Ledger."](../../../assets/img/mem2.png) + +Don't let this fool you. I didn't just move boxes around, add new boxes and renamed stuff and called it a day (even though that's what i did ;). But the main realization I had and the main framework that Omnia will follow from now on out is that **memories for an agent shouldn't be discrete rather they should be episodic.** + +When one remembers something, they don't remember it in isolated bits and pieces. You remember them in sequences that are chained together. Remembering something often leads to remembering events that either caused it or were caused by it. Like a chain. This chain is the episode this is what makes Omnia's memory system different: **Memory isn't pure hierarchy.** + +Each tier of memory serves its own purpose and has its own benefits and trade-offs but integrating them well together allows them to complement each other quite well. + +Putting this diagram into words: + +1. [**Tier 1: Cognitive Buffer**](../architecture/memory.md) is basically how the agent perceives its surroundings as-is. It is analgoues to a vision to text thing where whatever the agent "sees" is written down here, in the sense that this is high resolution and very verbose. So it contains actions, dialogues of others and itself but also its own thoughts, feelings, monologues. +2. [**Handoff**](../architecture/handoff.md) is what determines how important each event in the cognitive buffer is to be promoted to Memories. It's also responsible for compressing multiple actions into a single Memory Ledger entry. +3. [**Tier 2: Memory Ledger**](../architecture/memory-tier2.md) contains the bulk of an agent's memory. All memories are stored by when it happened, where it happened and who/what were involved in it. Given the size it will grow to, there was a need to implement a retrieval system (more than 1 of them). +4. [**Tier 3: Dossiers**](../architecture/) is the component of Omnia that allows for a per-actor subjective reality mapping. Every fact an actor knows whether it's about themselves or something else is stored as a dossier. + +Dossiers also dictate what series of memories from the memory ledger populate the context for an actor allowing for episodic retreival of memories alongside the general ledger retriever that works on semantic similarity. + +The main difference between the cognitive buffer+memory ledger and dossiers is that the former are immutable. Once something happens, it stays in the memory. It can become less relevant or harder to remember overtime (through time decay) but it stays in the memory as an immutable form. + +Dossiers however, are mutable. They are an ever-changing object in the actor's memory that define what they think about something at that intance of time. This 'thought' or 'impression' can be about anything - themselves, another actor, location, abstract idea, etc.