Skip to content

Hotfix Soniox fallback keys for dev#3221

Open
isaiahb wants to merge 4 commits into
devfrom
codex/soniox-fallback-hotfix-dev
Open

Hotfix Soniox fallback keys for dev#3221
isaiahb wants to merge 4 commits into
devfrom
codex/soniox-fallback-hotfix-dev

Conversation

@isaiahb

@isaiahb isaiahb commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Backports the Soniox fallback key hotfix to dev for legacy Cloud v1.

Why

The primary Soniox org/key can hit account-level limits, causing every new transcription or translation stream to fail through the same exhausted credential. This branch mirrors the main hotfix so dev has the same operational behavior.

What changed

  • Adds SONIOX_FALLBACK_API_KEYS support for transcription and translation.
  • Uses a shared Soniox key-pool helper with failure classification and cooldowns.
  • Keeps SONIOX_API_KEY as primary while healthy.
  • Logs only safe key fingerprints.
  • Includes issue docs under cloud/issues/108-soniox-fallback-api-keys/.

Validation

  • bun test cloud/packages/cloud/src/services/session/soniox/__tests__/SonioxKeyPool.test.ts
  • git diff --check HEAD~1..HEAD
  • cd cloud && bun run build

Note: cd cloud/packages/cloud && bun run build currently fails on dev with local workspace resolution for @mentra/display-utils, unrelated to this Soniox hotfix diff.


Note

Medium Risk
Changes live Soniox stream creation and retry paths for all sessions; misconfigured keys or cooldown logic could affect STT/translation availability, though behavior is scoped to Soniox and covered by new tests.

Overview
Adds SONIOX_FALLBACK_API_KEYS (comma-separated) so Cloud v1 can rotate across multiple Soniox org keys when the primary hits limits, instead of retrying the same exhausted credential.

Introduces a shared SonioxKeyPool: prefer SONIOX_API_KEY, round-robin fallbacks, dedupe, per-key cooldowns from classified failures (concurrency, rate limit, quota, auth disable, transient), and SHA-256 fingerprints in logs only. Soniox transcription and translation providers loop credentials on stream creation (SDK + WebSocket), cache one SDK client per credential, and record runtime stream failures against the active key.

TranscriptionManager and TranslationManager treat “no available credentials” and capacity-class Soniox errors as retryable so new streams can pick another key. Default Soniox realtime model is bumped to stt-rt-v5. Includes issue docs and SonioxKeyPool unit tests.

Reviewed by Cursor Bugbot for commit a157880. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Backports the Soniox fallback key hotfix to dev for Cloud v1. Adds a shared credential pool with retry/rotation, tightens quota cooldown handling, and defaults Soniox to stt-rt-v5 to reduce failed stream creations.

  • New Features

    • Added SONIOX_FALLBACK_API_KEYS (comma‑separated) with parsing and dedupe.
    • Introduced SonioxKeyPool: prefers primary, round-robins fallbacks, classifies failures (auth, concurrency, rate_limit, quota, transient) with per-key cooldowns; quota uses a long cooldown, and success no longer clears an active cooldown; logs only SHA‑256 key fingerprints.
    • Updated Soniox transcription and translation providers to try multiple credentials (SDK and WS), cache one SDK client per credential, and record per-credential success/failure, including runtime stream errors.
    • Improved retries in TranscriptionManager and TranslationManager for Soniox capacity/quota errors and “No available Soniox (translation) credentials”.
    • Defaulted the Soniox model to stt-rt-v5 across transcription and translation; added tests and docs under cloud/issues/108-soniox-fallback-api-keys/.
  • Migration

    • Set SONIOX_FALLBACK_API_KEYS in .env where multiple Soniox keys are available. No other changes required.

Written for commit a157880. Summary will update on new commits.

Review in cubic

@isaiahb isaiahb requested a review from aisraelov as a code owner June 21, 2026 01:54
@github-actions

Copy link
Copy Markdown

📋 PR Review Helper

📱 Mobile App Build

Waiting for build...

🕶️ ASG Client Build

Waiting for build...


🔀 Test Locally

gh pr checkout 3221

@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: 8d18f4e8cd

ℹ️ 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 +53 to +59
if (
code === 401 ||
lower.includes("invalid api key") ||
lower.includes("invalid_api_key") ||
lower.includes("bad api key") ||
lower.includes("unauthorized")
) {

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 403 Soniox auth failures

If Soniox returns Soniox error 403: ... for an authorization/forbidden key, this classifier falls through to transient unless the text happens to include unauthorized; elsewhere the transcription manager already treats 401 and 403 as auth errors. That means a forbidden primary/fallback key is only cooled down for 10 seconds and then selected again for future streams instead of being disabled for the process as the new key-pool spec requires. Include code === 403 in the auth classification.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Leaving this open intentionally for follow-up. We are not broadening 403 into process-disable behavior in the ASAP hotfix.

this.config,
throw (
lastError ??
new Error(`No available Soniox credentials: ${JSON.stringify(this.keyPool.describeAvailability())}`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Last error blocks credential retries

Medium Severity

When stream creation tries every credential in the pool and none succeed, it always rethrows the last failure. If that message is a non-retryable Soniox auth error while other keys are only on short cooldowns, TranscriptionManager stops retrying instead of waiting for a recoverable credential.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b2ee0a2. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Leaving this open intentionally for follow-up. The last-error masking case is valid but outside the narrowed prod outage fix; the pushed fix covers the spend-cap quota path.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8ab0ba7. Configure here.

lower.includes("bad api key") ||
lower.includes("unauthorized")
) {
return { kind: "auth", cooldownMs: Number.POSITIVE_INFINITY, disabled: true };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HTTP 403 not auth disabled

Medium Severity

classifySonioxCredentialFailure treats Soniox 401 and several auth phrases as auth and disables the credential, but 403 and typical “forbidden” wording are omitted. Those failures fall through to transient with a short cooldown, so forbidden keys stay in rotation instead of being disabled for the process as the spec requires.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8ab0ba7. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Leaving this open intentionally for follow-up. We are not broadening 403 into process-disable behavior in the ASAP hotfix.

Comment thread cloud/packages/cloud/src/services/session/soniox/SonioxKeyPool.ts
@isaiahb

isaiahb commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Related Soniox fallback PRs:

Current prod/main hotfix head: e06781b.

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