Skip to content

🧹 Decouple HTTP exceptions from VAD utility - #11338

Open
undivisible wants to merge 6 commits into
mainfrom
fix-vad-http-exception-coupling-5064561204901573843
Open

🧹 Decouple HTTP exceptions from VAD utility#11338
undivisible wants to merge 6 commits into
mainfrom
fix-vad-http-exception-coupling-5064561204901573843

Conversation

@undivisible

@undivisible undivisible commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

🎯 What: The apply_vad_for_speech_profile utility function in backend/utils/stt/vad.py was directly raising a FastAPI HTTPException(400) when a processed audio file was empty. This has been replaced with a domain-specific VADEmptyError. The HTTPException logic has been moved up to the routing layer in backend/routers/speech_profile.py. The background script backend/scripts/stt/j_apply_vad_to_speech_profiles.py was also updated to catch VADEmptyError.

💡 Why: This change separates concerns and decouples domain/utility logic from web framework-specific exceptions. HTTPException should only be thrown from routing layers. This makes the utility function safer to reuse across different contexts, such as the j_apply_vad_to_speech_profiles.py background script which previously would have crashed upon encountering an empty audio file.

Verification: Ran pytest tests against the updated files (backend/tests/unit/test_speech_profile_wav_decode.py, backend/tests/unit/test_user_speaker_embedding.py, backend/tests/unit/test_vad_onnx.py) to confirm no regressions and tested API compatibility. Code Review was completed.

Result: A cleaner architectural separation of concerns between core utility code and web layers, and a more robust background script that won't crash when encountering empty voice segments.


PR created automatically by Jules for task 5064561204901573843 started by @undivisible

Review in cubic


Note

Low Risk
Small layering refactor on speech-profile upload validation; HTTP 400 for empty audio is preserved and covered by tests.

Overview
apply_vad_for_speech_profile no longer raises FastAPI HTTPException when VAD finds no speech. It now raises a domain VADEmptyError, and vad.py drops its FastAPI dependency.

The /v3/upload-audio handler catches VADEmptyError and still returns 400 with "Audio is empty", so API behavior for empty speech uploads is unchanged. The batch j_apply_vad_to_speech_profiles script catches the same error, logs, and skips re-upload instead of failing the job.

Unit tests cover the new exception in apply_vad_for_speech_profile, the upload route’s 400 mapping, and the batch script’s skip path.

Reviewed by Cursor Bugbot for commit e4f12d7. Configure here.

@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_e3840d6f-32c9-432e-b77a-80cf8f24a3c8)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 921c6fcf4d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +86 to +87
except VADEmptyError:
raise HTTPException(status_code=400, detail="Audio is empty")

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 Badge Add regression coverage for the new exception boundary

When VAD finds no speech, this commit changes the utility's exception contract and adds translations at the HTTP and batch-script boundaries, but it modifies no tests; an incorrect exception type or catch would therefore turn the upload's intended 400 into a 500 or let the maintenance thread fail unnoticed. Add a behavioral test that drives the zero-segment path and verifies VADEmptyError is translated correctly, as required for behavior-changing bug fixes.

AGENTS.md reference: AGENTS.md:L26-L28

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files

Confidence score: 4/5

  • In backend/routers/speech_profile.py, the VADEmptyError400 "Audio is empty" branch is currently untested, so a future change could silently alter this user-facing contract (for example returning a generic error instead of the expected 400). Add a focused router test that triggers VADEmptyError and asserts the exact status code/message to de-risk regressions.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/routers/speech_profile.py">

<violation number="1" location="backend/routers/speech_profile.py:86">
P3: The new `VADEmptyError` handling path is untested. The router branch that converts `VADEmptyError` into the `400 "Audio is empty"` response is the exact user-facing behavior this PR preserves, and the script's `except VADEmptyError: return` is the new robustness behavior that motivated the change — but neither has a regression test (existing tests only cover the WAV decode/duration failure branches, and nothing asserts the empty-audio path). Consider adding a small unit test that patches `apply_vad_for_speech_profile` to raise `VADEmptyError` and asserts the router returns 400 without uploading, and one for the script's early-return-on-empty branch.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

apply_vad_for_speech_profile(file_path)
try:
apply_vad_for_speech_profile(file_path)
except VADEmptyError:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The new VADEmptyError handling path is untested. The router branch that converts VADEmptyError into the 400 "Audio is empty" response is the exact user-facing behavior this PR preserves, and the script's except VADEmptyError: return is the new robustness behavior that motivated the change — but neither has a regression test (existing tests only cover the WAV decode/duration failure branches, and nothing asserts the empty-audio path). Consider adding a small unit test that patches apply_vad_for_speech_profile to raise VADEmptyError and asserts the router returns 400 without uploading, and one for the script's early-return-on-empty branch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/routers/speech_profile.py, line 86:

<comment>The new `VADEmptyError` handling path is untested. The router branch that converts `VADEmptyError` into the `400 "Audio is empty"` response is the exact user-facing behavior this PR preserves, and the script's `except VADEmptyError: return` is the new robustness behavior that motivated the change — but neither has a regression test (existing tests only cover the WAV decode/duration failure branches, and nothing asserts the empty-audio path). Consider adding a small unit test that patches `apply_vad_for_speech_profile` to raise `VADEmptyError` and asserts the router returns 400 without uploading, and one for the script's early-return-on-empty branch.</comment>

<file context>
@@ -81,7 +81,10 @@ def upload_profile(file: UploadFile, uid: str = Depends(auth.get_current_user_ui
-    apply_vad_for_speech_profile(file_path)
+    try:
+        apply_vad_for_speech_profile(file_path)
+    except VADEmptyError:
+        raise HTTPException(status_code=400, detail="Audio is empty")
 
</file context>

@undivisible undivisible added human Human-authored pull request backend Backend Task (python) workflow-review Needs maintainer review for workflow, automation, hooks, or CI behavior AI and removed human Human-authored pull request labels Aug 10, 2026
@Git-on-my-level Git-on-my-level removed the workflow-review Needs maintainer review for workflow, automation, hooks, or CI behavior label Aug 10, 2026
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Reviewed the full three-file diff; this looks like a good separation-of-concerns cleanup.

  • backend/utils/stt/vad.py: removing the FastAPI import from the VAD utility and replacing the previous HTTPException(400, "Audio is empty") with a domain-specific VADEmptyError keeps the utility layer framework-agnostic. The no-speech branch still exits before trimming/exporting, so the production behavior remains fail-fast for empty VAD results.
  • backend/routers/speech_profile.py: catching VADEmptyError at the upload route boundary correctly preserves the existing client-facing 400 / "Audio is empty" response while keeping the decode, sample-rate, and duration guards ahead of VAD processing.
  • backend/scripts/stt/j_apply_vad_to_speech_profiles.py: catching VADEmptyError and returning from single() means the migration/maintenance script skips empty profiles instead of crashing the batch, while still only re-uploading after the existing duration validation.

Backend CI is green. I also removed workflow-review because this PR does not touch workflow/CI/automation files; the existing backend category is the right primary area. A focused regression test for the new router/script VADEmptyError paths would be a nice follow-up, but I don’t see a production blocker in this diff.

Automated maintainer review; final merge decision remains with the maintainers.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@Git-on-my-level Git-on-my-level added the positive-signal Good PR — positive signal, not a formal approval label Aug 10, 2026
@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_644ec186-dc8a-499c-849d-3e7693c026c9)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e1665c14c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +145 to +146
) as mock_aseg, patch.object(mod, "VADEmptyError", _FakeVADEmptyError), patch.object(
mod, "apply_vad_for_speech_profile", side_effect=_FakeVADEmptyError("Audio is empty")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exercise the real zero-segment exception boundary

Fresh evidence since the earlier missing-coverage comment is that this new test replaces both VADEmptyError and apply_vad_for_speech_profile with matching fakes, so it never executes the changed zero-segment branch in utils/stt/vad.py. If the real utility continued raising HTTPException or later raised another type, this test would still pass while silent uploads return 500 and the batch script fails to handle them; patch vad_is_empty to return [] and invoke the real utility through the route (or separately assert the real utility's exception) so the regression test covers the production contract.

AGENTS.md reference: AGENTS.md:L43-L45

Useful? React with 👍 / 👎.

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Introduces VADEmptyError so empty speech-profile audio returns 400 instead of 500, with a unit test. CI green. Approve-only (refactor, no linked bug issue).

@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Thanks for the update — I reviewed the current four-file diff on this head, including the newly added regression test.

  • backend/utils/stt/vad.py: apply_vad_for_speech_profile() now raises a domain-specific VADEmptyError when VAD returns no speech segments, and the VAD utility no longer imports FastAPI. The trimming/export path for non-empty segments is unchanged.
  • backend/routers/speech_profile.py: the upload route now owns the FastAPI translation by catching VADEmptyError and preserving the existing 400 / "Audio is empty" API response after the existing decode, sample-rate, and duration guards.
  • backend/scripts/stt/j_apply_vad_to_speech_profiles.py: the maintenance script catches VADEmptyError, logs the affected uid, and returns from single(), so one empty profile no longer crashes the batch before later users are processed.
  • backend/tests/unit/test_speech_profile_wav_decode.py: the new test patches apply_vad_for_speech_profile to raise the VAD-empty exception and asserts the route returns the expected 400 without uploading, which covers the previously noted user-facing boundary.

Validation: backend CI is green. I also ran py_compile, git diff --check, and an AST/static check confirming the utility has no FastAPI import, defines/raises VADEmptyError, and both callers catch it. The focused local pytest collection is still blocked by this checkout’s missing backend test dependency (google via tests/unit/conftest.py), so I’m relying on the green hermetic backend CI for the runtime test signal.

This still looks like a clean backend separation-of-concerns cleanup, and the existing backend + positive-signal labels fit. No maintainer escalation from me beyond the normal final merge decision.


by AI on behalf of David — automated maintainer review; final merge decisions remain with the maintainers.

@undivisible
undivisible force-pushed the fix-vad-http-exception-coupling-5064561204901573843 branch from 4e1665c to 5466314 Compare August 10, 2026 21:11
@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_892655a0-1a99-445d-ad8c-1c9f5ad4013d)

undivisible and others added 2 commits August 11, 2026 07:11
Refactored `apply_vad_for_speech_profile` in `backend/utils/stt/vad.py` to raise a new `VADEmptyError` instead of FastAPI's `HTTPException(400)`. This logic is now caught in the `backend/routers/speech_profile.py` router and `backend/scripts/stt/j_apply_vad_to_speech_profiles.py` script, decoupling web exceptions from core domain utilities.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@undivisible
undivisible force-pushed the fix-vad-http-exception-coupling-5064561204901573843 branch from 5466314 to 84043ba Compare August 10, 2026 23:11
@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_20ce6641-379a-4e88-b712-b418987d762b)

