From 7412ab48ea9b0de3fe30f2c578ce5b34fb8d4b2c Mon Sep 17 00:00:00 2001 From: Aditya Gupta Date: Mon, 6 Jul 2026 23:21:04 +0530 Subject: [PATCH] refactor: Remove serializer and polymorphed forms from AttributableObject AC in favor of generic helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Decoupled Attributes Serialization: • Removed all serialize() methods from AttributableObject (attribute.ts), WorldState (world.ts), and Entity (entity.ts). • Implemented a standalone, uncoupled function serializeAttributes(attributes: Attribute[]): string in attribute.ts. This function receives an array of attributes and outputs their formatted representation. 2. System Objective Serializer: • Implemented serializeObjectiveWorldState(worldState: WorldState): string in world.ts for system LLMs that need objective reality dumps (e.g. validators and intent decoders). It manually retrieves and formats attributes using serializeAttributes() alongside class-specific fields like locationId . 3. System prompt updates: • Updated LLMValidator (llm-validator.ts), TimeDeltaGenerator (delta.ts), and IntentDecoder (intent-decoder.ts) to use the new standalone serializeObjectiveWorldState(worldState) helper imported from @omnia/core . 4. Unit Tests (Tier 1): • Updated core.test.ts to verify serializeAttributes and serializeObjectiveWorldState utilities directly. --- packages/architect/src/delta.ts | 4 +- packages/architect/src/index.ts | 1 + packages/architect/src/llm-validator.ts | 4 +- packages/core/src/attribute.ts | 20 ++++---- packages/core/src/entity.ts | 12 ----- packages/core/src/world.ts | 67 ++++++++++++++----------- packages/core/tests/core.test.ts | 12 +++-- packages/intent/src/intent-decoder.ts | 4 +- 8 files changed, 61 insertions(+), 63 deletions(-) diff --git a/packages/architect/src/delta.ts b/packages/architect/src/delta.ts index 30a1ac2..96e8b5f 100644 --- a/packages/architect/src/delta.ts +++ b/packages/architect/src/delta.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { WorldState } from "@omnia/core"; +import { WorldState, serializeObjectiveWorldState } from "@omnia/core"; import { ILLMProvider } from "@omnia/llm"; export const TimeDeltaSchema = z.object({ @@ -41,7 +41,7 @@ Return a structured JSON object containing: === CURRENT WORLD STATE === Current Time: ${worldState.clock.get().toISOString()} World Details: -${worldState.serialize()} +${serializeObjectiveWorldState(worldState)} === ACTION === Actor ID: ${actorId} diff --git a/packages/architect/src/index.ts b/packages/architect/src/index.ts index 19e95a8..e6ce4b8 100644 --- a/packages/architect/src/index.ts +++ b/packages/architect/src/index.ts @@ -1,3 +1,4 @@ export * from "./llm-validator.js"; export * from "./architect.js"; export * from "./delta.js"; + diff --git a/packages/architect/src/llm-validator.ts b/packages/architect/src/llm-validator.ts index a6e2670..5fa2eb0 100644 --- a/packages/architect/src/llm-validator.ts +++ b/packages/architect/src/llm-validator.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { WorldState } from "@omnia/core"; +import { WorldState, serializeObjectiveWorldState } from "@omnia/core"; import { ILLMProvider } from "@omnia/llm"; export const ValidationResultSchema = z.object({ @@ -29,7 +29,7 @@ export class LLMValidator { } // 1. Serialize the objective world state for the LLM - const serializedWorld = worldState.serialize(); + const serializedWorld = serializeObjectiveWorldState(worldState); // 2. Build the prompts const systemPrompt = ` diff --git a/packages/core/src/attribute.ts b/packages/core/src/attribute.ts index 3564a36..f3e1123 100644 --- a/packages/core/src/attribute.ts +++ b/packages/core/src/attribute.ts @@ -112,14 +112,14 @@ export abstract class AttributableObject implements IAttribute { attr.hasAccess(viewerId), ); } - - serialize(): string { - const lines: string[] = []; - for (const [name, attr] of this.attributes.entries()) { - const aclList = Array.from(attr.getAllowedEntities()); - const aclStr = aclList.length > 0 ? ` (Visible to: ${aclList.join(", ")})` : ""; - lines.push(`* ${name}: ${attr.getValue()} (Visibility: ${attr.getVisibility()})${aclStr}`); - } - return lines.join("\n"); - } +} + +export function serializeAttributes(attributes: Attribute[]): string { + const lines: string[] = []; + for (const attr of attributes) { + const aclList = Array.from(attr.getAllowedEntities()); + const aclStr = aclList.length > 0 ? ` (Visible to: ${aclList.join(", ")})` : ""; + lines.push(`* ${attr.name}: ${attr.getValue()} (Visibility: ${attr.getVisibility()})${aclStr}`); + } + return lines.join("\n"); } diff --git a/packages/core/src/entity.ts b/packages/core/src/entity.ts index d593ba6..d98f5ec 100644 --- a/packages/core/src/entity.ts +++ b/packages/core/src/entity.ts @@ -7,16 +7,4 @@ export class Entity extends AttributableObject { super(id); this.locationId = locationId ?? null; } - - override serialize(): string { - const lines: string[] = []; - if (this.locationId) { - lines.push(`* Location ID: ${this.locationId}`); - } - const selfSerialized = super.serialize(); - if (selfSerialized) { - lines.push(selfSerialized); - } - return lines.join("\n"); - } } diff --git a/packages/core/src/world.ts b/packages/core/src/world.ts index 4ac97b1..e42a132 100644 --- a/packages/core/src/world.ts +++ b/packages/core/src/world.ts @@ -1,4 +1,4 @@ -import { AttributableObject } from "./attribute.js"; +import { AttributableObject, serializeAttributes } from "./attribute.js"; import { Entity } from "./entity.js"; import { WorldClock } from "./clock.js"; @@ -27,33 +27,40 @@ export class WorldState extends AttributableObject { getEntity(id: string): Entity | undefined { return this.entities.get(id); } - - override serialize(): string { - const lines: string[] = []; - - // 1. Serialize self attributes (world attributes) - const selfSerialized = super.serialize(); - if (selfSerialized) { - lines.push("World Attributes:"); - lines.push(selfSerialized.split("\n").map(l => " " + l).join("\n")); - } - - // 2. Serialize entities - lines.push("Entities:"); - if (this.entities.size > 0) { - for (const entity of this.entities.values()) { - lines.push(` - Entity [ID: ${entity.id}]:`); - const entitySerialized = entity.serialize(); - if (entitySerialized) { - lines.push(entitySerialized.split("\n").map(l => " " + l).join("\n")); - } else { - lines.push(" * (No attributes)"); - } - } - } else { - lines.push(" (No entities)"); - } - - return lines.join("\n"); - } +} + +/** + * Objective world state serializer for system LLM tasks. + * Bypasses epistemic privacy bounds for system/physics validation. + */ +export function serializeObjectiveWorldState(worldState: WorldState): string { + const lines: string[] = []; + + // Serialize world attributes + if (worldState.attributes.size > 0) { + lines.push("World Attributes:"); + const worldAttrsStr = serializeAttributes(Array.from(worldState.attributes.values())); + lines.push(worldAttrsStr.split("\n").map(l => " " + l).join("\n")); + } + + // Serialize entities and their attributes + lines.push("Entities:"); + if (worldState.entities.size > 0) { + for (const entity of worldState.entities.values()) { + lines.push(` - Entity [ID: ${entity.id}]:`); + if (entity.locationId) { + lines.push(` * Location ID: ${entity.locationId}`); + } + if (entity.attributes.size > 0) { + const entityAttrsStr = serializeAttributes(Array.from(entity.attributes.values())); + lines.push(entityAttrsStr.split("\n").map(l => " " + l).join("\n")); + } else { + lines.push(" * (No attributes)"); + } + } + } else { + lines.push(" (No entities)"); + } + + return lines.join("\n"); } diff --git a/packages/core/tests/core.test.ts b/packages/core/tests/core.test.ts index 2ad80f2..46001a4 100644 --- a/packages/core/tests/core.test.ts +++ b/packages/core/tests/core.test.ts @@ -8,6 +8,8 @@ import { WorldClock, WorldState, SQLiteRepository, + serializeAttributes, + serializeObjectiveWorldState, } from "@omnia/core"; // A concrete implementation of AttributableObject for testing @@ -171,18 +173,18 @@ describe("SQLiteRepository Unit Tests (Tier 1)", () => { }); }); -describe("Serializer Unit Tests (Tier 1)", () => { - test("AttributableObject serialization", () => { +describe("Serializer & serializeObjectiveWorldState Unit Tests (Tier 1)", () => { + test("serializeAttributes utility", () => { const obj = new MockAttributable("obj-1"); obj.addAttribute("health", "100", AttributeVisibility.PUBLIC); obj.addAttribute("secret", "key-123", AttributeVisibility.PRIVATE, new Set(["alice"])); - const result = obj.serialize(); + const result = serializeAttributes(Array.from(obj.attributes.values())); expect(result).toContain("* health: 100 (Visibility: PUBLIC)"); expect(result).toContain("* secret: key-123 (Visibility: PRIVATE) (Visible to: alice)"); }); - test("WorldState serialization", () => { + test("serializeObjectiveWorldState utility", () => { const world = new WorldState("world-1"); world.addAttribute("gravity", "9.8", AttributeVisibility.PUBLIC); @@ -193,7 +195,7 @@ describe("Serializer Unit Tests (Tier 1)", () => { const bob = new Entity("bob"); // no attributes world.addEntity(bob); - const result = world.serialize(); + const result = serializeObjectiveWorldState(world); expect(result).toContain("World Attributes:"); expect(result).toContain(" * gravity: 9.8 (Visibility: PUBLIC)"); expect(result).toContain("Entities:"); diff --git a/packages/intent/src/intent-decoder.ts b/packages/intent/src/intent-decoder.ts index 7898fe1..1c2b6d4 100644 --- a/packages/intent/src/intent-decoder.ts +++ b/packages/intent/src/intent-decoder.ts @@ -1,4 +1,4 @@ -import { WorldState } from "@omnia/core"; +import { WorldState, serializeObjectiveWorldState } from "@omnia/core"; import { ILLMProvider } from "@omnia/llm"; import { IntentSequence, IntentSequenceSchema } from "./intent.js"; @@ -47,7 +47,7 @@ Rules: ${entityIds.length > 0 ? entityIds.join(", ") : "(No entities)"} === WORLD STATE === -${worldState.serialize()} +${serializeObjectiveWorldState(worldState)} === ACTOR === Actor ID: ${actorId}