@sisu-ai/mw-control-flow
v12.0.0
Published
Express branching, routing, loops, and graphs in agent pipelines with explicit middleware control flow.
Maintainers
Readme
@sisu-ai/mw-control-flow
Express branching, routing, loops, and graphs in agent pipelines with explicit middleware control flow.
Setup
npm i @sisu-ai/mw-control-flowDocumentation
Discover what you can do through examples or documentation. Check it out at https://github.com/finger-gun/sisu
API
sequence([a,b,c]): Run middlewares in order as one unit. Good for composing small steps into a named phase.branch(pred, onTrue, onFalse?): Classic if/else routing. Pred is(ctx) => boolean.switchCase(select, routes, fallback?): Route by key(ctx) => stringto a middleware fromroutes.loopWhile(pred, body, { max }): While-loop; evaluatespred(ctx)before each iteration.loopUntil(done, body, { max }): Do-while; runsbodyat least once untildone(ctx)returns true.parallel([a,b], merge?): Fork the samectxthrough branches concurrently, thenmerge(ctx, results).graph(nodes, edges, start): Small DAG runner. Each node has anidandrun(ctx, next).edgesdecide traversal.
Usage
import { sequence, branch, switchCase, loopUntil } from '@sisu-ai/mw-control-flow';
const decide = async (c, next) => { c.state.intent = c.input?.match(/tools/i) ? 'tool' : 'chat'; await next(); };
const toolFlow = sequence([/* tool loop */]);
const chatFlow = sequence([/* plain chat */]);
const app = new Agent()
.use(decide)
.use(switchCase(c => String(c.state.intent), { tool: toolFlow, chat: chatFlow }, chatFlow));Branch
Use branch when a boolean predicate cleanly splits flow.
import { branch, sequence } from '@sisu-ai/mw-control-flow';
const playful = sequence([/* witty system prompt + generate */]);
const practical = sequence([/* pragmatic system prompt + generate */]);
app.use(branch(c => /joke|humor/i.test(c.input ?? ''), playful, practical));switchCase
Route by an intent or mode string computed from context.
import { switchCase, sequence } from '@sisu-ai/mw-control-flow';
const classify = async (c, next) => { c.state.intent = /weather/.test(c.input ?? '') ? 'tool' : 'chat'; await next(); };
const toolPipeline = sequence([/* register tools, toolCalling, etc. */]);
const chatPipeline = sequence([/* plain completion */]);
app.use(classify).use(switchCase(c => c.state.intent, { tool: toolPipeline, chat: chatPipeline }, chatPipeline));loopUntil / loopWhile
Iterate a sub-pipeline while a condition holds (with a safety cap).
import { loopUntil, sequence } from '@sisu-ai/mw-control-flow';
const decideIfMore = async (c, next) => { c.state.more = c.messages.at(-1)?.role === 'tool'; await next(); };
const body = sequence([/* toolCalling */ decideIfMore]);
app.use(loopUntil(c => !c.state.more, body, { max: 6 }));graph
Encode multi-step flows as nodes + conditional edges (DAG). Good for “classify → handle → polish” shapes.
import { graph, type Node, type Edge } from '@sisu-ai/mw-control-flow';
const nodes: Node[] = [
{ id: 'classify', run: async (c, next) => { c.state.intent = pickIntent(c.input); await next(); } },
{ id: 'draft', run: async (c) => {/* generate a plan */} },
{ id: 'chat', run: async (c) => {/* simple completion */} },
{ id: 'polish', run: async (c) => {/* refine output */} },
];
const edges: Edge[] = [
{ from: 'classify', to: 'draft', when: c => c.state.intent === 'draft' },
{ from: 'classify', to: 'chat', when: c => c.state.intent !== 'draft' },
{ from: 'draft', to: 'polish' },
{ from: 'chat', to: 'polish' },
];
app.use(graph(nodes, edges, 'classify'));Notes
- Keep node bodies small and reuse regular middlewares inside
graphnodes where possible. - Prefer
switchCase/branchfor simple splits; reach forgraphwhen you have 3+ phases or need to rejoin branches.
Community & Support
Discover what you can do through examples or documentation. Check it out at https://github.com/finger-gun/sisu. Example projects live under examples/ in the repo.
Documentation
Core — Package docs · Error types
Adapters — OpenAI · Anthropic · Ollama
- @sisu-ai/mw-agent-run-api
- @sisu-ai/mw-context-compressor
- @sisu-ai/mw-control-flow
- @sisu-ai/mw-conversation-buffer
- @sisu-ai/mw-cors
- @sisu-ai/mw-error-boundary
- @sisu-ai/mw-guardrails
- @sisu-ai/mw-invariants
- @sisu-ai/mw-orchestration
- @sisu-ai/mw-rag
- @sisu-ai/mw-react-parser
- @sisu-ai/mw-register-tools
- @sisu-ai/mw-tool-calling
- @sisu-ai/mw-trace-viewer
- @sisu-ai/mw-usage-tracker
- @sisu-ai/tool-aws-s3
- @sisu-ai/tool-azure-blob
- @sisu-ai/tool-extract-urls
- @sisu-ai/tool-github-projects
- @sisu-ai/tool-rag
- @sisu-ai/tool-summarize-text
- @sisu-ai/tool-terminal
- @sisu-ai/tool-web-fetch
- @sisu-ai/tool-web-search-duckduckgo
- @sisu-ai/tool-web-search-google
- @sisu-ai/tool-web-search-openai
- @sisu-ai/tool-wikipedia
Anthropic — hello · control-flow · stream · weather
Ollama — hello · stream · vision · weather · web-search
OpenAI — hello · weather · stream · vision · reasoning · react · control-flow · branch · parallel · graph · orchestration · orchestration-adaptive · guardrails · error-handling · rag-chroma · web-search · web-fetch · wikipedia · terminal · github-projects · server · aws-s3 · azure-blob
Contributing
We build Sisu in the open. Contributions welcome.
Contributing Guide · Report a Bug · Request a Feature · Code of Conduct
Star on GitHub if Sisu helps you build better agents.
Quiet, determined, relentlessly useful.
