Command Palette

Search for a command to run...

Hectal
PHASE 0Beginner ~24 min· topic 3 of 5

Topic 0.3

How This Course's Live Editor Works

In one line

The live editor has no server, no network and no API key, so it runs the server part inside the page with serve() and replaces the model with a scripted stand-in. The browser code you write and read is real; only the model's words are scripted.

Think of it like this

A flight simulator. The cockpit, the controls and the instruments are the real ones, and they behave as they do in the air. Only the sky is simulated, so a trainee can practise an engine failure a hundred times safely. This editor is a simulator for AI features: real controls, a simulated model.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Sandbox
A sealed area of the page where an example runs. It cannot reach Hectal's data, your accounts or the network.
serve(path, handler)
This editor's stand-in for a server: a fetch to that path runs your handler function.
Handler
A function that receives a Request and returns a Response, like a route on a real server.
Stand-in (fake) model
A scripted replacement for a real model. It returns what its script says, with realistic timing.
Deterministic
Giving the same output for the same input, every time. Real models are not; the stand-in is.
Script
What you tell the stand-in to answer: a sentence, a list of replies, or a function of the question.
Lab
A panel that sends a request to a real model through Hectal's server and shows the real answer.
Quota
A limit on how many requests are allowed in a period. The labs share one across all learners.

Step by step

01A server in three lines

serve registers a handler. The fetch below it looks exactly like a call to a real server, and gets a real Response object back.

previewwhole filejs
serve("/api/hello", async (req) => {
  const { name } = await req.json();
  return Response.json({ greeting: `Hello, ${name}!` });
});

const res = await fetch("/api/hello", { method: "POST", body: JSON.stringify({ name: "Asha" }) });

02The same handler in a real project

In a Next.js project the handler becomes an exported function in a file whose folder is the path. The body is unchanged. Other frameworks differ in the wrapper, not in the idea.

app/api/hello/route.ts (real app)whole filets
export async function POST(req: Request) {
  const { name } = await req.json();
  return Response.json({ greeting: `Hello, ${name}!` });
}

03Three outcomes of a request

The first live example makes three requests: one that works, one whose handler crashes, and one to a path nobody serves. Compare what the browser code receives in each case: a 200 with data, a 500 it can read, and an exception it must catch.

These are the same three outcomes you get from a real server, and good AI frontends handle all three differently.

04Scripting the model

A script can be a function of the question. In the second live example the stand-in answers one way if the question mentions returns and another way otherwise, and asking the same question twice gives the same answer both times.

It also takes real time. The example measures each call and labels it "took a moment": even a fake model makes you wait, so the waiting states you build are tested for real.

Scripting the modeldiagram
Rendering diagram…

Try it yourself

  1. 1

    Teach the stand-in a new answer

    In the second example, add a third case to the script so a question containing ship answers "Orders ship in 1 to 2 working days." Then add await ask("When will it ship?");.

    This is how every later example sets up a situation: the script decides what the "model" says, so the lesson can focus on what your code does with it.

  2. 2

    Check the status before reading

    In the first example, change the second request to const data = await broken.json();. What happens?

    It throws SyntaxError: Unexpected token 'I', "Internal S"... is not valid JSON: the 500 body is plain text, not JSON. Reading an error response as if it were a success is one of the most common AI frontend bugs. Always check res.ok first.

  3. 3

    Compare with a real model

    Go back to the lab in Topic 0.1 and send it twice. The stand-in gave identical answers to identical questions; the real model probably did not. That difference is exactly why this course checks your *handling* with the stand-in and shows *behaviour* with labs.

Code & diagrams

serve(): a working route, a crashing route, a missing route

The line starting (server) is what the server itself would log. The browser code only sees the 500 and its text: it never sees why, which is how a real server should behave.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

200 { greeting: 'Hello, Asha!' }
(server) Error: the database is down
500 Internal Server Error
TypeError: Failed to fetch
A scripted model: same question, same answer, real waiting

The script receives the user's text and decides the reply. Edit the function to make the stand-in answer your own questions.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

"You can return items within 7 days." (took a moment)
"You can return items within 7 days." (took a moment)
"I can help with orders, shipping and returns." (took a moment)
Scripting a failure: a rate limit, then a normal answer

This is how later phases practise failure on demand: the script decides when the "provider" says no. A real provider's 429 carries a retry-after header (seconds to wait), and the stand-in sends one too.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

status: 429 | retry-after: 20 | Rate limit reached.
status: 200 | Masala chai is black tea boiled with milk.
status: 200 | Masala chai is black tea boiled with milk.

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Return something that isn't a Response

In the first example, change the first handler's last line to return { greeting: "Hello" }; (a plain object, no Response.json).

terminal
$ Console
── what you'll see ──
(server) TypeError: serve(): the handler must return a Response
Uncaught SyntaxError: Unexpected token 'I', "Internal S"... is not valid JSON

Myth vs fact

Myth

The examples only work on this site.

Fact

Only serve and @hectal/fake-llm are specific to the editor. The browser code is standard, and each topic shows the real-project equivalent of the server part.

Myth

The stand-in model is a small real AI.

Fact

It has no intelligence. It returns scripted text with realistic timing. That is deliberate: it makes every example repeatable and checkable.

Myth

If it works with the fake model, it will work with a real one.

Fact

