Skip to main content
import { Workflow } from "smithers-orchestrator";

type WorkflowProps = {
  name: string;
  cache?: boolean; // skip already-completed nodes on resume
  children?: ReactNode;
};
import { createSmithers } from "smithers-orchestrator";
import { ToolLoopAgent as Agent } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";

const { Workflow, Task, smithers, outputs } = createSmithers({
  research: z.object({ findings: z.string() }),
});

const researcher = new Agent({
  model: anthropic("claude-fable-5"),
  instructions: "You are a research assistant.",
});

export default smithers((ctx) => (
  <Workflow name="research-pipeline" cache>
    <Task id="research" output={outputs.research} agent={researcher}>
      {`Research: ${ctx.input.topic}`}
    </Task>
  </Workflow>
));

Notes

  • Direct children run sequentially; <Sequence> is only needed inside other control-flow components.
  • Two ways to get <Workflow>, both equivalent. You can either import { Workflow } from "smithers-orchestrator" (top-level export) or destructure it from createSmithers(...); they render the identical node. The factory’s Workflow is a thin pass-through to the same component (it injects no schema or context), unlike Task/Approval/Sandbox/Signal, which the factory wires to the run’s context and your output schemas. Convention: destructure Workflow from createSmithers alongside Task, smithers, and outputs so the workflow’s components all come from one place; this is what the example above and ~95% of examples/ do. Importing Workflow (or Sequence, Branch, Loop, Parallel, also pure structural components) directly from "smithers-orchestrator" is equally valid and handy in tiny single-file workflows.
  • Custom Drizzle tables require runId, nodeId, and iteration columns with a composite primary key (run_id, node_id, iteration). Tasks outside a <Loop> write iteration = 0.