LangChain video generation tool that runs a Sume Format

A LangChain @tool can start a Sume Format run, cap its spend, key it for safe retries, and return a run id the agent checks until the video is ready.

5 min readSume
All posts

A LangChain video generation tool for Sume is a @tool function that starts a Format run with POST /v1/formats/{handle}/{slug}/runs, passes the agent's brief as input, caps spend with generation_spend_cap_usd, sends a stable Idempotency-Key, and returns the run id, because the run itself takes minutes.

The Sume facts come from Create a run, Runs and results, and Sume basics; the LangChain facts come from its Tools, MCP, and MCP authentication pages, all read on 2026-09-27. Sume has no official LangChain integration: this is a plain HTTPS call from your tool. How to embed AI video generation in your product covers the same API from a TypeScript backend.

Why wrap a Format instead of a model call?

A Format is a saved recipe. For each run, Sume boots a fresh sandbox, loads the recipe, runs the Agent with generation tools, and returns artifacts plus optional structured JSON; Sume's basics page calls it the surface most partners should integrate. Your LangChain agent decides that a video is needed, and the Format decides how to make it. Call your own Format at {handle}/{slug} or a catalog Format at sume/{slug}, with a key that has formats:write. New to Formats? Start with What is a Sume Format?

How do I write the tool?

LangChain's @tool decorator turns a function into a tool. Type hints are required because they define the tool's input schema, and the docstring becomes the description the model reads. These two tools start a run and read it back; pass both to create_agent:

import hashlib, os, requests
from langchain.tools import tool

API = "https://api.sume.com/v1"
AUTH = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}

@tool
def start_video_run(brief: str, product_url: str) -> str:
    """Start a Sume video run for a product. Returns a run id; the video takes minutes."""
    key = "lc-" + hashlib.sha256(f"{product_url}|{brief}".encode()).hexdigest()[:40]
    body = {"input": {"brief": brief, "product_url": product_url}, "generation_spend_cap_usd": 20}
    res = requests.post(f"{API}/formats/acme/product-video/runs", json=body,
                        headers={**AUTH, "Idempotency-Key": key}, timeout=30)
    res.raise_for_status()
    return res.json()["data"]["id"]

@tool
def get_video_run(run_id: str) -> dict:
    """Read a Sume video run. While status is queued or processing, check again later."""
    run = requests.get(f"{API}/format-runs/{run_id}", headers=AUTH, timeout=30).json()["data"]
    videos = [a["url"] for a in run["artifacts"] if a["type"] == "video"]
    return {"status": run["status"], "videos": videos, "error": run["error"]}

What goes in the request body?

The body must name at least one of instruction, input, previous_run_id, or attachments. This tool sends input and lets the Format's default instruction run:

From Create a run, read 2026-09-27.
FieldIn this toolRule from the docs
inputThe agent's brief and the product URL.A JSON object, at most 64 top-level keys and 2 MiB, written whole to a file. The run is told it is caller-supplied data, not instructions.
instructionOmitted.Up to 8000 characters; about the first 4000 reach the run. Omit it to run the Format's own default instruction.
generation_spend_cap_usd20Up to 500. 0 or above 500 is a 400. Omit it to inherit the Format's cap.
Idempotency-Key headerA hash of the arguments.Same key and body: 200 with the original run. Same key, different body: 409 idempotency_conflict. Up to 255 characters, scoped to one Format.
output_schemaNot sent.Bind a JSON Schema and output comes back in that shape.

Why derive the Idempotency-Key from the arguments?

The docs say to derive the key from the thing being made, not from the moment of asking. LangChain middleware can retry failed tool calls; when it does, the same arguments give the same key, and Sume answers with the original run instead of a second paid one. A 409 idempotency_key_in_use means a duplicate arrived at the same moment: wait about a second and resend to receive the original run.

How does the agent get the finished video?

The create answers 202 with a receipt. get_video_run reads GET /v1/format-runs/{run_id}: queued and processing mean check again later, and completed, failed, canceled, and skipped are final. artifacts[] lists every durable file the run generated, as media.sume.com URLs that do not expire and are public to anyone holding the URL.

Long-form video is 15 to 30 minutes of work, so back off between checks, doubling the gap up to a minute. expires_at is the deadline past which a run is force-finalized as failed, at most 90 minutes after created_at. Your server can also send communication.webhook_url, and Sume POSTs one signed receipt to it when the run completes or fails; the docs have production integrations keep a read of result_url as the backup. See Format run lifecycle.

Can I use LangChain's MCP adapter instead?

For single generations, yes. LangChain's MCPAdapter loads an MCP server's tools into create_agent, and a FastMCP Client(url, auth=token) sends a bearer token. The langchain.mcp namespace requires langchain[mcp]>=1.4.0 and is in beta. Sume's hosted MCP tools wrap selected API capabilities, such as generate_video and jobs_wait, and the documented tool inventory has no Format-run tool, so a Format run still goes through the Format API above. Sume's basics page also says hosted MCP still works but is not part of the primary path today.

Sources

Related posts

More in Integrations

All Integrations posts

Written by Sume