Repository navigation
feat: add the video job contract and provider error taxonomy - #349
Merged
Merged
Conversation
Video providers each spoke their own dialect: Seedance blocked inside one call with no job ID, Kling needed a task type to poll, Gemini's cancel was a no-op, and callers told a likeness rejection from a quota error by matching provider wording. This adds the shared contract they will all move onto, and moves Runway first. - `VideoGenerator` (ai-providers/src/video): submitVideo, getVideoJob, cancelVideoJob, downloadVideo, over a serializable `VideoJob` handle. `VideoRequest.from` carries extend/edit continuations (Omni sessions, Kling extend). `waitForVideoJob` polls any generator. - `ProviderError` with a `kind` (auth, quota, rate-limit, likeness, moderation, invalid-request, unsupported, model-retired, not-found, timeout, provider, network) and `classifyProviderError`. `ModelRetiredError` is now a ProviderError. - `providerRequest` (ai-providers/src/shared/http.ts): one HTTP path with retries on 429/5xx and network errors, Retry-After, a timeout, and classified errors whose messages never include the query string. - `resolveVideoModel`: catalog lookup plus the shutdown check, before any request. - `describeVideoContract`: the reusable suite each provider must pass. - The fake provider network moves to `@vibeframe/ai-providers/testing` with no test-runner dependency; the CLI re-exports it with its routes. - RunwayProvider implements the contract; its older methods wrap it. - Provider counts now count directories with a `*Provider.ts`, so shared code is not counted as an integration (14, not 16). Claude-Session: https://claude.ai/code/session_011S1BLTaFctZNQzGERpkCuA
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Oct 4, 2026
This branch was successfully deployed
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.
First PR of the provider interface work (step 3.3): the shared contract, with Runway moved onto it.
Why
Each video provider spoke its own dialect.
Seedance blocks inside one
fal.subscribecall with no job ID, so a crash mid-wait loses a paid job.Kling needs a task type just to poll, Gemini's cancel is a no-op, and wait methods have five different names.
Callers told a likeness rejection from a quota error by matching provider wording, which breaks silently when a provider rewords a message.
The CLI branches on provider name in 16 places in
generate videoalone.What this adds
VideoGenerator(ai-providers/src/video/contract.ts):submitVideo,getVideoJob,cancelVideoJob?,downloadVideo.VideoJobis plain, serializable data, so a job submitted in one process can be polled, resumed, or cancelled from another.VideoRequest.fromis where Omni multi-turn edits and Kling/Veo extension will plug in.ProviderErrorwith 12kinds andclassifyProviderError. Content wording beats status codes, so a 422 likeness filter reads aslikenessand a 429 "insufficient credits" reads asquota.ModelRetiredErroris now one of these.providerRequest(ai-providers/src/shared/http.ts): one HTTP path. It retries 429/502/503/504 and network errors and honoursRetry-After. Every failure becomes a classified error, and messages carry the path without the query string, so keys never leak.resolveVideoModel: catalog lookup and the shutdown check before any request.waitForVideoJob: generic polling that rides out retryable read errors, supports an abort signal, and on timeout keeps the job ID in the error.describeVideoContract: a reusable suite every provider must pass. It covers handles, poll and download, classified job failures, classified submit errors, model validation before any request, declared continuations, and cancel.@vibeframe/ai-providers/testingwith no test-runner dependency, and the CLI re-exports it with its build routes.RunwayProviderimplements the contract, and its older methods wrap it, so CLI callers are unchanged until the CLI moves (PR 3).Also
sync-counts.shand the website counted every folder underai-providers/src, socatalogandsharedwere counted as integrations. They now count folders that contain a*Provider.ts: 14, not 16.fetchJsoninshared/http.tsstays until Gemini moves ontoproviderRequest.Verification
pnpm build,pnpm lint,pnpm typecheck, tests (providers 164, CLI 1215, MCP 73), pre-push gate.vibe generate video -p runway --duration 2downloaded a 2.04 s clip (about $0.24).{kind: "auth", status: 401, retryable: false}with Runway's message.Next
PR 2 moves Kling, Grok, Seedance (onto the fal queue, so jobs survive a crash), and Omni onto the contract.
PR 3 removes the provider-name branches from the CLI.
https://claude.ai/code/session_011S1BLTaFctZNQzGERpkCuA