Skip to content

feat: whisper context lifecycle, constrained generation, and a home slot - #626

Open
dishit-wednesday wants to merge 19 commits into
devfrom
feat/sidecar-pipeline
Open

feat: whisper context lifecycle, constrained generation, and a home slot#626
dishit-wednesday wants to merge 19 commits into
devfrom
feat/sidecar-pipeline

Conversation

@dishit-wednesday

@dishit-wednesday dishit-wednesday commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Core capabilities plus a submodule pointer bump. No product code here - the changes are to whisper's context lifecycle, model loading, constrained generation, and the home slot registry.

Whisper context lifecycle

The transcription context is now safe under a second, long-running consumer. Three ways it could be lost or corrupted underneath a caller:

  • One shared in-flight load. Two callers racing to load the model each got their own context; one was leaked. They now share the single in-flight promise.
  • Eviction is vetoed during a file transcribe. Memory pressure could evict the context out from under a decode that was still running.
  • The context resets after a wedged transcribe, so one hung call cannot hold it indefinitely. Previously the only recovery was restarting the app.

maxThreads is also passed through transcribeFile, where it was being silently dropped.

Model loading

  • skipVision - a text-only load that leaves the projector on disk, for callers that will never send an image.
  • Paired with a fix so a text-only load no longer satisfies a caller that asked for vision. That was the bug that made the flag safe to add rather than dangerous: without it, skipVision could poison a later vision request.

Constrained generation

llmConstraints collects grammar, repeat-penalty and thinking overrides into one module, accepted by generateWithMaxTokens as ConstrainedCompletionOpts. Each override was previously threaded through separately.

Slots

A home.recorder slot, rendered above recent conversations. Core declares the slot; anything may fill it or not. A build without the submodule renders nothing and behaves exactly as before.

Build and test config

ios/Podfile.lock, jest.config.js and react-native.config.js move so the submodule autolinks by root only, declares its own platforms, and runs its suite from the root config.

Reviewing this

19 commits, 14 files, +233/-45. Three are submodule pointer bumps; the rest are the changes above, from a lineage that had no open PR - so this is the first time they are proposed for dev.

Not device-verified. The whisper changes in particular are reasoned and unit-tested, not observed on hardware under real memory pressure.

dishit-wednesday and others added 19 commits August 7, 2026 10:13
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
…on disk

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
…sion

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
…eak contexts

Observed on device: 4 native contexts at 406MB each, none releasable, kernel killed the foreground app at 1.85GB swap.

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Unloading mid-decode cancels the native job and whisper.rn returns empty, so the clip reads as transcribed-to-nothing rather than as interrupted.

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
…babel config

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
… platforms

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
pro/ has its own package.json, so a test living inside it resolved no Babel
config at all. Naming the config crosses that boundary - scoped to pro's own
tests, because setting it globally disables per-package .babelrc lookup inside
node_modules, which several React Native libraries rely on.

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
… forever

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
Pointer only. Everything the bump carries is private to the pro submodule - the
native VAD sidecar, the logical conversation projection, and the conversation-first
worker that finishes the oldest ended conversation before touching anything newer.

Nothing in core changes: locket is still reached through the same feature registry
entry it was before, which is what makes a change of this size a one-line commit
here.

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
… doc

Carries the todo source-playback fixes - per-clip ranges for a conversation that
crossed a file roll, and resolving a recording's stored `.wav` name to the `.m4a`
that replaced it - plus the pipeline architecture document.

Co-Authored-By: Dishit Karia <hanmadishit74@gmail.com>
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: db6ee165-a015-4d5b-9a00-aba2b571ff27

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

// vision. Without this, a background load that skipped the projector to save memory would leave
// chat unable to see images and no path back: the id matches, so every later load short-circuits
// and the projector is never initialised.
return !(needsVision && model?.mmProjPath && !llmService.getMultimodalSupport()?.vision);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Same-model vision upgrade is skipped

When a model is first loaded with skipVision and later requested for vision, this check correctly rejects the text-only context, but the same-ID load retains that context and llmService.loadModel returns early for the unchanged model path. The load therefore reports success without initializing the projector, leaving image attachments unavailable until an explicit unload.

// decode: unloading cancels the native job and whisper.rn returns an empty result, so
// the clip reads as transcribed-to-nothing rather than as interrupted. This veto is how
// the owner is told "not right now" instead of the caller second-guessing the policy.
canEvict: () => !whisperService.isFileTranscribing(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Eviction veto has a startup race

If a file transcription starts after residency evaluates canEvict as true but before the selected resident is unloaded, transcription startup occurs outside the residency lock and the context is released during native decoding. Whisper then returns an empty transcription that is treated as legitimate clip output.

@dishit-wednesday dishit-wednesday changed the title feat: whisper residency, LLM constraints, and the recorder slot feat: whisper context lifecycle, constrained generation, and a home slot Aug 10, 2026
@sonarqubecloud

Copy link
Copy Markdown

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