cd /news/artificial-intelligence/building-wan-3-0-the-hard-parts-of-a… · home topics artificial-intelligence article
[ARTICLE · art-108489] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

Building Wan 3.0: The Hard Parts of an AI Video Workspace

The engineering team behind Wan 3.0, an AI video workspace, detailed the complex backend required to support text, image, frame, and reference-based video generation. They highlighted the use of explicit scene types, provider adapters, and a five-state task lifecycle to handle asynchronous generation, retries, and varying provider APIs. The team emphasized that early validation and normalized task records are crucial for reliability and auditability.

read6 min views3 publishedAug 24, 2026

A prompt box makes an AI product look simple. The user writes a sentence,

clicks Generate, and waits for a video.

The real system is less tidy. A request can outlive the browser tab, a provider

can accept a job and fail later, and a retry can accidentally create a second

billable task. Add multiple models, several input modes, and usage-based

pricing, and the prompt box becomes the smallest part of the product.

These are some of the engineering decisions behind

Wan 3.0, the AI video workspace we have been building for

text, image, frame, and reference-based generation. This is not a launch post

disguised as a tutorial. It is a practical look at the parts that took more

thought than the interface suggests.

Text-to-video and image-to-video may end with the same file type, but they do

not begin with the same contract.

A text request needs a prompt, aspect ratio, resolution, and duration. An

image-to-video request also needs an uploaded asset. A frame transition needs

two ordered images, while reference-based generation may accept a clip or a

set of visual references. Model support differs as well.

We represent those paths as explicit scenes rather than stretching one loose

payload across every model:

type VideoScene =
  | 'text-to-video'
  | 'image-to-video'
  | 'frames-to-video'
  | 'reference-to-video'
  | 'video-edit'
  | 'video-extend'
  | 'video-upscale';

Each model declares the scenes and fields it supports. The UI can then adapt

to the chosen workflow, and the server can reject combinations that do not

make sense before contacting a provider.

That early validation matters. An upstream API error is slower, harder to

explain, and sometimes more expensive than a local validation error.

Provider APIs disagree about nearly everything: parameter names, callback

formats, status values, result shapes, and whether polling or webhooks are the

preferred completion path.

Letting those differences leak into the product would couple every form and

task screen to a specific vendor. Instead, Wan 3.0 puts a small adapter around

each provider:

interface AIProvider {
  readonly name: string;
  readonly supportsWebhook: boolean;

  generate(params: AIGenerateParams): Promise<AIProviderResult>;
  query?(providerTaskId: string): Promise<AIProviderResult>;
  verifyWebhook?(request: Request): Promise<AIProviderResult>;
  cancel?(providerTaskId: string): Promise<void>;
}

The rest of the application works with one internal result shape and a small

set of task states. Provider-specific code stays at the edge.

This does not make providers interchangeable. Models still have different

inputs and capabilities. It does, however, give the application one place to

translate those differences instead of scattering conditional logic across

the codebase.

Video generation is asynchronous by nature. Treating it like a normal request

and keeping the browser waiting creates fragile behavior for both the user and

the server.

Our task lifecycle uses five states:

pending -> processing -> succeeded
                      -> failed
                      -> canceled

Providers can complete synchronously, through polling, or by webhook. Those

transport details are normalized into the same task record and result format.

The browser can leave, return later, and read the current state from history.

The simplified flow looks like this:

scene + model + inputs
        |
        v
validation and credit estimate
        |
        v
task creation + credit reservation
        |
        v
provider adapter
        |
        v
webhook or polling
        |
        v
result history or automatic refund

Persisting the task also gives us a useful audit trail: selected model,

provider, normalized input, pricing snapshot, cost, timestamps, and terminal

result all belong to the same operation.

Retries are normal. A user can double-click, the network can time out after

the server accepts a request, or a client can retry because it never received

the first response.

For a paid generation, “probably only once” is not good enough.

Every create request carries an idempotency key. We also calculate a

fingerprint from the model, scene, and validated parameters. If the same key

returns with the same fingerprint, the existing task is reused. If that key

appears with different input, the request is rejected.

The fingerprint check closes an easy-to-miss gap: an idempotency key should

identify one operation, not become a container for whichever payload arrives

last.

Usage-based products should show the cost before the expensive operation

starts. The harder requirement is making sure the displayed estimate and the

recorded charge use the same calculation.

Wan 3.0 calculates credits from the selected model and validated settings.

Depending on the model, duration, resolution, and other options can change the

result. The task stores both the calculated cost and a pricing snapshot, so a

later configuration change does not rewrite the meaning of an older task.

Task insertion and credit reservation happen in one database transaction. If

either step fails, neither should survive on its own. That keeps us away from

two awkward states:

The UI benefit is straightforward: the number shown before submission is tied

to the task the user sees afterward.

External generation can fail after a provider has accepted the request. It can

also time out or send the same callback more than once. A refund handler must

therefore be safe to repeat.

Our refund path locks the task record, checks whether the task is already in a

terminal or refunded state, writes a refund transaction, restores the balance,

and marks the task as refunded. All of that happens inside a transaction.

The goal is not “try to refund.” It is a narrower invariant:

A failed generation that reserved credits can restore them once, even if the

failure signal is processed more than once.

This is one of those backend details that becomes a product feature. The user

does not need to know about row locks or duplicate webhooks. They only need to

see that a failed render did not consume their balance.

If we started another asynchronous AI product tomorrow, we would define four

things before polishing the generation form:

None of these decisions produces a dramatic screenshot. Together, they make

the simple screenshot honest.

Wan 3.0 is a browser-based workspace for generating AI videos and images. Its

video workflows include text, image, frame-pair, and reference inputs where

the selected model supports them.

No. Models declare their supported scenes and parameters. The interface and

server validation use that configuration to prevent unsupported combinations.

If a task reserved credits and later fails, the refund flow restores those

credits once and records the refund against the task.

The key identifies the operation. The fingerprint confirms that repeated uses

of the key contain the same model, scene, and input. Together, they prevent a

retry from silently becoming a different generation.

Building an AI video workspace is mostly an exercise in managing uncertainty:

slow jobs, changing providers, variable costs, duplicate requests, and partial

failures. A clean prompt box is valuable, but it only stays clean when the

task, provider, and credit systems underneath it have clear contracts.

You can try Wan 3.0 at wan3.io. If you are building an

asynchronous AI product, I would be interested to hear how you handle provider

drift, retries, and usage reconciliation.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @wan 3.0 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/building-wan-3-0-the…] indexed:0 read:6min 2026-08-24 ·