@Git-on-my-level Git-on-my-level left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks — this looks like a good narrow backend cleanup. I reviewed the current head (84043baef77fa1e23442ad297539e9fc2ec8f9fa):

  • backend/utils/stt/vad.py: replacing the FastAPI HTTPException with VADEmptyError keeps the VAD utility framework-independent while preserving the empty-audio signal before any trimming/export work.
  • backend/routers/speech_profile.py: catching VADEmptyError at the upload route preserves the user-facing 400 "Audio is empty" response and still bails out before duration caching, upload, or embedding extraction.
  • backend/scripts/stt/j_apply_vad_to_speech_profiles.py: handling VADEmptyError lets the maintenance script skip empty profiles instead of crashing on a web-layer exception, which matches the decoupling goal.
  • backend/tests/unit/test_speech_profile_wav_decode.py: the added empty-VAD test asserts the 400 response and verifies upload is not called, covering the earlier automated concern around this route behavior.

CI is green, and I do not see a blocking issue in this diff. Keeping this as a positive signal; final merge judgment can stay with the human maintainer path already in progress.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

Exercise the real VAD zero-segment exception at the utility boundary and cover the HTTP and batch translations at their callers.

Failure-Class: none

Tests: backend/.venv/bin/python -m pytest -q tests/unit/test_speech_profile_wav_decode.py tests/unit/test_vad_onnx.py
@cursor

