Skip to content

DAG Node Specification

Scope

@robota-sdk/dag-node is the node authoring infrastructure package for the Robota DAG system. It provides the abstract base class, lifecycle wrappers, registries, IO accessors, value objects, and helper functions that node implementors use to build concrete node definitions. This package sits between dag-core (which owns the domain contracts and interfaces) and dag-nodes (which contains the concrete node implementations).

Boundaries

  • No domain contracts. Interfaces (IDagNodeDefinition, INodeLifecycle, INodeTaskHandler, etc.), type definitions, state machines, and error builders belong to @robota-sdk/dag-core.
  • No concrete node implementations. Specific node types (e.g., llm-text-openai, image-source) belong to @robota-sdk/dag-nodes.
  • No orchestration or runtime. DAG scheduling, worker execution, and run coordination belong to dag-runtime, dag-worker, dag-scheduler.
  • No API layer. HTTP/REST composition belongs to application packages.
  • No execution engine or lifecycle runner. The NodeLifecycleRunner and LifecycleTaskExecutorPort belong to @robota-sdk/dag-core.

Architecture Overview

Layer Structure

dag-node/
  src/
    lifecycle/           -- Abstract base class, IO accessor, lifecycle wrappers, factory
    registry/            -- Static manifest registry
    schemas/             -- Zod schemas for media references
    utils/               -- Node descriptor (buildConfigSchema)
    value-objects/       -- MediaReference immutable value object
    node-definition-assembly.ts -- buildNodeDefinitionAssembly factory
    port-definition-helpers.ts  -- Binary port definition factory and presets
    __tests__/           -- Unit tests

Design Patterns

  • Abstract template pattern: AbstractNodeDefinition<TSchema> provides a config-parsing template that automatically validates node config against a Zod schema before delegating to *WithConfig methods. This ensures every lifecycle step receives a typed, validated config object.
  • Adapter pattern: RegisteredNodeLifecycle wraps an INodeTaskHandler (partial interface) into a full INodeLifecycle with base port validation for inputs and outputs.
  • Factory pattern: StaticNodeLifecycleFactory creates INodeLifecycle instances by looking up handlers in a registry and wrapping them.
  • Registry pattern: StaticNodeManifestRegistry and StaticNodeTaskHandlerRegistry provide in-memory lookup for node manifests and task handlers by node type.
  • Value object pattern: MediaReference is an immutable object with factory methods (fromAssetReference, fromBinary, fromCandidate) and no public constructor.
  • Result pattern: All operations that can fail return TResult<T, IDagError> instead of throwing.

Type Ownership

Types owned by this package (defined here, not imported):

TypeLocationPurpose
IMediaReferenceCandidatevalue-objects/media-reference.tsLoosely-typed input for creating a MediaReference
IParsedBinaryValuelifecycle/binary-value-parser.tsValidated binary port value with kind, MIME type, and URI
IBinaryPortPresetport-definition-helpers.tsPre-configured binary kind and MIME type combination
IBinaryPortDefinitionInputport-definition-helpers.tsInput for createBinaryPortDefinition factory

Types imported from @robota-sdk/dag-core (not owned):

TypePurpose
IDagNodeDefinitionInterface that AbstractNodeDefinition implements
INodeLifecycleInterface that RegisteredNodeLifecycle implements
INodeLifecycleFactoryInterface that StaticNodeLifecycleFactory implements
INodeTaskHandlerPartial lifecycle handler interface
INodeTaskHandlerRegistryInterface that StaticNodeTaskHandlerRegistry implements
INodeManifestRegistryInterface that StaticNodeManifestRegistry implements
INodeManifestNode registration manifest
INodeExecutionContextExecution context passed to lifecycle methods
ICostEstimateCost estimate returned from estimateCost
TResult<T, E>Discriminated union result type
IDagErrorCanonical error structure
TPortPayload, TPortValuePort value types
IPortDefinitionPort schema definition
IPortBinaryValueBinary port value structure
TAssetReference, TAssetReferenceType, TBinaryKindAsset and binary kind types

Public API Surface

ExportKindDescription
AbstractNodeDefinition<TSchema>Abstract classBase class for all node implementations; parses config via Zod, delegates to *WithConfig template methods
NodeIoAccessorClassTyped accessor for reading input values and building output payloads within node execution
RegisteredNodeLifecycleClassWraps an INodeTaskHandler into a full INodeLifecycle with base port validation
StaticNodeLifecycleFactoryClassCreates INodeLifecycle instances from a static handler registry
StaticNodeTaskHandlerRegistryClassIn-memory registry of INodeTaskHandler by node type
StaticNodeManifestRegistryClassIn-memory registry of INodeManifest by node type
MediaReferenceValue objectImmutable media reference with factory methods and conversion helpers
MediaReferenceSchemaZod schemaZod validation schema for media reference config
createMediaReferenceConfigSchemaFunctionCreates a Zod schema wrapping MediaReferenceSchema under an asset key
parseBinaryValueFunctionParses and validates a raw port value as a binary payload
createBinaryPortDefinitionFunctionCreates an IPortDefinition for binary ports using a preset
BINARY_PORT_PRESETSConstantPredefined binary port presets (IMAGE_PNG, IMAGE_COMMON, VIDEO_MP4, etc.)
buildNodeDefinitionAssemblyFunctionBuilds manifests and handler registry from an array of IDagNodeDefinition
buildConfigSchemaFunctionConverts a Zod schema to JSON Schema 7 for node config
createStaticNodeLifecycleFactoryFunctionFactory function that creates a StaticNodeLifecycleFactory from a handler map

Extension Points

AbstractNodeDefinition<TSchema>

The primary extension point for node implementors. Concrete node classes must:

  1. Extend AbstractNodeDefinition<TSchema> where TSchema is a Zod schema type.
  2. Declare nodeType, displayName, category, inputs, outputs, and configSchemaDefinition.
  3. Implement executeWithConfig(input, context, config) -- the core execution logic.
  4. Implement estimateCostWithConfig(input, context, config) -- cost estimation before execution.
  5. Optionally override initializeWithConfig, validateInputWithConfig, validateOutputWithConfig, and disposeWithConfig.

The base class automatically parses and validates node config against the Zod schema before delegating to any *WithConfig method. Config parse failures produce DAG_VALIDATION_NODE_CONFIG_SCHEMA_INVALID errors.

NodeIoAccessor

Provides typed input reading within node execution:

  • requireInput(key) / requireInputString(key) / requireInputArray(key) -- scalar and array access with validation errors.
  • requireInputBinary(key, kind?) / requireInputBinaryList(key, kind?, options?) -- binary payload access with kind and MIME-type validation.
  • requireInputMediaReference(key, options?) / requireInputBinaryReference(key, kind?) -- media reference access returning MediaReference value objects.
  • setOutput(key, value) / toOutput() -- output assembly.

INodeTaskHandler

A lighter alternative to full INodeLifecycle. Only execute is required; all other lifecycle methods are optional. The RegisteredNodeLifecycle wrapper fills in defaults and adds base port validation for handlers that omit validateInput/validateOutput.

Error Taxonomy

All errors use codes and categories defined in @robota-sdk/dag-core. This package produces errors in the following categories:

Validation Errors (category: validation, retryable: false)

