workflow 5.0.0-beta.4 → 5.0.0-beta.40
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.
- package/README.md +63 -20
- package/dist/api-workflow.d.ts +1 -1
- package/dist/api-workflow.d.ts.map +1 -1
- package/dist/api-workflow.js +1 -1
- package/dist/api.d.ts +5 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +12 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/internal/builtins.d.ts +17 -0
- package/dist/internal/builtins.d.ts.map +1 -1
- package/dist/internal/builtins.js +65 -1
- package/dist/internal/errors.d.ts +1 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +2 -2
- package/dist/nest-builder.d.ts +2 -0
- package/dist/nest-builder.d.ts.map +1 -0
- package/dist/nest-builder.js +2 -0
- package/dist/nest-vercel-builder.d.ts +2 -0
- package/dist/nest-vercel-builder.d.ts.map +1 -0
- package/dist/nest-vercel-builder.js +2 -0
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -2
- package/dist/runtime.d.ts +2 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +5 -2
- package/docs/ai/chat-session-modeling.mdx +7 -3
- package/docs/ai/defining-tools.mdx +2 -2
- package/docs/ai/index.mdx +30 -25
- package/docs/ai/message-queueing.mdx +10 -10
- package/docs/ai/resumable-streams.mdx +9 -1
- package/docs/api-reference/index.mdx +24 -0
- package/docs/api-reference/meta.json +8 -0
- package/docs/api-reference/vitest/index.mdx +28 -7
- package/docs/api-reference/workflow/create-hook.mdx +79 -0
- package/docs/api-reference/workflow/create-webhook.mdx +1 -0
- package/docs/api-reference/workflow/define-hook.mdx +26 -24
- package/docs/api-reference/workflow/fatal-error.mdx +29 -7
- package/docs/api-reference/workflow/fetch.mdx +8 -4
- package/docs/api-reference/workflow/index.mdx +3 -0
- package/docs/api-reference/workflow/set-attributes.mdx +61 -0
- package/docs/api-reference/workflow/sleep.mdx +1 -1
- package/docs/api-reference/workflow-ai/durable-agent.mdx +7 -45
- package/docs/api-reference/workflow-ai/index.mdx +2 -2
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +44 -1
- package/docs/api-reference/workflow-api/get-hook-by-token.mdx +9 -0
- package/docs/api-reference/workflow-api/get-run.mdx +25 -0
- package/docs/api-reference/workflow-api/index.mdx +6 -8
- package/docs/api-reference/workflow-api/resume-hook.mdx +60 -1
- package/docs/api-reference/workflow-api/resume-webhook.mdx +6 -4
- package/docs/api-reference/workflow-api/start.mdx +39 -6
- package/docs/api-reference/workflow-astro/index.mdx +18 -0
- package/docs/api-reference/workflow-astro/meta.json +4 -0
- package/docs/api-reference/workflow-astro/workflow.mdx +45 -0
- package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
- package/docs/api-reference/workflow-errors/index.mdx +88 -0
- package/docs/api-reference/workflow-errors/meta.json +6 -0
- package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +68 -0
- package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/workflow-error.mdx +52 -0
- package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +16 -6
- package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
- package/docs/api-reference/workflow-globals.mdx +4 -1
- package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
- package/docs/api-reference/workflow-nest/index.mdx +31 -0
- package/docs/api-reference/workflow-nest/meta.json +9 -0
- package/docs/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
- package/docs/api-reference/workflow-nest/workflow-controller.mdx +40 -0
- package/docs/api-reference/workflow-nest/workflow-module.mdx +74 -0
- package/docs/api-reference/workflow-next/with-workflow.mdx +56 -2
- package/docs/api-reference/workflow-nitro/index.mdx +60 -0
- package/docs/api-reference/workflow-nuxt/index.mdx +48 -0
- package/docs/api-reference/workflow-observability/hydrate-data.mdx +35 -0
- package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
- package/docs/api-reference/workflow-observability/index.mdx +64 -0
- package/docs/api-reference/workflow-observability/meta.json +11 -0
- package/docs/api-reference/workflow-observability/observability-revivers.mdx +50 -0
- package/docs/api-reference/workflow-observability/parse-class-name.mdx +41 -0
- package/docs/api-reference/workflow-observability/parse-step-name.mdx +40 -0
- package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
- package/docs/api-reference/workflow-runtime/create-world.mdx +39 -0
- package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/get-world.mdx +7 -10
- package/docs/api-reference/workflow-runtime/health-check.mdx +50 -0
- package/docs/api-reference/workflow-runtime/index.mdx +43 -0
- package/docs/api-reference/workflow-runtime/meta.json +12 -0
- package/docs/api-reference/workflow-runtime/set-world.mdx +49 -0
- package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +42 -0
- package/docs/api-reference/workflow-runtime/world/analytics.mdx +138 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/index.mdx +10 -10
- package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/queue.mdx +8 -6
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +18 -5
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +2 -2
- package/docs/api-reference/workflow-serde/index.mdx +0 -1
- package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +1 -2
- package/docs/api-reference/workflow-serde/workflow-serialize.mdx +2 -2
- package/docs/api-reference/workflow-sveltekit/index.mdx +18 -0
- package/docs/api-reference/workflow-sveltekit/meta.json +4 -0
- package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
- package/docs/api-reference/workflow-vite/index.mdx +18 -0
- package/docs/api-reference/workflow-vite/meta.json +4 -0
- package/docs/api-reference/workflow-vite/workflow.mdx +48 -0
- package/docs/changelog/attributes-mvp.mdx +380 -0
- package/docs/changelog/eager-processing.mdx +269 -0
- package/docs/changelog/index.mdx +3 -1
- package/docs/changelog/lazy-event-creation.md +127 -0
- package/docs/changelog/meta.json +9 -1
- package/docs/changelog/resilient-resume.mdx +22 -0
- package/docs/changelog/resilient-start.mdx +31 -283
- package/docs/changelog/step-message-ownership.mdx +360 -0
- package/docs/changelog/turbo-mode.md +87 -0
- package/docs/comparisons/index.mdx +66 -0
- package/docs/comparisons/meta.json +11 -0
- package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +55 -0
- package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +111 -0
- package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +71 -0
- package/docs/comparisons/workflow-sdk-vs-inngest.mdx +102 -0
- package/docs/comparisons/workflow-sdk-vs-temporal.mdx +123 -0
- package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +103 -0
- package/docs/configuration/build-and-diagnostics.mdx +70 -0
- package/docs/configuration/cli-and-web-ui.mdx +182 -0
- package/docs/configuration/framework-options.mdx +165 -0
- package/docs/configuration/index.mdx +32 -0
- package/docs/configuration/meta.json +12 -0
- package/docs/configuration/runtime-tuning.mdx +276 -0
- package/docs/configuration/worlds.mdx +275 -0
- package/docs/cookbook/advanced/child-workflows.mdx +203 -256
- package/docs/cookbook/advanced/meta.json +1 -1
- package/docs/cookbook/advanced/publishing-libraries.mdx +33 -24
- package/docs/cookbook/advanced/serializable-steps.mdx +12 -4
- package/docs/cookbook/advanced/upgrading-workflows.mdx +199 -0
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +34 -75
- package/docs/cookbook/agent-patterns/durable-agent.mdx +14 -142
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +11 -3
- package/docs/cookbook/common-patterns/batching.mdx +4 -0
- package/docs/cookbook/common-patterns/idempotency.mdx +40 -52
- package/docs/cookbook/common-patterns/rate-limiting.mdx +5 -1
- package/docs/cookbook/common-patterns/saga.mdx +6 -2
- package/docs/cookbook/common-patterns/scheduling.mdx +12 -0
- package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +4 -0
- package/docs/cookbook/common-patterns/timeouts.mdx +6 -1
- package/docs/cookbook/common-patterns/webhooks.mdx +4 -0
- package/docs/cookbook/common-patterns/workflow-composition.mdx +19 -16
- package/docs/cookbook/index.mdx +3 -3
- package/docs/cookbook/integrations/ai-sdk.mdx +64 -28
- package/docs/cookbook/integrations/chat-sdk.mdx +17 -0
- package/docs/cookbook/integrations/sandbox.mdx +17 -0
- package/docs/{deploying/index.mdx → deploying.mdx} +7 -7
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +84 -0
- package/docs/errors/corrupted-event-log.mdx +5 -5
- package/docs/errors/deployment-mismatch.mdx +71 -0
- package/docs/errors/fetch-in-workflow.mdx +4 -0
- package/docs/errors/hook-conflict.mdx +60 -4
- package/docs/errors/index.mdx +1 -35
- package/docs/errors/node-js-module-in-workflow.mdx +4 -0
- package/docs/errors/replay-divergence.mdx +27 -0
- package/docs/errors/runtime-decryption-failed.mdx +77 -0
- package/docs/errors/serialization-failed.mdx +4 -0
- package/docs/errors/start-invalid-workflow-function.mdx +4 -0
- package/docs/errors/step-executed-multiple-times.mdx +23 -0
- package/docs/errors/step-not-registered.mdx +1 -1
- package/docs/errors/timeout-in-workflow.mdx +4 -0
- package/docs/errors/webhook-response-not-sent.mdx +4 -0
- package/docs/foundations/cancellation.mdx +459 -0
- package/docs/foundations/errors-and-retries.mdx +7 -3
- package/docs/foundations/hooks.mdx +29 -0
- package/docs/foundations/idempotency.mdx +243 -11
- package/docs/foundations/index.mdx +1 -23
- package/docs/foundations/meta.json +3 -1
- package/docs/foundations/serialization.mdx +77 -41
- package/docs/foundations/starting-workflows.mdx +79 -2
- package/docs/foundations/streaming.mdx +14 -23
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/getting-started/astro.mdx +12 -2
- package/docs/getting-started/express.mdx +6 -2
- package/docs/getting-started/fastify.mdx +6 -2
- package/docs/getting-started/hono.mdx +6 -2
- package/docs/getting-started/index.mdx +16 -10
- package/docs/getting-started/meta.json +4 -1
- package/docs/getting-started/nestjs.mdx +77 -3
- package/docs/getting-started/next.mdx +12 -6
- package/docs/getting-started/nitro.mdx +28 -2
- package/docs/getting-started/nuxt.mdx +6 -2
- package/docs/getting-started/python.mdx +24 -18
- package/docs/getting-started/react-router/index.mdx +33 -0
- package/docs/getting-started/react-router/meta.json +5 -0
- package/docs/getting-started/react-router/v7.mdx +237 -0
- package/docs/getting-started/react-router/v8.mdx +232 -0
- package/docs/getting-started/sveltekit.mdx +12 -2
- package/docs/getting-started/tanstack-start.mdx +245 -0
- package/docs/getting-started/vite.mdx +6 -2
- package/docs/how-it-works/cancellation.mdx +287 -0
- package/docs/how-it-works/code-transform.mdx +21 -17
- package/docs/how-it-works/encryption.mdx +5 -5
- package/docs/how-it-works/event-sourcing.mdx +6 -6
- package/docs/how-it-works/framework-integrations.mdx +96 -337
- package/docs/how-it-works/meta.json +2 -1
- package/docs/internal/index.mdx +21 -0
- package/docs/internal/meta.json +10 -0
- package/docs/internal/nitro-native-build.mdx +38 -0
- package/docs/internal/nitro-web-ui.mdx +24 -0
- package/docs/internal/serializable-abort-controller.mdx +148 -0
- package/docs/meta.json +2 -2
- package/docs/observability/attributes.mdx +112 -0
- package/docs/observability/index.mdx +20 -1
- package/docs/observability/meta.json +1 -1
- package/docs/observability/tracing.mdx +124 -0
- package/docs/testing/index.mdx +2 -2
- package/package.json +17 -13
- package/docs/api-reference/workflow-api/world/meta.json +0 -4
- package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
- package/docs/cookbook/advanced/distributed-abort-controller.mdx +0 -318
- package/docs/deploying/building-a-world.mdx +0 -251
- package/docs/deploying/meta.json +0 -4
- package/docs/deploying/world/local-world.mdx +0 -84
- package/docs/deploying/world/meta.json +0 -4
- package/docs/deploying/world/postgres-world.mdx +0 -222
- package/docs/deploying/world/vercel-world.mdx +0 -179
- package/docs/migration-guides/index.mdx +0 -34
- package/docs/migration-guides/meta.json +0 -9
- package/docs/migration-guides/migrating-from-aws-step-functions.mdx +0 -363
- package/docs/migration-guides/migrating-from-inngest.mdx +0 -314
- package/docs/migration-guides/migrating-from-temporal.mdx +0 -318
- package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -337
|
@@ -7,12 +7,17 @@ prerequisites:
|
|
|
7
7
|
- /docs/foundations/workflows-and-steps
|
|
8
8
|
related:
|
|
9
9
|
- /docs/errors/fetch-in-workflow
|
|
10
|
+
- /docs/foundations/idempotency
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
Makes HTTP requests from within a workflow. This is a special step function that wraps the standard `fetch` API, automatically handling serialization and providing retry semantics.
|
|
13
14
|
|
|
14
15
|
This is useful when you need to call external APIs or services from within your workflow.
|
|
15
16
|
|
|
17
|
+
<Callout type="warn">
|
|
18
|
+
Because workflow `fetch()` has retry semantics, use idempotency keys when the request mutates an external system, such as creating a charge, sending an email, or enqueueing work. See [Idempotency](/docs/foundations/idempotency).
|
|
19
|
+
</Callout>
|
|
20
|
+
|
|
16
21
|
<Callout>
|
|
17
22
|
`fetch` is a *special* type of step function provided and should be called directly inside workflow functions.
|
|
18
23
|
</Callout>
|
|
@@ -88,7 +93,7 @@ This API is provided as a convenience to easily use `fetch` in workflow, but oft
|
|
|
88
93
|
|
|
89
94
|
### Customizing Fetch Behavior
|
|
90
95
|
|
|
91
|
-
Here's an example of a custom fetch wrapper that provides more sophisticated error handling with custom retry logic:
|
|
96
|
+
Here's an example of a custom fetch wrapper that provides more sophisticated error handling with custom retry logic. Call `globalThis.fetch` inside your own `"use step"` function — calling the workflow `fetch` imported from `workflow` would nest a step inside a step:
|
|
92
97
|
|
|
93
98
|
```typescript lineNumbers
|
|
94
99
|
import { FatalError, RetryableError } from "workflow"
|
|
@@ -99,7 +104,7 @@ export async function customFetch(
|
|
|
99
104
|
) {
|
|
100
105
|
"use step"
|
|
101
106
|
|
|
102
|
-
const response = await fetch(url, init)
|
|
107
|
+
const response = await globalThis.fetch(url, init)
|
|
103
108
|
|
|
104
109
|
// Handle client errors (4xx) - don't retry
|
|
105
110
|
if (response.status >= 400 && response.status < 500) {
|
|
@@ -140,7 +145,6 @@ export async function customFetch(
|
|
|
140
145
|
|
|
141
146
|
This example demonstrates:
|
|
142
147
|
|
|
143
|
-
- Setting custom `maxRetries` to 5 retries (6 total attempts including the initial attempt).
|
|
144
148
|
- Throwing [`FatalError`](/docs/api-reference/workflow/fatal-error) for client errors (400-499) to prevent retries.
|
|
145
149
|
- Handling 429 rate limiting by reading the `Retry-After` header and using [`RetryableError`](/docs/api-reference/workflow/retryable-error).
|
|
146
|
-
- Allowing automatic retries for server errors (5xx)
|
|
150
|
+
- Allowing automatic retries for server errors (5xx) by throwing a plain `Error`.
|
|
@@ -47,6 +47,9 @@ Workflow SDK contains the following functions you can use inside your workflow f
|
|
|
47
47
|
<Card href="/docs/api-reference/workflow/get-writable" title="getWritable()">
|
|
48
48
|
Access the current workflow run's default stream.
|
|
49
49
|
</Card>
|
|
50
|
+
<Card href="/docs/api-reference/workflow/set-attributes" title="setAttributes()">
|
|
51
|
+
Attach string metadata to the current workflow run.
|
|
52
|
+
</Card>
|
|
50
53
|
</Cards>
|
|
51
54
|
|
|
52
55
|
## Error Classes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: setAttributes
|
|
3
|
+
description: Attach string metadata to workflow run for observability.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: Use setAttributes inside a workflow or step function to set run attributes.
|
|
6
|
+
prerequisites:
|
|
7
|
+
- /docs/foundations/workflows-and-steps
|
|
8
|
+
related:
|
|
9
|
+
- /docs/observability/attributes
|
|
10
|
+
- /docs/api-reference/workflow/fatal-error
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Attaches string metadata to the current workflow run.
|
|
14
|
+
|
|
15
|
+
```typescript lineNumbers
|
|
16
|
+
import { setAttributes } from "workflow"
|
|
17
|
+
|
|
18
|
+
export async function orderWorkflow(orderId: string) {
|
|
19
|
+
"use workflow"
|
|
20
|
+
|
|
21
|
+
await setAttributes({
|
|
22
|
+
phase: "received",
|
|
23
|
+
orderId,
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## API Signature
|
|
29
|
+
|
|
30
|
+
### Parameters
|
|
31
|
+
|
|
32
|
+
<TSDoc
|
|
33
|
+
definition={`
|
|
34
|
+
import { setAttributes } from "workflow";
|
|
35
|
+
export default setAttributes;`}
|
|
36
|
+
showSections={['parameters']}
|
|
37
|
+
/>
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
Call `setAttributes` from a `"use workflow"` function or a `"use step"` function. Calling it from plain application code is not supported because there is no active workflow run.
|
|
42
|
+
|
|
43
|
+
Attribute values must be strings. Pass `undefined` to remove an attribute:
|
|
44
|
+
|
|
45
|
+
```typescript lineNumbers
|
|
46
|
+
import { setAttributes } from "workflow"
|
|
47
|
+
|
|
48
|
+
export async function cleanupAttributes() {
|
|
49
|
+
"use workflow"
|
|
50
|
+
|
|
51
|
+
await setAttributes({ staleKey: undefined })
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Attribute keys must be 1-256 characters, values must be strings up to 256 bytes, and each run can have up to 64 attributes. Keys that start with `$` are reserved for framework and library code.
|
|
56
|
+
|
|
57
|
+
Validation errors throw [`FatalError`](/docs/api-reference/workflow/fatal-error) and fail the run before an attribute write is attempted.
|
|
58
|
+
|
|
59
|
+
Calls from both workflow and step bodies append a native `attr_set` event, which the World materializes onto `run.attributes`. Workflow-originated events record a workflow writer; step-originated events record the originating step ID and attempt.
|
|
60
|
+
|
|
61
|
+
Native attributes require spec version 4 or later. Step-body storage errors throw from `setAttributes`; catch them inside the step if the write should be best-effort. Workflow-body writes are committed when the workflow suspends: transient storage errors are retried with the suspension, while a write the World rejects as invalid — such as exceeding the per-run attribute cap across multiple calls — fails the run with the validation error.
|
|
@@ -14,7 +14,7 @@ Suspends a workflow for a specified duration or until an end date without consum
|
|
|
14
14
|
This is useful when you want to resume a workflow after some duration or date.
|
|
15
15
|
|
|
16
16
|
<Callout>
|
|
17
|
-
`sleep` is a
|
|
17
|
+
`sleep` is a built-in workflow runtime function (backed by a timer event in the event log, not a step) and should be called directly inside workflow functions.
|
|
18
18
|
</Callout>
|
|
19
19
|
|
|
20
20
|
```typescript lineNumbers
|
|
@@ -1,59 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: DurableAgent
|
|
3
|
-
description:
|
|
3
|
+
description: Deprecated DurableAgent API reference; use WorkflowAgent for new durable agents.
|
|
4
4
|
type: reference
|
|
5
|
-
summary:
|
|
5
|
+
summary: "Deprecated: use AI SDK's WorkflowAgent instead of DurableAgent."
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/ai
|
|
8
8
|
related:
|
|
9
9
|
- /docs/ai/defining-tools
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
```typescript lineNumbers
|
|
17
|
-
import { DurableAgent } from "@workflow/ai/agent";
|
|
18
|
-
import { getWritable } from "workflow";
|
|
19
|
-
import { z } from "zod";
|
|
20
|
-
import type { UIMessageChunk } from "ai";
|
|
21
|
-
|
|
22
|
-
async function getWeather({ city }: { city: string }) {
|
|
23
|
-
"use step";
|
|
24
|
-
|
|
25
|
-
return `Weather in ${city} is sunny`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function myAgent() {
|
|
29
|
-
"use workflow";
|
|
30
|
-
|
|
31
|
-
const agent = new DurableAgent({
|
|
32
|
-
model: "anthropic/claude-haiku-4.5",
|
|
33
|
-
instructions: "You are a helpful weather assistant.",
|
|
34
|
-
temperature: 0.7,
|
|
35
|
-
tools: {
|
|
36
|
-
getWeather: {
|
|
37
|
-
description: "Get weather for a city",
|
|
38
|
-
inputSchema: z.object({ city: z.string() }),
|
|
39
|
-
execute: getWeather,
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// The agent will stream its output to the workflow
|
|
45
|
-
// run's default output stream
|
|
46
|
-
const writable = getWritable<UIMessageChunk>();
|
|
12
|
+
<Callout type="warn">
|
|
13
|
+
`DurableAgent` is deprecated. Use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) for new durable agents — see the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent).
|
|
14
|
+
</Callout>
|
|
47
15
|
|
|
48
|
-
|
|
49
|
-
messages: [{ role: "user", content: "How is the weather in San Francisco?" }],
|
|
50
|
-
writable,
|
|
51
|
-
});
|
|
16
|
+
This reference is kept for existing applications that still import `DurableAgent` from `@workflow/ai/agent`. Do not use `DurableAgent` for new code.
|
|
52
17
|
|
|
53
|
-
|
|
54
|
-
console.log(result.messages);
|
|
55
|
-
}
|
|
56
|
-
```
|
|
18
|
+
For current examples and implementation guidance, see AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) docs. For legacy code, the API surface below documents the existing `DurableAgent` exports.
|
|
57
19
|
|
|
58
20
|
## API Signature
|
|
59
21
|
|
|
@@ -13,9 +13,9 @@ Helpers for integrating AI SDK for building AI-powered workflows.
|
|
|
13
13
|
|
|
14
14
|
<Cards>
|
|
15
15
|
<Card title="DurableAgent" href="/docs/api-reference/workflow-ai/durable-agent">
|
|
16
|
-
|
|
16
|
+
Deprecated — use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent). Reference kept for existing `@workflow/ai/agent` imports.
|
|
17
17
|
</Card>
|
|
18
18
|
<Card title="WorkflowChatTransport" href="/docs/api-reference/workflow-ai/workflow-chat-transport">
|
|
19
|
-
|
|
19
|
+
Deprecated — use AI SDK's [`WorkflowChatTransport`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) from `@ai-sdk/workflow`. Reference kept for existing `@workflow/ai` imports.
|
|
20
20
|
</Card>
|
|
21
21
|
</Cards>
|
|
@@ -9,6 +9,10 @@ related:
|
|
|
9
9
|
- /docs/ai/resumable-streams
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
<Callout type="warn">
|
|
13
|
+
`WorkflowChatTransport` from `@workflow/ai` is deprecated. AI SDK ships a 1:1 port — use [`WorkflowChatTransport` from `@ai-sdk/workflow`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) instead. This reference is kept for existing applications that still import it from `@workflow/ai`.
|
|
14
|
+
</Callout>
|
|
15
|
+
|
|
12
16
|
A chat transport implementation for the AI SDK that provides reliable message streaming with automatic reconnection to interrupted streams. This transport is a drop-in replacement for the default AI SDK transport, enabling seamless recovery from network issues, page refreshes, or Vercel Function timeouts.
|
|
13
17
|
|
|
14
18
|
<Callout>
|
|
@@ -250,9 +254,48 @@ export default function ChatWithCustomConfig() {
|
|
|
250
254
|
}
|
|
251
255
|
```
|
|
252
256
|
|
|
257
|
+
## Mid-part resumes
|
|
258
|
+
|
|
259
|
+
A workflow stream is a flat sequence of chunks, but the AI SDK's UI protocol groups chunks into logical parts: a `text-start` opens a text part that subsequent `text-delta`s extend and a `text-end` closes, and the same shape applies to `reasoning-*` and `tool-input-*`. The AI SDK client enforces that grammar — a `reasoning-delta` whose `reasoning-start` was never seen throws and breaks the chat.
|
|
260
|
+
|
|
261
|
+
A non-zero `startIndex` (in particular a negative `initialStartIndex`) resolves to a chunk offset with no awareness of those part boundaries, so it can land in the middle of an open part. When that happens, `WorkflowChatTransport` will **drop chunks that reference a part it didn't see a start for** and log a one-time warning. The chat keeps working, but any partial part overlapping the resume cursor is discarded. Tool calls are an exception: `tool-input-available` / `tool-input-error` chunks are self-contained (they carry the full input), so a tool call is recovered as soon as one of those chunks appears in the resumed window — only its streamed input deltas are lost.
|
|
262
|
+
|
|
263
|
+
To preserve those partial parts, rewind to a step boundary on the server before returning the readable. `start-step` / `finish-step` chunks are the natural seams — no UI part is ever open across them. Sketch:
|
|
264
|
+
|
|
265
|
+
{/*@skip-typecheck: incomplete code sample*/}
|
|
266
|
+
|
|
267
|
+
```typescript title="app/api/chat/[id]/stream/route.ts"
|
|
268
|
+
const run = getRun(id);
|
|
269
|
+
const tailIndex = await run.getReadable().getTailIndex();
|
|
270
|
+
|
|
271
|
+
let resolved = startIndex < 0
|
|
272
|
+
? Math.max(0, tailIndex + 1 + startIndex)
|
|
273
|
+
: startIndex;
|
|
274
|
+
|
|
275
|
+
if (startIndex !== 0) {
|
|
276
|
+
// Walk back from `resolved` to the most recent start-step (or chunk 0),
|
|
277
|
+
// capping the lookback so a single huge step can't trigger an unbounded scan.
|
|
278
|
+
const LOOKBACK = 200;
|
|
279
|
+
const probe = run.getReadable({ startIndex: Math.max(0, resolved - LOOKBACK) });
|
|
280
|
+
let i = Math.max(0, resolved - LOOKBACK);
|
|
281
|
+
let lastBoundary = i;
|
|
282
|
+
for await (const chunk of probe as unknown as AsyncIterable<{ type: string }>) {
|
|
283
|
+
if (i >= resolved) break;
|
|
284
|
+
if (chunk.type === "start-step") lastBoundary = i;
|
|
285
|
+
i++;
|
|
286
|
+
}
|
|
287
|
+
resolved = lastBoundary;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return createUIMessageStreamResponse({
|
|
291
|
+
stream: run.getReadable({ startIndex: resolved }),
|
|
292
|
+
headers: { "x-workflow-stream-tail-index": String(tailIndex) },
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
253
296
|
## See Also
|
|
254
297
|
|
|
255
|
-
- [
|
|
298
|
+
- [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - Building durable, resumable AI agents (replaces `DurableAgent`)
|
|
256
299
|
- [AI SDK `useChat` Documentation](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat) - Using `useChat` with custom transports
|
|
257
300
|
- [Workflows and Steps](/docs/foundations/workflows-and-steps) - Understanding workflow fundamentals
|
|
258
301
|
- ["flight-booking-app" Example](https://github.com/vercel/workflow-examples/tree/main/flight-booking-app) - An example application which uses `WorkflowChatTransport`
|
|
@@ -5,14 +5,22 @@ type: reference
|
|
|
5
5
|
summary: Use getHookByToken to look up a hook's metadata and associated workflow run before resuming it.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/foundations/hooks
|
|
8
|
+
related:
|
|
9
|
+
- /docs/foundations/idempotency
|
|
8
10
|
---
|
|
9
11
|
|
|
10
12
|
Retrieves a hook by its unique token, returning the associated workflow run information and any metadata that was set when the hook was created. This function is useful for inspecting hook details before deciding whether to resume a workflow.
|
|
11
13
|
|
|
14
|
+
When `experimental_minRetention` is set, this function continues to return the Hook after its workflow ends until retention ends. That Hook cannot be resumed. Use `getRun(hook.runId)` to inspect the finished run.
|
|
15
|
+
|
|
12
16
|
<Callout type="warn">
|
|
13
17
|
`getHookByToken` is a runtime function that must be called from outside a workflow function.
|
|
14
18
|
</Callout>
|
|
15
19
|
|
|
20
|
+
<Callout type="info">
|
|
21
|
+
Looking up a deterministic hook token is useful in hook-based idempotency flows, but it is only an advisory check. If no hook exists yet, another request can still start the same workflow before your `start()` call registers its hook. Use the lookup to avoid obvious duplicate starts, and handle the race inside the workflow by checking `await hook.getConflict()` before duplicate-sensitive work — on a conflict it resolves with the run that owns the token, so the duplicate can route the caller to the active owner. If duplicates must be rejected before a workflow body runs, keep a durable request record until native atomic start-and-hook registration exists. See [Run idempotency](/docs/foundations/idempotency#run-idempotency).
|
|
22
|
+
</Callout>
|
|
23
|
+
|
|
16
24
|
```typescript lineNumbers
|
|
17
25
|
import { getHookByToken } from "workflow/api";
|
|
18
26
|
|
|
@@ -178,3 +186,4 @@ export async function POST(request: Request) {
|
|
|
178
186
|
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) - Resume a hook with a payload.
|
|
179
187
|
- [`createHook()`](/docs/api-reference/workflow/create-hook) - Create a hook in a workflow.
|
|
180
188
|
- [`defineHook()`](/docs/api-reference/workflow/define-hook) - Type-safe hook helper.
|
|
189
|
+
- [Idempotency](/docs/foundations/idempotency) - Deduplicate step side effects and workflow starts.
|
|
@@ -5,12 +5,18 @@ type: reference
|
|
|
5
5
|
summary: Use getRun to check a workflow run's status and metadata without blocking on completion.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/foundations/starting-workflows
|
|
8
|
+
related:
|
|
9
|
+
- /docs/foundations/idempotency
|
|
8
10
|
---
|
|
9
11
|
|
|
10
12
|
Retrieves the workflow run metadata and status information for a given run ID. This function provides immediate access to workflow run details without waiting for completion, making it ideal for status checking and monitoring.
|
|
11
13
|
|
|
12
14
|
Use this function when you need to check workflow status, get timing information, or access workflow metadata without blocking on workflow completion.
|
|
13
15
|
|
|
16
|
+
<Callout type="info">
|
|
17
|
+
`getRun()` retrieves a run when you already have its `runId`. It does not look up runs by a business key. For retried requests that should route to one active workflow, use a deterministic hook token and [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token). After a hook conflict, `HookConflictError.conflictingRunId` can be passed to `getRun()` to inspect, stream, or return the active owner. See [Run idempotency](/docs/foundations/idempotency#run-idempotency).
|
|
18
|
+
</Callout>
|
|
19
|
+
|
|
14
20
|
```typescript lineNumbers
|
|
15
21
|
import { getRun } from "workflow/api";
|
|
16
22
|
|
|
@@ -164,6 +170,25 @@ const { stoppedCount } = await run.wakeUp({
|
|
|
164
170
|
});
|
|
165
171
|
```
|
|
166
172
|
|
|
173
|
+
### Cancel a Run
|
|
174
|
+
|
|
175
|
+
Cancel a workflow run. You can pass an optional free-text `cancelReason` (up to 512 characters) that is recorded on the run's cancellation event and shown in the run detail view:
|
|
176
|
+
|
|
177
|
+
```typescript lineNumbers
|
|
178
|
+
import { getRun } from "workflow/api";
|
|
179
|
+
|
|
180
|
+
export async function POST(req: Request) {
|
|
181
|
+
const { runId } = await req.json();
|
|
182
|
+
const run = getRun(runId);
|
|
183
|
+
|
|
184
|
+
await run.cancel({ cancelReason: "Superseded by a newer submission" }); // [!code highlight]
|
|
185
|
+
|
|
186
|
+
return Response.json({ cancelled: true });
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The options object is optional — `await run.cancel()` cancels the run without recording a reason.
|
|
191
|
+
|
|
167
192
|
## Related Functions
|
|
168
193
|
|
|
169
194
|
- [`start()`](/docs/api-reference/workflow-api/start) - Start a new workflow and get its run ID.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "workflow/api"
|
|
3
|
-
description: Runtime functions to inspect runs, start workflows, and
|
|
3
|
+
description: Runtime functions to inspect runs, start workflows, and manage hooks.
|
|
4
4
|
type: overview
|
|
5
5
|
summary: Explore runtime functions for starting workflows, inspecting runs, and managing hooks.
|
|
6
6
|
---
|
|
@@ -9,7 +9,7 @@ API reference for runtime functions from the `workflow/api` package.
|
|
|
9
9
|
|
|
10
10
|
## Functions
|
|
11
11
|
|
|
12
|
-
The API package is for access and introspection of workflow data to inspect runs, start new runs,
|
|
12
|
+
The API package is for access and introspection of workflow data to inspect runs, start new runs, and manage hooks.
|
|
13
13
|
|
|
14
14
|
<Cards>
|
|
15
15
|
<Card href="/docs/api-reference/workflow-api/start" title="start()">
|
|
@@ -27,10 +27,8 @@ The API package is for access and introspection of workflow data to inspect runs
|
|
|
27
27
|
<Card href="/docs/api-reference/workflow-api/get-run" title="getRun()">
|
|
28
28
|
Get workflow run status and metadata without waiting for completion.
|
|
29
29
|
</Card>
|
|
30
|
-
<Card href="/docs/api-reference/workflow-api/get-world" title="getWorld()">
|
|
31
|
-
Async: resolve the World instance for storage, queuing, and streaming backends.
|
|
32
|
-
</Card>
|
|
33
|
-
<Card href="/docs/api-reference/workflow-api/world" title="World SDK">
|
|
34
|
-
Low-level API for inspecting runs, steps, events, hooks, streams, and queues.
|
|
35
|
-
</Card>
|
|
36
30
|
</Cards>
|
|
31
|
+
|
|
32
|
+
<Callout type="info">
|
|
33
|
+
Looking for `getWorld()` and the World SDK? They are exported from `workflow/runtime` — see the [`workflow/runtime` reference](/docs/api-reference/workflow-runtime).
|
|
34
|
+
</Callout>
|
|
@@ -7,12 +7,15 @@ prerequisites:
|
|
|
7
7
|
- /docs/foundations/hooks
|
|
8
8
|
related:
|
|
9
9
|
- /docs/api-reference/workflow-api/resume-webhook
|
|
10
|
+
- /docs/foundations/idempotency
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
Resumes a workflow run by sending a payload to a hook identified by its token.
|
|
13
14
|
|
|
14
15
|
It creates a `hook_received` event and re-triggers the workflow to continue execution.
|
|
15
16
|
|
|
17
|
+
A Hook kept by `experimental_minRetention` after its workflow ends cannot be resumed. `resumeHook()` throws `HookNotFoundError` in that case.
|
|
18
|
+
|
|
16
19
|
<Callout type="warn">
|
|
17
20
|
`resumeHook` is a runtime function that must be called from outside a workflow function.
|
|
18
21
|
</Callout>
|
|
@@ -47,7 +50,7 @@ showSections={["parameters"]}
|
|
|
47
50
|
|
|
48
51
|
### Returns
|
|
49
52
|
|
|
50
|
-
Returns a `Promise<
|
|
53
|
+
Returns a `Promise<ResumedHook>` — a `Hook` extended with an optional `resilientResume` flag. Resolving means the resume was accepted and the workflow will continue, whether the `hook_received` event was written directly or, on the parallel fast path, delivered through the workflow queue for the runtime to materialize (see the [lazy hook resume changelog](/docs/changelog/resilient-resume)). `resilientResume` is `true` only when the direct event write failed transiently and the resume was recovered through the queue; on the happy path it is absent. The resolved hook:
|
|
51
54
|
|
|
52
55
|
<TSDoc
|
|
53
56
|
definition={`
|
|
@@ -155,8 +158,64 @@ export async function POST(request: Request) {
|
|
|
155
158
|
}
|
|
156
159
|
```
|
|
157
160
|
|
|
161
|
+
### Resume or Start
|
|
162
|
+
|
|
163
|
+
A common endpoint shape is "resume or start": one route that resumes the active workflow run for a business key if one exists, or starts a new run otherwise. This comes up when the workflow uses a deterministic hook token as its idempotency key — for example, one active run per order or conversation.
|
|
164
|
+
|
|
165
|
+
`resumeHook()` is the resume half of that flow. Try it first; if it throws `HookNotFoundError`, no active run owns the token yet, so start the workflow. One subtlety: `start()` returns before the new run executes and registers its hook, so you cannot resume immediately after starting. Retry the resume until the hook is registered — if you drop the payload and only start the workflow, the data from this request is lost.
|
|
166
|
+
|
|
167
|
+
```typescript lineNumbers
|
|
168
|
+
import { resumeHook, start } from "workflow/api";
|
|
169
|
+
import { HookNotFoundError } from "workflow/errors";
|
|
170
|
+
import { processOrder } from "./workflows/process-order";
|
|
171
|
+
|
|
172
|
+
type OrderRequest = { confirmed: boolean };
|
|
173
|
+
|
|
174
|
+
async function resumeWithRetry(token: string, payload: OrderRequest) {
|
|
175
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
176
|
+
try {
|
|
177
|
+
return await resumeHook(token, payload); // [!code highlight]
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (!HookNotFoundError.is(error)) throw error;
|
|
180
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
throw new Error("Workflow did not register its hook in time");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function POST(request: Request) {
|
|
188
|
+
const { orderId, confirmed } = await request.json();
|
|
189
|
+
const token = `order:${orderId}`;
|
|
190
|
+
const payload = { confirmed };
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
// An active run already owns this token: resume it.
|
|
194
|
+
const hook = await resumeHook(token, payload); // [!code highlight]
|
|
195
|
+
return Response.json({ runId: hook.runId, reused: true });
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (!HookNotFoundError.is(error)) throw error;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// No hook yet: start a new run, then retry the resume so this
|
|
201
|
+
// request's payload still reaches the workflow.
|
|
202
|
+
const run = await start(processOrder, [orderId]); // [!code highlight]
|
|
203
|
+
const resumed = await resumeWithRetry(token, payload);
|
|
204
|
+
|
|
205
|
+
// A concurrent request can win the race between `start()` and hook
|
|
206
|
+
// registration; the resume always reaches the actual active owner.
|
|
207
|
+
return Response.json({
|
|
208
|
+
runId: resumed.runId,
|
|
209
|
+
reused: resumed.runId !== run.runId,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
See [Run idempotency](/docs/foundations/idempotency#run-idempotency) for the full pattern, including how the workflow claims the token with `hook.getConflict()` and how concurrent starts converge on one active owner.
|
|
215
|
+
|
|
158
216
|
## Related Functions
|
|
159
217
|
|
|
160
218
|
- [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token) - Get hook details before resuming.
|
|
161
219
|
- [`createHook()`](/docs/api-reference/workflow/create-hook) - Create a hook in a workflow.
|
|
162
220
|
- [`defineHook()`](/docs/api-reference/workflow/define-hook) - Type-safe hook helper.
|
|
221
|
+
- [Idempotency](/docs/foundations/idempotency) - Deduplicate step side effects and workflow starts.
|
|
@@ -50,11 +50,13 @@ showSections={['parameters']}
|
|
|
50
50
|
|
|
51
51
|
### Returns
|
|
52
52
|
|
|
53
|
-
Returns a `Promise<Response>` that resolves to:
|
|
53
|
+
Returns a `Promise<Response>` that resolves to one of:
|
|
54
54
|
|
|
55
|
-
- `
|
|
55
|
+
- A `202 Accepted` response when the webhook was created in the default mode (no `respondWith` option).
|
|
56
|
+
- The exact `Response` object configured via `createWebhook({ respondWith: new Response(...) })`.
|
|
57
|
+
- The workflow's manual `Response` when the webhook was created with `createWebhook({ respondWith: "manual" })` and a step calls `request.respondWith(response)`.
|
|
56
58
|
|
|
57
|
-
Throws
|
|
59
|
+
Throws [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error) if the token does not match an active webhook.
|
|
58
60
|
|
|
59
61
|
## Usage Note
|
|
60
62
|
|
|
@@ -81,7 +83,7 @@ export async function POST(request: Request) {
|
|
|
81
83
|
|
|
82
84
|
try {
|
|
83
85
|
const response = await resumeWebhook(token, request); // [!code highlight]
|
|
84
|
-
return response; //
|
|
86
|
+
return response; // 202 Accepted, a configured static Response, or a manual workflow response
|
|
85
87
|
} catch (error) {
|
|
86
88
|
return new Response("Webhook not found", { status: 404 });
|
|
87
89
|
}
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
title: start
|
|
3
3
|
description: Start and enqueue a new workflow run.
|
|
4
4
|
type: reference
|
|
5
|
-
summary: Use start to programmatically enqueue a new workflow run
|
|
5
|
+
summary: Use start to programmatically enqueue a new workflow run.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/foundations/starting-workflows
|
|
8
|
+
related:
|
|
9
|
+
- /docs/foundations/idempotency
|
|
8
10
|
---
|
|
9
11
|
|
|
10
12
|
Start/enqueue a new workflow run.
|
|
@@ -50,14 +52,17 @@ Learn more about [`WorkflowReadableStreamOptions`](/docs/api-reference/workflow-
|
|
|
50
52
|
|
|
51
53
|
## Good to Know
|
|
52
54
|
|
|
53
|
-
* The `start()` function is used in runtime
|
|
55
|
+
* The `start()` function is used in runtime contexts to programmatically trigger workflow executions.
|
|
56
|
+
* In v5, `start()` can also be called directly from a workflow function to spawn a child run or continue work in a new run. See [Workflow Composition](/cookbook/common-patterns/workflow-composition) and [Versioning](/docs/foundations/versioning).
|
|
54
57
|
* This is different from calling workflow functions directly, which is the typical pattern in Next.js applications.
|
|
55
58
|
* The function returns immediately after enqueuing the workflow - it doesn't wait for the workflow to complete.
|
|
59
|
+
* Each call to `start()` creates a new workflow run. If retried requests must route to one active workflow, have the workflow create a deterministic hook token and use [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token) to reuse an already-registered active hook. The lookup is not atomic with `start()`, so concurrent callers can still create extra runs before the hook is registered; handle that race inside the workflow by checking `await hook.getConflict()` before duplicate-sensitive work — on a conflict it resolves with the run that owns the token, so the duplicate can return the active owner to the caller. If duplicates must be rejected before a workflow body runs, keep a durable request record until native atomic start-and-hook registration exists. See [Idempotency](/docs/foundations/idempotency#run-idempotency).
|
|
56
60
|
* All arguments must be [serializable](/docs/foundations/serialization).
|
|
57
61
|
* When `deploymentId` is provided, the argument types and return type become `unknown` since there is no guarantee the workflow function's types will be consistent across different deployments.
|
|
62
|
+
* `attributes` seeds plaintext run metadata as part of creation and requires a World implementing spec version 4 or later. Keys that start with `$` are reserved for framework and library code; framework-level callers can pass `allowReservedAttributes: true` to seed reserved keys, with the same semantics as the [`setAttributes`](/docs/api-reference/workflow/set-attributes) option of the same name.
|
|
58
63
|
|
|
59
64
|
<Callout type="info">
|
|
60
|
-
If `start()` throws `'start' received an invalid workflow function. Ensure the Workflow
|
|
65
|
+
If `start()` throws `'start' received an invalid workflow function. Ensure the Workflow SDK is configured correctly and the function includes a 'use workflow' directive.`, the passed function was not transformed as a workflow. The two most common causes are a missing `"use workflow"` directive or missing framework integration. See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function).
|
|
61
66
|
</Callout>
|
|
62
67
|
|
|
63
68
|
## Examples
|
|
@@ -78,13 +83,14 @@ import { start } from "workflow/api";
|
|
|
78
83
|
import { myWorkflow } from "./workflows/my-workflow";
|
|
79
84
|
|
|
80
85
|
const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
|
|
81
|
-
deploymentId: "custom-deployment-id" // [!code highlight]
|
|
86
|
+
deploymentId: "custom-deployment-id", // [!code highlight]
|
|
87
|
+
attributes: { source: "checkout" } // [!code highlight]
|
|
82
88
|
}); // [!code highlight]
|
|
83
89
|
```
|
|
84
90
|
|
|
85
91
|
### Using `deploymentId: "latest"`
|
|
86
92
|
|
|
87
|
-
Set `deploymentId` to `"latest"` to automatically resolve the most recent deployment for the current environment. This is useful when you want to ensure a workflow run targets the latest deployed version of your application rather than the deployment that initiated the call.
|
|
93
|
+
Set `deploymentId` to `"latest"` to automatically resolve the most recent deployment for the current environment. This is useful when you want to ensure a workflow run targets the latest deployed version of your application rather than the deployment that initiated the call. For when to use this and how it fits with default run pinning, see [Versioning](/docs/foundations/versioning).
|
|
88
94
|
|
|
89
95
|
```typescript
|
|
90
96
|
import { start } from "workflow/api";
|
|
@@ -96,7 +102,9 @@ const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
|
|
|
96
102
|
```
|
|
97
103
|
|
|
98
104
|
<Callout type="info">
|
|
99
|
-
The `deploymentId` option is currently a Vercel-specific feature.
|
|
105
|
+
The `deploymentId` option is currently a Vercel-specific feature. Other Worlds may implement this option differently to match their own deployment runtimes, and the World spec may rename it from `deploymentId` to `version` in a future SDK version. On Vercel, `"latest"` resolves to the most recent deployment matching your current environment — the same production target for production deployments, or the same git branch for preview deployments.
|
|
106
|
+
|
|
107
|
+
In Worlds without atomic, immutable deployments (such as local development or self-hosted Postgres), there is no notion of multiple deployments to resolve between, so `deploymentId: "latest"` has no effect: the SDK logs a warning and the run targets the current deployment. This means a workflow that opts into `"latest"` on Vercel still runs unchanged in local development.
|
|
100
108
|
</Callout>
|
|
101
109
|
|
|
102
110
|
<Callout type="warn">
|
|
@@ -105,3 +113,28 @@ When using `deploymentId: "latest"`, the workflow run will execute on a potentia
|
|
|
105
113
|
- **Workflow identity**: The workflow ID is derived from the function name and file path. If the latest deployment has renamed the workflow function or moved it to a different directory, the workflow ID will no longer match and the run will fail to start.
|
|
106
114
|
- **Input and output compatibility**: The arguments passed to `start()` are serialized by the calling deployment but deserialized by the target deployment. Similarly, the workflow's return value is serialized by the target deployment but deserialized by the caller. If the workflow's expected arguments or return type have changed (e.g. added required fields, removed fields, or changed types), the run may fail or behave unexpectedly. Ensure that input and output schemas remain backward-compatible across deployments.
|
|
107
115
|
</Callout>
|
|
116
|
+
|
|
117
|
+
### Inside a Workflow Function
|
|
118
|
+
|
|
119
|
+
`start()` can be called directly from a workflow function to spawn a child run. It is step-backed, so the spawn records a deterministic step boundary in the parent's event log.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { start } from "workflow/api";
|
|
123
|
+
import { childWorkflow } from "./workflows/child";
|
|
124
|
+
|
|
125
|
+
export async function parentWorkflow(value: number) {
|
|
126
|
+
"use workflow";
|
|
127
|
+
|
|
128
|
+
const childRun = await start(childWorkflow, [value]); // [!code highlight]
|
|
129
|
+
const result = await childRun.returnValue; // [!code highlight]
|
|
130
|
+
return { childRunId: childRun.runId, result };
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
<Callout type="info">
|
|
135
|
+
The returned `Run` object is fully functional inside a workflow. Each property access or method call (`.status`, `.returnValue`, `.cancel()`) executes as a separate step. See [Workflow Composition](/cookbook/common-patterns/workflow-composition) for choosing between spawning a child run and awaiting a workflow function directly.
|
|
136
|
+
</Callout>
|
|
137
|
+
|
|
138
|
+
<Callout type="warn">
|
|
139
|
+
`returnValue` polls the child run every second and holds the polling step's worker slot open for as long as the child takes to finish. For long-running children, spawn without awaiting `returnValue` and have the child resume a [hook](/docs/foundations/hooks) when it completes — see the [`startAndWait()` pattern](/cookbook/advanced/child-workflows).
|
|
140
|
+
</Callout>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "workflow/astro"
|
|
3
|
+
description: Astro integration for automatic workflow bundling and route registration.
|
|
4
|
+
type: overview
|
|
5
|
+
summary: Explore the Astro integration for automatic workflow bundling and runtime support.
|
|
6
|
+
related:
|
|
7
|
+
- /docs/getting-started/astro
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Astro integration for Workflow SDK that transforms workflow code and builds the workflow bundles.
|
|
11
|
+
|
|
12
|
+
## Functions
|
|
13
|
+
|
|
14
|
+
<Cards>
|
|
15
|
+
<Card title="workflow()" href="/docs/api-reference/workflow-astro/workflow">
|
|
16
|
+
Astro integration that transforms workflow code (`"use step"`/`"use workflow"` directives)
|
|
17
|
+
</Card>
|
|
18
|
+
</Cards>
|