Your handling code will. But a real model adds variation, slower and uneven timing, and wrong answers. Labs and later phases prepare you for those.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The same trick is how professional teams test AI UIs. The Vercel AI SDK ships mock models and stream simulators for unit tests, and this course's fakeModel is built on them. You'll write tests this way in Topic 13.6: never call a real model in a UI test.

  • ▸

    The sandbox is an iframe with a unique, opaque origin and scripts allowed. That is why localStorage there is an in-memory copy that resets on each Run, why requests can't carry your cookies, and why nothing in an example can touch your Hectal account.

  • ▸

    Determinism here comes from logging on events (a token arrived, a state changed), never on wall-clock time. When you write your own demos or tests of streaming code, do the same: timers race with streams, events don't.

Remember this

  1. 1

    The problem this solves: A real AI feature needs a server, a paid account and a secret key, and a real model answers differently every time. None of that fits a lesson you can run with one click and compare with an expected result. This topic explains what the editor does instead, so you always know which parts of an example are real and which are stand-ins. Recall from Topic 0.2: the server in the middle is where the key and the checks live. In this editor serve() plays that part, and the stand-in model plays the provider.

  2. 2

    What is real. The JavaScript and React you see run in your browser, in a sandboxed frame. fetch, Response, ReadableStream, AbortController, TextDecoder and React are the browser's own. From Phase 5 the Vercel AI SDK (a popular library for AI features) is the real package too. If code works here, the same code works in your project.

  3. 3

    **serve(path, handler): a server inside the page.** The preview cannot reach a server, so the editor gives you one function that is not part of the browser: serve. You hand it a path and a handler, a function that receives a Request and returns a Response (the browser's standard objects for an incoming and an outgoing web message, the same ones fetch uses). After that, any fetch to that path runs your handler instead of the network. This is the same shape as a route handler on a real server, so the code moves to a real project almost unchanged: the function body stays, and serve("/api/chat", …) becomes a file such as app/api/chat/route.ts.

  4. 4

    **serve behaves like a connection, including when things go wrong.** If the handler throws, the browser side receives a 500 Internal Server Error response, and the Console shows a line starting (server) so you can see what the server would have logged. A path nobody serves fails with TypeError: Failed to fetch, the error a browser gives when a request cannot reach anything. Cancelling a request stops the handler's stream. You'll use all three to practise failures on purpose.

  5. 5

    The stand-in model. The package @hectal/fake-llm plays the part of the model. tokenStream(text) gives a stream of text pieces. fakeOpenAI(reply) gives a handler that speaks the same request and response format (the exact JSON and text layout sent over the network) as the OpenAI-compatible chat endpoints that many providers offer; you'll study it in Phases 1 and 2. fakeModel(reply) is a model for the AI SDK. Each answers from a script you write: a fixed sentence, a list of replies, or a function of the question. It waits a little before the first piece and between pieces, like a real model, and it can be told to fail in specific ways: a step such as { fail: { status: 429, retryAfter: 20 } } makes the call fail before any word, exactly like a rate limit (the third example below).

  6. 6

    Why scripted, and what you lose. A scripted model is deterministic: the same input gives the same output, every run. That lets each example show an *Expected console output* box and lets the site check every example automatically, so what you read is known to be true. The cost: the stand-in is not intelligent. It doesn't understand your question; it returns what the script says. Everything about *handling* a model is real here; the model's judgement is not.

  7. 7

    Real-model labs. Some topics include a lab: a small panel that sends a request to a real hosted model through Hectal's server and streams the true answer back. Use labs to see real behaviour: real variation, real speed, real refusals. Labs share a free quota across all learners, so there are only a few per phase, and a lab's answer is never part of a checked output, because it changes every time. When the quota is used up, the lab shows the error it received (a 429, for example) instead of an answer, which is itself a real rate limit to learn from. The rest of the lesson still works, because no other example depends on a lab.

  8. 8

    Reading the panels. The code is editable: change it and press Run (or Ctrl+Enter). The Preview shows the page. The Console shows every console.log, in order. Under it, *Expected console output* shows what the unmodified example prints, with a green tick when your run matches. A line starting Uncaught is an error your code didn't catch.

Explain it without notes

01

What does serve() do, and how does its handler relate to a real server route?

02

Why does this course use a scripted model instead of a real one for examples?

03

What are the three outcomes of a request shown in the first example, and how must browser code treat each?

Practice

01

Write a serve route /api/echo that returns the request's JSON body with an added field receivedAt: "server". Call it and log the result.

02

Write a script for fakeOpenAI that answers "Yes, we deliver there." when the question contains Pune or Mumbai, and "Sorry, we don't deliver there yet." otherwise.

Trade-offs

  • ↔

    A simulated model makes lessons repeatable and free, but it can hide how messy real output is. Use the labs, and treat every "happy" scripted answer as the easy case.

  • ↔

    Running the server part in the page shows both sides together, which is clearer for learning. In real projects keep them apart: code in a route file runs on the server and may hold secrets; code in a component runs in the browser and may not.

Done when you can

  • I can say which parts of a live example are real and which are simulated.

  • I can write a serve route and call it with fetch.

  • I can explain how a serve handler maps to a route file in a real project.

  • I can tell a failure response (500) from a rejected fetch and handle both.

  • I can script the stand-in model to give a chosen answer.