Skip to content
12 min read · 2,398 words

@nhtio/adk/batteries/orchestration/types

The orchestration battery's shared type contracts — the normative source for every type more than one part of the battery touches.

Remarks

A type belongs here when two or more modules read or write it. Anything with no dependents — a cell's internal AST, the in-memory store's private index, a renderer's line-wrapping helper — is deliberately left to its implementation rather than fixed here.

Two conventions in this file are load-bearing and easy to undo by accident. Discrimination is by CLASS, not by a kind field: NodeRef and ParamRef are registered encoder classes whose is* guards are instanceof checks, because a plain record can wear {kind: 'nodeRef'} and a resolver keying on that would silently rewrite a literal. And EncodableValue is a deliberate SUBSET of the encoder's own Encodable — it omits Function, Error and consumer-defined custom classes, so a staged argument cannot carry a closure that serialises by source text or a class the battery cannot register on the consumer's behalf.

Interfaces

| Interface | Description | | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | --------------- | ---------------------------------------------------- | | ApprovalRecord | An operator's decision, bound to exactly the content they were shown. The digest is lossless, so two plans that differ in any staged value cannot share one — which is what stops an approval authorising a plan that was never rendered. | | ArtifactClassLike | An artifact CLASS, structurally. Carries only its OWN descriptors — the base seven are on an ancestor, per core's shadowing rule — so the battery must walk the chain rather than read this one array. effectiveToolMethods is the only place that walk happens. | | ArtifactMethodDescriptor | Structural, per CONTRIBUTING §13 — the battery does not import the core classes. Note argsSchema: an earlier draft omitted it while claiming freeze validates a step's args against it, so the type could not support the check it was cited for. serialise likewise, since the transform runtime needs the descriptor's own formatter rather than a guess. | | AuthorityClaim | One unit of authority a call node claims. Approval binds the canonicalised union of every claim in the plan, so what an operator approved and what may run are the same set. | | BranchId | A path identity: the route from entry to a frame, kept as the route itself. | | BranchNodeDefinition | A two-way branch: the predicate's verdict picks the match or no_match handle. | | CallNodeDefinition | A staged tool invocation — the node kind the whole staging environment exists to gate. | | ClonedFrom | A clone's lineage. | | EntryNodeDefinition | The one place external input enters the graph. | | FrameRef | Identifies one execution of one node: the node, and the path that reached it. kind rides along so the fold can classify without the graph (only a call frame can be indeterminate). viaEdgeId is the edge that produced this frame — undefined for the entry frame, which no edge produced. branchId is the path identity and is what makes a frame unique. | | FreezeInputs | What freeze validation needs that is NOT derivable from the plan itself. | | InstantiatedFrom | Instantiation lineage, for the renderer and for audit. Not a taint mechanism — see below. | | InvocableTools | The Tier-C boundary: which of the consumer's tools a staged call may invoke, and what each returns. Supplied by the consumer, because they are the only party that knows. | | JoinNodeDefinition | A join is a DIAMOND join only: it closes a fan-out that a single ancestor opened. The restriction is what makes joins implementable, and it is stated over the DIVERGENCE POINT, not over the immediate predecessors. | | JoinState | A join's partial barrier. | | MediaLike | A media value, structurally. Refused at freeze for a node whose output declares fields. | | NodeOutput | What a node produced on one path. Always an ARRAY, even for a single result. | | Orchestration | The public surface. Each member is specified in its own section; this is the assembly. | | OutputItem | One unit of a node's output. Items, after n8n — a node may emit several. The field is named json for continuity with that lineage, but its values are EncodableValue, so a tool may legitimately return a Date, a RegExp, a Map — the same domain a staged argument may hold, which is what lets an output feed an argument without a lossy hop. It is NOT restricted to JSON-representable values, and an earlier draft's "JSON-shaped only" gloss was wrong. | | PendingFrame | A live frame: its identity, its branch-local value table, and its branch-local artifact table. artifacts is cloned on fan-out exactly like outputs and is what a transform reads its source instance from; it persists as handles, so a snapshot carries pointers, never bytes. | | PhaseEntry | One phase's entry in an outline. Carries exact surface forms, never paraphrase. | | PlanBounds | The resource envelope. Plan CONTENT, so it is digested and an operator approves it. | | PlanDiff | Structural delta between two folded states — what a diff UI renders. | | PlanEdge | A directed edge. Its handle decides when it fires; the graph alone orders execution. | | PlanIssue | One finding from validation. Model-addressed, because a model is what usually acts on it. | | PlanOutline | ONE flat level. Entries carry exact surface forms, not paraphrase. | | PlanSlice | A slice. Self-locating: it carries enough neighbourhood to keep linking without re-reading. | | PlanSummary | A plan's headline, for listings. Carries state, which RawPlanView deliberately does not. | | PlanTemplate | A consumer-defined plan shape, written in TypeScript and registered at construction — so it versions with the consuming application, needs no store seeding, and can be validated once at boot rather than per instantiation. | | PredicateContext | What a cell may read when evaluating. Deliberately narrow: outputs and the frame, nothing live. | | PredicateEvaluator | A predicate cell: the seam that lets a branch/select interpret its own predicate form without this battery specifying an expression language. | | RawPlanView | The folded plan CONTENT at a revision. rawPlan() returns this; the renderer and validator read it. Note there is deliberately no state field: lifecycle state is not a PlanOp, so it cannot be folded from the log, and a historical revision therefore has no recoverable lifecycle state to report. state is a property of the plan NOW — read it from PlanStore.readState(), which is where it lives. A RawPlanView at revision 7 answers "what did the content look like then", not "what state was it in then". | | ReasonNodeDefinition | A reason node ENDS IN A TOOL CALL, and that tool call IS its output — it never returns prose to be parsed. outputSchema becomes the forced tool's inputSchema, so the model physically cannot answer unstructured: the validator rejects malformed args and the battery retries within maxAttempts. The captured, validated args are the node's OutputItem.json. Note this node carries a Schema, NOT DeclaredField[] — a validator expresses nested objects and unions that DeclaredField cannot, and it is what the forced tool needs anyway. | | RunDeps | The execution dependencies. Supplied at construction, per run, or both. | | RunOptions | Per-run inputs. Every RunDeps member is OPTIONAL here: createOrchestration already holds whatever was configured, so a caller repeats only what it wants to override. Orchestration's executePlan is therefore this shape, not the fully-required RunDeps — an earlier draft made every dependency mandatory per run while also calling construction the assembly point, which meant a caller had to repeat what it had just configured and left the override rule undefined. | | RunProjection | What foldRun returns: the whole answer to "where did it stop and what happened". | | SelectNodeDefinition | An n-way switch: the verdict names a case, or falls to the required default handle. | | SpooledArtifactLike | A spooled artifact instance, structurally — per CONTRIBUTING §13, the battery does not import the core classes. This is the value a call may return and a transform reads its methods from. | | TransformNodeDefinition | A transform node converts one node's output into the shape a downstream node needs — the bridge between what ADK tools actually return (string | Uint8Array | SpooledArtifact | Media[]) and the pathable fields a NodeRef reads. |

