Early development. New in 0.1.3: a frozen model server is restarted, a muted microphone is noticed, and frun bench measures how many callers your server takes. On one RTX 3090 with SGLang, twelve callers stayed under 1.5 s, counted from when they stopped talking. Long calls are still unmeasured.
open-weight · self-hosted · one command

STT, LLM and TTS
from one command, on your GPU.

Speech-to-text, the language model and text-to-speech run together on hardware you own and stream into each other, so a reply starts playing while it's still being generated. No per-minute API bills. No audio leaves your machine.

# install (Python 3.11 to 3.13)
$ pip install fusion-runtime
 
# pull the default models (~0.9 GB) and check your machine
$ frun models pull && frun doctor
 
# start the server
$ frun up
 
# open http://localhost:8000 and click Talk
# (or talk from a second terminal: frun talk)

How it works

One GPU, the whole conversation

Speech runs in fusion's own process. The language model runs there too, or on vLLM or SGLang on the same GPU for several callers at once; frun up starts it either way.

mic audio
→
Silero VADspeech only
→
faster-whisperrolling window
→
turn detectionsilence + resume
→
llama.cppor vLLM / SGLang
→
Kokoro TTSspeaks each sentence
→
audio out

A barge-in watcher runs alongside the pipeline: talk over the reply and generation and playback stop. The server decides that, because it hears clean audio — echo cancellation happens on the device, in the browser or in the terminal client, so it works on laptop speakers without headphones.


New in 0.1.3

A call you can trust

The ways a call breaks quietly, a frozen model server, a muted microphone, audio in the wrong format, a model running below strength, are noticed now, and either fixed or said out loud.

$ frun bench --audio order --callers 1,4,8,12,16 --target-ms 1500
   1 caller(s):  median   824 ms   worst   832 ms
  12 caller(s):  median  1440 ms   worst  3636 ms
Speech is where callers wait: stt went from 220 to 4553 ms from 1 to 16 caller(s),
while the LLM held (llm first token 49 ms).
Up to 12 caller(s) stayed under 1500 ms on this setup.

A frozen server is restarted

vLLM or SGLang that stays up but stops answering is restarted after 60 s, and warmed before callers reach it. /health says it's degraded while it's down.

A dead microphone is noticed

No audio, or only digital silence, for 3 s and the caller is told. Silence never reaches speech-to-text, even if the voice detector failed to load.

Measured, not promised

frun bench runs real callers against your server and says how many stayed under your target, and which stage made the rest wait.

Tested on an RTX 3090 with vLLM and SGLang. Model server docs →


Since 0.1.2

One command starts the model server too

Name vLLM or SGLang in the agent, and frun up starts it before speech loads, restarts it if it exits, and stops it with you. Install the engine once, in its own environment.

agent = Agent(
    prompt="You are the order line for ShopKart.",
    greeting="Hi, this is ShopKart. Which order can I help you with?",
    llm=LLM("vllm:hf:Qwen/Qwen2.5-7B-Instruct-AWQ"),   # or "sglang:hf:..."
)

Sized for one card

The server takes 60% of the GPU and speech the rest, so a 4-bit 7B model fits beside Whisper and Kokoro on 24 GB. If that much isn't free, frun up says what's holding it before anything loads.

The agent speaks first

A greeting plays the moment a caller connects, so nobody sits in silence wondering whether to talk. Talking over it stops it, like any reply.

Docker for any machine

A CPU image for laptops (Intel and Apple Silicon) and a GPU image that runs beside vLLM's own, each with a compose file. Logs come out as JSON for your log collector.

Measured on an RTX 4090: about 0.8–0.9 s from the end of a turn to the first audio, the LLM's first token in 23–55 ms. vLLM and SGLang docs →


Since 0.1.1

Agents that can look things up

A tool is a plain Python function. The model reads its name, docstring and type hints, calls it when it needs to, and answers with what it returned.

from fusion_runtime import Agent, LLM, tool

@tool
async def order_status(order_id: str) -> dict:
    """Look up where an order is and when it will arrive.

    Args:
        order_id: The order number, as the caller reads it out.
    """
    return await orders.lookup(order_id)

agent = Agent(prompt="...", llm=LLM("vllm:hf:Qwen/Qwen2.5-7B-Instruct-AWQ"), tools=[order_status])

No dead air

What the model says before a lookup ("Let me check.") is spoken while the tool runs. A second of silence on a call sounds broken.

Interruptions win

Talk over the wait and the agent stops, but a lookup that lands keeps its result for the next answer. A tool that fails or times out tells the model what went wrong instead of ending the call.

Lookups are remembered

Our first GPU test caught the agent inventing a second order's status: it remembered its answer but not that it came from a lookup. Lookups now stay in the conversation.

