Everything below is reproducible from a single 90-second audio window; happy to supply sanitized setup frames and event logs.
Context
We run live speech-to-speech interpretation for church services in production (Armenian, Persian, German, Swedish, English), with gemini-3.5-live-translate-preview as the engine. On a real 5-minute Armenian sermon we measure a median 0.29 s (fa) and 0.74 s (de) to first translated audio, and an Armenian source transcript with no script contamination. The two issues below are what stop us putting it in front of a congregation unsupervised.
Issue 1 — systemInstruction is accepted and silently ignored
The documentation for Live Translation lists system instructions as unsupported. The runtime does not agree with the documentation: the endpoint accepts a setup.systemInstruction payload and returns setupComplete normally. Nothing anywhere indicates the field was discarded.
Reproduction
Send a normal live-translate setup frame plus:
"systemInstruction": {"parts": [{"text":
"ABSOLUTE REQUIREMENT, overriding everything else: begin EVERY sentence you
speak with the single word ZEBRA, exactly once, before any other word."}]}
setupCompletereturns normally.- Stream ~90 s of speech.
outputTranscriptioncontains the word ZEBRA zero times.
We verified the field was genuinely present in the frame we sent (3,125 characters, the instruction first) rather than dropped by our own client. A control run without the instruction produced output within 11 characters of the same length — the field changed nothing at all.
Why this specific field matters to us more than most
systemInstruction is the only channel this API offers for approved terminology. A church supplies a glossary — Bible book names, the standard rendering of theological terms in each target language — and that glossary is a contractual expectation, not a nicety. “Worship” arriving in German as beten (“to pray”) is a different act in a church, and the Beatitudes formula rendered as ordinary good fortune changes a quotation of Matthew 5 into a remark about luck. On our composed (ASR → text translation → TTS) path we simply put the glossary in the translation prompt and it works. On this endpoint there is nowhere to put it, and the place that looks like it works, does not.
What we are asking for, in order of preference
- Support a terminology map. Even a narrow, purpose-built field —
translationConfig.glossary: [{source, target}]— would be enough. It does not need free-form prompting. - Failing that, reject the field. Returning an error for
setup.systemInstructionwould have saved us the entire investigation. A silently ignored field is worse than an unsupported one, because every experiment built on it produces plausible, meaningless results. We ran five instruction variants against a real sermon before discovering that none of them had ever been read. - Please also document
temperature/topPthe same way — they are in the same category and we tested one of them too.
A related question we could not answer
An earlier internal measurement (2026-07-28) found that naming the source language inside systemInstruction moved our Persian input transcript from ~74% to ~99.5% accuracy, reproducibly, 3 runs out of 3. That result is incompatible with the field being ignored. Either the model’s handling of this field changed between July and August 2026, or that measurement was confounded. If the behaviour did change, knowing that would help us a great deal — the API has no source-language field at all, so if the instruction channel ever worked for pinning it, losing it silently is a significant regression for auto-detect-prone languages.
Issue 2 — polarity reversals on long or self-interrupting sentences
This is the quality problem that actually blocks unsupervised use. The model occasionally produces a fluent sentence that asserts the opposite of the source. In a sermon this is the most damaging error possible, and because the output is fluent, nobody in the room can detect it.
Measured
Real Armenian sermon audio, 5 minutes, source hy, targets fa and de, sentence-aligned scoring against an independent transcript:
| target | reversals per 100 source sentences |
|---|---|
fa |
10.2 |
de |
4.1 |
Extrapolated to a 40-minute sermon that is roughly 16–40 reversed sentences per language, of which we judged about a third theologically consequential.
Examples (meaning of source → what was produced)
- “it is not a fact that this man will be saved” → German “es ist sicher, dass dieser Mensch gerettet wird” (it is certain that he will be saved).
- “the Lord gave to all his favoured heroes” → Persian “killed all his favourite heroes”.
- “they were provided for and were not in poverty” → Persian “lived in poverty”.
- “there are things even worse than poverty” → German “poverty is worse than other things” — the comparison inverted. Armenian marks the standard of comparison with the ablative, and the marked noun is being read as the greater side.
Two findings that may help you localise it
- It is not a recognition failure. The model’s own
inputTranscriptioncontains 21–23 negation markers against an independent ASR pass’s 24 on the same audio. It hears the negation and reverses it downstream. - It concentrates in long, self-interrupting sentences. Reversed sentences averaged 122 characters against a 53-character median, and 4 of 6 fell in the 5 longest sentences of the sermon. The worst — 256 characters, where the preacher interrupts himself twice — reversed independently in both target languages. Two specific sentences reversed in 8 German runs out of 8 across five different configurations, so at least part of this is deterministic rather than sampling noise.
Environment
- Model
gemini-3.5-live-translate-preview, Gemini Developer API (WebSocketBidiGenerateContent), paid tier. - Setup:
responseModalities: ["AUDIO"],translationConfig(targetLanguageCode,echoTargetLanguage: false),inputAudioTranscriptionandoutputAudioTranscriptionat the top level ofsetup(as required — not insidegenerationConfig, which contradicts the docs and is already reported by another user),contextWindowCompression.slidingWindow,sessionResumption,realtimeInputConfig.activityHandling: NO_INTERRUPTION. - Input PCM16 mono 16 kHz in 100 ms frames, streamed at wall-clock speed.
We can provide the audio, the full setup frames, and both transcripts for any of the runs above.