workflow 5.0.0-beta.1 → 5.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +4 -4
  2. package/dist/api-workflow.js +1 -1
  3. package/dist/api.js +1 -1
  4. package/dist/astro.js +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/internal/builtins.js +1 -1
  7. package/dist/internal/class-serialization.js +1 -1
  8. package/dist/internal/errors.js +1 -1
  9. package/dist/nest.js +1 -1
  10. package/dist/next.cjs +1 -1
  11. package/dist/nitro.js +1 -1
  12. package/dist/nuxt.js +1 -1
  13. package/dist/observability.js +1 -1
  14. package/dist/runtime.js +1 -1
  15. package/dist/stdlib.js +1 -1
  16. package/dist/sveltekit.js +1 -1
  17. package/dist/typescript-plugin.cjs +1 -1
  18. package/dist/vite.js +1 -1
  19. package/dist/workflow.js +1 -1
  20. package/docs/ai/resumable-streams.mdx +1 -1
  21. package/docs/api-reference/workflow/create-webhook.mdx +37 -18
  22. package/docs/api-reference/workflow/get-workflow-metadata.mdx +34 -0
  23. package/docs/api-reference/workflow-ai/durable-agent.mdx +0 -4
  24. package/docs/api-reference/workflow-ai/index.mdx +0 -5
  25. package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +0 -4
  26. package/docs/cookbook/advanced/custom-serialization.mdx +168 -0
  27. package/docs/cookbook/advanced/durable-objects.mdx +148 -0
  28. package/docs/cookbook/advanced/isomorphic-packages.mdx +145 -0
  29. package/docs/cookbook/advanced/meta.json +10 -0
  30. package/docs/cookbook/advanced/publishing-libraries.mdx +279 -0
  31. package/docs/cookbook/advanced/serializable-steps.mdx +135 -0
  32. package/docs/cookbook/agent-patterns/durable-agent.mdx +191 -0
  33. package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +278 -0
  34. package/docs/cookbook/agent-patterns/meta.json +10 -0
  35. package/docs/cookbook/agent-patterns/stop-workflow.mdx +216 -0
  36. package/docs/cookbook/agent-patterns/tool-orchestration.mdx +255 -0
  37. package/docs/cookbook/agent-patterns/tool-streaming.mdx +181 -0
  38. package/docs/cookbook/common-patterns/batching.mdx +179 -0
  39. package/docs/cookbook/common-patterns/child-workflows.mdx +372 -0
  40. package/docs/cookbook/common-patterns/content-router.mdx +207 -0
  41. package/docs/cookbook/common-patterns/fan-out.mdx +208 -0
  42. package/docs/cookbook/common-patterns/idempotency.mdx +107 -0
  43. package/docs/cookbook/common-patterns/meta.json +15 -0
  44. package/docs/cookbook/common-patterns/rate-limiting.mdx +228 -0
  45. package/docs/cookbook/common-patterns/saga.mdx +152 -0
  46. package/docs/cookbook/common-patterns/scheduling.mdx +249 -0
  47. package/docs/cookbook/common-patterns/webhooks.mdx +185 -0
  48. package/docs/cookbook/index.mdx +41 -0
  49. package/docs/cookbook/integrations/ai-sdk.mdx +204 -0
  50. package/docs/cookbook/integrations/chat-sdk.mdx +203 -0
  51. package/docs/cookbook/integrations/meta.json +4 -0
  52. package/docs/cookbook/integrations/sandbox.mdx +128 -0
  53. package/docs/cookbook/meta.json +5 -0
  54. package/docs/deploying/world/local-world.mdx +1 -1
  55. package/docs/deploying/world/postgres-world.mdx +1 -1
  56. package/docs/deploying/world/vercel-world.mdx +1 -1
  57. package/docs/errors/start-invalid-workflow-function.mdx +1 -1
  58. package/docs/getting-started/index.mdx +8 -1
  59. package/docs/getting-started/meta.json +2 -1
  60. package/docs/getting-started/python.mdx +165 -0
  61. package/docs/meta.json +1 -0
  62. package/docs/migration-guides/index.mdx +34 -0
  63. package/docs/migration-guides/meta.json +9 -0
  64. package/docs/migration-guides/migrating-from-aws-step-functions.mdx +311 -0
  65. package/docs/migration-guides/migrating-from-inngest.mdx +282 -0
  66. package/docs/migration-guides/migrating-from-temporal.mdx +284 -0
  67. package/docs/migration-guides/migrating-from-trigger-dev.mdx +296 -0
  68. package/package.json +13 -13
@@ -0,0 +1,128 @@
1
+ ---
2
+ title: Sandbox
3
+ description: Orchestrate Vercel Sandbox lifecycle -- creation, code execution, snapshotting -- inside durable workflows.
4
+ type: guide
5
+ summary: Use workflow steps to provision sandboxes, run code, and manage sandbox lifecycle with automatic cleanup on failure.
6
+ related:
7
+ - /docs/ai/defining-tools
8
+ - /docs/foundations/errors-and-retries
9
+ - /docs/api-reference/workflow-ai/durable-agent
10
+ ---
11
+
12
+ [Vercel Sandbox](https://vercel.com/docs/sandbox) provides isolated code execution environments. The `@vercel/sandbox` package implements first-class support for the Workflow SDK -- the `Sandbox` class is serializable, and its methods (`create`, `runCommand`, `destroy`, etc.) implicitly run as steps. This means you can interact with sandboxes directly inside workflow functions without wrapping each operation in a separate `"use step"` function.
13
+
14
+ ## What It Enables
15
+
16
+ - **Durable sandbox sessions** -- Sandbox provisioning and teardown survive cold starts
17
+ - **Automatic cleanup** -- Saga-style compensation ensures sandboxes are destroyed on failure
18
+ - **Multi-step code execution** -- Run a sequence of commands in the same sandbox with each step logged
19
+ - **Agent-driven sandboxes** -- Give your DurableAgent a tool that spins up sandboxes on demand
20
+
21
+ ## When to Use
22
+
23
+ Use this integration when your workflow needs to:
24
+
25
+ - Execute user-provided or AI-generated code safely
26
+ - Run multi-step build/test pipelines in isolated environments
27
+ - Provision temporary environments for interactive sessions
28
+ - Snapshot sandbox state between steps for reproducibility
29
+
30
+ ## Sandbox Lifecycle in a Workflow
31
+
32
+ Because `@vercel/sandbox` methods are implicit steps, each call is automatically persisted to the event log. If a failure occurs partway through, the workflow replays from where it left off.
33
+
34
+ ```typescript title="workflows/sandbox-pipeline.ts" lineNumbers
35
+ import { Sandbox } from "@vercel/sandbox";
36
+
37
+ export async function sandboxPipeline(input: {
38
+ template: string;
39
+ commands: string[];
40
+ }) {
41
+ "use workflow";
42
+
43
+ const sandbox = await Sandbox.create({ template: input.template }); // [!code highlight]
44
+
45
+ try {
46
+ const results = [];
47
+ for (const command of input.commands) {
48
+ const result = await sandbox.runCommand(command); // [!code highlight]
49
+ results.push(result);
50
+ }
51
+ return { status: "completed", results };
52
+ } catch (error) {
53
+ await sandbox.destroy(); // [!code highlight]
54
+ throw error;
55
+ }
56
+ }
57
+ ```
58
+
59
+ ## Sandbox as an Agent Tool
60
+
61
+ Give a DurableAgent the ability to create and use sandboxes. The agent decides when to spin up a sandbox, what code to run, and when to tear it down. Since sandbox methods are implicit steps, the tool execute functions can call them directly.
62
+
63
+ ```typescript title="workflows/code-agent.ts" lineNumbers
64
+ import { Sandbox } from "@vercel/sandbox";
65
+ import { DurableAgent } from "@workflow/ai/agent";
66
+ import { convertToModelMessages, type UIMessage, type UIMessageChunk } from "ai";
67
+ import { getWritable } from "workflow";
68
+ import z from "zod/v4";
69
+
70
+ export async function codeAgent(messages: UIMessage[]) {
71
+ "use workflow";
72
+
73
+ let activeSandbox: Sandbox | null = null;
74
+
75
+ const agent = new DurableAgent({
76
+ model: "anthropic/claude-sonnet-4-20250514",
77
+ instructions:
78
+ "You are a coding assistant. You can create sandboxes to run code. " +
79
+ "Always create a sandbox first, then execute code in it. " +
80
+ "Clean up the sandbox when you are done.",
81
+ tools: {
82
+ createSandbox: {
83
+ description: "Create an isolated sandbox environment for running code",
84
+ inputSchema: z.object({
85
+ template: z.string().describe("The sandbox template (e.g., 'node', 'python')"),
86
+ }),
87
+ execute: async ({ template }) => {
88
+ activeSandbox = await Sandbox.create({ template }); // [!code highlight]
89
+ return { sandboxId: activeSandbox.id };
90
+ },
91
+ },
92
+ executeCode: {
93
+ description: "Execute a command in the active sandbox",
94
+ inputSchema: z.object({
95
+ command: z.string().describe("The command to execute"),
96
+ }),
97
+ execute: async ({ command }) => {
98
+ if (!activeSandbox) throw new Error("No active sandbox");
99
+ return activeSandbox.runCommand(command); // [!code highlight]
100
+ },
101
+ },
102
+ cleanupSandbox: {
103
+ description: "Destroy the active sandbox when finished",
104
+ inputSchema: z.object({}),
105
+ execute: async () => {
106
+ if (!activeSandbox) throw new Error("No active sandbox");
107
+ await activeSandbox.destroy(); // [!code highlight]
108
+ activeSandbox = null;
109
+ return { cleaned: true };
110
+ },
111
+ },
112
+ },
113
+ });
114
+
115
+ const result = await agent.stream({
116
+ messages: await convertToModelMessages(messages),
117
+ writable: getWritable<UIMessageChunk>(),
118
+ });
119
+
120
+ return { messages: result.messages };
121
+ }
122
+ ```
123
+
124
+ ## Saga Pattern for Cleanup
125
+
126
+ Combine sandbox orchestration with the [saga pattern](/docs/cookbook/common-patterns/saga) to ensure sandboxes are always cleaned up, even when a step in the middle of your pipeline fails.
127
+
128
+ The example above uses a try/catch around the command execution loop. For more complex pipelines with multiple resources (sandbox + database + external API), push compensation functions onto a stack as shown in the [saga recipe](/docs/cookbook/common-patterns/saga).
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Cookbook",
3
+ "defaultOpen": true,
4
+ "pages": ["common-patterns", "agent-patterns", "integrations", "advanced"]
5
+ }
@@ -32,7 +32,7 @@ npx workflow web
32
32
 
