Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
"atomic-runs-publish",
"atomic-step-created-event",
"attr-inprocess-replay",
"attr-set-duplicate-inert",
"attr-set-duplicate-observability",
"attributes-mvp-plan",
"attributes-row-remove-flex-1",
"avoid-peer-major-bumps",
Expand Down Expand Up @@ -112,6 +114,7 @@
"cache-step-port-discovery",
"calm-dodos-retry",
"calm-events-guard",
"calm-events-wait",
"calm-geese-observe",
"calm-geese-share",
"cancel-v4-frame-stream",
Expand Down Expand Up @@ -174,6 +177,7 @@
"duplicate-event-log-level",
"durable-agent-stream-result-totalusage",
"durable-agent-tool-stop-detection",
"durable-hook-resume",
"e2e-ci-retry",
"e2e-pickup-watchdog",
"e2e-test-budgets",
Expand All @@ -199,6 +203,7 @@
"error-subclass-serialization",
"errors-no-chalk",
"esm-builders",
"esm-dirname-filename-shim",
"event-count-guard",
"event-limit-enforcement",
"event-list-solid-borders",
Expand Down Expand Up @@ -328,6 +333,7 @@
"jk-nav-autoscroll",
"large-inline-sourcemap-remap",
"large-regions-talk",
"late-hooks-rearm",
"lazy-discovery-bare-specifiers",
"lazy-discovery-default",
"lazy-discovery-hmr",
Expand All @@ -351,7 +357,9 @@
"local-world-vercel-warning",
"log-order-draws",
"log-queue-handler-retries",
"lost-payload-terminal",
"loud-pugs-recycle",
"lucky-pandas-listen",
"lucky-windows-smash",
"many-peas-jog",
"marker-kind-prefix",
Expand All @@ -375,6 +383,7 @@
"next-base-path",
"next-dev-watch-gitignore",
"next-diagnostics-dist",
"next-entry-discovery",
"next-respect-package-exports",
"next-root-detection",
"ninety-buttons-dance",
Expand Down Expand Up @@ -403,6 +412,7 @@
"otel-api-optional-peer-external",
"otel-linked-trace-mode",
"outcome-event-workflowname",
"overlap-workflow-compile",
"parallel-inline-optimistic-start",
"pending-trace-viewer-gray-indicator",
"perf-cached-workflow-script",
Expand All @@ -417,13 +427,15 @@
"precise-timeline-ruler-ticks",
"precise-trace-viewer-durations",
"precondition-guard-default-on",
"prepare-streamed-replay-payloads",
"preserve-imports-used-by-hoisted-steps",
"preserve-run-key-status",
"preserve-step-fn-names",
"pretty-log-format",
"prewarm-appended-payloads",
"prewarm-next-swc-cache",
"private-member-dce",
"project-step-provenance",
"proud-friends-decide",
"prune-workflow-sandbox",
"python-workbench-app",
Expand All @@ -444,6 +456,7 @@
"quiet-events-merge",
"quiet-lamps-parse",
"quiet-marker-shadow",
"quiet-normal-execution-logs",
"quiet-runs-poll",
"quiet-sourcemap-warnings",
"quiet-trace-viewer-duration",
Expand Down Expand Up @@ -605,13 +618,17 @@
"tidy-dodos-observe",
"tidy-hoops-open",
"tidy-lamps-sort",
"tidy-local-shutdown",
"tidy-rivers-expand",
"timeline-queued-connector",
"tired-pigs-hug",
"tired-spiders-rhyme",
"trace-nav-tooltips",
"trace-replay-phases",
"trace-shortcut-helper-text-color",
"trace-shortcut-helper-timeline-align",
"trace-span-markers",
"trace-viewer-alt-hover",
"trace-viewer-cleanup",
"trace-viewer-event-icon-tooltips",
"trace-viewer-focus-easing",
Expand All @@ -628,6 +645,7 @@
"turbo-setattr-run-ready",
"turbo-skip-run-started-preload",
"type-event-create-results",
"typed-replay-stream-failures",
"typography-system-tokens",
"update-queue-client-version",
"update-vercel-queue",
Expand Down
55 changes: 42 additions & 13 deletions docs/content/docs/v4/getting-started/python.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ related:
---

