Smart home assistant demo walkthrough
TL;DR The demo evaluates every user utterance against one long question list — category, domain, device type, action, plus a Noul for "is this more than one command" — and lets code pick the answers that matter. An LLM is called only to split compound requests and to answer conversational ones. The source code is not public yet ("will be available on GitHub at release"), so this page documents the described design, not a file listing.
Scope and caveat
raw/docs/demos.md lists exactly one demo:
Smart Home Assistant Demo - Evaluate user smart home requests with speculative questions and LLM fallback.
raw/docs/demos__smart-home.md describes itself as "Demo code: a smart home assistant that uses TypeSafe to evaluate user requests," and links a Loom walkthrough video (https://www.loom.com/embed/18c4dbcf8db546dfb2d7f2ef018e78e4). But the page's closing section says:
This demo is a simple Vite/React single-page app that uses the TypeSafe API to evaluate user requests. The full source code will be available on GitHub at release. Its README includes instructions for running the demo locally and an overview of which bits of the source code are responsible for which parts of the demo.
So: the stack is a Vite/React single-page app, and the repository was not yet published as of the 2026-09-17 capture. Everything below is the design as the docs describe it. The exact instructions and criteria strings are not given by the source — this page quotes the questions as the docs phrase them in prose and does not invent JSON for them.
Step 1: understand the worked example
The docs walk one request through the system:
"Turn off all of the lights in the house"
This is a very simple request, and our code will only need to consider the answers to the following questions:
- "What category of request is this?" (smarthome command)
- "What domain is this request targeting?" (whole house)
- "What type of device is this request targeting?" (lights)
- "What action should be taken on the lights?" (turn off)
Four questions, four answers, one device command. The demo's question list is longer than four — "Each user request is evaluated against a long list of questions, including many that will end up irrelevant for most requests."
Mapping to primitives (inferred — the docs give the question text but not each question's type): the first three read as Choice questions over fixed option sets (categories, domains, device types), and "what action should be taken on the lights" as another Choice over that device's action set. The one question whose type is stated is the compound-request detector, which is a Noul.
Step 2: see why the last question is speculative
Notice that the last question is written with the assumption that the user is issuing a command to lights, and we ask it before we know what the user is actually requesting. This is what we call a "speculative question" - we ask it before we even know if it's relevant, allowing us to evaluate all questions in parallel and rely on code to filter out the irrelevant results after the fact. This is a key pattern for building systems that can handle a wide variety of user requests with a single set of questions.
That is Speculative fan-out exactly: the premise ("the user is commanding lights") is stated inside the question, the question is asked unconditionally, and code discards the answer when the category or device type says it does not apply.
Step 3: know what the sequential version would cost
The docs spell out the anti-pattern, verbatim:
The wrong way to do this would be to separate the questions in to multiple API calls, waiting to ask questions only once you are certain you need the answer:
- "What category of request is this?" (smarthome command)
Then, only once you know it's a smarthome command:
- "What domain is this request targeting?" (whole house)
- "What type of device is this request targeting?" (lights)
Then, only once you know it's targeting lights:
- "What action should be taken on the lights?" (turn off)
This approach optimizes for a minimum number of questions, but it ends up being much slower and more expensive than batching all of the questions in to one upfront API call.
Three serialized round trips, each re-sending the same utterance, versus one call. For a voice-style interface where the user is waiting, that is the whole product.
Step 4: how the code uses the answers
The docs describe three distinct consumption paths:
a. Device commands — pure code
For the smarthome command category, code reads the domain, device type, and action answers and issues the corresponding device call. No LLM is involved on this path. (The docs describe the routing in prose; the dispatch code itself is not published.)
b. Compound requests — Noul gate, then an LLM splitter
Splitting a compound user request: One of the questions in this demo is a Noul question identifying if the user request is asking for more than one distinct action. If this is true, the system uses an LLM to split the request into a list of atomic commands. The split requests are then evaluated by TypeSafe individually.
The loop, then: one fan-out call per utterance → if the compound Noul is high, an LLM turns one utterance into N atomic utterances → each of those goes back through the same fan-out call. A Noul returns a probability in 0–1 with no separate confidence field, so this gate is a threshold on noul itself; the demo's threshold value is not published.
c. Conversation — LLM fallback
Falling back to a conversational LLM: When TypeSafe determines that the user query is a request for general information or conversation, the system calls an LLM to generate a freeform response. This allows an interactive system to handle requests with known deterministic behavior in a fast and cost efficient way, while still allowing for the flexibility provided by a generative LLM when needed. The initial TypeSafe response is so fast compared to the LLM response that it adds negligible latency to the overall system.
That last sentence is the architectural claim worth remembering: putting Jev in front of an LLM does not meaningfully slow down the requests that end up at the LLM anyway, and it removes the LLM entirely from the requests that do not. This is Intent routing with a generative escape hatch.
Step 5: adapt it
What to change for your own domain (inferred from the described design):
- The category question is the top-level router: device command vs. conversation vs. whatever else your app does.
- The domain and device-type questions are the addressing scheme — rooms, zones, appliance classes. Keep option sets bounded; high-cardinality device catalogs want Cookbook: Hierarchical classification.
- One speculative action question per device class. With N device classes you have N action questions in the fan-out, and code reads the one the device type selected.
- The compound Noul is generic; it belongs in any natural-language command surface.
- Keep questions and thresholds in one file. The agent-skill guidance: "Put the constants (questions and thresholds) in a single place so they're easy to review."
Gotchas
- The source is not published. Do not cite specific files, function names, or threshold values for this demo; they are not in the sources as of 2026-09-17.
- The speculative action question needs an explicit premise. Asked of "what's the weather," "what action should be taken on the lights" still returns an answer. It is only harmless while code ignores it.
- Free of latency, not free of tokens. Every utterance pays for the whole question list. See Models, aliases, pricing, rate limits, context.
- Compound splitting re-enters the pipeline. A splitter that emits N commands means N more Jev calls; budget for the worst case, not the average.
- Client-side keys. It is a single-page app; the agent skill's rule still applies — "Keep API credentials server-side in web apps." The demo's own key handling is not documented.
Related
- Speculative fan-out — the pattern this demo exists to show
- Intent routing — the LLM/code/human routing shape
- Noul (yes/no) questions — the compound-request detector's primitive
- Choice questions — category, domain, device, action
- Quickstart: first call in HTTP, Python, JS — making the same call yourself
- Use-case map by industry — other interactive-assistant use cases
- Patterns overview — the pattern catalog
Sources
- raw/docs/demos.md (https://docs.typesafe.ai/demos)
- raw/docs/demos__smart-home.md (https://docs.typesafe.ai/demos/smart-home)
- raw/docs/patterns__fan-out.md (https://docs.typesafe.ai/patterns/fan-out)