From 1bdd85621a384c92e47d0e4905853baa37dab30d Mon Sep 17 00:00:00 2001 From: Adam Urpsis Date: Thu, 10 Sep 2026 17:20:37 -0600 Subject: [PATCH 1/2] feat(dictation): add stt_prompt to DictationConfig The Dictation API takes a transcription prompt describing what the audio is about, distinct from the LLM rewrite instruction. `DictationConfig` had no field for it and rejects unknown keys, so SDK callers could not send one at all. Adds `stt_prompt`, capped at 4096 characters to match the service. The server also accepts `prompt` as an alias, but the SDK exposes only the one spelling: sending both is a 400, and no SDK release has ever accepted `prompt`, so there is no compatibility reason to carry two names. Co-Authored-By: Claude Opus 5 --- README.md | 3 ++- assemblyai/dictation/v1/models.py | 14 ++++++++++++-- tests/unit/test_dictation.py | 30 +++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b7f6d5bc..6330757c 100644 --- a/README.md +++ b/README.md @@ -790,6 +790,7 @@ aai.settings.api_key = "" config = aai.DictationConfig( language_codes=["en", "es"], # one code, or several for multilingual audio + stt_prompt="A doctor dictating a visit note.", # what the audio is about; ≤4096 chars keyterms_prompt=["AssemblyAI", "Universal"], # bias the decoder; ≤2048 chars total llm_instruction="Fix punctuation only.", # optional LLM pass ) @@ -797,7 +798,7 @@ config = aai.DictationConfig( result = aai.DictationTranscriber().transcribe_live("./note.wav", config=config) ``` -`sample_rate` and `channels` are required only for raw PCM; WAV carries them in its own header. A config passed to `transcribe_live()` or `open_live()` overrides the transcriber's default config for that call. `DictationConfig` rejects unknown fields, so a typo or a sync-only option surfaces as a validation error instead of a setting that quietly does nothing. +`stt_prompt` describes the situation the audio was recorded in and steers the decoder as it writes the transcript; `llm_instruction` reshapes that transcript afterwards. `sample_rate` and `channels` are required only for raw PCM; WAV carries them in its own header. A config passed to `transcribe_live()` or `open_live()` overrides the transcriber's default config for that call. `DictationConfig` rejects unknown fields, so a typo or a sync-only option surfaces as a validation error instead of a setting that quietly does nothing. diff --git a/assemblyai/dictation/v1/models.py b/assemblyai/dictation/v1/models.py index 6d5c0f30..7c689d5b 100644 --- a/assemblyai/dictation/v1/models.py +++ b/assemblyai/dictation/v1/models.py @@ -52,14 +52,15 @@ def __init__( _DICTATION_MAX_KEYTERMS_PROMPT_LEN = 2048 _DICTATION_MAX_LLM_INSTRUCTION_LEN = 2048 +_DICTATION_MAX_STT_PROMPT_LEN = 4096 class DictationConfig(BaseModel): """ Options for a Dictation API request. - `language_codes` and `keyterms_prompt` shape the transcript; - `llm_instruction` asks the server to run a follow-up LLM pass over it + `language_codes`, `stt_prompt` and `keyterms_prompt` shape the + transcript; `llm_instruction` asks the server to run a follow-up LLM pass over it (the rewrite lands in `DictationResponse.llm_response`). `sample_rate` and `channels` are required only for raw PCM audio — container formats carry them in their own headers. @@ -87,6 +88,15 @@ class DictationConfig(BaseModel): `["en", "es"]`) for multilingual audio. Defaults to None, which leaves the language to the server's default.""" + stt_prompt: Optional[str] = Field( + default=None, max_length=_DICTATION_MAX_STT_PROMPT_LEN + ) + """Context for the transcription: a description of what the audio is + about, e.g. "A doctor dictating a patient visit note." It describes the + situation rather than instructing the model, and steers the decoder as it + writes the transcript — where `llm_instruction` reshapes the transcript + afterwards. Max 4096 characters.""" + keyterms_prompt: Optional[List[str]] = None "Keyterms biasing the decoder. Whitespace is stripped and empty terms dropped. Max 2048 characters total." diff --git a/tests/unit/test_dictation.py b/tests/unit/test_dictation.py index ebff0e22..6ae74a8b 100644 --- a/tests/unit/test_dictation.py +++ b/tests/unit/test_dictation.py @@ -555,7 +555,35 @@ def test_config_rejects_unknown_fields(): # Given an option the Dictation API does not accept # When building the config, then it is rejected rather than dropped with pytest.raises(ValueError): - aai.DictationConfig(prompt="Transcribe verbatim.") + aai.DictationConfig(word_boost=["AssemblyAI"]) + + +def test_config_rejects_the_prompt_spelling(): + # Given the server-side alias for stt_prompt + # When building the config, then the one spelling the SDK exposes wins — + # sending both is a 400, so there is nothing to gain from accepting two + with pytest.raises(ValueError): + aai.DictationConfig(prompt="A doctor dictating a visit note.") + + +def test_transcribe_live_sends_stt_prompt(httpx_mock: HTTPXMock): + # Given a mocked live endpoint + _mock_ok(httpx_mock) + + # When streaming with transcription context + config = aai.DictationConfig(stt_prompt="A doctor dictating a visit note.") + aai.DictationTranscriber().transcribe_live(_chunks(b"RIFF"), config=config) + + # Then the config part carries it under the name the API documents + body = httpx_mock.get_requests()[0].read() + assert b'"stt_prompt"' in body + assert b"A doctor dictating a visit note." in body + + +def test_stt_prompt_too_long_raises(): + # Given an stt_prompt exceeding the 4096-char cap + with pytest.raises(ValueError): + aai.DictationConfig(stt_prompt="x" * 5000) def test_keyterms_prompt_too_long_raises(): From b0b0d991bc9722be8a92068e3c8dd1dabbb9a80b Mon Sep 17 00:00:00 2001 From: Adam Urpsis Date: Thu, 10 Sep 2026 17:30:31 -0600 Subject: [PATCH 2/2] chore: bump version to 1.5.1 Co-Authored-By: Claude Opus 5 --- assemblyai/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assemblyai/__version__.py b/assemblyai/__version__.py index 5b601886..0f228f25 100644 --- a/assemblyai/__version__.py +++ b/assemblyai/__version__.py @@ -1 +1 @@ -__version__ = "1.5.0" +__version__ = "1.5.1"