Repository navigation
fix(providers): poll OpenRouter video jobs and serve the clip safely - #16372
Merged
diegosouzapw merged 7 commits intoOct 18, 2026
Conversation
5 tasks done
LuisAlejandro
force-pushed
the
fix/16369-openrouter-video-job
branch
from
October 11, 2026 19:56
3fba497 to
46b65b0
Compare
OpenRouter was absent from the video registry, so its models were unreachable.
Wired through the synchronous openai-video handler instead, POST /api/v1/videos
answers 202 with a job id and the handler reported that as success with an empty
`data` array, which stopped a combo from trying the next target. The finished
clip arrives in `unsigned_urls` pointing at an endpoint that 401s without the
OpenRouter key, and an `expired` job was polled until the timeout.
Register openrouter against a new submit->poll preset. It treats `expired` as
terminal, downloads the auth-gated result with the provider credential, and
re-serves it from GET /api/v1/media/{id} as a URL built from the caller's
forwarded host rather than the bind address or BASE_URL.
Served media is scoped to the key that generated it: the owner travels in the id
as a truncated digest of the api key id, so no side table is needed and a URL
does not leak which key produced it. A mismatch is a 404 rather than a 403, so
the route does not confirm that an unowned id exists. Files expire on the
call-log retention window (CALL_LOG_RETENTION_DAYS, default 7) via a
prune-on-write sweep, so there is one retention knob and no scheduler.
The video route now establishes runWithCallLogApiKeyContext, the wrapper the
images and chat paths already use, which is what makes the media owner
attributable. The usage/call-log rows for this path are a follow-up.
Closes cheaper-inference#16369
LuisAlejandro
force-pushed
the
fix/16369-openrouter-video-job
branch
from
October 11, 2026 19:56
46b65b0 to
e8b7b4f
Compare
… proxied origins, scope media like files - Move the media store to src/lib/media and inject a per-request media sink (owner + public origin) into the open-sse video job pipeline, removing the four new open-sse -> src imports (dataPaths, logEnv, callLogApiKeyContext, resolveRequestOrigin). - Media URLs use the configured public base URL, then forwarding headers only from a trusted proxy (resolvePublicOrigin), then the direct Host; an untrusted X-Forwarded-Host is ignored. - Media ownership follows canAccessOwnedRecord: the generating key (or the anonymous-owner sentinel under REQUIRE_API_KEY=false), a manage-scope key or the dashboard session; anonymous media is no longer readable by any authenticated key, and session media needs the session. - The media route validates the id with Zod, rejects an invalid key with 401 and answers through buildErrorBody; OpenAPI entry added. - The provider credential is only sent to a result URL on the provider's own origin.
diegosouzapw
merged commit Oct 18, 2026
d0ae778
into
cheaper-inference:release/v3.8.52
6 of 8 checks passed
diegosouzapw
added a commit
to Kizuno18/OmniRoute
that referenced
this pull request
Oct 27, 2026
Resolve the five conflicts: - imageRegistryData.ts: keep the tip's muse-code import and the PR's Grok Build endpoint import. - videoGeneration.ts / videoGeneration/job.ts / videoCombo.ts: keep the tip's recordCall, mediaSink (cheaper-inference#16372), provider and poll-retry backoff (cheaper-inference#15536) and thread the PR's AbortSignal through them: the job wrapper forwards signal to runVideoJobGeneration, the poll wait is sleep(nextDelay, signal) with an abort check before the next poll, and fetchJson carries both raw and signal. - PROVIDER_REFERENCE.md: regenerated with npm run gen:provider-reference. Co-authored-by: Kizuno18 <appdoleo@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
openrouterjoins the video registry against a submit→poll preset, becausePOST /api/v1/videosanswers 202 with a job id rather than a finished clip. The synchronousopenai-videohandler reported that 202 as success with an emptydataarray, so a combo stopped instead of trying its next target.GET /api/v1/media/{id}, becauseunsigned_urlspoints at an endpoint that 401s without the OpenRouter key. Anexpiredjob is now terminal instead of polling until a misleading 504.X-Forwarded-Host/X-Forwarded-Proto, thenHost), not the bind address orBASE_URL. Served media is scoped to the key that generated it, and files expire on the call-log retention window.Related Issues
usageHistoryattribution fallback, are an independent PR (fix(api): record job-preset video calls and attribute them to the API key #16378), not stacked on this one. Both are based onrelease/v3.8.52.Validation
npm run lintnpm run check:provider-consistencydid not run locally: it is abunscript andbunis not installed in this environment (npm suggestscd node_modules/bun && node install.js). CI-only for this branch.provider.tstranslate-path golden snapshot fails locally onzyloai, which this diff does not touch.release/v3.8.52is already red — see 🔴 Release branch not green: release/v3.8.52 #15306.Tests Added Or Updated
tests/unit/services/openrouter-video-job.test.ts— extended: registry→preset wiring, submit→poll completion served as a URL, owner-tag digesting, retention prune, api-key-context owner, malformed-id traversal, cancelled job.tests/unit/services/resolve-request-origin.test.ts— new (forwarded host/proto precedence, comma-separated headers, direct-call fallback).Coverage Notes
open-sse/handlers/videoGeneration/mediaStore.tsandsrc/shared/utils/resolveRequestOrigin.tsare covered directly by the two test files above, as are the preset's auth-gated download and owner stamping inopen-sse/handlers/videoGeneration/job.ts.src/app/api/v1/media/[id]/route.tsis thin and mostly delegates — the id pattern, the owner digest and the file read all live inmediaStoreand are asserted — but the route's own ownership comparison (unowned id → 404) has no route-level test. Correcting an earlier claim in this description that the route was covered by these tests. Worth a reviewer's eye; say the word and I will add one.Reviewer Notes
GET /api/v1/media/{id}is new. The id is validated against the exact patternmediaStoregenerates, so it cannot escapeMEDIA_DIR; an unowned id returns 404 rather than 403 so the route does not confirm that it exists; session auth may read any id.CALL_LOG_RETENTION_DAYS(default 7) through a prune-on-write sweep: one knob, no scheduler. Lowering it also shortens how long served media URLs stay valid, and nothing expires while no generation runs.runWithCallLogApiKeyContext, the wrapper the images and chat paths already use. Here it is what makes the media owner attributable; the same identity feeds the usage/call-log rows in fix(api): record job-preset video calls and attribute them to the API key #16378.handleVideoGenerationcall site, where this PR threadsmediaOrigin, and injob.ts, where fix(api): record job-preset video calls and attribute them to the API key #16378 splits the function head for recording. Whichever lands second needs a trivial rebase (keep the incoming wrapper, add the other change).openrouteris added to the video registry only; the chat provider of the same name is untouched.