fbp-evaluator

Lazy graph evaluator for Flow-Based Programming. Use when evaluating FBP graphs, running dataflow computations, or working with the @fbp/evaluator package.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "fbp-evaluator" with this command: npx skills add constructive-io/constructive-skills/constructive-io-constructive-skills-fbp-evaluator

Lazy graph evaluator for Flow-Based Programming.

Installation

pnpm add @fbp/evaluator

Overview

@fbp/evaluator provides a lazy evaluation engine for FBP graphs. It only evaluates nodes that are needed for the requested output, making it efficient for large graphs where only a subset of nodes contribute to the result.

Basic Usage

import { evaluate } from '@fbp/evaluator';
import type { Graph } from '@fbp/types';
import type { NodeDefinitionWithImpl } from '@fbp/evaluator';

// Define node implementations
const addDef: NodeDefinitionWithImpl = {
  context: 'js',
  category: 'math',
  type: 'js/math/add',
  inputs: [
    { name: 'a', type: 'number' },
    { name: 'b', type: 'number' }
  ],
  outputs: [{ name: 'sum', type: 'number' }],
  impl: (inputs) => ({
    sum: (inputs.a ?? 0) + (inputs.b ?? 0)
  })
};

const constNumberDef: NodeDefinitionWithImpl = {
  context: 'js',
  category: 'const',
  type: 'js/const/number',
  props: [{ name: 'value', type: 'number' }],
  outputs: [{ name: 'value', type: 'number' }],
  impl: (inputs, props) => ({
    value: props.value ?? 0
  })
};

// Create a graph
const graph: Graph = {
  name: 'simple-add',
  nodes: [
    { name: 'num1', type: 'js/const/number', props: [{ name: 'value', value: 5 }] },
    { name: 'num2', type: 'js/const/number', props: [{ name: 'value', value: 3 }] },
    { name: 'add', type: 'js/math/add' }
  ],
  edges: [
    { src: { node: 'num1', port: 'value' }, dst: { node: 'add', port: 'a' } },
    { src: { node: 'num2', port: 'value' }, dst: { node: 'add', port: 'b' } }
  ]
};

// Evaluate the graph
const result = evaluate(graph, {
  definitions: [constNumberDef, addDef],
  outputNode: 'add',
  outputPort: 'sum'
});

console.log(result); // 8

Node Definition with Implementation

interface NodeDefinitionWithImpl extends NodeDefinition {
  impl: (
    inputs: Record<string, any>,
    props: Record<string, any>
  ) => Record<string, any>;
}

The impl function receives:

  • inputs: Values from connected input ports
  • props: Property values set on the node instance

It returns an object with output port names as keys.

API

evaluate(graph, options)

Evaluates a graph starting from the specified output node/port.

const result = evaluate(graph, {
  definitions: NodeDefinitionWithImpl[],  // Node definitions with implementations
  outputNode: string,                      // Node to get output from
  outputPort: string,                      // Port to get output from
  inputs?: Record<string, any>,            // External inputs for graphInput nodes
  props?: Record<string, any>              // Props for graphProp nodes
});

Features

Lazy Evaluation

Only evaluates nodes that are needed for the output. If a node's output isn't connected to the requested output path, it won't be evaluated.

Multi-Input Ports

Supports ports that accept multiple incoming edges. Values are collected in edge array order:

const mergeDef: NodeDefinitionWithImpl = {
  type: 'js/array/merge',
  inputs: [{ name: 'items', type: 'any', multi: true }],
  outputs: [{ name: 'array', type: 'any[]' }],
  impl: (inputs) => ({
    array: inputs.items  // Array of all connected values
  })
};

Boundary Nodes

Supports graphInput, graphOutput, and graphProp boundary nodes for graph inputs/outputs/props:

// Provide external inputs
const result = evaluate(graph, {
  definitions,
  outputNode: 'output_result',
  outputPort: 'value',
  inputs: { a: 10, b: 20 },  // Keyed by portName
  props: { scale: 2.0 }       // Keyed by propName
});

Example: Building a Node Library

const mathNodes: NodeDefinitionWithImpl[] = [
  {
    context: 'js',
    category: 'math',
    type: 'js/math/add',
    inputs: [
      { name: 'a', type: 'number' },
      { name: 'b', type: 'number' }
    ],
    outputs: [{ name: 'sum', type: 'number' }],
    impl: (inputs) => ({ sum: (inputs.a ?? 0) + (inputs.b ?? 0) })
  },
  {
    context: 'js',
    category: 'math',
    type: 'js/math/multiply',
    inputs: [
      { name: 'a', type: 'number' },
      { name: 'b', type: 'number' }
    ],
    outputs: [{ name: 'product', type: 'number' }],
    impl: (inputs) => ({ product: (inputs.a ?? 1) * (inputs.b ?? 1) })
  },
  {
    context: 'js',
    category: 'math',
    type: 'js/math/negate',
    inputs: [{ name: 'value', type: 'number' }],
    outputs: [{ name: 'negated', type: 'number' }],
    impl: (inputs) => ({ negated: -(inputs.value ?? 0) })
  }
];

Best Practices

  1. Use descriptive type paths like context/category/name (e.g., js/math/add)
  2. Always provide default values in impl functions for missing inputs
  3. Keep node implementations pure — no side effects
  4. Use multi: true for ports that should accept multiple connections

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

constructive-graphql-codegen

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

github-workflows-ollama

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

github-workflows-pgpm

No summary provided by upstream source.

Repository SourceNeeds Review