feat: Phase 3 — engine read path + runtime context builder

- Add buildThreadContext(headHash, cas) to workflow-runtime
- Expand extract phase to return { meta, contentPayload, refs[] }
- Add parseCasThreadNode() to workflow-cas for node type parsing
- Update createWorkflow to write ContentMerkleNode with artifact refs
- Tests: 4 pass (build-context + extract-refs)
- Biome format pass on all files

Refs #155, closes #158

小橘 <xiaoju@shazhou.work>
This commit is contained in:
2026-05-09 08:00:24 +00:00
parent 81c582ae0e
commit 26cf51366f
51 changed files with 701 additions and 234 deletions
+3
View File
@@ -3,7 +3,9 @@
export type {
ContentMerkleNode,
StartNode,
StartNodePayload,
StateNode,
StateNodePayload,
} from "./cas-types.js";
export type {
@@ -14,6 +16,7 @@ export type {
CasStore,
ExtractContext,
ExtractFn,
ExtractResult,
LlmProvider,
Moderator,
ModeratorContext,
+2 -2
View File
@@ -1,9 +1,9 @@
import type { Result } from "./types.js";
export function ok<T>(value: T): Result<T, never> {
return { ok: true, value };
return { ok: true, value };
}
export function err<E>(error: E): Result<never, E> {
return { ok: false, error };
return { ok: false, error };
}
+75 -68
View File
@@ -12,10 +12,10 @@ export type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error:
// ── CAS ────────────────────────────────────────────────────────────
export type CasStore = {
put(content: string): Promise<string>;
get(hash: string): Promise<string | null>;
delete(hash: string): Promise<void>;
list(): Promise<string[]>;
put(content: string): Promise<string>;
get(hash: string): Promise<string | null>;
delete(hash: string): Promise<void>;
list(): Promise<string[]>;
};
// ── Workflow Descriptor ────────────────────────────────────────────
@@ -23,13 +23,13 @@ export type CasStore = {
export type WorkflowRoleSchema = Record<string, unknown>;
export type WorkflowRoleDescriptor = {
description: string;
schema: WorkflowRoleSchema;
description: string;
schema: WorkflowRoleSchema;
};
export type WorkflowDescriptor = {
description: string;
roles: Record<string, WorkflowRoleDescriptor>;
description: string;
roles: Record<string, WorkflowRoleDescriptor>;
};
// ── Role & Thread ──────────────────────────────────────────────────
@@ -37,131 +37,138 @@ export type WorkflowDescriptor = {
export type RoleMeta = Record<string, Record<string, unknown>>;
export type RoleOutput = {
role: string;
contentHash: string;
meta: Record<string, unknown>;
refs: string[];
role: string;
contentHash: string;
meta: Record<string, unknown>;
refs: string[];
};
export type StartStep = {
role: typeof START;
content: string;
meta: { maxRounds: number };
timestamp: number;
role: typeof START;
content: string;
meta: { maxRounds: number };
timestamp: number;
};
export type RoleStep<M extends RoleMeta> = {
[K in keyof M & string]: {
role: K;
meta: M[K];
contentHash: string;
refs: string[];
timestamp: number;
};
[K in keyof M & string]: {
role: K;
meta: M[K];
contentHash: string;
refs: string[];
timestamp: number;
};
}[keyof M & string];
export type ThreadContext<M extends RoleMeta = RoleMeta> = {
threadId: string;
depth: number;
start: StartStep;
steps: RoleStep<M>[];
threadId: string;
depth: number;
start: StartStep;
steps: RoleStep<M>[];
};
export type ModeratorContext<M extends RoleMeta = RoleMeta> = ThreadContext<M>;
export type AgentContext<M extends RoleMeta = RoleMeta> = ModeratorContext<M> & {
currentRole: {
name: string;
systemPrompt: string;
};
currentRole: {
name: string;
systemPrompt: string;
};
};
export type ExtractContext<M extends RoleMeta = RoleMeta> = AgentContext<M> & {
agentContent: string;
agentContent: string;
};
// ── Workflow Completion ────────────────────────────────────────────
export type WorkflowCompletion = {
returnCode: number;
summary: string;
returnCode: number;
summary: string;
};
export type WorkflowResult = WorkflowCompletion & {
rootHash: string;
rootHash: string;
};
// ── LLM Provider ───────────────────────────────────────────────────
export type LlmProvider = {
baseUrl: string;
apiKey: string;
model: string;
baseUrl: string;
apiKey: string;
model: string;
};
export type ProviderConfig = {
baseUrl: string;
apiKey: string;
baseUrl: string;
apiKey: string;
};
export type ResolvedModel = {
baseUrl: string;
apiKey: string;
model: string;
baseUrl: string;
apiKey: string;
model: string;
};
export type WorkflowConfig = {
maxDepth: number;
supervisorInterval: number;
providers: Record<string, ProviderConfig>;
models: Record<string, string>;
maxDepth: number;
supervisorInterval: number;
providers: Record<string, ProviderConfig>;
models: Record<string, string>;
};
// ── Functions ──────────────────────────────────────────────────────
/** Structured output of the extract phase (RFC v3 content Merkle + artifact refs). */
export type ExtractResult<T extends Record<string, unknown>> = {
meta: T;
contentPayload: string;
refs: string[];
};
export type ExtractFn = <T extends Record<string, unknown>>(
schema: z.ZodType<T>,
prompt: string,
ctx: ExtractContext,
) => Promise<T>;
schema: z.ZodType<T>,
prompt: string,
ctx: ExtractContext,
) => Promise<ExtractResult<T>>;
export type AgentFn = (ctx: AgentContext) => Promise<string>;
export type AgentBinding = {
agent: AgentFn;
overrides: Partial<Record<string, AgentFn>> | null;
agent: AgentFn;
overrides: Partial<Record<string, AgentFn>> | null;
};
// ── Workflow Runtime & Definition ──────────────────────────────────
export type WorkflowRuntime = {
cas: CasStore;
extract: ExtractFn;
cas: CasStore;
extract: ExtractFn;
};
export type WorkflowFn = (
thread: ThreadContext,
runtime: WorkflowRuntime,
thread: ThreadContext,
runtime: WorkflowRuntime,
) => AsyncGenerator<RoleOutput, WorkflowCompletion>;
export type RoleDefinition<Meta extends Record<string, unknown>> = {
description: string;
systemPrompt: string;
extractPrompt: string;
schema: z.ZodType<Meta>;
extractRefs: ((meta: Meta) => string[]) | null;
description: string;
systemPrompt: string;
extractPrompt: string;
schema: z.ZodType<Meta>;
extractRefs: ((meta: Meta) => string[]) | null;
};
export type Moderator<M extends RoleMeta> = (
ctx: ModeratorContext<M>,
ctx: ModeratorContext<M>,
) => (keyof M & string) | typeof END;
export type WorkflowDefinition<M extends RoleMeta> = {
description: string;
roles: { [K in keyof M & string]: RoleDefinition<M[K]> };
moderator: Moderator<M>;
description: string;
roles: { [K in keyof M & string]: RoleDefinition<M[K]> };
moderator: Moderator<M>;
};
export type AdvanceOutcome<M extends RoleMeta> =
| { kind: "complete"; completion: WorkflowCompletion }
| { kind: "yield"; output: RoleOutput; step: RoleStep<M> };
| { kind: "complete"; completion: WorkflowCompletion }
| { kind: "yield"; output: RoleOutput; step: RoleStep<M> };