v0.1 · MIT · ~340 LOC · 37 tests

Out-of-order tool calls
cannot reach your model.

ToolRoute wraps Vercel AI SDK tool definitions so each tool declares its legal nextAllowed successors. Compile-time narrowing plus a 50-line runtime guard reject the same illegal call from both sides.

$ pnpm add toolroute ai zod

One source of truth

nextAllowed lives on the tool itself. The type narrowing and the runtime guard read the same array — they cannot drift.

Runtime before types

The 50-line guard shipped first, with a recorded terminal session of a real rejection. The narrowing matches observable behaviour, not a compile-time lie.

Names derived

createRouterFromTools infers the name set from the array. Rename review once and every nextAllowed referencing it is a tsc error at its site, not yours.

Loud diagnostics

ToolRouteViolation carries prev, next, legalNext, and routerVersion — paste the message into a Sentry title and you know which SDK was on the box.

Edge-aware

console.warn is suppressed in Vercel Edge Functions. ToolRoute detects the runtime and emits a one-time init warning so violations do not vanish.

Calling card, not platform

No paid tier, no hosted dashboard, no playground in v1. ~340 LOC, 37 tests, weekly CI cron pinned to ai@latest. Zero distraction surface.

Inspect the graph in two minutes

printRouterGraph(router) emits a deterministic plain-text adjacency dump. Sorted alphabetically, terminals tagged, zero runtime dependencies. At 7+ tools your routing graph lives across files; this is your single-screen view.

How nextAllowed works
// printRouterGraph(router) — diff-stable, zero deps.
commit -> (terminal)
review -> commit
search -> review

// At runtime: every ToolRouteViolation carries the version
// you compiled against — paste into Sentry as-is.
routerVersion: "toolroute@0.1.0+ai-sdk@6.0.174"

Wrap an existing Vercel AI SDK agent in five minutes.

The 5-line quickstart in the docs is the same code as examples/code-review-agent/ in the repo — the same code that produced the recorded rejection.