Skip to content

fix(vscode): accelerate macOS speech capture - #12814

Merged
marius-kilocode merged 1 commit into
mainfrom
optimize-stt-initialization-performance
Aug 3, 2026
Merged

fix(vscode): accelerate macOS speech capture#12814
marius-kilocode merged 1 commit into
mainfrom
optimize-stt-initialization-performance

Conversation

@marius-kilocode

@marius-kilocode marius-kilocode commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

macOS voice input currently launches FFmpeg for every recording even though the platform already provides AVFoundation. FFmpeg process creation is inexpensive, but its AVFoundation capture path accounts for most of the delay before the UI can safely report that recording has started.

This change records 16 kHz mono PCM WAV audio through AVFoundation using the built-in macOS JavaScript bridge. Readiness is emitted only after AVAudioRecorder.record() succeeds, so the UI does not become optimistic and the beginning of speech is not clipped. The microphone remains closed while idle. If native capture fails, Kilo falls back to the existing bundled FFmpeg path. KILO_FFMPEG_PATH and FFMPEG_PATH continue to force FFmpeg explicitly.

Trigger-to-recording metric FFmpeg Native AVFoundation Change
Median 458.8 ms 222.7 ms 51.5% faster
p95 (nearest rank) 845.8 ms 441.9 ms 47.8% faster
Slowest run 852.2 ms 442.8 ms 48.0% faster

The comparison uses 20 capture-only starts per implementation in the same isolated VS Code environment with microphone permission already granted. Each recording is stopped and cancelled before transcription, so the numbers measure trigger-to-recording readiness rather than network or model latency.

Overhead Impact
npm/Bun dependency tree 0% increase. No package manifest or lockfile changes.
New binary/framework package 0. The implementation uses macOS /usr/bin/osascript, AVFoundation, and Foundation already provided by the OS.
Extension bundle Approximately 1.1 KB of inline script, about 0.014% of the current 8.47 MB extension bundle.
VS Code package size No increase. The existing FFmpeg fallback remains bundled.
Recording CPU No measurable change, about 0.08 seconds of user/system CPU for a one-second capture in the comparison.
Recording memory Native helper peak RSS is about 40 MB versus 30 MB for FFmpeg, approximately +10 MB or +33% while recording. The process exits after each recording.

Platform Scope And Risks

Platform Behavior Deployment implication
macOS Uses native AVFoundation by default, then falls back to FFmpeg if startup fails. Requires the standard macOS osascript and AVFoundation components. TCC, device, format, or managed-device restrictions can reject the native path. A native startup failure can pay the existing five-second readiness timeout before fallback.
Windows Existing FFmpeg capture path is unchanged. No new Windows dependency or native code path. The macOS speedup does not apply.
Linux Existing FFmpeg, PipeWire, PulseAudio, and ALSA paths are unchanged. No new Linux dependency or native code path. The macOS speedup does not apply.

The native script is static and receives the temporary output path as a separate argument. It does not interpolate user input into executable code. The output format remains the existing 16 kHz mono PCM WAV contract used by transcription.

The separate follow-up PR #12821 only improves macOS NSError diagnostics when native startup fails; it does not change capture behavior.

Comment thread packages/kilo-vscode/src/speech-to-text/capture.ts Outdated
Comment thread packages/kilo-vscode/src/speech-to-text/capture.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/kilo-vscode/src/speech-to-text/capture.ts 51 The NSError populated by initWithURLSettingsError is never read, so native capture failures fall back with only a generic log message
Files Reviewed (3 files)
  • packages/kilo-vscode/src/speech-to-text/capture.ts - 1 issue
  • packages/kilo-vscode/tests/unit/speech-to-text-capture.test.ts - 0 issues
  • .changeset/faster-macos-speech.md - 0 issues

Notes: re-reviewed at cd7d053 after the PR was reworked to native AVFoundation capture. Startup now awaits the mac and FFmpeg paths and returns booleans, and resolveFFmpeg() caches only the binary path while device enumeration runs per start, so a transient enumeration failure no longer discards the resolved binary. Stop flow closes stdin, letting the helper finalize the WAV before exit; stderr buffering stays bounded and startup listeners are removed on settle, so no new unbounded retention was found.

Fix these issues in Kilo Cloud

Previous Review Summary (commit 3aa37f2)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 3aa37f2)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-vscode/src/speech-to-text/capture.ts 71 return instead of return await lets finally clear starting before startup completes, reopening the concurrent-start window during candidate fallback and the Windows device refresh

SUGGESTION

File Line Issue
packages/kilo-vscode/src/speech-to-text/capture.ts 284 Merging device enumeration into the binary cache discards a resolved ffmpeg path when enumeration fails, forcing a full findFFmpeg() re-probe next time
Files Reviewed (3 files)
  • packages/kilo-vscode/src/speech-to-text/capture.ts - 2 issues
  • packages/kilo-vscode/tests/unit/speech-to-text-capture.test.ts - 0 issues (tests exercise real exports, no mocks)
  • .changeset/faster-speech-capture.md - 0 issues (user-facing wording is fine)

Notes: reviewed handler.ts and input-tools.ts for context on lifecycle/cancel flows and prewarm rejection handling; both handle the new promise shapes. Readiness buffering is bounded to 4000 chars and stderr listeners are removed on resolve/reject, so no new unbounded retention was found.

Fix these issues in Kilo Cloud


Reviewed by kimi-k3 · Input: 62.7K · Output: 15.5K · Cached: 400.4K

Review guidance: REVIEW.md from base branch main

@marius-kilocode
marius-kilocode force-pushed the optimize-stt-initialization-performance branch from 3aa37f2 to cd7d053 Compare August 3, 2026 15:10
@marius-kilocode marius-kilocode changed the title fix(vscode): speed up speech capture setup fix(vscode): accelerate macOS speech capture Aug 3, 2026
const error = Ref()
const url = $.NSURL.fileURLWithPath(args[0])
const recorder = $.AVAudioRecorder.alloc.initWithURLSettingsError(url, settings, error)
if (!recorder || !recorder.prepareToRecord || !recorder.record) throw new Error("Could not start recording")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: The NSError populated by initWithURLSettingsError is never read

When AVAudioRecorder initialization fails, the script throws a generic Could not start recording, discarding the NSError captured in the error Ref (error[0]). Native capture failures only surface through the console.warn fallback log, and on this brand-new platform-specific path failures will be heterogeneous (TCC denial, device busy, unsupported format keys) — including the underlying localizedDescription in the thrown message would make user bug reports much more actionable. Note osascript-thrown JS errors do reach summary() via stderr, so this only affects the explicit throw here.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@marius-kilocode
marius-kilocode merged commit 3e88ec9 into main Aug 3, 2026
24 checks passed
@marius-kilocode
marius-kilocode deleted the optimize-stt-initialization-performance branch August 3, 2026 15:21
@marius-kilocode
marius-kilocode restored the optimize-stt-initialization-performance branch August 3, 2026 15:37
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
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