<CopyPrompt
text="In this Python project, add `requires-python = &quot;&gt;=3.12&quot;` and `dependencies = [&quot;vercel&quot;]` under `[project]` in `pyproject.toml`. Add `[[tool.vercel.workflows]]` with `entrypoint = &quot;app.workflows:wf&quot;`. Create `app/workflow.py` with `from vercel import workflow` and `wf = workflow.Workflows()`. Create `app/workflows/ai_content_workflow.py` importing `wf`, define `@wf.workflow async def ai_content_workflow(*, topic: str)`, and call step functions such as `generate_draft` and `summarize_draft`. Export `wf` from `app/workflows/__init__.py` and import the workflow module so its definitions are registered. Mark step functions with `@wf.step`, use `await workflow.sleep(&quot;7 days&quot;)` for durable delays where needed, and use a `workflow.BaseHook` Pydantic model plus `.wait(token=...)` and `.resume(token)` for external approval events. Verify the workflow entrypoint uses the `module:object` format and points to the exported `Workflows` registry."
text="In this Python project, add `requires-python = &quot;&gt;=3.12&quot;` and `dependencies = [&quot;vercel&quot;]` under `[project]` in `pyproject.toml`. Add `[[tool.vercel.workflows]]` with `entrypoint = &quot;app.workflows:wf&quot;`. Create `app/workflow.py` with `from vercel import workflow` and `wf = workflow.Workflows()`. Create `app/workflows/ai_content_workflow.py` importing `wf`, define `@wf.workflow async def ai_content_workflow(*, topic: str)`, and call step functions such as `generate_draft` and `summarize_draft`. Export `wf` from `app/workflows/__init__.py` and import the workflow module so its definitions are registered. Mark step functions with `@wf.step`, use `await workflow.sleep(timedelta(days=7))` after importing `timedelta` from `datetime` for durable delays where needed, and use a `workflow.BaseHook` Pydantic model plus `.wait(token=...)` and `.resume(token)` for external approval events. Verify the workflow entrypoint uses the `module:object` format and points to the exported `Workflows` registry."
/>

<Callout type="warn">
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/workflows/python).
The Python SDK is currently in **beta**. APIs and behavior may change.
</Callout>

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.
Expand Down Expand Up @@ -99,14 +99,17 @@ Each step compiles into an isolated route. While the step executes, the workflow

Sleep pauses a workflow for a specified duration without consuming compute resources:

```python filename="app/workflows/ai_refine.py" {7}
```python filename="app/workflows/ai_refine.py" {10}
from datetime import timedelta

from app.workflow import wf
from vercel import workflow

@wf.workflow
async def ai_refine_workflow(*, draft_id: str):
draft = await fetch_draft(draft_id)

await workflow.sleep("7 days") # Wait 7 days to gather more signals.
await workflow.sleep(timedelta(days=7)) # Wait 7 days to gather more signals.

refined = await refine_draft(draft)