cursor Bot commented Aug 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_ceb5afbc-f18d-4c7f-bd6a-208ae658e701)

undivisible and others added 2 commits August 11, 2026 11:48
Exercise the production VAD zero-segment exception through the upload route and batch maintenance script, asserting both user-facing translations and their side-effect guards.

Failure-Class: none
Refactored `apply_vad_for_speech_profile` in `backend/utils/stt/vad.py` to raise a new `VADEmptyError` instead of FastAPI's `HTTPException(400)`. This logic is now caught in the `backend/routers/speech_profile.py` router and `backend/scripts/stt/j_apply_vad_to_speech_profiles.py` script, decoupling web exceptions from core domain utilities.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@mintlify

mintlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
omi 🟢 Ready View Preview Aug 11, 2026, 4:08 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Refactored `apply_vad_for_speech_profile` in `backend/utils/stt/vad.py` to raise a new `VADEmptyError` instead of FastAPI's `HTTPException(400)`. This logic is now caught in the `backend/routers/speech_profile.py` router and `backend/scripts/stt/j_apply_vad_to_speech_profiles.py` script, decoupling web exceptions from core domain utilities.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3e4715d46

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +137 to +139
if isinstance(value, str) and value:
try:
action_item_data[date_field] = datetime.fromisoformat(value.replace('Z', '+00:00'))

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 Badge Normalize action-item dates to UTC before Firestore writes

When a tool or LLM supplies a date-only ISO string such as 2024-01-01, datetime.fromisoformat produces a timezone-naive value; an already-parsed naive datetime bypasses this branch entirely. Those values are then handed to Firestore, which rejects them, causing extracted action items—potentially an entire background batch—to be lost. Convert both string and datetime inputs to timezone-aware UTC before returning.

Useful? React with 👍 / 👎.

Comment on lines +4 to +6
# Manual only: automatic push/schedule tagging was cutting a new macOS candidate
# tag on nearly every desktop-affecting main merge and every 15 minutes. Plan and
# publish a candidate deliberately via workflow_dispatch; qualification/promotion

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 Badge Restore an automatic desktop release trigger

After this edit, desktop_auto_release.yml has only workflow_dispatch, so ordinary merges never invoke the planner and no daily beta candidate is cut unless an operator remembers to run the workflow manually. Restore the scheduled automatic trigger required by the repository's desktop release pipeline.

AGENTS.md reference: AGENTS.md:L126-L128

Useful? React with 👍 / 👎.

Comment thread backend/routers/users.py
Comment on lines +484 to 487
if url == '' or url == ',':
disable_user_webhook_db(uid, wtype)
else:
enable_user_webhook_db(uid, wtype)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Disable cleared audio webhooks regardless of retained delay

When a mobile user clears the audio-bytes webhook and saves, developer_mode_provider.dart posts ,<delay> (normally ,5), which does not match either literal here. The endpoint therefore re-enables a webhook with no URL, so the toggle comes back on and audio processing remains enabled despite the user's attempt to disable it; determine emptiness from the URL portion before the comma.

Useful? React with 👍 / 👎.

Comment on lines +35 to +36
String? selectedLanguageName = selectedLanguage != null
? homeProvider.availableLanguages.entries.firstWhere((element) => element.value == selectedLanguage).key

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve unknown stored languages when opening the picker

