Tool Dispatch Viz

An interactive walkthrough of the layer that sits between a model's tool-call output and the real-world handler. The dispatch pipeline validates arguments, routes to a registered handler, executes, classifies failures, retries with exponential backoff when appropriate, falls back to alternatives when the retry budget is spent, and finally formats a result back into something the model can read.

Four built-in scenarios cover the canonical paths: happy (no failures), timeout (one transient 503 absorbed by retry), rate-limit (429 walked through exponential backoff), and cascade failure (retry budget exhausted, primary tool dead, fallback chain activates). Two extra modes harden intuition: Predict asks the viewer to pick the next move at branching points; Challenge runs multiple-choice rounds about transient-vs-permanent errors, backoff strategy, and graceful-degradation semantics.

When a model outputs a tool call, a dispatch layer sits between intent and execution. It validates arguments, routes to the right handler, manages retries on failure, and formats the result back into something the model can read. Pick a scenario to see how the pipeline handles success and different failure modes.
Scenario
Tool CallSelect a scenario
Validate
Route
Execute
Format
Result

When a model outputs a tool call, a dispatch layer sits between intent and execution. It validates arguments, routes to the right handler, manages retries on failure, and formats the result back into something the model can read. Pick a scenario to see how the pipeline handles success and different failure modes.

Customize
Scenario
happy

Installation

npx shadcn@latest add https://craftbits.dev/r/tool-dispatch-viz.json

Usage

import { ToolDispatchViz } from "@craft-bits/viz/tool-dispatch-viz";
 
<ToolDispatchViz />

Swap in your own scenarios:

<ToolDispatchViz
  scenarios={[
    {
      id: "happy",
      label: "Cache hit",
      toolCall: { name: "cache_lookup", arguments: { key: "user:42" } },
      steps: [
        { stage: "validate", narration: "Key arg validated." },
        { stage: "route", narration: "Matched cache_lookup handler." },
        { stage: "execute", narration: "Cache returned hit." },
        { stage: "format", narration: "Wrapped as structured result." },
        { stage: "done", narration: "Done — no retries needed." },
      ],
    },
  ]}
/>

Customise the Challenge rounds:

<ToolDispatchViz
  challengeRounds={[
    {
      prompt: "An idempotent POST returns 502. Retry safe?",
      options: ["Yes — idempotent + transient", "No — POSTs are never safe to retry"],
      correctIdx: 0,
      explanation:
        "502 is a transient gateway error and the operation is idempotent. The retry is safe and the standard pattern.",
    },
  ]}
/>

Understanding the component

  1. Mode strip. A role="tablist" switches between Explore / Predict / Challenge with aria-selected on each tab.
  2. Scenario pills. Each scenario is a pill with aria-pressed. Selecting one in Explore mode jumps to step 0 of that scenario. Pill colour reflects outcome family (success / warning / failure) so the viewer reads the run's shape at a glance.
  3. Pipeline strip. Four stage boxes (Validate · Route · Execute · Format) wired with arrows. The current stage carries the accent colour; past stages flip to success; an erroring stage flips to error. A subtle relief glow tints the strip when retries or fallbacks were involved.
  4. Tool-call card. Syntax-highlighted JSON of the incoming tool call. Card opacity tracks whether a scenario is selected.
  5. Result card. Animates from empty → success on stage === "done". The via {fallbackTool} annotation appears when the dispatch landed via the fallback chain.
  6. Error banner. Shown for any error stage (error-classify, retry, backoff, fallback-activate, fallback-execute). Renders the error code + classification chip, a retry counter, a live backoff timer, and a primary→fallback handoff label for the fallback stages.
  7. Step indicator. A dot + label below the strip names the current stage. Includes a "(after N retries)" suffix when the active step is past the retry phase.
  8. BackoffTimer. A 50ms-tick progress bar that auto-advances the step on completion. Under reduced motion, it skips its countdown and fires onComplete immediately.
  9. Predict mode. Rounds at canonical branching points (503 received → classify; 429 received → backoff; budget exhausted → fallback; 401 received → don't retry; backoff sum).
  10. Challenge mode. Shorter rounds about permanent-vs-transient errors, why-backoff, graceful-degradation, and counting attempts. A ScoreDots row tracks correctness.
  11. Reduced motion. Every entrance collapses to { duration: 0 }; the BackoffTimer skips its countdown and immediately advances; the perfect-score bounce on summary degrades to a snap.

Props

PropTypeDefaultDescription
scenariosreadonly ToolDispatchVizScenario[]4 default scenariosScenarios available in Explore mode.
predictRoundsreadonly ToolDispatchVizPredictRound[]5 default roundsMultiple-choice rounds for Predict mode.
challengeRoundsreadonly ToolDispatchVizChallengeRound[]4 default roundsMultiple-choice rounds for Challenge mode.
transitionTransitionSPRINGS.snapOverride entrance spring for rows and panels.
classNamestringMerged onto the root via cn().

Accessibility

  • The root is role="figure" with an aria-label summarising the visualisation.
  • The mode strip is a real role="tablist" with aria-selected on each tab; the scenario pills carry aria-pressed to mirror the active scenario.
  • An sr-only polite live region announces stage / round transitions via the narration string.
  • Every interactive control has a visible focus ring and a ≥ 36px hit area.
  • ScoreDots rows in Predict / Challenge mode are role="status" with aria-label.
  • Stage, error type, and pass / fail signals are paired with a non-colour cue (numeric badge, error code text, ✓ / ✗ glyph, via fallback label).
  • Motion respects prefers-reduced-motion: reduce — every entrance collapses to instant and the BackoffTimer advances immediately.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/systems/ToolDispatchViz.tsx). The source was a lesson primitive built on the Widget / useWidgetHistory / ModeStrip / ChallengeBtn / FeedbackBadge / ScoreDots lesson-chrome stack and carried the CA palette tokens (--color-ink-*, --color-surface-elevated, --color-accent-400, --color-warn-400, --color-success-400, --color-fail-400) plus the ca-narration banner class. The extract strips all lesson chrome and rebuilds a self-contained mode-tablist + scenario-pill + pipeline-strip + body + narration shell, remapping every palette reference to semantic cb-* tokens. The four hard-coded scenarios, five Predict rounds, and four Challenge rounds are lifted into scenarios / predictRounds / challengeRounds props with defaults preserved (DEFAULT_TOOL_DISPATCH_VIZ_SCENARIOS / DEFAULT_TOOL_DISPATCH_VIZ_PREDICT_ROUNDS / DEFAULT_TOOL_DISPATCH_VIZ_CHALLENGE_ROUNDS). Re-architected to forwardRef + cn() + ...props spread. Inline SPRINGS.snappy / SPRINGS.gentle / MICRO.tap / STAGGER.tight / TIMING.* re-key to canonical SPRINGS.snap / SPRINGS.bouncy / TAP_SCALE / STAGGER from @craft-bits/core/motion. lessonId, the inline SvgLabel helper, the ChallengeBtn chrome button, and the undo/redo useWidgetHistory were stripped.