diff --git a/packages/actor/src/actor-prompt-builder.ts b/packages/actor/src/actor-prompt-builder.ts index b461cd2..c401afa 100644 --- a/packages/actor/src/actor-prompt-builder.ts +++ b/packages/actor/src/actor-prompt-builder.ts @@ -4,6 +4,7 @@ import { WorldState, naturalizeTime, serializeSubjectiveWorldState, + resolveAlias, } from "@omnia/core"; import { BufferEntry, @@ -239,7 +240,7 @@ Guidelines: let content = entry.content; // Resolve system IDs to subjective aliases in the content for (const targetId of entry.involvedEntityIds) { - const alias = entity.aliases.get(targetId) ?? targetId; + const alias = resolveAlias(entity, targetId); content = content.replace(new RegExp(targetId, "g"), alias); } if (entry.locationId) { diff --git a/packages/core/src/alias.ts b/packages/core/src/alias.ts new file mode 100644 index 0000000..eccc9b8 --- /dev/null +++ b/packages/core/src/alias.ts @@ -0,0 +1,6 @@ +import { Entity } from "./entity.js"; + +export function resolveAlias(viewer: Entity, targetId: string): string { + if (targetId === viewer.id) return "you"; + return viewer.aliases.get(targetId) ?? "an unfamiliar figure"; +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3eb484c..90ba4e1 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,5 +1,13 @@ +/** + * Monorepo Hygiene Note: + * If a pure function only touches types owned by core (e.g., Entity, WorldState, Attribute), + * it belongs here in the core package (e.g., in a dedicated file like alias.ts), even if + * a higher-level package is currently its only consumer. + */ export * from "./attribute.js"; export * from "./entity.js"; export * from "./world.js"; export * from "./clock.js"; export * from "./repository.js"; +export * from "./alias.js"; + diff --git a/packages/core/src/world.ts b/packages/core/src/world.ts index f2bc2a3..371b73b 100644 --- a/packages/core/src/world.ts +++ b/packages/core/src/world.ts @@ -1,6 +1,7 @@ import { AttributableObject, Attribute, serializeAttributes } from "./attribute.js"; import { Entity } from "./entity.js"; import { WorldClock } from "./clock.js"; +import { resolveAlias } from "./alias.js"; export class WorldState extends AttributableObject { /** @@ -118,19 +119,6 @@ export function serializeObjectiveWorldState(worldState: WorldState): string { return lines.join("\n"); } -/** - * Resolves how a viewer subjectively refers to a target entity. - * - Self → "you" - * - Known (in the viewer's alias map) → the subjective alias - * - Unknown → "an unfamiliar figure" - * - * Mirrors the implementation in @omnia/memory's resolveAlias, inlined here - * to avoid a circular dependency (memory depends on core). - */ -function resolveAliasViewer(viewer: Entity, targetId: string): string { - if (targetId === viewer.id) return "you"; - return viewer.aliases.get(targetId) ?? "an unfamiliar figure"; -} /** * Serializes a single attribute the way a viewer perceives it — name and @@ -164,7 +152,7 @@ export function serializeSubjectiveWorldState( } const lines: string[] = []; - const viewerAlias = resolveAliasViewer(viewer, viewerId); + const viewerAlias = resolveAlias(viewer, viewerId); // --- World attributes (only those the viewer can see) --- const worldVisible = worldState.getVisibleAttributesFor(viewerId); @@ -208,7 +196,7 @@ export function serializeSubjectiveWorldState( if (coLocated.length > 0) { lines.push(" Entities present with you:"); for (const e of coLocated) { - const alias = resolveAliasViewer(viewer, e.id); + const alias = resolveAlias(viewer, e.id); lines.push(` - ${alias}:`); const eVisible = e.getVisibleAttributesFor(viewerId); lines.push(serializeVisibleAttributes(eVisible).split("\n").map((l) => " " + l).join("\n")); @@ -220,7 +208,7 @@ export function serializeSubjectiveWorldState( if (elsewhere.length > 0) { lines.push(" Other presences you are aware of (elsewhere):"); for (const e of elsewhere) { - const alias = resolveAliasViewer(viewer, e.id); + const alias = resolveAlias(viewer, e.id); lines.push(` - ${alias} [elsewhere]`); } } diff --git a/packages/memory/src/buffer.ts b/packages/memory/src/buffer.ts index 5983bda..9132c71 100644 --- a/packages/memory/src/buffer.ts +++ b/packages/memory/src/buffer.ts @@ -1,5 +1,5 @@ import Database from "better-sqlite3"; -import { Entity } from "@omnia/core"; +import { Entity, resolveAlias } from "@omnia/core"; import { Intent } from "@omnia/intent"; export interface BufferEntry { @@ -16,10 +16,7 @@ export interface BufferEntry { }; } -export function resolveAlias(viewer: Entity, targetId: string): string { - if (targetId === viewer.id) return "you"; - return viewer.aliases.get(targetId) ?? "an unfamiliar figure"; -} +export { resolveAlias } from "@omnia/core"; export function serializeSubjectiveBufferEntry( entry: BufferEntry, diff --git a/packages/scenario/src/loader.ts b/packages/scenario/src/loader.ts index 2497f6f..13ad99c 100644 --- a/packages/scenario/src/loader.ts +++ b/packages/scenario/src/loader.ts @@ -106,7 +106,6 @@ export class ScenarioLoader { world.addEntity(entity); this.coreRepo.saveEntity(entity, world.id); - // Seed initial memory buffer history if (entData.initialMemories) { for (const mem of entData.initialMemories) { this.bufferRepo.save({ @@ -114,7 +113,11 @@ export class ScenarioLoader { ownerId: entData.id, timestamp: mem.timestamp, locationId: mem.locationId, - intent: mem.intent, + intent: { + ...mem.intent, + selfDescription: mem.intent.selfDescription ?? "", + modifiers: mem.intent.modifiers ?? [], + }, outcome: mem.outcome, }); } diff --git a/packages/scenario/src/schema.ts b/packages/scenario/src/schema.ts index c2ed31e..307522a 100644 --- a/packages/scenario/src/schema.ts +++ b/packages/scenario/src/schema.ts @@ -33,8 +33,10 @@ export const ScenarioMemoryEntrySchema = z.object({ type: z.enum(["dialogue", "action", "monologue"]), originalText: z.string(), description: z.string(), + selfDescription: z.string().optional(), actorId: z.string(), targetIds: z.array(z.string()), + modifiers: z.array(z.string()).optional(), }), outcome: z.object({ isValid: z.boolean(),