Repository navigation
feat: add a Dictation mode setting (Fast / Smart) - #247
Merged
Merged
Conversation
Adds RewriteMode (fast default, smart opt-in) persisted by RewriteModeStore under a new DefaultsKey case, mirroring the trigger-activation setting. Smart sends the dictation API's config.rewrite_mode: "smart"; Fast omits the key so the default request is unchanged; nothing is sent while enhanced transcripts are off, since that rewrite is discarded unread. Settings > Styles gains a "Dictation mode" picker under the Enhanced transcripts switch, disabled with it. Co-Authored-By: Claude <noreply@anthropic.com>
alexkroman
marked this pull request as ready for review
October 15, 2026 00:56
alexkroman
enabled auto-merge (squash)
October 15, 2026 00:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Before: Every dictation's cleanup rewrite ran on the dictation API's fast model, and there was no way to choose another one.
After: Settings › Styles has a Dictation mode picker (Fast / Smart) under the Enhanced transcripts switch. A footer line explains it: "Smart uses a larger model for better rewrites; Fast is quicker." Fast is the default, so nothing changes for anyone who leaves it alone. When Enhanced transcripts is off, the picker is greyed out, the same way the Custom Styles section is.
How: A new
RewriteModeenum (fastis the default, plussmart) and aRewriteModeStore(Sources/BlurtEngine/Config/RewriteModeStore.swift) follow the same pattern asTriggerActivation/TriggerActivationStore. That means a newDefaultsKey.rewriteModecase (BlurtRewriteMode),fromPersistedsending unset or unknown values to Fast, a picker that writes through the store, and@AppStoragethat only observes.AssemblyAITranscriberreads the mode on every request through an injectablerewriteModeclosure. The wire field is the dictation API'srewrite_modeoption (smart|fast). It goes in as a top-levelconfigkey, alongsidellm_instruction. The config has no nestedllmblock, so this is the only place that fits the current request shape. That placement is an assumption: I couldn't reach the API reference from the environment I worked in. Fast leaves the key out instead of sending"fast", so the default request is byte-for-byte what ships today. Smart sendsrewrite_mode: "smart". While Enhanced transcripts is off, the key is never sent, because that rewrite gets thrown away unread and the larger model would only add latency.Before merging, please confirm that the dictation API reference documents
rewrite_modeand where it goes, per AGENTS.md's "call the API only the way its docs describe" rule.Not built: retrying Smart with Fast when it fails. The upload is streamed from the microphone while the user is still speaking, and nothing keeps the audio afterwards. A retry would need a new buffering path, which is far more than a few lines. A Smart rewrite that misses the server's budget already falls back to the verbatim transcript (
llm_error,transcript(from:)) instead of failing the dictation. A retry or fallback is a possible follow-up. The iPhone app's settings are unchanged: it reads the same store, gets Fast, and so behaves as before.How it was tested
RewriteModeTestscovers the default, the round-trip, and the unknown-value fallback. It also covers the request: with Fast the key is absent and the config's keys are exactlychannels,llm_instruction,sample_rate; with Smart it is"smart"; with Smart and Enhanced transcripts off it is absent.PersistedSettingsTestsnow includes the new key, and its key counts go from 17 to 18. The shared transcriber test helpers pinrewriteModeso no test reads the process's realUserDefaults.I ran
scripts/check.sh --portable(passes, including the settled-decision invariants with the new files included) and checked line lengths. These were written on Linux, so the Swift build,swift test, the coverage gate, swift-format and swiftlint, periphery, and the UI tests have not run. CI on macOS is the authority on whether this is green. No Settings-pane height test exists onmain; the Styles pane gains one row and one footer line.scripts/check.shpasses (or CI will, if I'm not on a Mac)🤖 Generated with Claude Code