Skip to content

feat(video): orchestrate Audio Bridge STT with one-download budgets (FU-06, #11654) - #12012

Merged
diegosouzapw merged 27 commits into
release/v3.8.51from
feat/11654-video-audio-bridge-stt
Aug 29, 2026
Merged

diegosouzapw merged 27 commits into
release/v3.8.51from
feat/11654-video-audio-bridge-stt

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

⚠️ base-red inherited: #11874 — Docs sync + fabricated-docs (strict): README.md does NOT mention 356 for providers. Pre-existing on release/v3.8.51, not touched by this branch.

Summary

FU-06 (Video Bridge series, parent #9760): server-side orchestration that
lets Video Bridge extract audio from a video and run it through Audio
Bridge STT — the original acceptance the fusion primitive (fuseVideoAndAudio)
never covered, since today it only fuses an already-materialized
audioTranscript a caller supplies.

Scope delivered:

  • One download, two extractions. The new orchestration
    (src/lib/guardrails/videoBridgeAudioOrchestration.ts) takes the already
    -downloaded video bytes as input — it has no download path of its own, so
    it structurally cannot re-fetch the video.
  • New loopback-only broker operation
    (src/app/api/modality-bridge/video/extract/route.ts, mode=audio query
    flag) extracts bounded mono 16 kHz PCM WAV via array-argument ffmpeg
    (src/lib/guardrails/videoBridgeAudioExtraction.ts, reusing
    probeLocalVideo's existing safe-container/format/dimension checks —
    no parallel validation). Never a shell string (Hard Rule deps: bump qs from 6.14.1 to 6.14.2 #13).
  • Shared budgets, not a parallel set of limits. mode=audio runs
    through the exact same route file, the same module-level extractionQueue
    singleton, the same MAX_INPUT_BYTES/BROKER_TIMEOUT_MS, and the same
    deadline/AbortSignal composition the frame path already uses.
  • Dual opt-in, enforced before either the broker or the transcription
    boundary is ever touched:
    • Operator: modalityBridgeVideoAudioTranscriptionEnabled (new settings
      key, default false — Hard Rule feat: v0.2.0 — advanced routing services, cost analytics, pricing overhaul #20 spirit).
    • Request: a per-request opt-in the caller passes in.
    • Only operatorOptIn && requestOptIn reaches the STT call; all three
      other permutations return attempted: false and never invoke
      extractAudio/transcribe (asserted directly in tests).
  • Reuses the existing Audio Bridge transcription boundary —
    callAudioTranscriptionTimed, a new sibling of callAudioTranscription
    in audioBridgeHelpers.ts sharing one refactored-out HTTP/multipart
    helper (sendAudioTranscriptionRequest) — no new STT client. It requests
    response_format=verbose_json and preserves provider-supplied per-segment
    timestamps (timingPrecision: "exact") when present, falling back to one
    whole-clip observation spanning the extracted audio's duration
    (timingPrecision: "coarse") when the provider ignores it.
  • Provenance stays server-owned: the orchestrator mints its own
    FusionObservations (source: "audio") directly from the STT response —
    it never calls normalizeVideoTranscript on untrusted client JSON, so it
    does not depend on (or duplicate) the source-trust work feat(guardrails): enforce video transcript provenance, budgets and reconciliation (FU-05 core) #12009 is doing
    on that function.
  • Failures stay partial. Every failure path (PROVIDER_UNAVAILABLE,
    EXTRACTION_FAILED, TRANSCRIPTION_FAILED, TIMEOUT, ABORTED) returns
    track: null instead of throwing — a caller's visual-only fallback always
    has a well-defined result to check.
  • Result cache (BridgeCache, same primitive Vision/Audio Bridge
    already use) keyed on the video part's ref + STT model — a repeated
    request for the same video does not re-extract or re-transcribe (no
    repeat paid STT call).

Deliberately deferred — composes with #12009 (FU-05, not yet merged):
wiring this orchestration into videoBridgeHelpers.ts::describeVideoPart's
existing fuseVideoAndAudio call site is not done in this PR. That
exact block is also where #12009 is landing the transcript-contract/
provenance-trust rewrite (normalizeVideoTranscript's trustedSource
option, focus scoping, contributingSources reconciliation, cache v4→v5).
Rather than risk a conflicting rewrite of the same lines from two
directions, this PR ships the orchestration as a complete, independently
tested, composable primitive. The follow-up wiring PR (feeding
orchestrateVideoAudioTranscription's FusionTrack into
describeVideoPart's existing audio branch, tagged
source: "audio-bridge" — the transcript-source value already declared in
VideoTranscriptSource but never produced today) is small once #12009's
seam lands.

Test evidence (RED→GREEN, all mocked at the process/provider boundary)

  • tests/unit/guardrails/videoBridgeAudioOrchestration.test.ts (17 tests):
    all 4 opt-in permutations (only "both" transcribes; the other 3 assert
    extractAudio/transcribe were never called), extraction success →
    coarse observation, STT segments → exact timing, unavailable provider
    (extraction never runs), extraction timeout vs. generic extraction
    failure, transcription timeout vs. generic transcription failure, caller
    abort during either step, cache hit skips both the broker and the STT
    call, a different video's cache key stays isolated, and the same
    timeoutMs/signal threading through both steps.
  • tests/unit/guardrails/videoBridgeAudioExtraction.test.ts (4 tests):
    bounded WAV extraction reusing the probed duration, propagating the
    shared duration cap, rejecting output over the byte cap, and surfacing
    ffmpeg's own "no audio stream" failure.
  • tests/unit/guardrails/audioBridgeHelpers.test.ts (+3 tests): the timed
    boundary requests verbose_json, falls back to no-segments when the
    provider ignores it, and drops malformed provider segments instead of
    trusting them — plus all 7 pre-existing tests still pass unmodified
    (callAudioTranscription's behavior is byte-for-byte unchanged).
  • tests/unit/video-bridge-broker.test.ts (+6 tests) /
    tests/unit/video-bridge-route-security.test.ts (all 9 pre-existing
    still pass): audio broker client round-trip, malformed/non-WAV response
    rejection, the audio operation observes the identical
    VideoExtractionQueueError/503+Retry-After contract as frames, the
    module-level singleton queue is referenced by both branches, frame-only
    query params are rejected under mode=audio, and the injected extractor
    receives the shared deadline/byte budget.
  • tests/unit/video-bridge-settings.test.ts (+1 test): the operator opt-in
    defaults false and the new Zod schema field accepts/rejects correctly.

173/173 tests green across all touched files (command run):

node --import tsx/esm --test \
  tests/unit/guardrails/audioBridgeHelpers.test.ts tests/unit/guardrails/audioBridge.test.ts \
  tests/unit/guardrails/videoAudioFusion.test.ts tests/unit/guardrails/videoBridge.test.ts \
  tests/unit/guardrails/videoBridgeHelpers.test.ts tests/unit/guardrails/videoBridgeRuntime.test.ts \
  tests/unit/guardrails/videoBridgeTranscriptProvenance.test.ts \
  tests/unit/guardrails/videoBridgeAudioExtraction.test.ts \
  tests/unit/guardrails/videoBridgeAudioOrchestration.test.ts \
  tests/unit/video-bridge-broker.test.ts tests/unit/video-bridge-route-security.test.ts \
  tests/unit/video-bridge-settings.test.ts tests/unit/audio-bridge-settings.test.ts \
  tests/unit/modality-bridge-settings.test.ts tests/unit/audio-transcription-handler.test.ts

No existing assertion was weakened or removed.

Gates run locally (green)

  • npm run typecheck:core — exit 0
  • npm run typecheck:noimplicit:core — exit 0
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files> — 0 problems
  • npm run check:complexity-ratchets — OK (2673/2774 cyclomatic, 1193/1223 cognitive — both improved vs. baseline, no new violations)
  • node scripts/check/check-file-size.mjs — OK (both new files well under the 1000-line cap; no frozen file touched)
  • node scripts/check/check-test-discovery.mjs — OK
  • npm run check:cycles — OK, no cycles

Did not run npm run test:coverage per instructions (heaviest gate; CI runs it).

Pending live validation (cannot be done from this environment)

  • Working-set/queue caps measured on VPS 192.168.0.15 — not accessible
    from this environment; the shared queue/byte/deadline budgets are proven
    structurally and via unit tests (identical singleton, identical
    VideoExtractionQueueError capacity contract) but not load-measured live.
  • Real ffmpeg audio extraction — all ffmpeg/ffprobe invocations are
    exercised through the injectable VideoCommandRunner in tests (no real
    binary invoked); the array-argument construction is asserted directly,
    but a real multi-format video → WAV round-trip was not run here.
  • Real provider STT call with verbose_json — callAudioTranscriptionTimed
    is proven against mocked fetch responses shaped like OpenAI-compatible
    verbose_json output; no live call to a real STT provider was made to
    confirm which providers actually return segments.
  • Streaming/non-streaming live request checks (sanitized headers
    preserved, no transcript-text retention) — not wired into the live
    request pipeline in this PR (see "Deliberately deferred" above), so there
    is no live streaming/non-streaming request to check yet; the module
    itself never logs or persists transcript text.
  • Both test runners (test:unit + test:vitest) and the full release gate
    set on the exact candidate SHA — not run here; only the focused suites
    above were run locally.

Given the above, this uses Refs #11654, not Closes — VPS-side budget
measurement and live-pipeline wiring remain open follow-up work once
#12009 lands.

Refs #11654

hartmark and others added 27 commits August 29, 2026 07:48
…11654)

Add server-side orchestration composing three existing seams: the same
already-downloaded video bytes, a new loopback-only broker mode=audio
operation (mono 16kHz PCM WAV) that shares the frame path's exact process
queue/deadline/AbortSignal/byte budgets, and the existing Audio Bridge
transcription boundary (callAudioTranscriptionTimed, extended to preserve
provider segment timing when supplied and mark whole-clip fallback timing
as coarse). Transcription only ever runs when BOTH the operator setting
(modalityBridgeVideoAudioTranscriptionEnabled, default false) AND a
per-request opt-in are present; every other permutation and every failure
mode (unavailable provider, timeout, abort, extraction failure) returns a
well-defined partial with track: null so the visual-only fallback stays
available, and a result cache avoids repeat paid STT calls for the same
video+model.

Full request-pipeline wiring into videoBridgeHelpers.describeVideoPart is
deferred: that exact fusion call site is also touched by the in-flight
#12009 (FU-05 transcript contract) PR, so this orchestration ships as a
composable, fully unit-tested primitive rather than risking a conflicting
rewrite of shared lines.
…t createTask flow (#11296) (#11985)

flux/kontext is catalogued with isMarket: true, so handleKieImageGeneration
routed it through KIE's unified Market createTask endpoint with
model: "flux/kontext". KIE does not expose Flux Kontext through the Market
catalog at all -- it lives under a dedicated API tree
(POST /api/v1/flux/kontext/generate, poll GET /api/v1/flux/kontext/record-info,
models flux-kontext-pro/flux-kontext-max) -- so the Market endpoint rejected it
with "model name not supported", matching the reporter's exact error text.

Special-case flux/kontext ahead of the isMarket branch so it hits the
dedicated endpoint/payload shape instead of being treated as a Market entry.
z-image/4.0-*/4.5-* remains intentionally untouched (still blocked on
reporter/live confirmation per the existing in-code comment).

Co-authored-by: Markus Hartung <mail@hartmark.se>
…outs (#11500) (#11989)

* fix(db): rate-limit Arena ELO fetch-failure warnings on repeated timeouts (#11500)

* test(quality): split the #11500 fetch-failure-dedup tests into their own file

tests/unit/arena-elo-sync.test.ts crossed the 1000-line new-test-file cap
(file-size gate, PR mode). The two new tests don't need the file's DB
fixture (fetchArenaLeaderboards() never touches the DB), so they move to a
self-contained sibling file instead of growing the frozen suite.

---------

Co-authored-by: Markus Hartung <mail@hartmark.se>
…te path (#11707) (#11984)

enforceCodexResponsesLiteParallelToolCalls() forces parallel_tool_calls:false
at the top of CodexExecutor.execute(), but transformRequest() early-returns
the body before its RESPONSES_API_ALLOWLIST field filter only when
_nativeCodexPassthrough is set. Any request that reaches the codex
executor via the translated (non-native-passthrough) path never gets that
flag, so the allowlist filter silently deleted parallel_tool_calls right
before the fetch body was sent, reproducing the reported upstream
rejection ('X-OpenAI-Internal-Codex-Responses-Lite requires
parallel_tool_calls to be false') for every model.

Add parallel_tool_calls to RESPONSES_API_ALLOWLIST so the value survives
the translated path too. Update the sibling #2608 allowlist test that
previously asserted parallel_tool_calls gets stripped like other Chat
Completions-only fields -- it is a legitimate Responses API field that
must now survive.

Co-authored-by: Markus Hartung <mail@hartmark.se>
…publish's opencode-plugin skip check (#11787) (#11990)

* fix(cli): drop the never-produced dist/index.cjs requirement from prepublish's opencode-plugin skip check (#11787)

* test(build): resolve tsup/npm portably in the #11787 regression test instead of a hardcoded .bin path

The old test assumed @omniroute/opencode-plugin/node_modules/.bin/tsup
already existed. A fresh checkout (CI's npm ci never installs this
standalone package's own deps) has no such node_modules at all, so the
test failed with MODULE_NOT_FOUND in CI while passing locally on a devbox
that had installed it before. Mirror scripts/build/prepublish.ts's own
install-then-resolveLocalBinEntry approach.

---------

Co-authored-by: Markus Hartung <mail@hartmark.se>
…dispatches (#11810) (#11986)

Co-authored-by: Markus Hartung <mail@hartmark.se>
…ic alias (#11824) (#11988)

Co-authored-by: Markus Hartung <mail@hartmark.se>
…ked rows (#9133) (#11994)

* fix(sse): stop the auto-combo candidates inspector from dropping blocked rows (#9133)

prepareVirtualAutoComboInputs applied filterResilienceBlockedCandidates
before the #7819 read-only candidate inspector ever saw the pool, so a
model-locked or cooled-down candidate silently disappeared from
/auto-combo/*/candidates instead of showing up as reachable:false with a
reason (modelLocked/connectionCooldown/breakerState were dead fields by
construction). Add an opt-in `skip` parameter so the inspector builds its
own unfiltered pool; routing (createVirtualAutoCombo/createBuiltinAutoCombo
called without a prepared override) is unchanged. Also aligns
isModelLocked's model argument to the bare model id, matching every lock
writer and the routing-side filter, instead of the "provider/model" string.

Regression test: tests/unit/auto-combo-candidates-locked-model-visible.test.ts
(red before the fix — locked account's row silently missing; green after).

* chore(quality): register the #9133 regression test in stryker tap.testFiles

tests/unit/auto-combo-candidates-locked-model-visible.test.ts covers
open-sse/services/accountFallback.ts (via isModelLocked) but wasn't listed,
so its mutant kills wouldn't count toward mutation coverage.

---------

Co-authored-by: Markus Hartung <mail@hartmark.se>
…SBOM on dispatch (twin of #11982 + #12020) (#12022)

* fix(release): resync the electron lockfile, build a dispatch from a repaired ref, keep curated notes, attach the SBOM on dispatch (release/v3.8.51 twin of #11982 + #12020)

Same four changes as #11982 and #12020 on main, applied to this branch's own copies:

- electron/package-lock.json regenerated (271 -> 284 entries): the optional
  electron-builder-squirrel-windows subtree was missing and `npm ci` refused the lock
  (EUSAGE) on the Linux and macOS legs; a clean `npm ci --ignore-scripts` on the
  result exits 0.
- electron-release.yml: `build_ref` dispatch input (default: the version tag) and
  `generate_release_notes` only on the tag push (a re-attach dispatch appended
  GitHub's auto notes to the curated body on v3.8.50).
- npm-publish.yml: the SBOM attaches to the GitHub Release on workflow_dispatch
  publishes too, whenever a release for the tag exists.

actionlint and prettier clean; electron-release-desktop-channel-8949,
electron-release-efficiency, electron-release-latest-yml.repro, check-workflows
and npm-publish-artifact-provenance suites pass.

* fix(release): validate build_ref in the validate job before any checkout uses it

CodeQL (actions/cache-poisoning/poisonable-step, high) on release/v3.8.51 — the
default branch: a raw dispatch input checked out next to setup-node's npm cache is a
cache-poisoning vector. The input now goes through the validate job's regex
allowlist (main or release/vX.Y.Z, empty = the version tag) and every build job
checks out needs.validate.outputs.build_ref, never the input itself.

* fix(release): drop the build_ref input — a dispatch builds the ref it is dispatched on

CodeQL (actions/cache-poisoning/poisonable-step) tracks the input through the
validate job's output regardless of the regex allowlist: an input-controlled
checkout next to setup-node's npm cache on the default branch is a cache-poisoning
vector. The ref is not an input any more; the checkouts use github.ref, so
`gh workflow run electron-release.yml --ref v3.8.50 -f version=v3.8.50` rebuilds
the tag and `--ref main` builds the repaired line. The tag-push path is unchanged.
…12021)

* fix(ci): stop hosted docker-publish OOM and unpaint Build (advisory)

docker-publish was firing 8 concurrent hosted builds on every merge
storm; each died ResourceExhausted in npm run build (#11976). One
publish per ref, webpack instead of Turbopack so native RSS stays
inside the V8 heap we can cap. Build (advisory) is skipped: continue-on-error
still reports FAILURE and was painting every fork PR red.

Closes #11976

* fix(ci): run docker-publish amd64 on omni-build and share the heavy lane

The .113 box is 31 GB / 32 cores — enough for one next-build. Hosted
ubuntu-24.04 is ~7 GB and ResourceExhausted every publish (#11976).
amd64 now targets [self-hosted, omni-build] (Turbopack) when
USE_VPS_RUNNER is on, joins the existing heavy-build-main group so it
queues beside ci.yml Build instead of becoming a third heavy, and
falls back to hosted + webpack if the VPS is off. arm64 stays on
ubuntu-24.04-arm with webpack (no ARM box).

* test(ci): align the advisory-build contract with the hosted-OOM skip

if: ${{ false }} tripped zizmor obfuscation (194→195). Bare if: false
skips the job without a new finding. The #7307 test now pins the skip
and keeps the job body as the restore recipe.
…t a driver line the primary path never prints (twin of #12032) (#12047)

* fix(release): the packaged-app smoke verifies the database opened, not a driver line the primary path never prints (release/v3.8.51 twin of #12032)

Same change as #12032 on main: the packaged app opens SQLite during the smoke but
its primary open path prints no "[DB] Driver: …" line (only the recovery path and
the sql.js fallback do), so the #7592 assertion failed every Linux release leg. The
guard rejects the sql.js fallback line, accepts a native driver line, and otherwise
accepts demonstrable database activity; after readiness the smoke requests
/api/monitoring/health and waits for that activity outside the readiness loop.
electron-smoke-script suite 10/10.

* fix(release): reapply the smoke rework on top of release/v3.8.51's own copy of the script

The previous commit copied main's file wholesale and dropped this branch's
ensureSmokeEnvDirs(currentPlatform) fix and its tests; this reapplies only the
DB-open evidence change as a patch. electron-smoke-script suite green.
* docs(ops): the .113 heavy-build ceiling is one runner, not two

Two concurrent next-builds (15.4 GB + 17.2 GB RSS) OOM-killed one on 2026-08-29 17:26 UTC;
systemd booked the kill on the other runner's unit and its job died with the same
"shutdown signal" text a hosted-runner OOM shows. omni-build now lives on
omniroute-113-5 only; 113-6 keeps omni-release. The janitor ceiling counts every
listener on the box (4 OmniRoute + OmniHeuris + OmniMind = 6). The second heavy slot
returns when the Proxmox VM gets more RAM; the exact command is in the doc.

* docs(ops): apply the single-heavy-slot text (previous commit only carried formatting)
Turbopack had 31 GB on omniroute-113-6 and still panicked
(TurbopackInternalError: there must be a path to a root, run
33253576569). The same tree's arm64 webpack build on hosted ARM
succeeded. Dockerfile already documents webpack as the Docker
escape hatch. Keep amd64 on the one omni-build slot (#12048).
#11600) (#11996)

Fixes the blocking Lint job's own ci.yml cache: PR #11963 removed the stale restore-keys fallback from quality.yml but left ci.yml's two "Restore ESLint file cache" steps carrying the same prefix-match fallback that lets a cache from a different lint config report stale per-file verdicts. Byte-level parity with #11963's already-merged fix.

Deliberately half of #11600 — the other half (run-eslint-json.mjs) is covered by PR #11983 from a parallel session, so the two don't collide on the same file.
… list (#11949) (#11995)

Local no-API-key providers (ollama-local, lm-studio, vllm, etc.) were invisible in the Qdrant embedding-model dropdown because configuredProviders required a real apiKey or OAuth. Extended the filter to also include providerAllowsOptionalApiKey(connection.provider) — the same canonical helper already used for the identical check elsewhere. TDD: 21/21 integration tests pass (was 20/21 before the fix).
) (#11993)

Fixes a copy-paste label typo (Hermes-4-405B mislabeled "7B") in both the registry and the free-model catalog data, spotted in the #11861 comment thread. TDD: 3/3 tests, generic parameter-size consistency check + exact regression guard.
…start (#11885) (#12005)

Fixes three defects in the "update doesn't restart the running process" bug class: CLI update guidance now detects a live server and tells the operator to restart instead of implying the update is already live; the dashboard's Update button tries OmniRoute's own PID-file supervisor before falling back to pm2 instead of hardcoding pm2 and silently skipping; getLatestVersionFromNpmCli now uses --prefer-online (same fix pattern as #4376). TDD throughout, 63/63 targeted regression tests pass.
…1481) (#11997)

Adds opt-in modelVisibilityAllowlist/modelVisibilityDenylist settings so an operator can curate exactly which models GET /v1/models advertises, mirrored into auto/* combo candidate pools (the same trap #6512 fixed for hidePaidModels). Default off, no behavior change for anyone who doesn't opt in.

TDD: 4 new test files, 22/22 passing (16 node:test + 6 vitest) + regression sweep across virtual-auto-combo/hide-paid/hide-auto-no-think suites (21/21).

Rebased onto the updated tip (a sibling #9133 landed first, same file) — kept both rebaseline annotations in file-size-baseline.json and set the value to the real measured line count after both merged.
…conciliation (#11652) (#12009)

FU-05 core (closes #11652): caller-supplied Video Bridge transcripts had no bounded, deterministic contract — a client could self-assert source: "embedded"/"audio-bridge" and it was accepted verbatim. normalizeVideoTranscript gained a code-only trustedSource seam unreachable from request-body JSON; without it, any cue declaring embedded/audio-bridge is reclassified to client. Added budgets (256 cues, 4096 code units/cue, 4KiB/cue, 64KiB total), malformed-surrogate rejection, focus-window scoping, deterministic cross-source reconciliation, and bumped the result-cache version v4→v5 so old-contract cache entries can never serve new-contract requests.

All 187 videoBridge* tests pass (185 pass, 2 unrelated pre-existing skips).
…ker (#11659) (#12011)

FU-05 subtitle adapter (Refs #11659 — deliberately not Closes: the adapter is not yet wired into the live describeVideoPart path, that composition point is sibling #12009 which just landed): server-owned, loopback-only ffprobe/ffmpeg subtitle extraction that legitimately earns the "embedded" provenance label, mirroring the existing frame-extraction lifecycle. Broker route now also serves ?subtitles=1, stamped with the shared broker fingerprint so the client-side adapter can verify the payload actually came from the trusted process. Bounded, ReDoS-safe WebVTT parser.
…or, evaluator and allowlist scaffold (#11656) (#12008)

FU-07/FU-09 promotion-evidence harness (Refs #11656): delivers the manifest schema, deterministic fixture recipes, metrics aggregator, and promotion-verdict evaluator #11656 asks for — deliberately does NOT deliver the promotion verdicts themselves (they require real models against real fixtures on a live host, HOLD with explicit reason instead of any fabricated result). New files only, no collision with sibling PRs.
…ution variants (FU-08) (#12006)

FU-08 (Refs #11655): drill-down producer/consumer lifecycle on top of the existing cache substrate, without modifying it — new VideoDrilldownLifecycle (opaque sha256 handles, principal-bound resolve/delete with no existence oracle, preview/standard/detail multiresolution variants, 8-frame/32MiB page budget) plus a new authenticated remote-consumer route, both opt-in (default false).
…lared (#11661) (#12001)

Reconciles the Video Bridge FU-01..09 backlog docs against verified code and GitHub state (ground truth established first, per this repo's Documentation accuracy rule), correcting a real gap in GUARDRAILS.md: the transcript source field was documented as validated without noting OmniRoute didn't yet verify server-side extraction — exactly the gap #11652 (now merged as #12009) closes. Refs #11661, not Closes — truthfully closing it needs the sibling PRs' actual landed state folded back in, left as an explicit follow-up.
@diegosouzapw
diegosouzapw merged commit 5fcd39b into release/v3.8.51 Aug 29, 2026
8 of 10 checks passed
@diegosouzapw
diegosouzapw deleted the feat/11654-video-audio-bridge-stt branch September 4, 2026 11:11
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…FU-06, cheaper-inference#11654) (cheaper-inference#12012)

FU-06 (Audio Bridge STT orchestration): one download, two extractions — takes already-downloaded video bytes and extracts bounded mono 16kHz PCM WAV via the loopback broker's new mode=audio operation, sharing the exact same queue/deadline/byte budgets as the frame path. Dual opt-in (operator setting default false + per-request), only reaches the STT call when both are on.

Rebased onto the tip after sibling cheaper-inference#12011 (subtitle mode) landed first, both touching the same broker route/client — combined additively so frames/audio/subtitles all share the one extractionQueue singleton. Re-validated: 59/59 focused tests pass.
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