mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-22 03:52:48 +05:30
refactor(gui): Use structured logging over string parsing
This commit is contained in:
@@ -29,24 +29,37 @@ export function PromptModal({ entry, onClose }: PromptModalProps) {
|
||||
systemPrompt: string,
|
||||
userContext: string,
|
||||
inputTokens: number,
|
||||
sectionsObj?: {
|
||||
worldInfo: string;
|
||||
memoryLedger: string;
|
||||
cognitiveBuffer: string;
|
||||
},
|
||||
) => {
|
||||
const recentHeader = "=== COGNITIVE BUFFER ===";
|
||||
const ledgerHeader = "=== MEMORY LEDGER ===";
|
||||
|
||||
const recentIdx = userContext.indexOf(recentHeader);
|
||||
let worldStr = userContext;
|
||||
let worldStr = "";
|
||||
let recentStr = "";
|
||||
let ledgerStr = "";
|
||||
|
||||
if (recentIdx !== -1) {
|
||||
worldStr = userContext.substring(0, recentIdx).trim();
|
||||
const rest = userContext.substring(recentIdx).trim();
|
||||
const ledgerIdx = rest.indexOf(ledgerHeader);
|
||||
if (ledgerIdx !== -1) {
|
||||
recentStr = rest.substring(0, ledgerIdx).trim();
|
||||
ledgerStr = rest.substring(ledgerIdx).trim();
|
||||
} else {
|
||||
recentStr = rest;
|
||||
if (sectionsObj) {
|
||||
worldStr = sectionsObj.worldInfo;
|
||||
recentStr = sectionsObj.cognitiveBuffer;
|
||||
ledgerStr = sectionsObj.memoryLedger;
|
||||
} else {
|
||||
const recentHeader = "=== COGNITIVE BUFFER ===";
|
||||
const ledgerHeader = "=== MEMORY LEDGER ===";
|
||||
|
||||
const recentIdx = userContext.indexOf(recentHeader);
|
||||
worldStr = userContext;
|
||||
|
||||
if (recentIdx !== -1) {
|
||||
worldStr = userContext.substring(0, recentIdx).trim();
|
||||
const rest = userContext.substring(recentIdx).trim();
|
||||
const ledgerIdx = rest.indexOf(ledgerHeader);
|
||||
if (ledgerIdx !== -1) {
|
||||
recentStr = rest.substring(0, ledgerIdx).trim();
|
||||
ledgerStr = rest.substring(ledgerIdx).trim();
|
||||
} else {
|
||||
recentStr = rest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +157,7 @@ export function PromptModal({ entry, onClose }: PromptModalProps) {
|
||||
entry.rawPrompt.systemPrompt,
|
||||
entry.rawPrompt.userContext,
|
||||
entry.usage.inputTokens,
|
||||
entry.rawPrompt.sections,
|
||||
)
|
||||
: null;
|
||||
const decoderBreakdown =
|
||||
|
||||
@@ -20,6 +20,11 @@ export interface LogEntry {
|
||||
rawPrompt?: {
|
||||
systemPrompt: string;
|
||||
userContext: string;
|
||||
sections?: {
|
||||
worldInfo: string;
|
||||
memoryLedger: string;
|
||||
cognitiveBuffer: string;
|
||||
};
|
||||
};
|
||||
usage?: {
|
||||
inputTokens: number;
|
||||
|
||||
@@ -165,6 +165,11 @@ export async function processNpcTurn(
|
||||
narrativeProse: result.narrativeProse,
|
||||
intents: [],
|
||||
timestamp: worldState.clock.get().toISOString(),
|
||||
rawPrompt: {
|
||||
systemPrompt: result.systemPrompt || "",
|
||||
userContext: result.userContext || "",
|
||||
sections: result.promptComponents,
|
||||
},
|
||||
};
|
||||
|
||||
if (
|
||||
@@ -175,10 +180,6 @@ export async function processNpcTurn(
|
||||
session.actorProvider.lastCalls[
|
||||
session.actorProvider.lastCalls.length - 1
|
||||
];
|
||||
entry.rawPrompt = {
|
||||
systemPrompt: actorCall.systemPrompt,
|
||||
userContext: actorCall.userContext,
|
||||
};
|
||||
entry.usage = actorCall.usage;
|
||||
}
|
||||
|
||||
@@ -243,8 +244,9 @@ export async function executePlayerAction(
|
||||
intents: [],
|
||||
timestamp: worldState.clock.get().toISOString(),
|
||||
rawPrompt: {
|
||||
systemPrompt: ctx.systemPrompt,
|
||||
userContext: ctx.userContext,
|
||||
systemPrompt: result.systemPrompt || ctx.systemPrompt,
|
||||
userContext: result.userContext || ctx.userContext,
|
||||
sections: result.promptComponents,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -54,16 +54,27 @@ export class ActorPromptBuilder {
|
||||
private ledgerLimit = 5,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Assembles the system prompt and user context for a given entity.
|
||||
*/
|
||||
/**
|
||||
* Assembles the system prompt and user context for a given entity.
|
||||
*/
|
||||
build(
|
||||
worldState: WorldState,
|
||||
entity: Entity,
|
||||
): { systemPrompt: string; userContext: string } {
|
||||
): {
|
||||
systemPrompt: string;
|
||||
userContext: string;
|
||||
sections: {
|
||||
worldInfo: string;
|
||||
memoryLedger: string;
|
||||
cognitiveBuffer: string;
|
||||
};
|
||||
} {
|
||||
const systemPrompt = this.buildSystemPrompt();
|
||||
const userContext = this.buildUserContext(worldState, entity);
|
||||
return { systemPrompt, userContext };
|
||||
const { userContext, sections } = this.buildUserContext(worldState, entity);
|
||||
return { systemPrompt, userContext, sections };
|
||||
}
|
||||
|
||||
private buildSystemPrompt(): string {
|
||||
@@ -84,23 +95,28 @@ Guidelines:
|
||||
- Stay strictly within what your character knows. Do not invent knowledge that doesn't exist or act on it.
|
||||
- You are limited by just your memory. If your memory is limited, then that's all you can remember. If you do make stuff up then that's lying. Which is allowed, but remember that you're lying
|
||||
- Only describe your character's own actions, spoken words, and internal reactions. Do NOT narrate the environment or your surroundings, or other characters' actions.
|
||||
- Be clear about who or what you are interacting with.
|
||||
".
|
||||
`.trim();
|
||||
}
|
||||
|
||||
private buildUserContext(worldState: WorldState, entity: Entity): string {
|
||||
const sections: string[] = [];
|
||||
private buildUserContext(
|
||||
worldState: WorldState,
|
||||
entity: Entity,
|
||||
): {
|
||||
userContext: string;
|
||||
sections: {
|
||||
worldInfo: string;
|
||||
memoryLedger: string;
|
||||
cognitiveBuffer: string;
|
||||
};
|
||||
} {
|
||||
const now = worldState.clock.get();
|
||||
|
||||
// --- Subjective present time ---
|
||||
sections.push(
|
||||
`=== CURRENT MOMENT ===\nIt is ${now.toISOString()} right now.`,
|
||||
);
|
||||
|
||||
// --- Subjective world state (self + perceived entities + co-location) ---
|
||||
sections.push(
|
||||
`=== THE WORLD AS YOU PERCEIVE IT ===\n${serializeSubjectiveWorldState(worldState, entity.id)}`,
|
||||
);
|
||||
// --- Subjective present time & world state ---
|
||||
const momentStr = `=== CURRENT MOMENT ===\nIt is ${now.toISOString()} right now.`;
|
||||
const perceivedStr = `=== THE WORLD AS YOU PERCEIVE IT ===\n${serializeSubjectiveWorldState(worldState, entity.id)}`;
|
||||
const worldInfo = `${momentStr}\n\n${perceivedStr}`;
|
||||
|
||||
// Fetch recent buffer entries once
|
||||
let recentEntries: BufferEntry[] = [];
|
||||
@@ -112,16 +128,6 @@ Guidelines:
|
||||
}
|
||||
}
|
||||
|
||||
// --- Cognitive Buffer ---
|
||||
const memorySection = this.buildCognitiveBufferSection(
|
||||
entity,
|
||||
recentEntries,
|
||||
now,
|
||||
);
|
||||
if (memorySection) {
|
||||
sections.push(memorySection);
|
||||
}
|
||||
|
||||
// --- Recalled Memory Ledger ---
|
||||
const ledgerSection = this.buildLedgerSection(
|
||||
worldState,
|
||||
@@ -129,11 +135,30 @@ Guidelines:
|
||||
recentEntries,
|
||||
now,
|
||||
);
|
||||
if (ledgerSection) {
|
||||
sections.push(ledgerSection);
|
||||
}
|
||||
const memoryLedger = ledgerSection || "";
|
||||
|
||||
return sections.join("\n\n");
|
||||
// --- Cognitive Buffer ---
|
||||
const memorySection = this.buildCognitiveBufferSection(
|
||||
entity,
|
||||
recentEntries,
|
||||
now,
|
||||
);
|
||||
const cognitiveBuffer = memorySection || "";
|
||||
|
||||
// Assemble final user context
|
||||
const parts: string[] = [worldInfo];
|
||||
if (memoryLedger) parts.push(memoryLedger);
|
||||
if (cognitiveBuffer) parts.push(cognitiveBuffer);
|
||||
const userContext = parts.join("\n\n");
|
||||
|
||||
return {
|
||||
userContext,
|
||||
sections: {
|
||||
worldInfo,
|
||||
memoryLedger,
|
||||
cognitiveBuffer,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private buildCognitiveBufferSection(
|
||||
|
||||
@@ -54,6 +54,13 @@ export interface ActorTurnResult {
|
||||
narrativeProse: string;
|
||||
/** The decoded intent sequence (split/classified from the prose). */
|
||||
intents: IntentSequence;
|
||||
systemPrompt?: string;
|
||||
userContext?: string;
|
||||
promptComponents?: {
|
||||
worldInfo: string;
|
||||
memoryLedger: string;
|
||||
cognitiveBuffer: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +123,7 @@ export class ActorAgent {
|
||||
);
|
||||
}
|
||||
|
||||
const { systemPrompt, userContext } = this.promptBuilder.build(
|
||||
const { systemPrompt, userContext, sections } = this.promptBuilder.build(
|
||||
worldState,
|
||||
entity,
|
||||
);
|
||||
@@ -145,6 +152,9 @@ export class ActorAgent {
|
||||
return {
|
||||
narrativeProse,
|
||||
intents,
|
||||
systemPrompt,
|
||||
userContext,
|
||||
promptComponents: sections,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,14 +128,18 @@ describe("Talking Room Demo Scenario Test (Tier 1)", () => {
|
||||
|
||||
// 7. Assert initial pre-seeded memories
|
||||
const alphaMemories = bufferRepo.listForOwner(alphaId);
|
||||
expect(alphaMemories).toHaveLength(2);
|
||||
expect(alphaMemories).toHaveLength(3);
|
||||
expect(alphaMemories[0].id).toBe("ab3f29d2-cf11-4111-9a99-b13c126d123e");
|
||||
expect(alphaMemories[0].intent.type).toBe("monologue");
|
||||
expect(alphaMemories[0].intent.content).toContain("jail");
|
||||
|
||||
expect(alphaMemories[1].id).toBe("zz3f29d2-as11-9811-9a99-b13c126d123e");
|
||||
expect(alphaMemories[1].id).toBe("10ak29d2-as11-9811-9a99-b13c126d123e");
|
||||
expect(alphaMemories[1].intent.type).toBe("action");
|
||||
expect(alphaMemories[1].intent.content).toContain("sleep");
|
||||
expect(alphaMemories[1].intent.content).toContain("another man");
|
||||
|
||||
expect(alphaMemories[2].id).toBe("zz3f29d2-as11-9811-9a99-b13c126d123e");
|
||||
expect(alphaMemories[2].intent.type).toBe("action");
|
||||
expect(alphaMemories[2].intent.content).toContain("sleep");
|
||||
|
||||
const betaMemories = bufferRepo.listForOwner(betaId);
|
||||
expect(betaMemories).toHaveLength(1);
|
||||
|
||||
Reference in New Issue
Block a user