Skip to content

AssemblyAI Universal-3.6 Pro Realtime STT - #741

Merged
tschellenbach merged 4 commits into
acceleratefrom
model/assemblyai-stt
Oct 4, 2026
Merged

tschellenbach merged 4 commits into
acceleratefrom
model/assemblyai-stt

Conversation

@tschellenbach

Copy link
Copy Markdown
Member

Why

Universal-3.6 Pro Realtime (universal-3-6-pro, launched 2026-09-29) is first on Coval's streaming STT WER leaderboard (2.2% WER, 138 ms to final segment, October 2026). Artificial Analysis has not benchmarked it yet. It adds 32 languages with code-switching, keyterms and word-aware end-of-turn detection to the STT router.

Facts checked against AssemblyAI's own docs and pricing page, and confirmed on the live socket:

Fact Confirmed
Price $0.45/hr, billed on session duration, keyterms included
Auth Authorization: <api key>, no Bearer prefix (socket_test.go TestTheKeyTravelsAsItIsInTheAuthorizationHeader)
speech_model enum lists universal-3-6-pro, and Begin echoes it back as configuration.model

How it works

sequenceDiagram
    participant C as Call (20 ms frames)
    participant P as assemblyai.STT
    participant S as streaming.assemblyai.com/v3/ws
    P->>S: dial with speech_model, mode, keyterms_prompt, language_codes and Authorization
    S-->>P: Begin with configuration
    Note over P: refuse if the model or preset differs from what was asked
    C->>P: ProcessAudio 20 ms
    P->>S: binary PCM, gathered to at least 50 ms and split at 1000 ms
    S-->>P: Turn with end_of_turn false
    P-->>C: Transcript ModeReplacement
    S-->>P: Turn with end_of_turn true
    P-->>C: Transcript ModeFinal
    C->>P: Close
    P->>S: tail padded to 50 ms, then Terminate
    S-->>P: last Turn, Termination, close 1000
Loading
Change Result Proven by
Begin check (assemblyai.go:351) unknown params are silently ignored, so a misspelled model or preset fails at Start TestAMisspeltModelIsRefusedRatherThanServedByTheDefault (live), TestASessionOpenedOnAnotherModelIsRefused
Frame gathering (assemblyai.go:389) the server rejects frames under 50 ms with 3007 TestCallAudioIsGatheredIntoFramesTheServerAccepts, live suite at ChunkMs: 20
Default mode=max_accuracy balanced ended a turn at the 390 ms pause after "a map." in the fixture TestACallGetsThePresetThatDoesNotEndATurnMidSentence, live TestWordsArriveWhileTheCallerIsStillSpeaking
Terminate on Close (assemblyai.go:410) the tail settles, and billing stops when the call ends TestClosingSendsTheLastAudioAndAsksForTheTurnToSettle, live TestClosingSettlesTheTailOfTheCall
Registry and router.yaml silence_ms sets max_turn_silence. overwrites sets mode, min_turn_silence and max_turn_silence TestAssemblyAITakesItsPresetFromOverwritesAndRefusesOneItHasNot
sttsuite clock test AssemblyAI writes "party of 4" as a digit live TestAMidUtteranceClockTimeSettlesAsOneTranscript

What the router config declares, per router-stt:

Supports Refuses (not declared)
keyterms (100 terms, 50 characters each), endpointing, realtime, 32 languages diarize, language detection, redaction, profanity filter. The model can do these, but nothing here sends them

The data policy is trains_on_data: "yes" and retention: unspecified, because self-serve accounts are in the model-improvement program until an admin opts out.

Live suite: all 8 tests pass against the real API, and the default turn settles about 760 ms after the last word. Free-tier accounts allow about 5 new sessions per minute. One earlier run, started straight after a burst of probe sessions, failed two tests in 60 ms each. That fits the rate limit, but I did not capture the error message, so it is unverified.

Changes

  • New package acceleration/internal/stt/assemblyai, with unit tests, fake-socket tests and the integration suite
  • Registry entry in sttrouter, plus a router.yaml entry for assemblyai/universal-3-6-pro
  • sttsuite accepts a digit for "four"
  • CHANGELOG.md entry
Open in Web Open in Cursor 

cursoragent and others added 3 commits October 4, 2026 05:03
AssemblyAI formats spoken numbers as digits, so the clock-time clip came back as "party of 4" and failed a check that only knew the word.

Co-authored-by: Thierry Schellenbach <thierryschellenbach@gmail.com>
Streams 16 kHz PCM to the v3 socket, gathering 20 ms call frames into the 50-1000 ms the server takes, and refuses a session whose Begin reports another model or preset, since unknown query parameters are silently ignored. Close sends Terminate so the tail settles. Calls default to the max_accuracy preset: balanced ends a turn at a 390 ms pause mid-sentence.

Co-authored-by: Thierry Schellenbach <thierryschellenbach@gmail.com>
Registers the provider, maps silence_ms to max_turn_silence, reads mode and the two turn silences from overwrites, and lists the model in router.yaml at $0.45 an hour with keyterms and endpointing.

Co-authored-by: Thierry Schellenbach <thierryschellenbach@gmail.com>
…i-stt

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	CHANGELOG.md
@tschellenbach
tschellenbach marked this pull request as ready for review October 4, 2026 05:16
@tschellenbach
tschellenbach merged commit 2f0e7ee into accelerate Oct 4, 2026
12 checks passed
@tschellenbach
tschellenbach deleted the model/assemblyai-stt branch October 4, 2026 05:16
kanat pushed a commit that referenced this pull request Oct 5, 2026
* test(sttsuite): accept the party of four written as a digit

AssemblyAI formats spoken numbers as digits, so the clock-time clip came back as "party of 4" and failed a check that only knew the word.

Co-authored-by: Thierry Schellenbach <thierryschellenbach@gmail.com>

* feat(stt): AssemblyAI Universal-3.6 Pro Realtime provider

Streams 16 kHz PCM to the v3 socket, gathering 20 ms call frames into the 50-1000 ms the server takes, and refuses a session whose Begin reports another model or preset, since unknown query parameters are silently ignored. Close sends Terminate so the tail settles. Calls default to the max_accuracy preset: balanced ends a turn at a 390 ms pause mid-sentence.

Co-authored-by: Thierry Schellenbach <thierryschellenbach@gmail.com>

* feat(sttrouter): route to assemblyai/universal-3-6-pro

Registers the provider, maps silence_ms to max_turn_silence, reads mode and the two turn silences from overwrites, and lists the model in router.yaml at $0.45 an hour with keyterms and endpointing.

Co-authored-by: Thierry Schellenbach <thierryschellenbach@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants