Three agents on two orchestrators: one plan-and-execute agent with replan for Script and Image (the LLM plans once, code runs and checks, replan only on problems), a single planner loop for Quick Video. Plus the stack, the eval behind the switch, and the pain points found in real use.
One chat turn = one background job. Drafts film script, episode outline, episode script, scene prompts and keyframes. The old fixed graph stays as a fallback.
Separate chat thread per project. Drafts the style, character cards and location cards; images are generated only when the user clicks.
Chat prompt + a few images → a video under 60 seconds. The LLM picks the step; code checks the rules and holds the money gate.
Modular monolith split by layer. Every AI call runs in the worker, never inside an HTTP request.
langgraph: plan-and-execute agent with replan (fixed graph as fallback)langgraph-checkpoint-postgres chat memorylangchain-core interfaces · Langfuse tracing (dev)httpx REST to OpenAI and Vidu, no SDKgpt-6-lunagpt-image-2viduq3-turbouv.lock · Docker image python:3.12-slim with dev / prod targets · pytest + pytest-asyncio (fake providers only) · ruff · eval suite: 10 cases, LLM judge, real model on demand3 runs per case, gpt-6-luna runs and judges (2026-10-13). #1 right tool call (code) · #2 meets the request · #3 usable by a director (LLM judge).
| Total | Fixed graph | ReAct agent | Plan + replan | + light reasoning (D) |
|---|---|---|---|---|
| Runs | 10 × 3 | 10 × 3 | 11 × 3 | 11 × 3 |
| #1 Right tool call | 80% | 73% | 88% | 91% |
| #2 Meets the request | 60% | 58% | 71% | 67% |
| #3 Usable by a director | 58% | 51% | 66% | 70% |
| LLM calls per run | 3.2 | 2.4 | 2.5 | 2.6 |
| Tool calls (drafts made) | 15 | 15 | 23 | 25 |
| Cost (assistant only) | $0.0443 | $0.0336 | $0.0519 | $0.0512 |
| Planner time p50 | — | — | 10.0 s | 6.6 s |
| Hit the cap · errors | — · 0 | 0 · 0 | 0 · 0 | 0 · 0 |
lowlowlow (round 2)| A · baseline | B · light coordination | C · B + light tools | D · B + compact respond | E1 · only planner at low | |
|---|---|---|---|---|---|
| #1 / #2 / #3 quality | 91 / 69 / 70 | 88 / 66 / 64 | 91 / 64 / 69 | 91 / 67 / 70 | 97 / 74 / 67 |
| Assistant cost | $0.0607 | $0.0508 (−16%) | $0.0474 (−22%) | $0.0512 (−16%) | $0.0590 |
| Time per turn (median) | 22.9 s | 17.1 s (−25%) | 20.3 s (−11%) | 20.4 s (−11%) | 25.3 s |
| Planner (median per call) | 10.0 s | 7.4 s (−27%) | 8.1 s | 6.6 s (−34%) | — |
apps/api/evals/assistant/reports/compare-graph-vs-agent-plan.md (jobs 463, 462, 465, 469) · tuning: reports/tuning-2026-10-13-005.md · D rerun 91 / 63 / 66 vs D 91 / 67 / 70: noise · D1 (shared prompt prefix): no cache gain · E1 is round 2: vs D rerun +9% cost, +29% timeT2V, I2V, R2V, V2V) and the model.edit_of: scene N) and code makes a new take.I2V, else T2V.I2V start-end, else R2V.R2V + last frame of the previous scene.R2V.I2V start-end → I2V → R2V.docs/10-model-routing.md §3, §5 (exploring, no proposal yet) · related: PP-012 · most platforms (Vidu, Flow) and every API make the user / caller pick the mode explicitlyPros and cons are still hypotheses, to be tested by a dev on the web UI before any of it becomes a routing rule.
| Type | Input | Pros | Cons | In the app today |
|---|---|---|---|---|
| T2Vtext to video | Prompt only | Needs only a prompt: no image to prepare first | Nothing anchors the face or the composition | Not used |
| I2Vimage to video · start / start-end | Prompt + start image (+ end image) | Composition and setting match the start (and end) image; Keyframe mode already has these frames | Needs the image to exist first; the prompt must not contradict it | Only sheet_cut with first frame (img2video) |
| R2Vreference to video | Prompt + subject images (characters, background) | Keeps a character's face across many scenes, from the character card images | Does not lock the composition; needs @Name and @background in the prompt | Default for almost every scene (reference2video) |
| V2Vvideo to video | Prompt + source video | Edits or restyles an existing video without redoing the whole scene | Needs a source video, so it cannot be chosen at planning time | Not used (planned for the post-production tab) |
start_frame, end_frame, subject:<name>, background, source_video. A last frame of T2V can feed I2V; an I2V output can be an R2V subject.stale and the agent rewrites it.docs/10-model-routing.md §1, §2, §4, §9 · code: services/video.py::to_vidu_request, vidu_endpoint