33
33
  Learn more in the [Observability](/docs/observability) documentation.
34
34
 
35
- ## Testing & Performance
35
+ ## Testing & Compatibility
36
36
 
37
37
  <WorldTestingPerformance />
38
38
 
@@ -141,7 +141,7 @@ If `WORKFLOW_POSTGRES_URL` is not set, the CLI defaults to `postgres://world:wor
141
141
 
142
142
  Learn more in the [Observability](/docs/observability) documentation.
143
143
 
144
- ## Testing & Performance
144
+ ## Testing & Compatibility
145
145
 
146
146
  <WorldTestingPerformance />
147
147
 
@@ -83,7 +83,7 @@ npx workflow inspect runs \
83
83
 
84
84
  Learn more in the [Observability](/docs/observability) documentation.
85
85
 
86
- ## Testing & Performance
86
+ ## Testing & Compatibility
87
87
 
88
88
  <WorldTestingPerformance />
89
89
 
@@ -123,7 +123,7 @@ Before calling `start()`:
123
123
  1. Confirm the function includes `"use workflow"` as its first statement.
124
124
  2. Confirm your framework integration is enabled (for Next.js, wrap `next.config.ts` with [`withWorkflow()`](/docs/api-reference/workflow-next/with-workflow)).
125
125
  3. Pass the imported workflow function directly to `start()`, not a wrapper callback.
126
- 4. Keep the function in a file that goes through Workflow DevKit's transform step.
126
+ 4. Keep the function in a file that goes through Workflow SDK's transform step.
127
127
 
128
128
  ## Related
129
129
 
@@ -8,7 +8,7 @@ related:
8
8
  - /docs/foundations/workflows-and-steps
9
9
  ---
10
10
 
11
- import { Next, Nitro, SvelteKit, Nuxt, Hono, Bun, AstroDark, AstroLight, TanStack, Vite, Express, Nest, Fastify } from "@/app/[lang]/(home)/components/frameworks";
11
+ import { Next, Nitro, SvelteKit, Nuxt, Hono, Bun, AstroDark, AstroLight, TanStack, Vite, Express, Nest, Fastify, Python } from "@/app/[lang]/(home)/components/frameworks";
12
12
 
13
13
  <Cards>
14
14
  <Card href="/docs/getting-started/next">
@@ -63,6 +63,13 @@ import { Next, Nitro, SvelteKit, Nuxt, Hono, Bun, AstroDark, AstroLight, TanStac
63
63
  <span className="font-medium">SvelteKit</span>
64
64
  </div>
65
65
  </Card>
66
+ <Card href="/docs/getting-started/python">
67
+ <div className="flex flex-col items-center justify-center gap-2">
68
+ <Python className="size-16" />
69
+ <span className="font-medium">Python</span>
70
+ <Badge variant="secondary">Beta</Badge>
71
+ </div>
72
+ </Card>
66
73
  <Card className="opacity-50">
67
74
  <div className="flex flex-col items-center justify-center gap-2">
68
75
  <Nest className="size-16 dark:invert grayscale" />
@@ -9,7 +9,8 @@
9
9
  "nitro",
10
10
  "nuxt",
11
11
  "sveltekit",
12
- "vite"
12
+ "vite",
13
+ "python"
13
14
  ],
14
15
  "defaultOpen": true
15
16
  }
@@ -0,0 +1,165 @@
1
+ ---
2
+ title: Python
3
+ description: Build durable workflows and AI agents in Python with the Vercel SDK.
4
+ type: guide
5
+ summary: Set up the Workflow Python SDK in your Python application.
6
+ prerequisites:
7
+ - /docs/getting-started
8
+ related:
9
+ - /docs/foundations
10
+ - /docs/foundations/workflows-and-steps
11
+ ---
12
+
13
+ <Callout type="warn">
14
+ The Python SDK is currently in **beta**. APIs and behavior may change. For the latest documentation and updates, see the [official Vercel Workflow Python documentation](https://vercel.com/docs/workflow/python?language=py).
15
+ </Callout>
16
+
17
+ You can build durable workflows in Python using the [`vercel` Python SDK](https://pypi.org/project/vercel/). Your workflow code can pause, resume, and maintain state, just like the JavaScript and TypeScript Workflow SDK.
18
+
19
+ ## Getting Started
20
+
21
+ Install the `vercel` package:
22
+
23
+ ```bash filename="Terminal"
24
+ pip install vercel
25
+ ```
26
+
27
+ Configure `experimentalServices` in your `vercel.json`:
28
+
29
+ ```json filename="vercel.json"
30
+ {
31
+ "experimentalServices": {
32
+ "ai_content_workflow": {
33
+ "type": "worker",
34
+ "entrypoint": "app/workflows/ai_content_workflow.py",
35
+ "topics": ["__wkf_*"]
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ ## Workflows
42
+
43
+ A workflow is a stateful function that coordinates multi-step logic over time. Create a `Workflows` instance and use the `@wf.workflow` decorator to mark a function as durable:
44
+
45
+ ```python filename="app/workflow.py" {3}
46
+ from vercel import workflow
47
+
48
+ wf = workflow.Workflows()
49
+ ```
50
+
51
+ ```python filename="app/workflows/ai_content_workflow.py" {3}
52
+ from app.workflow import wf
53
+
54
+ @wf.workflow
55
+ async def ai_content_workflow(*, topic: str):
56
+ draft = await generate_draft(topic=topic)
57
+ summary = await summarize_draft(draft=draft)
58
+
59
+ return {
60
+ "draft": draft,
61
+ "summary": summary,
62
+ }
63
+ ```
64
+
65
+ Under the hood, the workflow compiles into a route that orchestrates execution. All inputs and outputs are recorded in an event log. If a deploy or crash happens, the system replays execution deterministically from where it stopped.
66
+
67
+ ## Steps
68
+
69
+ A step is a stateless function that runs a unit of durable work inside a workflow. Use `@wf.step` to mark a function as a step:
70
+
71
+ ```python filename="app/steps/generate_draft.py" {4,8}
72
+ import random
73
+ from app.workflow import wf
74
+
75
+ @wf.step
76
+ async def generate_draft(*, topic: str):
77
+ return await ai_generate(prompt=f"Write a blog post about {topic}")
78
+
79
+ @wf.step
80
+ async def summarize_draft(*, draft: str):
81
+ summary = await ai_summarize(text=draft)
82
+
83
+ # Simulate a transient error. The step automatically retries.
84
+ if random.random() < 0.3:
85
+ raise Exception("Transient AI provider error")
86
+
87
+ return summary
88
+ ```
89
+
90
+ Each step compiles into an isolated route. While the step executes, the workflow suspends without consuming resources. When the step completes, the workflow resumes automatically where it left off.
91
+
92
+ ## Sleep
93
+
94
+ Sleep pauses a workflow for a specified duration without consuming compute resources:
95
+
96
+ ```python filename="app/workflows/ai_refine.py" {7}
97
+ from vercel import workflow
98
+
99
+ @wf.workflow
100
+ async def ai_refine_workflow(*, draft_id: str):
101
+ draft = await fetch_draft(draft_id)
102
+
103
+ await workflow.sleep("7 days") # Wait 7 days to gather more signals.
104
+
105
+ refined = await refine_draft(draft)
106
+
107
+ return {
108
+ "draft_id": draft_id,
109
+ "refined": refined,
110
+ }
111
+ ```
112
+
113
+ The sleep call pauses the workflow and consumes no resources. The workflow resumes automatically when the time expires.
114
+
115
+ ## Hooks
116
+
117
+ A hook lets a workflow wait for external events such as user actions, webhooks, or third-party API responses.
118
+
119
+ Define a hook model with Pydantic and `workflow.BaseHook`:
120
+
121
+ ```python filename="app/workflows/approval.py" {3,14}
122
+ from vercel import workflow
123
+
124
+ class Approval(BaseModel, workflow.BaseHook):
125
+ """Human approval for AI-generated drafts"""
126
+
127
+ decision: Literal["approved", "changes"]
128
+ notes: str | None = None
129
+
130
+ @wf.workflow
131
+ async def ai_approval_workflow(*, topic: str):
132
+ draft = await generate_draft(topic=topic)
133
+
134
+ # Wait for human approval events
135
+ async for event in Approval.wait(token="draft-123"):
136
+ if event.decision == "approved":
137
+ await publish_draft(draft)
138
+ break
139
+
140
+ revised = await refine_draft(draft, event.notes)
141
+ await publish_draft(revised)
142
+ ```
143
+
144
+ Resume the workflow when data arrives:
145
+
146
+ ```python filename="app/api/resume.py" {5}
147
+ @app.post("/api/resume")
148
+ async def resume(approval: Approval):
149
+ """Resume the workflow when an approval is received"""
150
+
151
+ await approval.resume("draft-123")
152
+ return {"ok": True}
153
+ ```
154
+
155
+ When a hook receives data, the workflow resumes automatically. You don&apos;t need polling, message queues, or manual state management.
156
+
157
+ ## Learn More
158
+
159
+ For comprehensive documentation, examples, and the latest updates, visit the [official Vercel Workflow Python documentation](https://vercel.com/docs/workflow/python).
160
+
161
+ ## Next Steps
162
+
163
+ - Learn more about the [Foundations](/docs/foundations).
164
+ - Check [Errors](/docs/errors) if you encounter issues.
165
+ - Explore the [API Reference](/docs/api-reference).
package/docs/meta.json CHANGED
@@ -10,6 +10,7 @@
10
10
  "testing",
11
11
  "deploying",
12
12
  "errors",
13
+ "migration-guides",
13
14
  "api-reference"
14
15
  ]
15
16
  }
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Migration Guides
3
+ description: Move your existing durable workflow system to the Workflow SDK with side-by-side code comparisons and a realistic migration example.
4
+ type: overview
5
+ summary: Migrate from Temporal, Inngest, AWS Step Functions, or trigger.dev to the Workflow SDK.
6
+ related:
7
+ - /docs/foundations/workflows-and-steps
8
+ - /docs/getting-started
9
+ ---
10
+
11
+ <Callout type="info">
12
+ Install the Workflow SDK migration skill:
13
+
14
+ ```bash
15
+ npx skills add https://github.com/vercel/workflow --skill migrating-to-workflow-sdk
16
+ ```
17
+ </Callout>
18
+
19
+ Move an existing orchestration system to the Workflow SDK. Each guide pairs a concept-mapping table with side-by-side code, so you can translate one piece of your codebase at a time.
20
+
21
+ <Cards>
22
+ <Card href="/docs/migration-guides/migrating-from-temporal" title="Migrating from Temporal">
23
+ Map Activities, Workers, Signals, and Child Workflows onto workflows, steps, hooks, and `start()` / `getRun()`.
24
+ </Card>
25
+ <Card href="/docs/migration-guides/migrating-from-inngest" title="Migrating from Inngest">
26
+ Map `createFunction`, `step.run`, `step.sleep`, `step.waitForEvent`, and `step.invoke` onto workflows, steps, and hooks.
27
+ </Card>
28
+ <Card href="/docs/migration-guides/migrating-from-aws-step-functions" title="Migrating from AWS Step Functions">
29
+ Replace ASL JSON states, Task / Choice / Wait / Parallel states, and `.waitForTaskToken` callbacks with TypeScript.
30
+ </Card>
31
+ <Card href="/docs/migration-guides/migrating-from-trigger-dev" title="Migrating from trigger.dev">
32
+ Map `task()`, `schemaTask()`, `wait.for` / `wait.forToken`, `triggerAndWait`, and `metadata.stream` onto workflows, steps, hooks, and `start()` / `getRun()`.
33
+ </Card>
34
+ </Cards>
@@ -0,0 +1,9 @@
1
+ {
2
+ "title": "Migration Guides",
3
+ "pages": [
4
+ "migrating-from-temporal",
5
+ "migrating-from-inngest",
6
+ "migrating-from-aws-step-functions",
7
+ "migrating-from-trigger-dev"
8
+ ]
9
+ }