The form router is a small example web app that sorts form submissions (sales leads, support requests, bug reports, insurance claims, identity documents, maintenance requests, street problems, payment disputes, marketplace reports) by deciding which team should get each one, how urgent it is, and whether it's spam, from the text and from any screenshots or photos attached. DecisionNode Flash answers every question in milliseconds, and only the questions it isn't sure about go to the full DecisionNode MoE model, so most decisions are fast and cheap while the hard ones still get the most accurate answer.
Developers who handle incoming forms, tickets or messages and want them sorted automatically would use it as a starting point. It shows them how to settle most of those decisions on the fast, low-cost model and pay for the most accurate one only when it is needed.
- Repository
- decision-node-form-router on GitHub, MIT
- Built with
- Next.js and the TypeScript SDK,
@decisionnode/sdk - Models
decisionnode-1.0-flashfirst,decisionnode-1.0for what DecisionNode Flash is unsure of- Rules
- A knowledge base per company, read through the
knowledgebooster - Pictures
- Screenshots and photos, up to 4 per submission
- You need
- Node.js 22 and an API key
Route by your own rules#
Team names and a line of criteria are not enough to route a submission like your company would. Who owns which product, which customers are on an enterprise contract, what counts as urgent, what always goes to a particular team: those are your rules, and they change. The form router keeps them in a knowledge base, and every request reads the rules that apply to it through the knowledge booster, on the first answer and on the re-check alike.
- A playbook per form: one Markdown document per team, saying what it owns and what it does not, and one pinned document with the rules every submission must see.
- One knowledge base, scoped by form, so a sales lead never reads the claims rules.
pnpm knowledge:setuploads the playbooks into a knowledge base in your workspace and writes its id to.env.local. Edit a playbook and run it again: only what changed is rewritten.- The rules are required. If they cannot be read, the submission is not routed; it is retried once, then shown as an error with the API's reason.
- Each answer shows the passages it rested on, so a person can see why a submission went where it did.
import { DecisionNode, knowledge } from "@decisionnode/sdk";
const RULES = "col_..."; // the knowledge base pnpm knowledge:setup made
const dn = new DecisionNode();
const decision = await dn.decide({
model: "decisionnode-1.0-flash",
state: submission,
questions,
boosters: [knowledge(RULES, { scope: form.id, require: true })],
});With the rules in front of it, DecisionNode Flash is sure more often, so fewer questions need the full model. Each request that reads the rules is one knowledge call; a submission that escalates makes two.
How a submission is decided#
- 1.The submission becomes one request: its fields are the state, its pictures go in
images, and the questions carry the form's teams and guidance. The submission is evidence to judge, never instructions to follow. - 2.DecisionNode Flash answers every question: the team (a Choice), the urgency (a Score) and the form's checks (Truth), such as spam or whether the picture fits what the person wrote.
- 3.Each answer's confidence is compared with the threshold, 0.7 by default. The questions below it, and only those, go to DecisionNode MoE with
"fallback": false, so the re-check comes from the full model. - 4.A question still below the threshold takes its safe action: the triage team, an urgency shown as unsure, a check marked for review. Nothing is rejected by the router.
A Truth answer's confidence is its distance from 0.5 on the same 0 to 1 scale, |2p - 1|, so one threshold works for every question. Confidence-gated routing explains how to tune it on your own traffic.
Nine forms#
| Industry | Form | What a picture adds |
|---|---|---|
| General business | Sales leads | Text only |
| General business | Customer contact | An invoice screenshot goes to billing, an error dialog to technical support |
| General business | Bug reports | A layout glitch to frontend, an error page to the platform team |
| Insurance | Insurance claim | The damage photo picks the team and the urgency, and is checked against the description |
| Identity | Identity verification | Which document it is, whether it is readable, whether the name matches. It sorts submissions only; it does not verify identity |
| Property | Maintenance request | The photo picks the trade and spots an emergency |
| Public sector | Report a street problem | A pothole, a dark streetlight or a fallen tree, hazards first |
| Finance | Dispute a charge | The statement or receipt shows the charge and the merchant |
| Marketplaces | Report a listing or seller | The screenshot shows what the listing claims |
Each form is one data file in the repository, with its own fields, teams, checks, samples and playbook, so adding your own form is one more file.
Run it#
git clone https://github.com/Bynn-Intelligence/decision-node-form-router.git
cd decision-node-form-router
pnpm install
cp .env.example .env.local # set DECISIONNODE_API_KEY
pnpm knowledge:setup
pnpm devMake a key in the console; the knowledge setup and the passages' text need a Full access key. The app also deploys to Vercel as it runs locally. The repository's README has every setting, the email delivery and how to add your own forms.