UNPKG

@radcliffetech/symbolos-core

Version:

Core symbolic simulation and execution engine for Symbolos

171 lines (170 loc) 6.37 kB
import { createSymbolicObject } from "../lib/object-factory"; import crypto from "node:crypto"; function createPipelineRunObject(pipelineId, runId, tick, stepCount, forkedFromRunId) { return createSymbolicObject("PipelineRun", { id: `pipeline-run-${crypto.randomUUID()}`, label: forkedFromRunId ? `Forked Run from ${forkedFromRunId}` : "Pipeline Run", pipelineId, runId, tickCount: tick, stepCount, status: "completed", ...(forkedFromRunId && { forkedFromRunId }), }); } function addToArtifacts(context, obj) { if (!obj?.id) return; context._artifactsById.set(obj.id, obj); } function flattenSymbolicObjects(obj) { const results = []; const seen = new Set(); const stack = [obj]; while (stack.length) { const current = stack.pop(); if (!current || typeof current !== "object") continue; if (current.id && current.type && !seen.has(current.id)) { seen.add(current.id); results.push(current); } for (const val of Object.values(current)) { stack.push(val); } } return results; } const recordSymbolicAction = async ({ entry, transformationId, context, instrumentId, purpose, tick, outputObject, }) => { const action = createSymbolicObject("SymbolicAction", { id: `action-${crypto.randomUUID()}`, label: `${entry.type} Action`, transformationId, actorId: outputObject?.rootId ?? context.subjectiveFrame?.id ?? entry.rootId ?? "unknown-actor", contextId: context.contextualFrame?.id ?? "unknown-context", instrumentId: instrumentId ?? context.instrumentId ?? "default-instrument", // Use provided instrumentId or default purpose: purpose ?? context.purpose ?? "default-purpose", // Use provided purpose or default inputId: outputObject?.rootId ?? entry.rootId ?? entry.id, outputId: outputObject?.id ?? entry.id, rootId: "action-root", // all actions are linked to a root action status: "completed", tick, }); addToArtifacts(context, action); }; export function createWorldInstanceFromFrame({ frame, pipelineId, runId, }) { const artifacts = new Map(); for (const obj of frame.members) { artifacts.set(obj.id, obj); } return { id: frame.id || `world-${frame.tick}`, tick: frame.tick ?? 0, step: frame.step ?? 0, runId, pipelineId, artifacts, context: {}, }; } export function createWorld(worldId, runId) { const id = worldId || "world-" + crypto.randomUUID(); return { id, tick: 0, step: 0, runId: runId || new Date().toISOString().replace(/[:.]/g, "-"), pipelineId: worldId || "world-" + crypto.randomUUID(), artifacts: new Map(), context: {}, }; } // Dedicated Gen3 pipeline runner for WorldInstance-only functors export async function runWorldPipeline({ world, steps, pipelineArgs, frameHandler = () => { }, }) { if (!world.context) world.context = {}; if (!world.artifacts) world.artifacts = new Map(); world.context._artifactsById = world.artifacts; if (!pipelineArgs) { pipelineArgs = createSymbolicObject("PipelineArgs", { id: "pipeline-args-" + crypto.randomUUID(), params: {}, }); } world.context.pipelineArgs = pipelineArgs; world.context.pipelineId = world.pipelineId; world.context.runId = world.runId; for (const [index, step] of Object.entries(steps)) { if (step.tickAdvance !== false) { world.tick += 1; } const result = await step.functor.apply({ world }); if (!result.world.context) result.world.context = {}; if (!result.world.artifacts) result.world.artifacts = new Map(); result.world.context._artifactsById = result.world.artifacts; if (!result.world.context._batchedEntries) result.world.context._batchedEntries = []; const outputObject = result.outputObject ?? null; const outputList = result.output ?? (outputObject ? [outputObject] : []); for (const entry of outputList) { result.world.context._batchedEntries.push({ entry, transformationId: step.id, instrumentId: step.functor.id, purpose: step.purpose, tick: world.tick, stepPrefix: String(Number(index) + 1).padStart(3, "0"), outputObject, }); } result.world.context._lastOutputObject = outputObject; await frameHandler(world); } for (const batched of world.context._batchedEntries ?? []) { console.log(`[symbolos] 📝 Recording action: ${batched.entry.type} at tick ${world.tick} with purpose "${batched.purpose}" and transformationId "${batched.transformationId}"`); await recordSymbolicAction({ entry: batched.entry, transformationId: batched.transformationId, instrumentId: batched.instrumentId, purpose: batched.purpose, context: world.context, stepPrefix: batched.stepPrefix, tick: batched.tick, outputObject: batched.outputObject, }); } world.context._batchedEntries = []; const pipelineRun = createPipelineRunObject(world.pipelineId, world.runId, world.tick, steps.length, world.context.forkedFromRunId); addToArtifacts(world.context, pipelineRun); return world; } export function forkWorld(sourceWorld, newParams) { const artifacts = new Map(); for (const [id, obj] of sourceWorld.artifacts.entries()) { artifacts.set(id, obj); } const newId = "forked-" + crypto.randomUUID(); return { id: newId, tick: sourceWorld.tick, step: sourceWorld.step, runId: newId, pipelineId: sourceWorld.pipelineId, artifacts, context: { _artifactsById: artifacts, ...sourceWorld.context, forkedFromRunId: sourceWorld.runId, ...(newParams ? { pipelineArgs: { params: newParams } } : {}), }, }; }