Type Aliases

Type AliasDescription
ArgValueA staged argument: any encodable value, or a reference to another node's output.
ArtifactTableLive artifact instances produced by call nodes, keyed identically to OutputTable (${nodeId}:${branchKey(branchId)}) so a transform's source: NodeRef addresses one with no second addressing scheme. This is the channel a transform receives its instance through — see TransformNodeDefinition, which explains why the value dataflow cannot carry it.
AuthorityVerbThe closed verb set. Closed so an authority set is comparable, not merely readable.
CallInvokerFnReturns the tool's result in the shape the tool actually produced — the same union an ADK ToolHandler returns (src/lib/classes/tool.ts:57). An earlier draft had this return OutputItem[], which quietly obliged every consumer to invent a conversion the plan never specified: a tool returning a JSON-in-a-string, or a SpooledArtifact handle, has no obvious mapping to pathable fields, and three implementors would have chosen three.
CreateOrchestrationTHE battery's single entry point. Everything public is reached through the object it returns, so it is the one place a precondition can be enforced for every operation — which is why the encoder check lives here (see Serialization).
DeclaredFieldOne field a node promises to produce, or that an entry/template accepts. Declaring a field is what makes it addressable by a NodeRef.path and checkable at freeze rather than at run time.
EdgeHandleAn edge's firing condition, drawn from the outcome of its source node.
EncodableValueThe value space of a staged argument and of a node's output: a DELIBERATE SUBSET of @nhtio/encoder's Encodable, declared structurally here rather than re-exported.
ExecutePlanFnStarts or resumes a run. Takes no entry argument — the entry node is unique by freeze invariant and its output is materialised from RunOptions.input.
InstantiateResultThe outcome of instantiating a template. Failure is a value, not a throw — a model reads it.
InterruptionCauseWhy a run stopped short of completing. Closed, so a caller can handle every case it must.
NodeIdA node's identity within one plan. Validated snake_case with no / and no leading ., so it can never be mistaken for a path or copied as a citation.
NodeOutcomeHow one frame settled. The three cases are exhaustive — a frame that has not settled has none.
OutputTableAppend-only, keyed ${nodeId}:${branchKey(branchId)} — path-unique, which is what makes a NodeRef resolve. Always build the key with branchKey, never by interpolating the object.
PlanIdA plan's stable identity, unique per store and never reused across a clone.
PlanNodeA node: its identity and phase, plus exactly one kind-specific definition.
PlanNodeKindThe closed set of node kinds. Each has its own definition type, and freeze validates per kind.
PlanOpOne authoring edit. Every op carries actor and lamport identity, and the fold is deterministic over any arrival order — so two offline authors' logs converge when they meet.
PlanProvenanceA clone's lineage. completedAtClone is the part that is not derivable later: the renderer must warn that "the parent already completed X, Y, Z, and approving this repeats them", and the parent's id/digest/revision identify CONTENT, not execution — a plan at that revision may never have run, may be halted, or may have completed a subset. So clonePlan snapshots the parent's completed node ids at clone time, which also makes the warning stable if the parent's run is later re-read or the parent is archived.
PlanStateThe three lifecycle states, in the only order they may be traversed.
PredicateVerdictA cell's decision, in the shape the node kind that asked for it expects.
PromptPartA prompt is a SEQUENCE of literal text and references — never a string with an embedded DSL.
ReasonerFnThe reason node's dispatcher. See ReasonNodeDefinition: it terminates in a tool call.
RouteSegmentA PATH identity — the route from entry to a frame, kept as the ROUTE ITSELF, not a hash of it, so ancestry questions are answered by reading the value. (An earlier draft hashed it and then tried to correlate joins by "longest common prefix of the ids", which computes nothing: a hash has no prefix relation to what it hashes.)
RunEventThe persisted wire contract. foldRun derives an entire RunProjection from a list of these with no graph, no store and no side channel, which is what makes resume a pure function of the log rather than of surviving process state.
TemplateArgValueA plan node whose staged values may additionally contain template holes.
TemplateDefinitionOfStructurally identical to the node definitions, with ArgValue widened to TemplateArgValue.
TemplateNodeA PlanNode whose definition may additionally contain template holes.
ToolResultExactly what an ADK tool handler may return. The battery narrows it, never guesses at it.

Variables

VariableDescription
DEFAULT_PLAN_BOUNDSThe canonical initial bounds — the fold's seed, not an op. foldOps starts from these, so a plan at revision 0 (an empty log) has a complete RawPlanView and a well-defined digest, and set_bounds ops override it thereafter. Without a fixed seed each implementor would invent a default or leave bounds absent, and since bounds are plan CONTENT that would give the same logical plan different digests across stores — breaking approval binding and store conformance. Every member stays required, so an override is total and cannot half-specify.

References

branchKey

Re-exports branchKey


effectiveToolMethods

Re-exports effectiveToolMethods


foldRun

Re-exports foldRun


NodeRef

Re-exports NodeRef


ParamRef

Re-exports ParamRef