mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-22 03:52:48 +05:30
refactor: Group subsequent events under a naturalized time head
Strips out actual world clock from memories.
This commit is contained in:
@@ -52,12 +52,12 @@ export class ActorPromptBuilder {
|
||||
worldState: WorldState,
|
||||
entity: Entity,
|
||||
): { systemPrompt: string; userContext: string } {
|
||||
const systemPrompt = this.buildSystemPrompt(entity);
|
||||
const systemPrompt = this.buildSystemPrompt();
|
||||
const userContext = this.buildUserContext(worldState, entity);
|
||||
return { systemPrompt, userContext };
|
||||
}
|
||||
|
||||
private buildSystemPrompt(entity: Entity): string {
|
||||
private buildSystemPrompt(): string {
|
||||
return `
|
||||
You are an actor agent embodying a single character in a narrative simulation. You ARE this character — act immersively, naturally, and in-character at all times. Do not break character, do not reference being an AI or a system, and do not narrate from outside the character's perspective.
|
||||
|
||||
@@ -74,15 +74,11 @@ Guidelines:
|
||||
- Keep your prose vivid but concise. A single response may contain more than one intent (e.g., you may think, then speak, then act) — write them in natural narrative order.
|
||||
- Not every response requires an outward action. It is perfectly valid to only think (a monologue) and do nothing perceivable.
|
||||
- Never speak or act on another entity's behalf — you only control your own character.
|
||||
|
||||
Your character's identifier in this world is "${entity.id}".
|
||||
".
|
||||
`.trim();
|
||||
}
|
||||
|
||||
private buildUserContext(
|
||||
worldState: WorldState,
|
||||
entity: Entity,
|
||||
): string {
|
||||
private buildUserContext(worldState: WorldState, entity: Entity): string {
|
||||
const sections: string[] = [];
|
||||
|
||||
// --- Subjective present time ---
|
||||
@@ -97,7 +93,10 @@ Your character's identifier in this world is "${entity.id}".
|
||||
);
|
||||
|
||||
// --- Recent memory ---
|
||||
const memorySection = this.buildMemorySection(entity, worldState.clock.get());
|
||||
const memorySection = this.buildMemorySection(
|
||||
entity,
|
||||
worldState.clock.get(),
|
||||
);
|
||||
if (memorySection) {
|
||||
sections.push(memorySection);
|
||||
}
|
||||
@@ -120,12 +119,22 @@ Your character's identifier in this world is "${entity.id}".
|
||||
}
|
||||
|
||||
const recent = entries.slice(-this.memoryLimit);
|
||||
const lines = recent.map((entry) => {
|
||||
const groupedLines: string[] = [];
|
||||
let currentGroup: string | null = null;
|
||||
|
||||
for (const entry of recent) {
|
||||
const serialized = serializeSubjectiveBufferEntry(entry, entity);
|
||||
const when = naturalizeTime(now, new Date(entry.timestamp));
|
||||
return `${serialized} (${when})`;
|
||||
});
|
||||
|
||||
return `=== YOUR RECENT MEMORY ===\n${lines.join("\n")}`;
|
||||
if (when !== currentGroup) {
|
||||
currentGroup = when;
|
||||
const header = when.charAt(0).toUpperCase() + when.slice(1);
|
||||
groupedLines.push(header);
|
||||
}
|
||||
|
||||
groupedLines.push(` - ${serialized}`);
|
||||
}
|
||||
|
||||
return `=== YOUR RECENT MEMORY ===\n${groupedLines.join("\n")}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,6 @@ export function serializeSubjectiveBufferEntry(
|
||||
entry: BufferEntry,
|
||||
viewer: Entity,
|
||||
): string {
|
||||
const dateObj = new Date(entry.timestamp);
|
||||
// Ensure a deterministic timezone/format for testing and model inputs:
|
||||
const timeStr = dateObj.toLocaleTimeString("en-US", {
|
||||
hour12: true,
|
||||
timeZone: "UTC",
|
||||
});
|
||||
|
||||
const actorAlias = resolveAlias(viewer, entry.intent.actorId);
|
||||
|
||||
const targetAliases = entry.intent.targetIds.map((tid) =>
|
||||
@@ -48,7 +41,7 @@ export function serializeSubjectiveBufferEntry(
|
||||
}
|
||||
}
|
||||
|
||||
return `[${timeStr}] ${actorAlias} ${details}`;
|
||||
return `${actorAlias} ${details}`;
|
||||
}
|
||||
|
||||
export class BufferRepository {
|
||||
|
||||
@@ -39,7 +39,7 @@ describe("Subjective Buffer Entry Serializer Tests (Tier 1)", () => {
|
||||
};
|
||||
|
||||
const result = serializeSubjectiveBufferEntry(entry, viewer);
|
||||
expect(result).toBe('[12:00:00 PM] the hooded figure spoke to the bartender: "Bob greets Charlie"');
|
||||
expect(result).toBe('the hooded figure spoke to the bartender: "Bob greets Charlie"');
|
||||
});
|
||||
|
||||
test("serializes action intent with outcome details", () => {
|
||||
@@ -65,7 +65,7 @@ describe("Subjective Buffer Entry Serializer Tests (Tier 1)", () => {
|
||||
};
|
||||
|
||||
const result = serializeSubjectiveBufferEntry(entry, viewer);
|
||||
expect(result).toBe('[12:05:00 PM] the hooded figure Bob attempts to break the lock latch (Outcome: Failed - The lock is made of reinforced steel.)');
|
||||
expect(result).toBe('the hooded figure Bob attempts to break the lock latch (Outcome: Failed - The lock is made of reinforced steel.)');
|
||||
});
|
||||
|
||||
test("serializes self-reference and unfamiliar actors", () => {
|
||||
@@ -86,7 +86,7 @@ describe("Subjective Buffer Entry Serializer Tests (Tier 1)", () => {
|
||||
};
|
||||
|
||||
const resultSelf = serializeSubjectiveBufferEntry(entrySelf, viewer);
|
||||
expect(resultSelf).toBe("[12:10:00 PM] you open the window");
|
||||
expect(resultSelf).toBe("you open the window");
|
||||
|
||||
const entryUnfamiliar: BufferEntry = {
|
||||
id: "entry-unfamiliar",
|
||||
@@ -103,7 +103,7 @@ describe("Subjective Buffer Entry Serializer Tests (Tier 1)", () => {
|
||||
};
|
||||
|
||||
const resultUnfamiliar = serializeSubjectiveBufferEntry(entryUnfamiliar, viewer);
|
||||
expect(resultUnfamiliar).toBe("[12:15:00 PM] an unfamiliar figure knock on the door");
|
||||
expect(resultUnfamiliar).toBe("an unfamiliar figure knock on the door");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user