AI integration
flowRS works with language models in the ways below, and each has a stated limit. None of them changes your graph, or anything attached to your computer, until a person says yes.
- The server agent answers the agent bar. It runs on flowrs-server, which calls a hosted model.
- Local AI runs an open model on your GPU, inside the browser tab, through WebLLM.
- The voice speaks the agent's replies with Kokoro, also inside the tab, and listens through the browser's own speech recognition.
- Tools for other agents: the Model Context Protocol, over stdio and over HTTP, the Reactive Agent Protocol for runtimes that hear about long work by callback, and WebMCP inside the page.
- Agent threads: an agent that can wait for a build, a run or your decision, for days if it must. In your browser it is kept on your machine and moves only while a tab is open; on a server you run, it moves while that server runs. See Agent threads.
This page replaces an earlier one that described Transformers.js and Qwen2.5-0.5B loaded from a CDN. That path is gone from the IDE. The page's Content-Security-Policy now refuses every model hub and CDN, and both in-browser models load only from this site's own mirror (below). The old CDN loader and the Rust crate that wrapped it are deleted from the repository.
What runs where
| Feature | Where it runs | Model | What it needs |
|---|---|---|---|
| Agent bar | flowrs-server, which calls the Anthropic Messages API | claude-sonnet-5-5 unless ANTHROPIC_MODEL names another | a server with an API key (ANTHROPIC_API_KEY_FILE or ANTHROPIC_API_KEY) |
| Local AI | your browser, on WebGPU | WebLLM's MLC builds of Llama 3.2 1B, Qwen2.5 3B and Llama 3.1 8B | WebGPU, and the site's model mirror |
| Spoken replies | your browser, in WebAssembly | Kokoro 82M (ONNX, 8-bit), voice af_heart | the site's model mirror |
| Speech input | your browser's Web Speech API | the browser's own recognizer | a browser that has one |
ai.complete nodes | your browser, on the Local AI model | whichever model Local AI loaded | Local AI loaded; otherwise a stand-in answers |
| MCP | flowrs-mcp over stdio; flowrs-server at POST /mcp | the client's own | an agent token for the HTTP endpoint |
| RAP | flowrs-server at POST /rap/invoke | the runtime's own | an agent token, a journal and FLOWRS_RAP_CALLBACK_ORIGINS |
| WebMCP | the page, for an agent the browser runs | the client's own | a browser that offers document.modelContext |
The server agent
Type what you want in the agent bar. The request carries your prompt and the graph that is open. The model sees that graph as typed code (the graph DSL) together with the nearest verified examples, and answers with a patch, not a whole new graph.
The patch then goes through the checker (flowrs_core::graph::verify). Its stages, by the names the code gives them, are:
parse: the patch is read.apply: it is applied to a copy of your graph.types: every wire still joins ports whose types agree.structure: the graph is still well formed.codegen: Rust is generated from it.compile: that Rust is checked by the compiler (cargo check) on the server.tests: the graph runs in the interpreter.tiers: the interpreter's run and the compiled program's agree.ledger: the choices the model made that you did not ask for are listed.
An edit that carries an app is also checked against the app's own rules (app). A stage that fails sends its findings back to the model, which may repair the patch over a few rounds. What reaches you is a proposal with each stage's result. Nothing is applied until you press Apply, and Discard leaves your graph as it was. When several reasonable designs exist, the agent can return alternatives, each checked the same way. When too many consequential choices are left open, it asks a question instead.
While a graded lesson is open, the agent follows the lesson's mode: in Tutor mode it gives hints and no patch, and in a solo challenge it does not edit at all.
The public server meters the agent, per visitor and per day, with a token budget per turn and per day (crates/flowrs-server/src/config.rs). A refused request says which limit it hit. With no server, no key or no allowance left, the agent bar falls back to the copilot, a set of deterministic rules that build a few common graphs with no model at all, and it tells you that it did.
Local AI: an open model in your tab
Open 💻 Local AI, pick a model and press Download & load. The panel shows each model's download size. The runtime is a vendored copy of web-llm 0.2.79 (Apache-2.0), served from this site. The weights and the compiled model library come from /ide/models/ on the same origin, and from nowhere else. If a model is not in the mirror's manifest, the panel says so and loads nothing. The browser keeps the downloaded weights, so the model works offline after the first load.
WebLLM needs WebGPU. Without it, loading fails with the runtime's own message, and there is no slower fallback for chat.
Local AI runs the same edit loop as the server agent, with one difference: no Rust compiler runs in a browser. So compile and tiers are reported as skipped, with that reason, and never as passed. The interpreter's tests stage does run. Its edits are proposals, labelled with the model that made them, and you review them as you would the server agent's.
The loaded model also answers ai.complete nodes when the graph runs in the page, one question at a time. In a generated program, and in the page when no model is loaded, ai.complete is a stand-in: a deterministic local answer, labelled flowrs-local, and the node reference marks it as one.
The voice
The agent's replies can be spoken. Speak replies with Kokoro is on by default. Kokoro is an 82-million-parameter text-to-speech model, run in the tab with ONNX Runtime's WebAssembly build, and it speaks sentence by sentence as the reply arrives. It runs in a worker of its own, so the editor stays responsive while a reply is spoken. The first spoken reply fetches its weights, about 90 MB, which the browser then keeps. Its weights and its voice come only from the site's model mirror. Without a mirror the replies are not spoken, and the IDE says why.
Speak your intent uses the browser's Web Speech API. The transcript is submitted to the agent as if you had typed it. flowRS runs no speech recognizer of its own, so the browser decides where the audio goes, and some browsers send it to their vendor's service.
The model mirror
/ide/models/ is served by flowrs-server from the directory FLOWRS_MODELS_DIR names, outside the site's own files. scripts/mirror-model.sh fetch fills it from scripts/models.lock.json:
- every file is pinned to an exact commit of its repository, with its size and SHA-256;
- each download is checked against its SHA-256 before it is renamed into place, so a file that does not verify is never put where the server would send it;
manifest.json, which the IDE reads, is written last, and only when every file has verified.
A file under a pinned commit's path is served as cacheable for a year, because its bytes cannot change at that URL. The manifest is revalidated on every use. A server with no mirror answers 404 there, and the IDE says that Local AI and the voice are unavailable. A test keeps the lock in step with the models the Local AI panel offers.
Tools for other agents
- flowrs-mcp is a Model Context Protocol server over stdio (protocol 2025-06-18, and it accepts the two earlier revisions). Its tools build, check, explain and run graphs and read the generated Rust. A session's profile decides which tools a client sees.
- flowrs-server speaks MCP 2026-07-28 over Streamable HTTP at
POST /mcp, with Tasks for long calls. It needs the agent's token (FLOWRS_AGENT_TOKEN) and refuses a person's, checks the request'sOrigin, and defaults to theplanprofile. Its tools act on twins and mock instruments, never on real hardware. An agent that wants to act on an instrument files a proposal, a person decides it in the Review level, and the decision is kept in a hash-chained audit log. - WebMCP: the page registers its graph and instrument tools with
document.modelContext, and withnavigator.modelContextin a browser that has only the older interface. The Local AI panel has Withdraw agent tools and Offer agent tools. In the browser, a proposed patch reports the compile and the tier comparison as not run.
What stays in your browser
- A program an agent receives for a graph that reads neural data carries zeros in place of every recorded sample. It has the same shape and none of the values.
- An app binds its readings by reference, so no sample travels to a model. Data an app exports becomes a count, a minimum, a maximum and a mean.
- Your lesson records live in the browser's private file store. A request to the agent carries only which item you are on and whether you have mastered it.
- Local AI and the voice run entirely in the tab. Your prompt to Local AI goes to no server.
What it does not do
- It loads no model, and no model code, from a hub or a CDN at run time.
- It does not claim a check it did not run: Local AI's compile is "skipped", never "passed".
- It applies no change, and drives no instrument, without a person.