mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-21 19:42:48 +05:30
refactor!(memory): Streamline memory terminology and architecture
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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.)",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<typeof IntentTypeSchema>;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
BIN
web/docs/src/assets/img/mem1.png
Normal file
BIN
web/docs/src/assets/img/mem1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
web/docs/src/assets/img/mem2.png
Normal file
BIN
web/docs/src/assets/img/mem2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
42
web/docs/src/content/docs/diary/2_Finalizing_memory.md
Normal file
42
web/docs/src/content/docs/diary/2_Finalizing_memory.md
Normal file
@@ -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
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
Reference in New Issue
Block a user