Skip to content

Raise the dictation recording cap from 2 to 20 minutes - #251

Draft
claude[bot] wants to merge 1 commit into
mainfrom
dictation-20-minute-cap
Draft

claude[bot] wants to merge 1 commit into
mainfrom
dictation-20-minute-cap

Conversation

@claude

@claude claude Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What & why

Before: a held dictation stops itself at ~1m55s (SyncSTTLimits.maxAudioSeconds 120 s minus the 5 s auto-release margin). Anything said after that is lost.

After: it stops itself at ~19m55s (1195 s). The dictation API now accepts 20-minute audio, so the cap moves to match.

How: the change is constants, the limits that follow from them, tests, and docs.

  • SyncSTTLimits.maxAudioSeconds: 120 → 1200. autoReleaseMargin stays 5 s, so autoReleaseSeconds (the default DictationSession.maxRecordingSeconds on Mac and iPhone) goes 115 → 1195.
  • iPhone keyboard staleness, SharedState.inFlightStaleAfter: already derived as cap + 10, so it moves 130 → 1210 s by itself. SharedStateTests.inFlight hard-coded 120/131 and now uses 1200/1211.
  • iPhone listening window: DictationCoordinator extends the window when a dictation starts, and that extension is now at least maxAudioSeconds (ListeningWindow.extend(atLeast:)). Before this, the 5- and 15-minute "Keep listening for" settings would hit windowClosingOnItsOwn and release a dictation partway through. That never happened under a 2-minute cap.
  • New SyncSTTLimitsTests.audioCapPinned test pins 1200 / 1195.
  • Comments and docs that named 120 s, 115 s or "two minutes": AGENTS.md, Sources/BlurtEngine/README.md, App/BlurtiOS/DESIGN.md, AssemblyAITranscriber, DictationKeyTap, HotkeyRaceTests.

Checked and left alone:

  • Request timeout (AssemblyAITranscriber.requestTimeoutSeconds, 90 s): this is an idle timeout. It resets every time bytes move, and the chunked upload sends audio the whole time the user is speaking. It only limits a stall, such as the wait after the last frame. It is the client timeout the API documents, so it is unchanged.
  • Upload size and memory: there is no byte cap or chunk-count cap. Audio streams into one chunked request while the user speaks (ChunkedRequestBody holds 32 kB), and MicCapture.stop() returns a byte count, not the audio. The only buffering that grows is the frame stream, and only when the uplink is slower than realtime. At 16 kHz mono S16LE (32,000 B/s), the worst case for 20 minutes is about 38.4 MB.

Worth checking by hand on a real long dictation, because a 2-minute cap never tested these:

  • The post-speech wait for a 20-minute clip stays under the 90 s idle timeout.
  • The server-side rewrite (it has a 5 s budget) still returns llm_response for a transcript that long. If it doesn't, the client falls back to the verbatim text, with no error.

How it was tested

Written in a Linux sandbox with no Swift toolchain, so nothing was built or tested locally. CI on macOS is the authority. scripts/check.sh --portable passes: prettier, the invariants, shell portability, ruff and pytest, release-lib tests, release-notes lint. swift-format, swiftlint, markdownlint, shellcheck, shfmt, jscpd, actionlint and zizmor weren't installed, so they were skipped. Changed Swift lines were checked against the 120-column limit.

  • 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

The dictation API now accepts 20-minute audio, so SyncSTTLimits.maxAudioSeconds
goes from 120 to 1200. The 5 s auto-release margin is unchanged, so a held
trigger now stops at 1195 s (19 min 55 s) instead of 115 s.

The iPhone keyboard's in-flight staleness (SharedState.inFlightStaleAfter)
derives from the cap and follows it to 1210 s; its test moves with it. The
iPhone listening window is now extended to at least the cap when a dictation
starts, so the 5- and 15-minute "Keep listening" settings can't release a
long dictation partway through.

Docs and comments that named 120 s / 115 s / two minutes are updated, and a
new test pins the cap and the auto-release point.

Co-Authored-By: Claude <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant