mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-22 03:52:48 +05:30
feat(core): Added isAgent field for entities
This commit is contained in:
@@ -1,23 +1,22 @@
|
||||
import { Entity, WorldState } from "@omnia/core";
|
||||
import { ILLMProvider } from "@omnia/llm";
|
||||
import { BufferEntry, BufferRepository, LedgerRepository } from "@omnia/memory";
|
||||
import { Intent, IntentDecoder, IntentSequence } from "@omnia/intent";
|
||||
import {
|
||||
BufferEntry,
|
||||
BufferRepository,
|
||||
LedgerRepository,
|
||||
} from "@omnia/memory";
|
||||
import {
|
||||
Intent,
|
||||
IntentDecoder,
|
||||
IntentSequence,
|
||||
} from "@omnia/intent";
|
||||
import { ActorPromptBuilder, ActorResponseSchema } from "./actor-prompt-builder.js";
|
||||
ActorPromptBuilder,
|
||||
ActorResponseSchema,
|
||||
} from "./actor-prompt-builder.js";
|
||||
|
||||
/**
|
||||
* Interface to generate narrative prose for an actor.
|
||||
* Allows switching between LLM generators and human CLI inputs.
|
||||
*/
|
||||
export interface IActorProseGenerator {
|
||||
generate(entityId: string, systemPrompt: string, userContext: string): Promise<string>;
|
||||
generate(
|
||||
entityId: string,
|
||||
systemPrompt: string,
|
||||
userContext: string,
|
||||
): Promise<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,7 +25,11 @@ export interface IActorProseGenerator {
|
||||
export class LLMActorProseGenerator implements IActorProseGenerator {
|
||||
constructor(private llmProvider: ILLMProvider) {}
|
||||
|
||||
async generate(entityId: string, systemPrompt: string, userContext: string): Promise<string> {
|
||||
async generate(
|
||||
entityId: string,
|
||||
systemPrompt: string,
|
||||
userContext: string,
|
||||
): Promise<string> {
|
||||
const response = await this.llmProvider.generateStructuredResponse({
|
||||
systemPrompt,
|
||||
userContext,
|
||||
@@ -89,7 +92,11 @@ export class ActorAgent {
|
||||
decoderProv = llmProvider;
|
||||
}
|
||||
|
||||
this.promptBuilder = new ActorPromptBuilder(bufferRepo, ledgerRepo, memoryLimit);
|
||||
this.promptBuilder = new ActorPromptBuilder(
|
||||
bufferRepo,
|
||||
ledgerRepo,
|
||||
memoryLimit,
|
||||
);
|
||||
this.decoder = new IntentDecoder(decoderProv);
|
||||
this.generator = generator ?? new LLMActorProseGenerator(actorProv);
|
||||
this.llmProvider = actorProv;
|
||||
@@ -102,10 +109,13 @@ export class ActorAgent {
|
||||
* 2. Asks the generator (LLM or human) for narrative prose.
|
||||
* 3. Decodes the prose into a structured IntentSequence.
|
||||
*/
|
||||
async act(
|
||||
worldState: WorldState,
|
||||
entity: Entity,
|
||||
): Promise<ActorTurnResult> {
|
||||
async act(worldState: WorldState, entity: Entity): Promise<ActorTurnResult> {
|
||||
if (!entity.isAgent) {
|
||||
throw new Error(
|
||||
`Entity "${entity.id}" is not an agent and cannot use the actor interface.`,
|
||||
);
|
||||
}
|
||||
|
||||
const { systemPrompt, userContext } = this.promptBuilder.build(
|
||||
worldState,
|
||||
entity,
|
||||
|
||||
19
packages/actor/tests/actor.test.ts
Normal file
19
packages/actor/tests/actor.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { WorldState, Entity } from "@omnia/core";
|
||||
import { ActorAgent } from "../src/actor.js";
|
||||
import { MockLLMProvider } from "@omnia/llm";
|
||||
|
||||
describe("ActorAgent Unit Tests", () => {
|
||||
it("should throw an error if trying to act with a non-agent entity", async () => {
|
||||
const world = new WorldState("world-123");
|
||||
const nonAgentEntity = new Entity("stone", null, false); // isAgent = false
|
||||
world.addEntity(nonAgentEntity);
|
||||
|
||||
const mockLlm = new MockLLMProvider([]);
|
||||
const actor = new ActorAgent(mockLlm);
|
||||
|
||||
await expect(actor.act(world, nonAgentEntity)).rejects.toThrow(
|
||||
'Entity "stone" is not an agent and cannot use the actor interface.',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3,9 +3,11 @@ import { AttributableObject } from "./attribute.js";
|
||||
export class Entity extends AttributableObject {
|
||||
locationId: string | null = null;
|
||||
readonly aliases: Map<string, string> = new Map();
|
||||
isAgent: boolean = true;
|
||||
|
||||
constructor(id?: string, locationId?: string | null) {
|
||||
constructor(id?: string, locationId?: string | null, isAgent?: boolean) {
|
||||
super(id);
|
||||
this.locationId = locationId ?? null;
|
||||
this.isAgent = isAgent ?? true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,13 @@ export class SQLiteRepository {
|
||||
} catch {
|
||||
// Column already exists, ignore error
|
||||
}
|
||||
|
||||
// Safely add is_agent column if it does not exist in an existing database
|
||||
try {
|
||||
this.db.exec("ALTER TABLE objects ADD COLUMN is_agent INTEGER;");
|
||||
} catch {
|
||||
// Column already exists, ignore error
|
||||
}
|
||||
}
|
||||
|
||||
save(obj: AttributableObject, type: string, worldId?: string): void {
|
||||
@@ -85,15 +92,20 @@ export class SQLiteRepository {
|
||||
let locationId: string | null = null;
|
||||
let aliasesJson: string | null = null;
|
||||
let connectionsJson: string | null = null;
|
||||
let isAgent: number | null = null;
|
||||
|
||||
if (obj instanceof Entity) {
|
||||
locationId = obj.locationId;
|
||||
aliasesJson = JSON.stringify(Array.from(obj.aliases.entries()));
|
||||
isAgent = obj.isAgent ? 1 : 0;
|
||||
}
|
||||
|
||||
// Check if it's a location (using duck typing to avoid circular import of Location)
|
||||
if (type === "location") {
|
||||
const loc = obj as { parentId?: string | null; connections?: unknown[] };
|
||||
const loc = obj as {
|
||||
parentId?: string | null;
|
||||
connections?: unknown[];
|
||||
};
|
||||
locationId = loc.parentId ?? null;
|
||||
if (loc.connections) {
|
||||
connectionsJson = JSON.stringify(loc.connections);
|
||||
@@ -104,18 +116,28 @@ export class SQLiteRepository {
|
||||
this.db
|
||||
.prepare(
|
||||
`
|
||||
INSERT INTO objects (id, type, world_id, clock_iso, location_id, aliases_json, connections_json)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO objects (id, type, world_id, clock_iso, location_id, aliases_json, connections_json, is_agent)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
type = excluded.type,
|
||||
world_id = excluded.world_id,
|
||||
clock_iso = excluded.clock_iso,
|
||||
location_id = excluded.location_id,
|
||||
aliases_json = excluded.aliases_json,
|
||||
connections_json = excluded.connections_json
|
||||
connections_json = excluded.connections_json,
|
||||
is_agent = excluded.is_agent
|
||||
`,
|
||||
)
|
||||
.run(obj.id, type, worldId || null, clockIso, locationId, aliasesJson, connectionsJson);
|
||||
.run(
|
||||
obj.id,
|
||||
type,
|
||||
worldId || null,
|
||||
clockIso,
|
||||
locationId,
|
||||
aliasesJson,
|
||||
connectionsJson,
|
||||
isAgent,
|
||||
);
|
||||
|
||||
// Get current attributes from db to delete the ones that are no longer present
|
||||
const existingAttrs = this.db
|
||||
@@ -208,16 +230,27 @@ export class SQLiteRepository {
|
||||
const objRow = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT type, location_id, aliases_json FROM objects WHERE id = ?
|
||||
SELECT type, location_id, aliases_json, is_agent FROM objects WHERE id = ?
|
||||
`,
|
||||
)
|
||||
.get(id) as { type: string; location_id: string | null; aliases_json: string | null } | undefined;
|
||||
.get(id) as
|
||||
| {
|
||||
type: string;
|
||||
location_id: string | null;
|
||||
aliases_json: string | null;
|
||||
is_agent: number | null;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
if (!objRow || objRow.type !== "entity") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const entity = new Entity(id, objRow.location_id);
|
||||
const entity = new Entity(
|
||||
id,
|
||||
objRow.location_id,
|
||||
objRow.is_agent !== null ? objRow.is_agent === 1 : true,
|
||||
);
|
||||
if (objRow.aliases_json) {
|
||||
const entries = JSON.parse(objRow.aliases_json) as [string, string][];
|
||||
for (const [k, v] of entries) {
|
||||
@@ -238,7 +271,13 @@ export class SQLiteRepository {
|
||||
SELECT type, location_id, connections_json FROM objects WHERE id = ?
|
||||
`,
|
||||
)
|
||||
.get(id) as { type: string; location_id: string | null; connections_json: string | null } | undefined;
|
||||
.get(id) as
|
||||
| {
|
||||
type: string;
|
||||
location_id: string | null;
|
||||
connections_json: string | null;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
if (!objRow || objRow.type !== "location") {
|
||||
return null;
|
||||
@@ -246,7 +285,9 @@ export class SQLiteRepository {
|
||||
|
||||
const location = factory(id, objRow.location_id);
|
||||
if (objRow.connections_json) {
|
||||
(location as { connections?: unknown[] }).connections = JSON.parse(objRow.connections_json);
|
||||
(location as { connections?: unknown[] }).connections = JSON.parse(
|
||||
objRow.connections_json,
|
||||
);
|
||||
}
|
||||
this.reconstituteAttributes(location);
|
||||
return location;
|
||||
@@ -262,13 +303,19 @@ export class SQLiteRepository {
|
||||
SELECT id, location_id, connections_json FROM objects WHERE type = 'location' AND world_id = ?
|
||||
`,
|
||||
)
|
||||
.all(worldId) as { id: string; location_id: string | null; connections_json: string | null }[];
|
||||
.all(worldId) as {
|
||||
id: string;
|
||||
location_id: string | null;
|
||||
connections_json: string | null;
|
||||
}[];
|
||||
|
||||
const locations: T[] = [];
|
||||
for (const row of rows) {
|
||||
const loc = factory(row.id, row.location_id);
|
||||
if (row.connections_json) {
|
||||
(loc as { connections?: unknown[] }).connections = JSON.parse(row.connections_json);
|
||||
(loc as { connections?: unknown[] }).connections = JSON.parse(
|
||||
row.connections_json,
|
||||
);
|
||||
}
|
||||
this.reconstituteAttributes(loc);
|
||||
locations.push(loc);
|
||||
@@ -300,13 +347,19 @@ export class SQLiteRepository {
|
||||
SELECT id, location_id, connections_json FROM objects WHERE type = 'location' AND world_id = ?
|
||||
`,
|
||||
)
|
||||
.all(id) as { id: string; location_id: string | null; connections_json: string | null }[];
|
||||
.all(id) as {
|
||||
id: string;
|
||||
location_id: string | null;
|
||||
connections_json: string | null;
|
||||
}[];
|
||||
|
||||
for (const row of locationRows) {
|
||||
const loc = new GenericObject(row.id);
|
||||
(loc as { parentId?: string | null }).parentId = row.location_id;
|
||||
if (row.connections_json) {
|
||||
(loc as { connections?: unknown[] }).connections = JSON.parse(row.connections_json);
|
||||
(loc as { connections?: unknown[] }).connections = JSON.parse(
|
||||
row.connections_json,
|
||||
);
|
||||
}
|
||||
this.reconstituteAttributes(loc);
|
||||
worldState.addLocation(loc);
|
||||
@@ -316,13 +369,22 @@ export class SQLiteRepository {
|
||||
const entityRows = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT id, location_id, aliases_json FROM objects WHERE type = 'entity' AND world_id = ?
|
||||
SELECT id, location_id, aliases_json, is_agent FROM objects WHERE type = 'entity' AND world_id = ?
|
||||
`,
|
||||
)
|
||||
.all(id) as { id: string; location_id: string | null; aliases_json: string | null }[];
|
||||
.all(id) as {
|
||||
id: string;
|
||||
location_id: string | null;
|
||||
aliases_json: string | null;
|
||||
is_agent: number | null;
|
||||
}[];
|
||||
|
||||
for (const row of entityRows) {
|
||||
const entity = new Entity(row.id, row.location_id);
|
||||
const entity = new Entity(
|
||||
row.id,
|
||||
row.location_id,
|
||||
row.is_agent !== null ? row.is_agent === 1 : true,
|
||||
);
|
||||
if (row.aliases_json) {
|
||||
const entries = JSON.parse(row.aliases_json) as [string, string][];
|
||||
for (const [k, v] of entries) {
|
||||
@@ -340,14 +402,22 @@ export class SQLiteRepository {
|
||||
const rows = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT id, aliases_json FROM objects WHERE type = 'entity'
|
||||
SELECT id, aliases_json, is_agent FROM objects WHERE type = 'entity'
|
||||
`,
|
||||
)
|
||||
.all() as { id: string; aliases_json: string | null }[];
|
||||
.all() as {
|
||||
id: string;
|
||||
aliases_json: string | null;
|
||||
is_agent: number | null;
|
||||
}[];
|
||||
|
||||
const entities: Entity[] = [];
|
||||
for (const row of rows) {
|
||||
const entity = new Entity(row.id);
|
||||
const entity = new Entity(
|
||||
row.id,
|
||||
null,
|
||||
row.is_agent !== null ? row.is_agent === 1 : true,
|
||||
);
|
||||
if (row.aliases_json) {
|
||||
const entries = JSON.parse(row.aliases_json) as [string, string][];
|
||||
for (const [k, v] of entries) {
|
||||
|
||||
@@ -61,16 +61,21 @@ describe("Attribute & AttributableObject Unit Tests (Tier 1)", () => {
|
||||
test("AttributableObject visibility filtering", () => {
|
||||
const actor = new MockAttributable("actor");
|
||||
actor.addAttribute("eyes", "blue", AttributeVisibility.PUBLIC);
|
||||
actor.addAttribute("secret", "42", AttributeVisibility.PRIVATE, new Set(["friend"]));
|
||||
actor.addAttribute(
|
||||
"secret",
|
||||
"42",
|
||||
AttributeVisibility.PRIVATE,
|
||||
new Set(["friend"]),
|
||||
);
|
||||
|
||||
// Public viewer should only see public attributes
|
||||
const publicAttrs = actor.getVisibleAttributesFor("stranger");
|
||||
expect(publicAttrs.map(a => a.name)).toEqual(["eyes"]);
|
||||
expect(publicAttrs.map((a) => a.name)).toEqual(["eyes"]);
|
||||
|
||||
// Authorized viewer should see both
|
||||
const privateAttrs = actor.getVisibleAttributesFor("friend");
|
||||
expect(privateAttrs.map(a => a.name)).toContain("eyes");
|
||||
expect(privateAttrs.map(a => a.name)).toContain("secret");
|
||||
expect(privateAttrs.map((a) => a.name)).toContain("eyes");
|
||||
expect(privateAttrs.map((a) => a.name)).toContain("secret");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -131,7 +136,12 @@ describe("SQLiteRepository Unit Tests (Tier 1)", () => {
|
||||
const alice = new Entity("alice", "location-a");
|
||||
alice.addAttribute("name", "Alice Smith", AttributeVisibility.PUBLIC);
|
||||
// Secret attribute visible only to 'bob'
|
||||
alice.addAttribute("diaries", "Private thoughts", AttributeVisibility.PRIVATE, new Set(["bob"]));
|
||||
alice.addAttribute(
|
||||
"diaries",
|
||||
"Private thoughts",
|
||||
AttributeVisibility.PRIVATE,
|
||||
new Set(["bob"]),
|
||||
);
|
||||
world.addEntity(alice);
|
||||
|
||||
const bob = new Entity("bob");
|
||||
@@ -161,7 +171,9 @@ describe("SQLiteRepository Unit Tests (Tier 1)", () => {
|
||||
expect(loadedAlice!.locationId).toBe("location-a");
|
||||
expect(loadedBob!.locationId).toBeNull();
|
||||
expect(loadedAlice!.attributes.get("name")?.getValue()).toBe("Alice Smith");
|
||||
expect(loadedAlice!.attributes.get("name")?.visibility).toBe(AttributeVisibility.PUBLIC);
|
||||
expect(loadedAlice!.attributes.get("name")?.visibility).toBe(
|
||||
AttributeVisibility.PUBLIC,
|
||||
);
|
||||
|
||||
const diaryAttr = loadedAlice!.attributes.get("diaries")!;
|
||||
expect(diaryAttr.getValue()).toBe("Private thoughts");
|
||||
@@ -191,17 +203,46 @@ describe("SQLiteRepository Unit Tests (Tier 1)", () => {
|
||||
|
||||
db.close();
|
||||
});
|
||||
|
||||
test("Save and load entity isAgent property", () => {
|
||||
const db = new Database(":memory:");
|
||||
const repo = new SQLiteRepository(db);
|
||||
|
||||
const world = new WorldState("world-xyz");
|
||||
const alice = new Entity("alice", null, false);
|
||||
const bob = new Entity("bob", null, true);
|
||||
world.addEntity(alice);
|
||||
world.addEntity(bob);
|
||||
|
||||
repo.saveWorldState(world);
|
||||
|
||||
const loadedWorld = repo.loadWorldState("world-xyz")!;
|
||||
const loadedAlice = loadedWorld.getEntity("alice")!;
|
||||
const loadedBob = loadedWorld.getEntity("bob")!;
|
||||
|
||||
expect(loadedAlice.isAgent).toBe(false);
|
||||
expect(loadedBob.isAgent).toBe(true);
|
||||
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
|
||||
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"]));
|
||||
obj.addAttribute(
|
||||
"secret",
|
||||
"key-123",
|
||||
AttributeVisibility.PRIVATE,
|
||||
new Set(["alice"]),
|
||||
);
|
||||
|
||||
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)");
|
||||
expect(result).toContain(
|
||||
"* secret: key-123 (Visibility: PRIVATE) (Visible to: alice)",
|
||||
);
|
||||
});
|
||||
|
||||
test("serializeObjectiveWorldState utility", () => {
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { WorldState, Entity, SQLiteRepository, AttributeVisibility } from "@omnia/core";
|
||||
import {
|
||||
WorldState,
|
||||
Entity,
|
||||
SQLiteRepository,
|
||||
AttributeVisibility,
|
||||
} from "@omnia/core";
|
||||
import { Location } from "@omnia/spatial";
|
||||
import { BufferRepository } from "@omnia/memory";
|
||||
import { ScenarioSchema, Scenario } from "./schema.js";
|
||||
@@ -17,24 +22,40 @@ export class ScenarioLoader {
|
||||
* @param targetWorldId The unique ID for the running instance to create (e.g. UUID).
|
||||
* Allows launching multiple active runs from one scenario.
|
||||
*/
|
||||
async initializeWorld(scenarioJson: unknown, targetWorldId: string): Promise<string> {
|
||||
async initializeWorld(
|
||||
scenarioJson: unknown,
|
||||
targetWorldId: string,
|
||||
): Promise<string> {
|
||||
// 1. Validate scenario template schema
|
||||
const scenario: Scenario = ScenarioSchema.parse(scenarioJson);
|
||||
|
||||
// 2. Instantiate running WorldState using the target instance ID
|
||||
const world = new WorldState(targetWorldId, new Date(scenario.startTime));
|
||||
|
||||
|
||||
// Seed world-level attributes as system-only (private, empty ACL)
|
||||
world.addAttribute("name", scenario.name, AttributeVisibility.PRIVATE, new Set());
|
||||
world.addAttribute("description", scenario.description, AttributeVisibility.PRIVATE, new Set());
|
||||
|
||||
world.addAttribute(
|
||||
"name",
|
||||
scenario.name,
|
||||
AttributeVisibility.PRIVATE,
|
||||
new Set(),
|
||||
);
|
||||
world.addAttribute(
|
||||
"description",
|
||||
scenario.description,
|
||||
AttributeVisibility.PRIVATE,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
if (scenario.world?.attributes) {
|
||||
for (const attr of scenario.world.attributes) {
|
||||
const vis = attr.visibility === "PUBLIC" ? AttributeVisibility.PUBLIC : AttributeVisibility.PRIVATE;
|
||||
const vis =
|
||||
attr.visibility === "PUBLIC"
|
||||
? AttributeVisibility.PUBLIC
|
||||
: AttributeVisibility.PRIVATE;
|
||||
world.addAttribute(
|
||||
attr.name,
|
||||
attr.value,
|
||||
vis,
|
||||
attr.name,
|
||||
attr.value,
|
||||
vis,
|
||||
attr.allowedEntities ? new Set(attr.allowedEntities) : null,
|
||||
);
|
||||
}
|
||||
@@ -47,10 +68,13 @@ export class ScenarioLoader {
|
||||
if (scenario.locations) {
|
||||
for (const locData of scenario.locations) {
|
||||
const location = new Location(locData.id, locData.parentId ?? null);
|
||||
|
||||
|
||||
if (locData.attributes) {
|
||||
for (const attr of locData.attributes) {
|
||||
const vis = attr.visibility === "PUBLIC" ? AttributeVisibility.PUBLIC : AttributeVisibility.PRIVATE;
|
||||
const vis =
|
||||
attr.visibility === "PUBLIC"
|
||||
? AttributeVisibility.PUBLIC
|
||||
: AttributeVisibility.PRIVATE;
|
||||
location.addAttribute(
|
||||
attr.name,
|
||||
attr.value,
|
||||
@@ -80,12 +104,19 @@ export class ScenarioLoader {
|
||||
// 5. Instantiate and Persist Entities (with Aliases & Memory Buffers)
|
||||
if (scenario.entities) {
|
||||
for (const entData of scenario.entities) {
|
||||
const entity = new Entity(entData.id, entData.locationId ?? null);
|
||||
|
||||
const entity = new Entity(
|
||||
entData.id,
|
||||
entData.locationId ?? null,
|
||||
entData.isAgent,
|
||||
);
|
||||
|
||||
// Load attributes
|
||||
if (entData.attributes) {
|
||||
for (const attr of entData.attributes) {
|
||||
const vis = attr.visibility === "PUBLIC" ? AttributeVisibility.PUBLIC : AttributeVisibility.PRIVATE;
|
||||
const vis =
|
||||
attr.visibility === "PUBLIC"
|
||||
? AttributeVisibility.PUBLIC
|
||||
: AttributeVisibility.PRIVATE;
|
||||
entity.addAttribute(
|
||||
attr.name,
|
||||
attr.value,
|
||||
|
||||
@@ -38,10 +38,12 @@ export const ScenarioMemoryEntrySchema = z.object({
|
||||
targetIds: z.array(z.string()),
|
||||
modifiers: z.array(z.string()).optional(),
|
||||
}),
|
||||
outcome: z.object({
|
||||
isValid: z.boolean(),
|
||||
reason: z.string(),
|
||||
}).optional(),
|
||||
outcome: z
|
||||
.object({
|
||||
isValid: z.boolean(),
|
||||
reason: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export const ScenarioEntitySchema = z.object({
|
||||
@@ -50,6 +52,7 @@ export const ScenarioEntitySchema = z.object({
|
||||
attributes: z.array(ScenarioAttributeSchema).optional(),
|
||||
aliases: z.record(z.string(), z.string()).optional(), // targetId -> subjective descriptor
|
||||
initialMemories: z.array(ScenarioMemoryEntrySchema).optional(),
|
||||
isAgent: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export const ScenarioSchema = z.object({
|
||||
@@ -57,9 +60,11 @@ export const ScenarioSchema = z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
startTime: z.string(), // ISO string
|
||||
world: z.object({
|
||||
attributes: z.array(ScenarioAttributeSchema).optional(),
|
||||
}).optional(),
|
||||
world: z
|
||||
.object({
|
||||
attributes: z.array(ScenarioAttributeSchema).optional(),
|
||||
})
|
||||
.optional(),
|
||||
locations: z.array(ScenarioLocationSchema).optional(),
|
||||
entities: z.array(ScenarioEntitySchema).optional(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user