Skip to main content
// Props
import { DecisionTable } from "smithers-orchestrator";

type DecisionTableProps = {
  id?: string;
  rules: DecisionRule[];
  default?: ReactElement; // rendered when no rule matches
  strategy?: "first-match" | "all-match"; // default "first-match"
  skipIf?: boolean;
};

type DecisionRule = {
  when: boolean; // evaluated at render time
  then: ReactElement;
  label?: string;
};
<DecisionTable
  rules={[
    {
      when: triage.severity === "critical",
      then: (
        <Task id="page-oncall" output={outputs.page} agent={pagerAgent}>
          Page the on-call engineer immediately.
        </Task>
      ),
    },
    {
      when: triage.severity === "high",
      then: <Task id="assign-senior" output={outputs.assign}>{{ assignee: "senior-pool" }}</Task>,
    },
  ]}
  default={<Task id="default-assign" output={outputs.assign}>{{ assignee: "general-pool" }}</Task>}
/>

Notes

  • first-match builds nested Branches; order matters.
  • all-match wraps every matching rule in a Parallel; no ordering guarantee.

Source

The <DecisionTable> implementation and the files it imports, straight from the package source. This section is generated; edit the source, not this block.
// @smithers-type-exports-begin
/** @typedef {import("./DecisionRule.ts").DecisionRule} DecisionRule */
/** @typedef {import("./DecisionTableProps.ts").DecisionTableProps} DecisionTableProps */
// @smithers-type-exports-end

import React from "react";
import { Branch } from "./Branch.js";
import { Parallel } from "./Parallel.js";
/**
 * Structured deterministic routing. Replaces deeply nested Branches with a
 * flat, declarative rule table.
 *
 * - `"first-match"` builds nested Branch elements so the first matching rule wins.
 * - `"all-match"` gathers all matching rules' `then` elements into a Parallel.
 *
 * Composes Branch and Parallel internally.
 * @param {DecisionTableProps} props
 */
export function DecisionTable(props) {
    if (props.skipIf)
        return null;
    const { rules, strategy = "first-match" } = props;
    if (strategy === "all-match") {
        const matching = rules.filter((r) => r.when).map((r) => r.then);
        if (matching.length === 0) {
            return props.default ?? null;
        }
        return React.createElement(Parallel, { id: props.id }, ...matching);
    }
    // "first-match": build nested Branches from the last rule backward.
    // The innermost else is the default fallback.
    let fallback = props.default ?? null;
    for (let i = rules.length - 1; i >= 0; i--) {
        const rule = rules[i];
        fallback = React.createElement(Branch, {
            if: rule.when,
            then: rule.then,
            else: fallback,
        });
    }
    return fallback;
}