Expand All @@ -116,21 +119,49 @@ async def ai_refine_workflow(*, draft_id: str):
}
```

The sleep call pauses the workflow and consumes no resources. The workflow resumes automatically when the time expires.
The parameter accepts four forms:

| Form | Description | Example |
| --- | --- | --- |
| `str` | Human-readable duration string | `"2 days"`, `"1w"`, `"1h 30m"` |
| `int` or `float` | Seconds from now | `5` (5 seconds) |
| `datetime.timedelta` | Duration from now | `timedelta(days=7)` |
| `datetime.datetime` | Absolute wake-up time (must be timezone-aware) | `datetime(2025, 1, 1, tzinfo=UTC)` |

The string form accepts one or more `<value><unit>` pairs. Supported units:

| Duration | Unit |
| --- | --- |
| Milliseconds | `ms` |
| Seconds | `s`, `second`, `seconds` |
| Minutes | `m`, `minute`, `minutes` |
| Hours | `h`, `hour`, `hours` |
| Days | `d`, `day`, `days` |
| Weeks | `w`, `week`, `weeks` |

<Callout>
`sleep()` must be called from the workflow body, not from inside a step. Calling it from a step raises a `RuntimeError`.
</Callout>

The sleep consumes no resources. The workflow resumes automatically when the time expires.

## Hooks

A hook lets a workflow wait for external events such as user actions, webhooks, or third-party API responses.

Define a hook model with Pydantic and `workflow.BaseHook`:

```python filename="app/workflows/approval.py" {3,14}
```python filename="app/workflows/approval.py" {7,18}
import typing

import pydantic
from app.workflow import wf
from vercel import workflow

class Approval(BaseModel, workflow.BaseHook):
class Approval(pydantic.BaseModel, workflow.BaseHook):
"""Human approval for AI-generated drafts"""

decision: Literal["approved", "changes"]
decision: typing.Literal["approved", "changes"]
notes: str | None = None

@wf.workflow
Expand All @@ -149,7 +180,9 @@ async def ai_approval_workflow(*, topic: str):

Resume the workflow when data arrives:

```python filename="app/api/resume.py" {5}
```python filename="app/api/resume.py" {4,7}
from app.workflows.approval import Approval

@app.post("/api/resume")
async def resume(approval: Approval):
"""Resume the workflow when an approval is received"""
Expand All @@ -160,10 +193,6 @@ async def resume(approval: Approval):

When a hook receives data, the workflow resumes automatically. You don&apos;t need polling, message queues, or manual state management.

## Learn more

For comprehensive documentation, examples, and the latest updates, visit the [official Vercel Workflow Python documentation](https://vercel.com/docs/workflows/python).

## Next steps

- Learn more about the [Foundations](/docs/foundations).
Expand Down
55 changes: 42 additions & 13 deletions docs/content/docs/v5/getting-started/python.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ related:
---

<CopyPrompt
text="In this Python project, add `requires-python = &quot;&gt;=3.12&quot;` and `dependencies = [&quot;vercel&quot;]` under `[project]` in `pyproject.toml`. Add `[[tool.vercel.workflows]]` with `entrypoint = &quot;app.workflows:wf&quot;`. Create `app/workflow.py` with `from vercel import workflow` and `wf = workflow.Workflows()`. Create `app/workflows/ai_content_workflow.py` importing `wf`, define `@wf.workflow async def ai_content_workflow(*, topic: str)`, and call step functions such as `generate_draft` and `summarize_draft`. Export `wf` from `app/workflows/__init__.py` and import the workflow module so its definitions are registered. Mark step functions with `@wf.step`, use `await workflow.sleep(&quot;7 days&quot;)` for durable delays where needed, and use a `workflow.BaseHook` Pydantic model plus `.wait(token=...)` and `.resume(token)` for external approval events. Verify the workflow entrypoint uses the `module:object` format and points to the exported `Workflows` registry."
text="In this Python project, add `requires-python = &quot;&gt;=3.12&quot;` and `dependencies = [&quot;vercel&quot;]` under `[project]` in `pyproject.toml`. Add `[[tool.vercel.workflows]]` with `entrypoint = &quot;app.workflows:wf&quot;`. Create `app/workflow.py` with `from vercel import workflow` and `wf = workflow.Workflows()`. Create `app/workflows/ai_content_workflow.py` importing `wf`, define `@wf.workflow async def ai_content_workflow(*, topic: str)`, and call step functions such as `generate_draft` and `summarize_draft`. Export `wf` from `app/workflows/__init__.py` and import the workflow module so its definitions are registered. Mark step functions with `@wf.step`, use `await workflow.sleep(timedelta(days=7))` after importing `timedelta` from `datetime` for durable delays where needed, and use a `workflow.BaseHook` Pydantic model plus `.wait(token=...)` and `.resume(token)` for external approval events. Verify the workflow entrypoint uses the `module:object` format and points to the exported `Workflows` registry."
/>

<Callout type="warn">
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/workflows/python).
The Python SDK is currently in **beta**. APIs and behavior may change.
</Callout>

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.
Expand Down Expand Up @@ -99,14 +99,17 @@ Each step executes separately from the workflow orchestrator. While the step exe

Sleep pauses a workflow for a specified duration without consuming compute resources:

```python filename="app/workflows/ai_refine.py" {7}
```python filename="app/workflows/ai_refine.py" {10}
from datetime import timedelta

from app.workflow import wf
from vercel import workflow

@wf.workflow
async def ai_refine_workflow(*, draft_id: str):
draft = await fetch_draft(draft_id)

await workflow.sleep("7 days") # Wait 7 days to gather more signals.
await workflow.sleep(timedelta(days=7)) # Wait 7 days to gather more signals.

refined = await refine_draft(draft)

Expand All @@ -116,21 +119,49 @@ async def ai_refine_workflow(*, draft_id: str):
}
```

