Skip to content

web: route Scope streams through the live-runner discovery flow#23

Open
qianghan wants to merge 1 commit into
livepeer:ja/live-runnerfrom
qianghan:fix/discovery
Open

web: route Scope streams through the live-runner discovery flow#23
qianghan wants to merge 1 commit into
livepeer:ja/live-runnerfrom
qianghan:fix/discovery

Conversation

@qianghan

Copy link
Copy Markdown

Why

livepeer-python-gateway already wraps the legacy AI‑worker path: start_lv2v(...)POST {orch}/live-video-to-video, where the orchestrator gates admission through orch.CheckAICapacityAIWorker.HasCapacity. That capacity check only sees AI workers.

Scope runs as a live runner, not an AI worker. Its capacity lives in the live‑runner registry that the ja/live-runner branch introduces (GET {orch}/discoveryPOST {orch}/apps/{runner_id}/session to reserve a session, then stream + per‑session payment). Because the legacy capacity check is blind to live runners, a live‑runner‑only orchestrator (e.g. our scope-1) rejects /live-video-to-video with "insufficient capacity" even when /discovery shows the runner healthy, priced, and idle.

ja/live-runner ships the client for the new flow as livepeer_gateway.scope.start_scope(...), but the FastAPI web wrapper (web/app.py) still routed every model through start_lv2v. So there was no way to drive a Scope live‑runner end‑to‑end through the SDK service — the discovery/reserve/pay path was unreachable from the HTTP API.

This PR wires the web wrapper to pick the right flow per model, so Scope streams actually reach the live runner.

What

  • web/app.py — route by model:
    • New _LIVE_RUNNER_MODELS = {"scope"} set.
    • In start_job, if model_id is a live‑runner model, call await start_scope(orch_url, req, token=..., signer_url=...) (discover → reserve → stream + payment challenge). Otherwise keep the legacy start_lv2v path (run in a thread since it's sync).
    • Rejection details from the orchestrator are surfaced in the 500 response (rejections: [{url, reason}]) for easier debugging.
  • The rest of the wrapper (job state, WS JPEG bridge, SSE events, control channel, shutdown handling) is unchanged — only the start path becomes flow‑aware.

This is purely additive: non‑Scope models keep the existing legacy behavior; only scope takes the live‑runner path.

Verified

Against a live scope-1 orchestrator (live‑runner only):

  • start_scope performs GET /discovery, reserves a session via POST /apps/{runner_id}/session, and answers the runner payment challenge — confirmed in orchestrator logs (discovery hit, session reserved, payment processed).
  • The legacy start_lv2v path used to fail this same orchestrator with "insufficient capacity"; the live‑runner path is admitted.

Known follow‑ups (not in this PR)

  • Media‑session wiring: the reserved live‑runner session's trickle in/out channels aren't yet bridged in the wrapper's media pipeline, so a full bidirectional stream still reaps idle (in=none, out=none). This PR unblocks discovery/reserve/pay; trickle media wiring is the next step.
  • Serverless vs live‑runner routing / fallback inside start_scope.
  • Sane default runner price under the gateway max‑price ceiling.

Base branch: ja/live-runner (these changes depend on the livepeer_gateway.scope module introduced there).

Scope runs as a live runner, so its capacity lives in the live-runner registry
(GET /discovery -> POST /apps/{runner}/session -> stream), not the AI-worker
CheckAICapacity path that legacy /live-video-to-video uses. The sdk-service
web/app.py called start_lv2v for everything, so Scope requests hit the AI-worker
capacity check (0 on a live-runner-only orchestrator) and got "insufficient
capacity" even with a healthy, priced, idle runner.

Wire web/app.py to call start_scope() (already implemented on ja/live-runner)
for live-runner models (scope), keeping start_lv2v for the legacy serverless
path. Built on top of ja/live-runner so the live-runner client lib
(discovery.py, live_runner.py, scope.start_scope) is present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: qianghan <qiang@livepeer.org>
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aa81bed5-4a33-4781-b89f-966f582f239d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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