CodeSourceDescription
DAG_VALIDATION_NODE_CONFIG_SCHEMA_INVALIDAbstractNodeDefinitionNode config fails Zod schema parse
DAG_VALIDATION_NODE_INPUT_MISSINGNodeIoAccessorRequired input key is missing
DAG_VALIDATION_NODE_INPUT_TYPE_MISMATCHNodeIoAccessor, RegisteredNodeLifecycleInput value type does not match port type
DAG_VALIDATION_NODE_INPUT_MIN_ITEMS_NOT_SATISFIEDNodeIoAccessor, RegisteredNodeLifecycleList input has fewer items than minItems
DAG_VALIDATION_NODE_INPUT_MAX_ITEMS_EXCEEDEDNodeIoAccessor, RegisteredNodeLifecycleList input has more items than maxItems
DAG_VALIDATION_NODE_REQUIRED_INPUT_MISSINGRegisteredNodeLifecycleRequired input port value is missing
DAG_VALIDATION_NODE_REQUIRED_OUTPUT_MISSINGRegisteredNodeLifecycleRequired output port value is missing
DAG_VALIDATION_NODE_OUTPUT_TYPE_MISMATCHRegisteredNodeLifecycleOutput value type does not match port type
DAG_VALIDATION_NODE_OUTPUT_MIN_ITEMS_NOT_SATISFIEDRegisteredNodeLifecycleList output has fewer items than minItems
DAG_VALIDATION_NODE_OUTPUT_MAX_ITEMS_EXCEEDEDRegisteredNodeLifecycleList output has more items than maxItems
DAG_VALIDATION_NODE_LIFECYCLE_NOT_REGISTEREDStaticNodeLifecycleFactoryNo lifecycle registered for node type
DAG_VALIDATION_MEDIA_REFERENCE_INVALIDMediaReferenceMedia reference structure is invalid
DAG_VALIDATION_MEDIA_REFERENCE_XOR_REQUIREDMediaReferenceExactly one of assetId or uri must be provided
DAG_VALIDATION_MEDIA_REFERENCE_TYPE_MISMATCHMediaReferencereferenceType does not match provided fields

Class Contract Registry

Interface Implementations

Interface (Owner)ImplementorKindLocation
IDagNodeDefinition (dag-core)AbstractNodeDefinitionabstract basesrc/lifecycle/abstract-node-definition.ts
INodeLifecycle (dag-core)RegisteredNodeLifecycleproductionsrc/lifecycle/registered-node-lifecycle.ts
INodeLifecycleFactory (dag-core)StaticNodeLifecycleFactoryproductionsrc/lifecycle/static-node-lifecycle-factory.ts
INodeManifestRegistry (dag-core)StaticNodeManifestRegistryproductionsrc/registry/static-node-manifest-registry.ts
INodeTaskHandlerRegistry (dag-core)StaticNodeTaskHandlerRegistryproductionsrc/lifecycle/default-node-task-handlers.ts

Cross-Package Consumers

Export (This Package)Consumer PackageNotes
AbstractNodeDefinitiondag-nodes (11 node definitions)Each implements executeWithConfig and estimateCostWithConfig
NodeIoAccessordag-nodes (11 node definitions)Used for input reading and output assembly
MediaReferencedag-nodes (media-handling nodes)Used for asset reference handling
BINARY_PORT_PRESETS, createBinaryPortDefinitiondag-nodes (binary-handling nodes)Used for port definitions
buildNodeDefinitionAssemblydag-runtime-server, dag-orchestrator-serverBuilds manifests + handler map from node definitions
StaticNodeLifecycleFactory, StaticNodeTaskHandlerRegistrydag-runtime-serverCreates lifecycle instances for node execution

Dependencies

DependencyPurpose
@robota-sdk/dag-coreDomain contracts, interfaces, error builders, type definitions
zodRuntime schema validation for node configs and media references
zod-to-json-schemaConverts Zod schemas to JSON Schema 7 for manifest configSchema

Test Strategy

Current Test Files

FileCoverage
__tests__/abstract-node-definition.test.tsConfig parsing, *WithConfig delegation, config validation error generation
__tests__/node-io-accessor.test.tsrequireInput* methods, binary access, media reference access, output assembly
__tests__/registered-node-lifecycle.test.tsPort validation (required ports, type matching, list constraints), handler delegation
__tests__/static-node-lifecycle-factory.test.tsFactory creation from registry, missing handler error
__tests__/static-node-manifest-registry.test.tsManifest lookup, listing
__tests__/media-reference.test.tsFactory methods, XOR validation, conversion helpers
__tests__/media-reference-schema.test.tsZod schema validation for media references
__tests__/binary-value-parser.test.tsBinary value parsing and validation
__tests__/node-descriptor.test.tsbuildConfigSchema Zod-to-JSON-Schema conversion and validation
__tests__/node-definition-assembly.test.tsbuildNodeDefinitionAssembly assembly, port definition helpers, presets

Released under the MIT License.