feat: Wire up intent and architect packages together

- Added  "@omnia/intent": "workspace:*"  dependency to package.json.
- Referenced  ../intent  in the project references of tsconfig.json.
- Updated  validate  in llm-validator.ts to accept intent:Intent instead
of actorId and actionIntent strings
- Promoted the LLM prompt's action details block to include the
structured fields of the intent (type ,  description ,  originalText ,
targetIds ), passing this context to the validator.)
- Updated the  IDeltaGenerator  interface and  TimeDeltaGenerator 's
generate  signature in delta.ts to accept  intent: Intent .
- Refined the LLM prompt's action details block in  TimeDeltaGenerator
to utilize the structured structured  Intent  object.
- Updated all validation and execution mock calls in architect.test.ts
to construct and pass valid Intent  objects.
This commit is contained in:
2026-07-06 23:49:12 +05:30
parent 7412ab48ea
commit 1b667446dd
7 changed files with 75 additions and 46 deletions

View File

@@ -9,6 +9,7 @@
"dependencies": {
"@omnia/core": "workspace:*",
"@omnia/llm": "workspace:*",
"@omnia/intent": "workspace:*",
"zod": "^4.4.3"
}
}

View File

@@ -2,6 +2,7 @@ import { WorldState, SQLiteRepository } from "@omnia/core";
import { LLMValidator, ValidationResult } from "./llm-validator.js";
import { TimeDeltaGenerator, TimeDelta } from "./delta.js";
import { ILLMProvider } from "@omnia/llm";
import { Intent } from "@omnia/intent";
export interface ProcessResult extends ValidationResult {
timeDelta?: TimeDelta;
@@ -22,10 +23,9 @@ export class Architect {
*/
async validateIntent(
worldState: WorldState,
actorId: string,
actionIntent: string,
intent: Intent,
): Promise<ValidationResult> {
return this.validator.validate(worldState, actorId, actionIntent);
return this.validator.validate(worldState, intent);
}
/**
@@ -34,11 +34,10 @@ export class Architect {
*/
async processIntent(
worldState: WorldState,
actorId: string,
actionIntent: string,
intent: Intent,
): Promise<ProcessResult> {
// 1. Validate the intent action
const validation = await this.validateIntent(worldState, actorId, actionIntent);
const validation = await this.validateIntent(worldState, intent);
if (!validation.isValid) {
return validation;
}
@@ -46,8 +45,7 @@ export class Architect {
// 2. Generate time delta for the valid action
const timeDelta = await this.timeDeltaGenerator.generate(
worldState,
actorId,
actionIntent,
intent,
);
// 3. Apply the time delta to the world state clock

View File

@@ -1,6 +1,7 @@
import { z } from "zod";
import { WorldState, serializeObjectiveWorldState } from "@omnia/core";
import { ILLMProvider } from "@omnia/llm";
import { Intent } from "@omnia/intent";
export const TimeDeltaSchema = z.object({
minutesToAdvance: z.number().int().nonnegative(),
@@ -12,8 +13,7 @@ export type TimeDelta = z.infer<typeof TimeDeltaSchema>;
export interface IDeltaGenerator<T> {
generate(
worldState: WorldState,
actorId: string,
actionIntent: string,
intent: Intent,
): Promise<T>;
}
@@ -22,8 +22,7 @@ export class TimeDeltaGenerator implements IDeltaGenerator<TimeDelta> {
async generate(
worldState: WorldState,
actorId: string,
actionIntent: string,
intent: Intent,
): Promise<TimeDelta> {
const systemPrompt = `
You are the Time Delta Generator for the World Architect.
@@ -44,8 +43,11 @@ World Details:
${serializeObjectiveWorldState(worldState)}
=== ACTION ===
Actor ID: ${actorId}
Action: "${actionIntent}"
Actor ID: ${intent.actorId}
Type: ${intent.type}
Description: "${intent.description}"
Original Text: "${intent.originalText}"
Target IDs: ${intent.targetIds.join(", ") || "(None)"}
`.trim();
const response = await this.llmProvider.generateStructuredResponse({

View File

@@ -1,6 +1,7 @@
import { z } from "zod";
import { WorldState, serializeObjectiveWorldState } from "@omnia/core";
import { ILLMProvider } from "@omnia/llm";
import { Intent } from "@omnia/intent";
export const ValidationResultSchema = z.object({
isValid: z.boolean(),
@@ -17,14 +18,13 @@ export class LLMValidator {
*/
async validate(
worldState: WorldState,
actorId: string,
actionIntent: string,
intent: Intent,
): Promise<ValidationResult> {
const actor = worldState.getEntity(actorId);
const actor = worldState.getEntity(intent.actorId);
if (!actor) {
return {
isValid: false,
reason: `Actor entity with ID "${actorId}" does not exist in the world state.`,
reason: `Actor entity with ID "${intent.actorId}" does not exist in the world state.`,
};
}
@@ -54,8 +54,11 @@ Entities & Attributes:
${serializedWorld}
=== PROPOSED ACTION ===
Actor ID: ${actorId}
Proposed Action: "${actionIntent}"
Actor ID: ${intent.actorId}
Type: ${intent.type}
Description: "${intent.description}"
Original Text: "${intent.originalText}"
Target IDs: ${intent.targetIds.join(", ") || "(None)"}
Decide if the proposed action is logically valid and physically possible.
`.trim();

View File

@@ -3,6 +3,7 @@ import Database from "better-sqlite3";
import { WorldState, Entity, SQLiteRepository } from "@omnia/core";
import { MockLLMProvider } from "@omnia/llm";
import { Architect } from "@omnia/architect";
import { Intent } from "@omnia/intent";
describe("Architect & LLMValidator Unit Tests (Tier 1)", () => {
test("returns valid response when LLM validates intent as successful", async () => {
@@ -17,11 +18,15 @@ describe("Architect & LLMValidator Unit Tests (Tier 1)", () => {
const llmProvider = new MockLLMProvider([mockResponse]);
const architect = new Architect(llmProvider);
const result = await architect.validateIntent(
world,
"alice",
"open the chest and read the scroll",
);
const intent: Intent = {
type: "action",
originalText: "open the chest and read the scroll",
description: "Open the chest and read the scroll",
actorId: "alice",
targetIds: [],
};
const result = await architect.validateIntent(world, intent);
expect(result.isValid).toBe(true);
expect(result.reason).toBe(
@@ -42,11 +47,15 @@ describe("Architect & LLMValidator Unit Tests (Tier 1)", () => {
const llmProvider = new MockLLMProvider([mockResponse]);
const architect = new Architect(llmProvider);
const result = await architect.validateIntent(
world,
"bob",
"unlock the gate and escape",
);
const intent: Intent = {
type: "action",
originalText: "unlock the gate and escape",
description: "Unlock the gate and escape",
actorId: "bob",
targetIds: [],
};
const result = await architect.validateIntent(world, intent);
expect(result.isValid).toBe(false);
expect(result.reason).toBe("Bob does not have the key to the iron gate.");
@@ -59,11 +68,15 @@ describe("Architect & LLMValidator Unit Tests (Tier 1)", () => {
const llmProvider = new MockLLMProvider([]); // No mock responses because it shouldn't be called
const architect = new Architect(llmProvider);
const result = await architect.validateIntent(
world,
"ghost",
"haunt the mansion",
);
const intent: Intent = {
type: "action",
originalText: "haunt the mansion",
description: "Haunt the mansion",
actorId: "ghost",
targetIds: [],
};
const result = await architect.validateIntent(world, intent);
expect(result.isValid).toBe(false);
expect(result.reason).toContain(
@@ -93,11 +106,15 @@ describe("TimeDeltaGenerator & Architect.processIntent Unit Tests (Tier 1)", ()
const architect = new Architect(llmProvider, repo);
const result = await architect.processIntent(
world,
"alice",
"pick the lock of the wooden chest",
);
const intent: Intent = {
type: "action",
originalText: "pick the lock of the wooden chest",
description: "Pick the lock of the wooden chest",
actorId: "alice",
targetIds: [],
};
const result = await architect.processIntent(world, intent);
// Assert results
expect(result.isValid).toBe(true);
@@ -131,11 +148,15 @@ describe("TimeDeltaGenerator & Architect.processIntent Unit Tests (Tier 1)", ()
const architect = new Architect(llmProvider, repo);
const result = await architect.processIntent(
world,
"bob",
"run away",
);
const intent: Intent = {
type: "action",
originalText: "run away",
description: "Run away",
actorId: "bob",
targetIds: [],
};
const result = await architect.processIntent(world, intent);
expect(result.isValid).toBe(false);
expect(result.reason).toBe("Bob is bound by chains.");

View File

@@ -7,6 +7,7 @@
"include": ["src"],
"references": [
{ "path": "../core" },
{ "path": "../llm" }
{ "path": "../llm" },
{ "path": "../intent" }
]
}