If the stored primary-language code is not in this bundled map, opening the forced language dialog throws StateError at firstWhere before it can render. This is reachable for valid server-supported values such as sw, cy, or af, which PATCH /v1/users/language accepts but the bundled map omits; use the existing safe lookup/fallback instead of assuming every stored code is present.

Useful? React with 👍 / 👎.

Comment on lines +101 to +109
setSegments((prev) => {
// Update existing segment or add new one
const existingIndex = prev.findIndex((s) => s.id === segment.id);
if (existingIndex >= 0) {
const updated = [...prev];
updated[existingIndex] = segment;
return updated;
}
return [...prev, segment];

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 Badge Bound the live transcript segment list

During long browser recordings, every finalized segment takes this append path, so the React state and rendered transcript grow without limit while each update copies the entire array. Sessions reaching hundreds of segments progressively stall Chrome and can make the recording UI unusable; retain only a bounded recent window while leaving the server-side session intact for finalization.

Useful? React with 👍 / 👎.

Comment thread backend/routers/mcp.py
Comment on lines +545 to 547
conversation_ids = vector_db.query_vectors(query, uid, starts_at=starts_at, ends_at=ends_at, k=limit)
if not conversation_ids:
return []

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 Badge Search transcript chunks in MCP conversation search

This route now queries only conversation summary vectors, which do not contain phrases spoken solely in transcript segments. Consequently, MCP clients receive no result for exact names, decisions, or quotes that were omitted from the generated summary even though matching transcript chunks are indexed; merge search_transcript_chunks hits with the summary results and return the corresponding snippets.

Useful? React with 👍 / 👎.

Comment on lines +1030 to +1032
// Content-derived hit region: the fixed window is larger than the
// visible chrome/menu, and its transparent margins must keep passing
// clicks through to windows below (hitTest returns nil outside this).

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 Badge Pass clicks through the notch panel's transparent margins

In notch mode the panel is intentionally fixed at its maximum hover size, leaving a large transparent area around the visible chrome. Returning nil from the content view's hitTest does not make the NSWindow click-through—the frame view still owns the event—and this change removes the window-level ignoresMouseEvents synchronization, so the invisible panel intercepts clicks on the main window's top navigation and other apps beneath it. Restore window-level mouse interception control or stop reserving the oversized transparent frame.

Useful? React with 👍 / 👎.

Comment on lines 129 to +132
]
for f in futures:
f.result()
ordered_chunks = [context_data[m.id] for m in memories if m.id in context_data]
context_str = '\n'.join(ordered_chunks).strip()
context_str = '\n'.join(context_data.values()).strip()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve ranked order when assembling RAG context

Each worker inserts its chunk into context_data when it finishes, so joining dict.values() orders context by nondeterministic thread completion rather than the similarity-ranked memories list established above. With multiple retrieved conversations this can present the LLM with arbitrarily reordered evidence and produce unstable or less relevant answers; rebuild the output by iterating memories and selecting matching IDs instead of deferring the known defect in an untracked TODO.

AGENTS.md reference: AGENTS.md:L93-L93

Useful? React with 👍 / 👎.

Comment thread app/lib/env/prod_env.dart
Comment on lines +11 to +13
@override
@EnviedField(varName: 'OPENAI_API_KEY', obfuscate: true)
final String? openAIAPIKey = _ProdEnv.openAIAPIKey;

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 Badge Keep the OpenAI server key out of the mobile binary

The production Codemagic app workflows write the real OPENAI_API_KEY into .env, and this EnviedField causes build_runner to compile that value into every released Flutter binary. obfuscate: true is reversible obfuscation rather than secret storage, so an app recipient can recover the provider credential and use it outside Omi; this also directly contradicts app/config/client_env_policy.yaml, which classifies OPENAI_API_KEY as server-only. Route OpenAI calls through an authenticated backend and remove the field from the public client.

Useful? React with 👍 / 👎.

Comment on lines 209 to 212
async def initialize_stt(self) -> bool:
request = self.host.request
provider = getattr(self.host.stt_service, 'value', self.host.stt_service)
if self.host.use_custom_stt:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Attribute fallback STT failures to the serving provider

When a session starts with Parakeet but _create_stt_socket falls back to Modulate, that method updates self.host.stt_service after this local value has already been captured. The death monitor and initialization failure paths therefore report parakeet in the client failure event and provider metrics even though Modulate was serving and failed, obscuring the actual incident and misleading provider-specific diagnostics; resolve the provider after socket creation or at each failure boundary.

Useful? React with 👍 / 👎.

@Git-on-my-level Git-on-my-level added needs-scope-reduction PR scope should be reduced or split security-review Touches auth, provider routing, secrets, or security-sensitive surfaces workflow-review Needs maintainer review for workflow, automation, hooks, or CI behavior and removed backend Backend Task (python) positive-signal Good PR — positive signal, not a formal approval labels Aug 11, 2026

@Git-on-my-level Git-on-my-level left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the original VAD cleanup — the small VADEmptyError part still looks directionally right (backend/utils/stt/vad.py, backend/routers/speech_profile.py, and backend/scripts/stt/j_apply_vad_to_speech_profiles.py keep the framework exception at the route/script boundary).

I need to request changes on the current head, though, because it has grown far beyond that refactor and now carries several unrelated, high-risk behavior changes:

  • app/lib/backend/http/openai.dart adds direct client calls to https://api.openai.com/v1/... with Authorization: Bearer ${Env.openAIAPIKey}, and app/.env.template / app/lib/env/*.dart add an app-side OpenAI key. That moves LLM calls and user content from the backend-managed/gateway path into the shipped app surface, which needs an explicit security/privacy/product decision rather than being bundled into a VAD utility cleanup.
  • backend/routers/desktop_chat.py removes the structured managed lane (CHAT_STRUCTURED_AUTO_LANE_ID, _MANAGED_STRUCTURED_ALIASES, lane-specific accounting) and routes managed gateway requests through the chat-agent lane. That can change model routing/personality/accounting for non-conversational extraction/planner calls.
  • backend/route_policy_manifest.yaml plus routers such as backend/routers/conversations.py, backend/routers/knowledge_graph.py, backend/routers/integrations.py, backend/routers/memories.py, and backend/routers/users.py remove multiple first-party extraction/synthesis/language endpoints and their policy entries, while many corresponding tests are deleted. That is a broad API/product contract change, not a decoupling refactor.
  • .github/workflows/desktop_auto_release.yml, .github/scripts/check-desktop-changelog.py, .github/scripts/plan-desktop-release.py, and their tests remove scheduled release-train/changelog/fallback behavior. This is release infrastructure and needs focused workflow review on its own.
  • desktop/macos/AGENTS.md changes AI/coding-agent release-pipeline guidance, but the new text says candidates are cut on every macOS-affecting merge plus a 15-minute schedule, while the workflow diff removes the schedule and leaves workflow_dispatch only. That instruction file can directly mislead future coding/review agents about how desktop releases work, so it should not land in this state.
  • backend/database/vector_db.py removes the injectable query_vector path and weakens transcript date filtering to only apply when both bounds are present. That changes retrieval behavior and testability independently of the VAD work.
  • web/app/package.json / web/app/package-lock.json remove Vitest and test scripts while web transcript tests are deleted, which further broadens the risk surface.

Please reduce this PR back to the VAD exception cleanup, or split/rework these unrelated backend API, desktop release, client-LLM, retrieval, web dependency, and agent-instruction changes into separately reviewed PRs with their own validation. The current head needs security-sensitive client/API-key review and release-workflow maintainer sign-off before it can be considered.


by AI on behalf of David — automated maintainer review; blocking here because the current head bundles unrelated security-sensitive client LLM/API-key changes, release workflow changes, and inaccurate agent-facing release guidance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI needs-scope-reduction PR scope should be reduced or split security-review Touches auth, provider routing, secrets, or security-sensitive surfaces workflow-review Needs maintainer review for workflow, automation, hooks, or CI behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants