Skip to content

feat: add a Dictation mode setting (Fast / Smart) - #247

Merged
alexkroman merged 1 commit into
mainfrom
feat/rewrite-mode-setting
Oct 15, 2026
Merged

alexkroman merged 1 commit into
mainfrom
feat/rewrite-mode-setting

Conversation

@claude

@claude claude Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

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 RewriteMode enum (fast is the default, plus smart) and a RewriteModeStore (Sources/BlurtEngine/Config/RewriteModeStore.swift) follow the same pattern as TriggerActivation / TriggerActivationStore. That means a new DefaultsKey.rewriteMode case (BlurtRewriteMode), fromPersisted sending unset or unknown values to Fast, a picker that writes through the store, and @AppStorage that only observes. AssemblyAITranscriber reads the mode on every request through an injectable rewriteMode closure. The wire field is the dictation API's rewrite_mode option (smart | fast). It goes in as a top-level config key, alongside llm_instruction. The config has no nested llm block, 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 sends rewrite_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_mode and 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

RewriteModeTests covers 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 exactly channels, llm_instruction, sample_rate; with Smart it is "smart"; with Smart and Enhanced transcripts off it is absent. PersistedSettingsTests now includes the new key, and its key counts go from 17 to 18. The shared transcriber test helpers pin rewriteMode so no test reads the process's real UserDefaults.

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 on main; the Styles pane gains one row and one footer line.

  • scripts/check.sh passes (or CI will, if I'm not on a Mac)
  • I read AGENTS.md and this doesn't reintroduce anything deliberately removed
  • Docs updated if behavior changed

🤖 Generated with Claude Code

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
alexkroman marked this pull request as ready for review October 15, 2026 00:56
@alexkroman
alexkroman enabled auto-merge (squash) October 15, 2026 00:56
@alexkroman
alexkroman merged commit 9405b76 into main Oct 15, 2026
13 checks passed
@alexkroman
alexkroman deleted the feat/rewrite-mode-setting branch October 15, 2026 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants