Pipelines
Build composable media workflows with compose()
Pipelines
Pipelines are the core abstraction in Synthome. They let you compose multiple operations into a single workflow that executes as one unit.
The compose() Function
Use compose() to create a pipeline:
import { compose, generateVideo, videoModel } from "@synthome/sdk";
const pipeline = compose(
generateVideo({
model: videoModel("bytedance/seedance-1-pro", "replicate"),
prompt: "A beautiful sunset",
}),
);Pipelines are lazy - nothing executes until you call .execute().
Executing Pipelines
Call .execute() to run the pipeline:
const execution = await pipeline.execute();
console.log(execution.id); // Execution ID
console.log(execution.status); // "completed" | "failed" | "pending" | "processing"
console.log(execution.result?.url); // URL to the generated mediaBy default, .execute() waits for the pipeline to complete and returns the result.
Composing Operations
Pipelines can contain multiple operations. Operations run in parallel when possible, but automatically wait for dependencies when one operation needs the output of another.
Using URLs and Generated Media
Operations accept both direct URLs and generated media. You can mix them freely:
import { compose, generateVideo, merge, videoModel } from "@synthome/sdk";
const execution = await compose(
merge([
// Direct URL - no generation needed
"https://example.com/intro.mp4",
// Generated video - runs in parallel with other generations
generateVideo({
model: videoModel("bytedance/seedance-1-pro", "replicate"),
prompt: "Scene 1: A rocket launching",
}),
// Another generated video - runs in parallel
generateVideo({
model: videoModel("bytedance/seedance-1-pro", "replicate"),
prompt: "Scene 2: Earth from orbit",
}),
// Another direct URL
"https://example.com/outro.mp4",
]),
).execute();This works the same way for images and audio:
// Mix URLs and generated images
merge([
"https://example.com/photo.jpg",
generateImage({ ... }),
])
// Mix URLs and generated audio
merge([
"https://example.com/music.mp3",
generateAudio({ ... }),
])Parallel Execution
Independent operations run in parallel automatically. In the example above:
- Both
generateVideo()calls run at the same time - The
merge()waits for all inputs to complete before combining them
Dependencies
When an operation depends on another's output, Synthome handles the sequencing automatically:
const execution = await compose(
captions(
merge([
generateVideo({ ... }),
generateVideo({ ... }),
]),
),
).execute();Execution order:
- Both
generateVideo()calls run in parallel merge()waits for both videos, then combines themcaptions()waits for the merged video, then adds subtitles
Async Execution with Webhooks
For long-running pipelines, use webhooks instead of waiting:
const execution = await compose(
generateVideo({ ... }),
).execute({
webhook: "https://your-server.com/webhook",
webhookSecret: "optional-secret-for-verification",
});
// Returns immediately with execution ID
console.log(execution.id);Your webhook receives a POST request when the pipeline completes:
{
"executionId": "exec_abc123",
"status": "completed",
"result": {
"url": "https://cdn.example.com/video.mp4",
"type": "video"
}
}Checking Execution Status
For async executions, check status manually:
import { getExecutionStatus } from "@synthome/sdk";
const status = await getExecutionStatus(execution.id);
console.log(status.status); // "processing" | "completed" | "failed"
console.log(status.progress); // 0-100
console.log(status.currentJob); // Current job name
console.log(status.completedJobs); // Number of completed jobs
console.log(status.totalJobs); // Total number of jobsError Handling
Handle errors with try/catch or the .onError() callback:
// Option 1: try/catch
try {
const execution = await compose(
generateVideo({ ... }),
).execute();
} catch (error) {
console.error("Pipeline failed:", error.message);
}
// Option 2: onError callback
const execution = await compose(
generateVideo({ ... }),
)
.onError((error) => {
console.error("Pipeline failed:", error.message);
})
.execute();Execution Options
The .execute() method accepts configuration options:
await pipeline.execute({
// Webhook for async execution
webhook: "https://your-server.com/webhook",
webhookSecret: "your-secret",
// Override API URL (for self-hosted)
apiUrl: "https://custom-api.example.com",
// Override API key
apiKey: "your-synthome-api-key",
// Provide provider API keys directly
providerApiKeys: {
replicate: "your-replicate-key",
fal: "your-fal-key",
},
});Execution Plans
Pipelines are converted to an execution plan (JSON) before running. This design enables powerful integrations:
- AI agents can generate execution plans directly
- Store and replay pipelines without code
- Debug and inspect what will execute
Inspecting the Plan
const pipeline = compose(
merge([
"https://example.com/intro.mp4",
generateVideo({ ... }),
]),
);
// Get the execution plan without executing
const plan = pipeline.toJSON();
console.log(JSON.stringify(plan, null, 2));Executing from JSON
Use executeFromPlan() to run a plan directly - no SDK pipeline code needed:
import { executeFromPlan } from "@synthome/sdk";
// Plan generated by AI, loaded from database, or built manually
const plan = {
jobs: [
{
id: "job1",
type: "generate",
params: {
modelId: "bytedance/seedance-1-pro",
prompt: "A beautiful sunset",
},
output: "$job1",
},
],
};
const execution = await executeFromPlan(plan);
console.log(execution.result?.url);This is particularly useful for AI agents that generate video workflows dynamically.
Next Steps
How is this guide?