Tools need a model server that can call them: vLLM, SGLang, llama-server --jinja or a hosted API. The in-process llama.cpp model can't yet, and frun up says so at startup. Tools docs →


Measured, not estimated

About half a second from "…and that's my order" to the reply starting

The production profile exactly as it ships — RTX 3090 at $0.50/hour, Qwen 7B, Whisper small and Kokoro all on the one card — through the browser client, 21 September 2026. A stopwatch from your last syllable reads 991 ms; the extra half second is the runtime waiting through silence to decide you've finished, which elapses while you're still finishing. Both numbers are below.

 MedianRange
Processing — the turn ends, audio comes back~490 ms288–657 ms
Stopwatch from your last syllable991 ms858–1061 ms
  ↳ of which: silence wait before the turn is judged over~500 msconfigurable
Speech-to-text119 ms58–329 ms
LLM first token27 ms20–70 ms
First token → first audio (a sentence gets written, then spoken)430 ms320–509 ms
Text-to-speech real-time factor0.09~11× faster than real time
LLM tokens per second127106–130

Interruptions fired on six of six attempts, and correctly ignored 192 ms of speech over the agent. The point isn't that a GPU beats a laptop — it's that a 7 B model answers as fast as a 0.5 B did on an 8 GB MacBook Air, because the pause you configure and the first sentence of speech dominate, not the model. Every figure comes from the runtime's own per-turn telemetry, so you can reproduce them on your own hardware.

Several callers at once

Same 3090, real WebSocket sessions, three turns each, 26 September 2026. The server's own response time, turn end to first audio:

CallersModel in-process (llama.cpp)vLLMSGLang
1~460 ms398 ms410 ms
4~740 ms698 ms848 ms
8~4600 ms1086 ms1054 ms
12~7500 ms1083 ms1264 ms
16—2064 ms1598 ms

In-process, one llama.cpp context decodes one reply at a time, so four callers is the ceiling. vLLM and SGLang batch every caller together: the model's first token stayed between 36 and 72 ms from one caller to sixteen. What grows now is speech — Kokoro's first audio reaches 1.5–2 s at sixteen callers — so batching speech is what comes next. With every caller asking about an order, vLLM made the lookup in 122 of 123 turns; SGLang in 109, skipping only questions it had already looked up. Qwen2.5-7B-Instruct-AWQ, 60% of the card for the model.


On your site

Two script tags, no build step

The runtime serves the browser client it uses itself, so the page you demo with is the one your site embeds.

<script src="https://your-server/fusion-runtime.js"></script>
<button id="talk"></button>
<script>FusionRuntime.attach({ button: "#talk" });</script>

The browser's own echo canceller handles the speaker, the microphone is resampled off the main thread, and replies are scheduled slightly ahead of real time so network jitter doesn't leave gaps. The page never holds an API key — your backend mints it a token that works once. Microphones need https://, so a deployment needs TLS and wss://. Browser client docs →


Why run it this way

What owning the whole stack buys you

You own the latency

Every stage runs in your process. Profile and fix any millisecond yourself instead of waiting on a vendor's queue or incident.

Nothing leaves your machine

Audio and transcripts stay local by default. No third-party inference call in the default path — an architecture, not a config flag.

Zero per-minute cost

No API metering per stage. It runs on hardware you already pay for, so the marginal cost of another conversation is compute, not a bill.


The honest trade

Open weights are behind the best closed APIs — today

Whisper tiny isn't Nova-3. Qwen 0.5B/7B isn't GPT-4o. Kokoro isn't ElevenLabs. That trade is right for some teams and not others.

Good fit

  • Narrow-domain agents — reservations, order status, logistics updates, IVR replacement
  • Privacy / data-residency — teams that can't send audio to a third-party cloud
  • Cost-sensitive, high-volume — where per-minute API pricing is the line item that hurts
  • Local-first developers — kiosks, robots, desktop apps, single-board devices

Not (yet) a fit

  • Open-ended assistants that need frontier-model reasoning
  • More than about twelve callers on one GPU — with the model on vLLM or SGLang, twelve answer in about a second; at sixteen the speech stages start to queue, and they aren't batched across callers yet
  • Phone deployments — telephony isn't built yet
  • Guaranteed numbers under load — one to sixteen callers are measured on a 3090, with three short turns each; long calls are not

Hosted cloud, later

Not everyone wants to run their own GPU. We're planning a hosted version of fusion-runtime — no date yet, and it isn't built. If you'd rather not run infrastructure yourself, leave your email and we'll tell you when it's real. This isn't a waitlist for the open-source runtime — that's just pip install away.

No spam, one email when it ships. Unsubscribe anytime.