The problem
Before reaching for a model to understand every user message, a lot of real traffic is predictable: “cancel my order,” “where’s my order,” a greeting. Routing those cheaply with plain pattern matching, and reserving a model call for genuinely ambiguous input, is both faster and cheaper than sending everything through an LLM.
Expected outcome
By the end of this guide you will have a small router that matches user text against a list of intents, in order, each with its own handler, and falls back to a default when nothing matches.
Requirements and costs
- Node.js (version 18 or newer).
- Cost: free. No API key, no model call.
Step-by-step implementation
- Download the starter from the link below.
- Define your intents as a list, each with a
match(text)function and ahandle(text)function:const router = createRouter([ { name: "cancel_order", match: (t) => /cancel.*order/i.test(t), handle: () => "..." }, { name: "greeting", match: (t) => /^(hi|hello)\b/i.test(t), handle: () => "Hello!" }, ]); - Route incoming text:
const result = router.route("please cancel my order"); // { intent: "cancel_order", reply: "..." } - Order matters — intents are checked in the order you listed them, and the first match wins, so put more specific intents before broader ones that might overlap.
A real example
"please cancel my order" -> cancel_order
"where is my order?" -> track_order
"hello there" -> greeting
"what's the weather like" -> unknown (falls back honestly, not guessed at)
Verification and troubleshooting
What we tested, on 5 October 2026 (record TNT-TEST-2026-10-05-020): 4 real inputs routed through 3 defined intents plus the fallback — “cancel my order” correctly matched cancel_order, “where is my order?” correctly matched track_order (not cancel_order, despite both mentioning “order”), a greeting correctly matched greeting, and an unrelated question correctly fell through to the honest “unknown” fallback rather than being forced into one of the 3 defined intents.
Troubleshooting:
- The wrong intent matches. Check intent order — a broader pattern listed before a more specific one will win first, even if the specific one is the better match.
- Everything falls through to “unknown.” Test each intent’s
match()regex in isolation against your real input text; a regex that’s too narrow is the most common cause. - You need to route to a model for anything the rules don’t catch. Make the fallback itself call your model, instead of returning a canned “not sure” reply — cheap rules handle the predictable cases, the model handles the rest.
Limitations and alternatives
This is pattern matching, not understanding — it will miss any phrasing its authors didn’t anticipate. That’s the entire trade: fast and free for the cases you’ve written rules for, with a graceful fallback (ideally to a real model) for everything else, rather than trying to write a rule for every possible phrasing.
Free resources
The download contains the router and a runnable demo covering all 4 cases above.
Download the intent router (ZIP, 1 KB)
Is there a paid version?
Not yet. This is the complete method. TNT Review has sold nothing to date and has no checkout, so any price we discuss in future should be read as a hypothesis, not an offer.