1. Waiting for a complete transcript before starting the LLM
Symptom
Every response feels a beat late, no matter how fast the model is.
The pattern
const transcript = await stt.transcribe(audioBuffer); // waits for silence
const reply = await llm.complete(transcript); // waits for full reply
const speech = await tts.synthesize(reply); // waits for full audio
await publish(speech);Why it bites
Each stage waits for the one before it to finish completely, so the user hears nothing until the sum of all three elapses. The pipeline is capable of overlapping almost all of that work — this shape simply forbids it.
The fix
// Overlap the stages: stream partials forward as they arrive.
stt.on("interim", (text) => llm.prime(text));
stt.on("final", async (text) => {
const stream = await llm.stream(text);
for await (const chunk of stream) {
// Synthesize and publish sentence-by-sentence — first audio in ~300ms
// rather than after the full completion.
tts.push(chunk);
}
});