The sleep call pauses the workflow and consumes no resources. The workflow resumes automatically when the time expires.
The parameter accepts four forms:

| Form | Description | Example |
| --- | --- | --- |
| `str` | Human-readable duration string | `"2 days"`, `"1w"`, `"1h 30m"` |
| `int` or `float` | Seconds from now | `5` (5 seconds) |
| `datetime.timedelta` | Duration from now | `timedelta(days=7)` |
| `datetime.datetime` | Absolute wake-up time (must be timezone-aware) | `datetime(2025, 1, 1, tzinfo=UTC)` |

The string form accepts one or more `<value><unit>` pairs. Supported units:

| Duration | Unit |
| --- | --- |
| Milliseconds | `ms` |
| Seconds | `s`, `second`, `seconds` |
| Minutes | `m`, `minute`, `minutes` |
| Hours | `h`, `hour`, `hours` |
| Days | `d`, `day`, `days` |
| Weeks | `w`, `week`, `weeks` |

<Callout>
`sleep()` must be called from the workflow body, not from inside a step. Calling it from a step raises a `RuntimeError`.
</Callout>

The sleep consumes no resources. The workflow resumes automatically when the time expires.

## Hooks

A hook lets a workflow wait for external events such as user actions, webhooks, or third-party API responses.

Define a hook model with Pydantic and `workflow.BaseHook`:

```python filename="app/workflows/approval.py" {3,14}
```python filename="app/workflows/approval.py" {7,18}
import typing

import pydantic
from app.workflow import wf
from vercel import workflow

class Approval(BaseModel, workflow.BaseHook):
class Approval(pydantic.BaseModel, workflow.BaseHook):
"""Human approval for AI-generated drafts"""

decision: Literal["approved", "changes"]
decision: typing.Literal["approved", "changes"]
notes: str | None = None

@wf.workflow
Expand All @@ -149,7 +180,9 @@ async def ai_approval_workflow(*, topic: str):

Resume the workflow when data arrives:

```python filename="app/api/resume.py" {5}
```python filename="app/api/resume.py" {4,7}
from app.workflows.approval import Approval

@app.post("/api/resume")
async def resume(approval: Approval):
"""Resume the workflow when an approval is received"""
Expand All @@ -160,10 +193,6 @@ async def resume(approval: Approval):

When a hook receives data, the workflow resumes automatically. You don&apos;t need polling, message queues, or manual state management.

## Learn more

For comprehensive documentation, examples, and the latest updates, visit the [official Vercel Workflow Python documentation](https://vercel.com/docs/workflows/python).

## Next steps

- Learn more about the [Foundations](/docs/foundations).
Expand Down
8 changes: 8 additions & 0 deletions packages/ai/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @workflow/ai

## 5.0.0-beta.15

### Patch Changes

- Updated dependencies [[`ffc5807`](https://github.com/vercel/workflow/commit/ffc58078d0c3cd2786d69bab7e41614566a9ea4e)]:
- @workflow/utils@5.0.0-beta.10
- workflow@5.0.0-beta.47

## 5.0.0-beta.14

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@workflow/ai",
"version": "5.0.0-beta.14",
"version": "5.0.0-beta.15",
"description": "Workflow SDK compatible helper library for the AI SDK",
"type": "module",
"main": "dist/index.js",
Expand Down
9 changes: 9 additions & 0 deletions packages/astro/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# @workflow/astro

## 5.0.0-beta.47

### Patch Changes

- Updated dependencies [[`88f5d21`](https://github.com/vercel/workflow/commit/88f5d214d48b15d3126943313ed03d48667e772c)]:
- @workflow/builders@5.0.0-beta.47
- @workflow/rollup@5.0.0-beta.47
- @workflow/vite@5.0.0-beta.47

## 5.0.0-beta.46

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@workflow/astro",
"version": "5.0.0-beta.46",
"version": "5.0.0-beta.47",
"description": "Astro integration for Workflow SDK",
"type": "module",
"main": "dist/index.js",
Expand Down
Loading
Loading