workflow 5.0.0-beta.0 → 5.0.0-beta.10
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 +4 -4
- package/dist/api-workflow.d.ts +2 -4
- package/dist/api-workflow.d.ts.map +1 -1
- package/dist/api-workflow.js +3 -7
- package/dist/api.d.ts +5 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +14 -2
- package/dist/astro.js +1 -1
- package/dist/index.js +1 -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/class-serialization.js +1 -1
- package/dist/internal/errors.js +1 -1
- package/dist/nest.js +1 -1
- package/dist/next.cjs +4 -2
- package/dist/next.d.cts +1 -1
- package/dist/next.d.cts.map +1 -1
- package/dist/nitro.js +1 -1
- package/dist/nuxt.js +1 -1
- package/dist/observability.d.ts +2 -2
- package/dist/observability.js +3 -3
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -2
- package/dist/stdlib.js +1 -1
- package/dist/sveltekit.js +1 -1
- package/dist/typescript-plugin.cjs +1 -1
- package/dist/vite.js +1 -1
- package/dist/workflow.js +1 -1
- package/docs/ai/index.mdx +6 -5
- package/docs/ai/resumable-streams.mdx +1 -1
- package/docs/api-reference/vitest/index.mdx +28 -1
- package/docs/api-reference/workflow/create-webhook.mdx +37 -18
- package/docs/api-reference/workflow/experimental-set-attributes.mdx +63 -0
- package/docs/api-reference/workflow/get-workflow-metadata.mdx +61 -0
- package/docs/api-reference/workflow/index.mdx +3 -0
- package/docs/api-reference/workflow-ai/durable-agent.mdx +0 -4
- package/docs/api-reference/workflow-ai/index.mdx +0 -5
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +0 -4
- package/docs/api-reference/workflow-api/get-world.mdx +6 -6
- package/docs/api-reference/workflow-api/index.mdx +1 -1
- package/docs/api-reference/workflow-api/start.mdx +5 -4
- package/docs/api-reference/workflow-api/world/index.mdx +2 -2
- package/docs/api-reference/workflow-api/world/observability.mdx +1 -1
- package/docs/api-reference/workflow-api/world/queue.mdx +1 -1
- package/docs/api-reference/workflow-api/world/storage.mdx +8 -8
- package/docs/api-reference/workflow-api/world/streams.mdx +38 -36
- package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +16 -6
- package/docs/api-reference/workflow-next/with-workflow.mdx +34 -2
- package/docs/changelog/attributes-mvp.mdx +368 -0
- package/docs/changelog/eager-processing.mdx +595 -0
- package/docs/changelog/index.mdx +2 -1
- package/docs/cookbook/advanced/child-workflows.mdx +313 -0
- package/docs/cookbook/advanced/meta.json +9 -0
- package/docs/cookbook/advanced/publishing-libraries.mdx +336 -0
- package/docs/cookbook/advanced/serializable-steps.mdx +147 -0
- package/docs/cookbook/advanced/upgrading-workflows.mdx +195 -0
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +156 -0
- package/docs/cookbook/agent-patterns/durable-agent.mdx +154 -0
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +255 -0
- package/docs/cookbook/agent-patterns/meta.json +4 -0
- package/docs/cookbook/common-patterns/batching.mdx +105 -0
- package/docs/cookbook/common-patterns/idempotency.mdx +107 -0
- package/docs/cookbook/common-patterns/meta.json +15 -0
- package/docs/cookbook/common-patterns/rate-limiting.mdx +228 -0
- package/docs/cookbook/common-patterns/saga.mdx +247 -0
- package/docs/cookbook/common-patterns/scheduling.mdx +129 -0
- package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +155 -0
- package/docs/cookbook/common-patterns/timeouts.mdx +99 -0
- package/docs/cookbook/common-patterns/webhooks.mdx +185 -0
- package/docs/cookbook/common-patterns/workflow-composition.mdx +111 -0
- package/docs/cookbook/index.mdx +38 -0
- package/docs/cookbook/integrations/ai-sdk.mdx +383 -0
- package/docs/cookbook/integrations/chat-sdk.mdx +307 -0
- package/docs/cookbook/integrations/meta.json +4 -0
- package/docs/cookbook/integrations/sandbox.mdx +520 -0
- package/docs/cookbook/meta.json +5 -0
- package/docs/deploying/building-a-world.mdx +46 -44
- package/docs/deploying/world/local-world.mdx +1 -1
- package/docs/deploying/world/postgres-world.mdx +15 -8
- package/docs/deploying/world/vercel-world.mdx +3 -1
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +80 -0
- package/docs/errors/hook-conflict.mdx +56 -4
- package/docs/errors/index.mdx +3 -0
- package/docs/errors/runtime-decryption-failed.mdx +77 -0
- package/docs/errors/start-invalid-workflow-function.mdx +1 -1
- package/docs/foundations/cancellation.mdx +460 -0
- package/docs/foundations/errors-and-retries.mdx +7 -3
- package/docs/foundations/index.mdx +3 -3
- package/docs/foundations/meta.json +3 -2
- package/docs/foundations/serialization.mdx +78 -42
- package/docs/foundations/starting-workflows.mdx +6 -2
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/getting-started/astro.mdx +6 -0
- package/docs/getting-started/index.mdx +13 -7
- package/docs/getting-started/meta.json +3 -1
- package/docs/getting-started/nestjs.mdx +8 -0
- package/docs/getting-started/next.mdx +29 -3
- package/docs/getting-started/nitro.mdx +22 -0
- package/docs/getting-started/python.mdx +165 -0
- package/docs/getting-started/sveltekit.mdx +6 -0
- package/docs/getting-started/tanstack-start.mdx +241 -0
- package/docs/how-it-works/cancellation.mdx +287 -0
- package/docs/how-it-works/code-transform.mdx +8 -7
- package/docs/how-it-works/event-sourcing.mdx +2 -2
- package/docs/how-it-works/meta.json +2 -1
- package/docs/internal/index.mdx +19 -0
- package/docs/internal/meta.json +5 -0
- package/docs/internal/serializable-abort-controller.mdx +148 -0
- package/docs/meta.json +1 -0
- package/docs/migration-guides/index.mdx +34 -0
- package/docs/migration-guides/meta.json +9 -0
- package/docs/migration-guides/migrating-from-aws-step-functions.mdx +358 -0
- package/docs/migration-guides/migrating-from-inngest.mdx +304 -0
- package/docs/migration-guides/migrating-from-temporal.mdx +313 -0
- package/docs/migration-guides/migrating-from-trigger-dev.mdx +328 -0
- package/docs/observability/attributes.mdx +66 -0
- package/docs/observability/index.mdx +9 -1
- package/docs/observability/meta.json +1 -1
- package/package.json +14 -14
- package/dist/internal/private.d.ts +0 -6
- package/dist/internal/private.d.ts.map +0 -1
- package/dist/internal/private.js +0 -6
- package/docs/foundations/common-patterns.mdx +0 -265
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: experimental_setAttributes
|
|
3
|
+
description: Attach string metadata to workflow run for observability.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: Use experimental_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
|
+
<Callout>
|
|
16
|
+
This API is experimental and may change before the stable attributes API is released.
|
|
17
|
+
</Callout>
|
|
18
|
+
|
|
19
|
+
```typescript lineNumbers
|
|
20
|
+
import { experimental_setAttributes } from "workflow"
|
|
21
|
+
|
|
22
|
+
export async function orderWorkflow(orderId: string) {
|
|
23
|
+
"use workflow"
|
|
24
|
+
|
|
25
|
+
await experimental_setAttributes({
|
|
26
|
+
phase: "received",
|
|
27
|
+
orderId,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## API Signature
|
|
33
|
+
|
|
34
|
+
### Parameters
|
|
35
|
+
|
|
36
|
+
<TSDoc
|
|
37
|
+
definition={`
|
|
38
|
+
import { experimental_setAttributes } from "workflow";
|
|
39
|
+
export default experimental_setAttributes;`}
|
|
40
|
+
showSections={['parameters']}
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
Call `experimental_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.
|
|
46
|
+
|
|
47
|
+
Attribute values must be strings. Pass `undefined` to remove an attribute:
|
|
48
|
+
|
|
49
|
+
```typescript lineNumbers
|
|
50
|
+
import { experimental_setAttributes } from "workflow"
|
|
51
|
+
|
|
52
|
+
export async function cleanupAttributes() {
|
|
53
|
+
"use workflow"
|
|
54
|
+
|
|
55
|
+
await experimental_setAttributes({ staleKey: undefined })
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
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.
|
|
60
|
+
|
|
61
|
+
Validation errors throw [`FatalError`](/docs/api-reference/workflow/fatal-error) and fail the run before an attribute write is attempted.
|
|
62
|
+
|
|
63
|
+
When called from a workflow body, the write is recorded through an internal step. When called from a step body, the step posts the attributes directly to the World. Storage errors from step-body calls throw from `experimental_setAttributes`, so catch them inside the step if the write should be best-effort.
|
|
@@ -13,6 +13,7 @@ You may want to use this function when you need to:
|
|
|
13
13
|
|
|
14
14
|
* Log workflow run IDs
|
|
15
15
|
* Access timing information of a workflow
|
|
16
|
+
* Detect whether encryption is enabled for the current run
|
|
16
17
|
|
|
17
18
|
<Callout>
|
|
18
19
|
If you need to access step context, take a look at [`getStepMetadata`](/docs/api-reference/workflow/get-step-metadata).
|
|
@@ -29,6 +30,66 @@ async function testWorkflow() {
|
|
|
29
30
|
}
|
|
30
31
|
```
|
|
31
32
|
|
|
33
|
+
### Detecting Workflow Runtime
|
|
34
|
+
|
|
35
|
+
You can use `getWorkflowMetadata` to detect whether your code is running inside a workflow context. This is useful when building shared utilities that need to behave differently inside and outside of workflows.
|
|
36
|
+
|
|
37
|
+
Since `getWorkflowMetadata` throws when called outside a workflow, you can wrap it in a try-catch:
|
|
38
|
+
|
|
39
|
+
```typescript lineNumbers
|
|
40
|
+
import { getWorkflowMetadata } from "workflow"
|
|
41
|
+
|
|
42
|
+
function isInWorkflow(): boolean {
|
|
43
|
+
try {
|
|
44
|
+
getWorkflowMetadata()
|
|
45
|
+
return true
|
|
46
|
+
} catch {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For example, a logging utility could include the workflow run ID when available:
|
|
53
|
+
|
|
54
|
+
```typescript lineNumbers
|
|
55
|
+
import { getWorkflowMetadata } from "workflow"
|
|
56
|
+
|
|
57
|
+
function log(message: string) {
|
|
58
|
+
try {
|
|
59
|
+
const { workflowRunId } = getWorkflowMetadata()
|
|
60
|
+
console.log(`[workflow:${workflowRunId}] ${message}`)
|
|
61
|
+
} catch {
|
|
62
|
+
console.log(message)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Detecting Encryption
|
|
68
|
+
|
|
69
|
+
The `features` object indicates which capabilities are active for the current run. Library authors can use `features.encryption` to control whether sensitive data is included in step return values, which are serialized to the event log:
|
|
70
|
+
|
|
71
|
+
```typescript lineNumbers
|
|
72
|
+
import { getWorkflowMetadata } from "workflow"
|
|
73
|
+
|
|
74
|
+
declare function getUserProfile(userId: string): Promise<{ name: string; ssn: string }>; // @setup
|
|
75
|
+
|
|
76
|
+
async function fetchUserProfile(userId: string) {
|
|
77
|
+
"use step"
|
|
78
|
+
|
|
79
|
+
const { features } = getWorkflowMetadata() // [!code highlight]
|
|
80
|
+
const profile = await getUserProfile(userId)
|
|
81
|
+
|
|
82
|
+
if (!features.encryption) { // [!code highlight]
|
|
83
|
+
// Omit sensitive fields from the return value,
|
|
84
|
+
// since it will be stored unencrypted in the event log
|
|
85
|
+
const { ssn, ...safe } = profile
|
|
86
|
+
return safe
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return profile
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
32
93
|
## API Signature
|
|
33
94
|
|
|
34
95
|
### Parameters
|
|
@@ -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/experimental-set-attributes" title="experimental_setAttributes()">
|
|
51
|
+
Attach experimental string metadata to the current workflow run.
|
|
52
|
+
</Card>
|
|
50
53
|
</Cards>
|
|
51
54
|
|
|
52
55
|
## Error Classes
|
|
@@ -9,10 +9,6 @@ related:
|
|
|
9
9
|
- /docs/ai/defining-tools
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<Callout type="warn">
|
|
13
|
-
The `@workflow/ai` package is currently in active development and should be considered experimental.
|
|
14
|
-
</Callout>
|
|
15
|
-
|
|
16
12
|
The `DurableAgent` class enables you to create AI-powered agents that can maintain state across workflow steps, call tools, and gracefully handle interruptions and resumptions.
|
|
17
13
|
|
|
18
14
|
Tool calls can be implemented as workflow steps for automatic retries, or as regular workflow-level logic utilizing core library features such as [`sleep()`](/docs/api-reference/workflow/sleep) and [Hooks](/docs/foundations/hooks).
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "@workflow/ai"
|
|
3
|
-
icon: FlaskConical
|
|
4
3
|
description: Helpers for building AI-powered workflows with the AI SDK.
|
|
5
4
|
type: overview
|
|
6
5
|
summary: Explore helpers for integrating AI SDK to build durable AI-powered workflows.
|
|
@@ -8,10 +7,6 @@ related:
|
|
|
8
7
|
- /docs/ai
|
|
9
8
|
---
|
|
10
9
|
|
|
11
|
-
<Callout type="warn">
|
|
12
|
-
The `@workflow/ai` package is currently in active development and should be considered experimental.
|
|
13
|
-
</Callout>
|
|
14
|
-
|
|
15
10
|
Helpers for integrating AI SDK for building AI-powered workflows.
|
|
16
11
|
|
|
17
12
|
## Classes
|
|
@@ -9,10 +9,6 @@ related:
|
|
|
9
9
|
- /docs/ai/resumable-streams
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<Callout type="warn">
|
|
13
|
-
The `@workflow/ai` package is currently in active development and should be considered experimental.
|
|
14
|
-
</Callout>
|
|
15
|
-
|
|
16
12
|
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.
|
|
17
13
|
|
|
18
14
|
<Callout>
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: getWorld
|
|
3
|
-
description:
|
|
3
|
+
description: Async function that resolves the World instance for low-level storage, queuing, and streaming operations.
|
|
4
4
|
type: reference
|
|
5
|
-
summary:
|
|
5
|
+
summary: Async function that resolves the World instance for low-level workflow storage, queuing, and streaming backends.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/deploying
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
Retrieves the World instance for direct access to workflow storage, queuing, and streaming backends. This function returns a `World
|
|
10
|
+
Retrieves the World instance for direct access to workflow storage, queuing, and streaming backends. This async function returns a `Promise<World>` which provides low-level access to manage workflow runs, steps, events, and hooks.
|
|
11
11
|
|
|
12
12
|
Use this function when you need direct access to the underlying workflow infrastructure, such as listing all runs, querying events, or implementing custom workflow management logic.
|
|
13
13
|
|
|
14
14
|
```typescript lineNumbers
|
|
15
15
|
import { getWorld } from "workflow/runtime";
|
|
16
16
|
|
|
17
|
-
const world = getWorld(); // [!code highlight]
|
|
17
|
+
const world = await getWorld(); // [!code highlight]
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## API Signature
|
|
@@ -25,7 +25,7 @@ This function does not accept any parameters.
|
|
|
25
25
|
|
|
26
26
|
### Returns
|
|
27
27
|
|
|
28
|
-
Returns a `World
|
|
28
|
+
Returns a `Promise<World>` object:
|
|
29
29
|
|
|
30
30
|
<TSDoc
|
|
31
31
|
definition={`
|
|
@@ -79,7 +79,7 @@ export async function GET(req: Request) {
|
|
|
79
79
|
const cursor = url.searchParams.get("cursor") ?? undefined;
|
|
80
80
|
|
|
81
81
|
try {
|
|
82
|
-
const world = getWorld(); // [!code highlight]
|
|
82
|
+
const world = await getWorld(); // [!code highlight]
|
|
83
83
|
const runs = await world.runs.list({
|
|
84
84
|
pagination: { cursor },
|
|
85
85
|
resolveData: "none",
|
|
@@ -28,7 +28,7 @@ The API package is for access and introspection of workflow data to inspect runs
|
|
|
28
28
|
Get workflow run status and metadata without waiting for completion.
|
|
29
29
|
</Card>
|
|
30
30
|
<Card href="/docs/api-reference/workflow-api/get-world" title="getWorld()">
|
|
31
|
-
|
|
31
|
+
Async: resolve the World instance for storage, queuing, and streaming backends.
|
|
32
32
|
</Card>
|
|
33
33
|
<Card href="/docs/api-reference/workflow-api/world" title="World SDK">
|
|
34
34
|
Low-level API for inspecting runs, steps, events, hooks, streams, and queues.
|
|
@@ -2,7 +2,7 @@
|
|
|
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
8
|
---
|
|
@@ -50,7 +50,8 @@ Learn more about [`WorkflowReadableStreamOptions`](/docs/api-reference/workflow-
|
|
|
50
50
|
|
|
51
51
|
## Good to Know
|
|
52
52
|
|
|
53
|
-
* The `start()` function is used in runtime
|
|
53
|
+
* The `start()` function is used in runtime contexts to programmatically trigger workflow executions.
|
|
54
|
+
* 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
55
|
* This is different from calling workflow functions directly, which is the typical pattern in Next.js applications.
|
|
55
56
|
* The function returns immediately after enqueuing the workflow - it doesn't wait for the workflow to complete.
|
|
56
57
|
* All arguments must be [serializable](/docs/foundations/serialization).
|
|
@@ -84,7 +85,7 @@ const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
|
|
|
84
85
|
|
|
85
86
|
### Using `deploymentId: "latest"`
|
|
86
87
|
|
|
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.
|
|
88
|
+
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
89
|
|
|
89
90
|
```typescript
|
|
90
91
|
import { start } from "workflow/api";
|
|
@@ -96,7 +97,7 @@ const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
|
|
|
96
97
|
```
|
|
97
98
|
|
|
98
99
|
<Callout type="info">
|
|
99
|
-
The `deploymentId` option is currently a Vercel-specific feature.
|
|
100
|
+
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.
|
|
100
101
|
</Callout>
|
|
101
102
|
|
|
102
103
|
<Callout type="warn">
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: World SDK
|
|
3
3
|
description: Low-level API for inspecting and managing workflow runs, steps, events, hooks, streams, and queues.
|
|
4
4
|
type: overview
|
|
5
|
-
summary: Access workflow infrastructure
|
|
5
|
+
summary: Access workflow infrastructure via await getWorld() for building observability dashboards, admin tools, and custom integrations.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/api-reference/workflow-api/get-world
|
|
8
8
|
keywords:
|
|
@@ -19,7 +19,7 @@ The World SDK provides direct access to workflow infrastructure — runs, steps,
|
|
|
19
19
|
```typescript lineNumbers
|
|
20
20
|
import { getWorld } from "workflow/runtime";
|
|
21
21
|
|
|
22
|
-
const world = getWorld(); // [!code highlight]
|
|
22
|
+
const world = await getWorld(); // [!code highlight]
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Interfaces
|
|
@@ -147,7 +147,7 @@ const hydrated = hydrateResourceIOWithKey(step, key); // [!code highlight]
|
|
|
147
147
|
import { getWorld } from "workflow/runtime";
|
|
148
148
|
import { parseStepName, parseWorkflowName } from "workflow/observability"; // [!code highlight]
|
|
149
149
|
|
|
150
|
-
const world = getWorld();
|
|
150
|
+
const world = await getWorld();
|
|
151
151
|
const run = await world.runs.get(runId, { resolveData: "none" });
|
|
152
152
|
console.log("Workflow:", parseWorkflowName(run.workflowName)?.shortName); // [!code highlight]
|
|
153
153
|
|
|
@@ -28,7 +28,7 @@ Queue methods live directly on the `world` object (not nested). They dispatch in
|
|
|
28
28
|
```typescript lineNumbers
|
|
29
29
|
import { getWorld } from "workflow/runtime";
|
|
30
30
|
|
|
31
|
-
const world = getWorld(); // [!code highlight]
|
|
31
|
+
const world = await getWorld(); // [!code highlight]
|
|
32
32
|
// Queue methods are called directly on world — e.g. world.queue()
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -37,7 +37,7 @@ The World storage interface exposes four sub-interfaces for querying workflow da
|
|
|
37
37
|
```typescript lineNumbers
|
|
38
38
|
import { getWorld } from "workflow/runtime";
|
|
39
39
|
|
|
40
|
-
const world = getWorld(); // [!code highlight]
|
|
40
|
+
const world = await getWorld(); // [!code highlight]
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
---
|
|
@@ -304,7 +304,7 @@ const result = await world.hooks.list({ // [!code highlight]
|
|
|
304
304
|
```typescript lineNumbers
|
|
305
305
|
import { getWorld } from "workflow/runtime";
|
|
306
306
|
|
|
307
|
-
const world = getWorld();
|
|
307
|
+
const world = await getWorld();
|
|
308
308
|
let cursor: string | undefined;
|
|
309
309
|
|
|
310
310
|
const runs = await world.runs.list({ // [!code highlight]
|
|
@@ -319,7 +319,7 @@ cursor = runs.cursor; // pass to next call for pagination
|
|
|
319
319
|
```typescript lineNumbers
|
|
320
320
|
import { getWorld } from "workflow/runtime";
|
|
321
321
|
|
|
322
|
-
const world = getWorld();
|
|
322
|
+
const world = await getWorld();
|
|
323
323
|
|
|
324
324
|
// Full data (default) — includes serialized input/output
|
|
325
325
|
const run = await world.runs.get(runId); // [!code highlight]
|
|
@@ -336,7 +336,7 @@ const lightweight = await world.runs.get(runId, { // [!code highlight]
|
|
|
336
336
|
import { getWorld } from "workflow/runtime";
|
|
337
337
|
import { parseStepName } from "workflow/observability"; // [!code highlight]
|
|
338
338
|
|
|
339
|
-
const world = getWorld();
|
|
339
|
+
const world = await getWorld();
|
|
340
340
|
const steps = await world.steps.list({ // [!code highlight]
|
|
341
341
|
runId,
|
|
342
342
|
resolveData: "none",
|
|
@@ -358,7 +358,7 @@ const progress = steps.data.map((step) => {
|
|
|
358
358
|
import { getWorld } from "workflow/runtime";
|
|
359
359
|
import { hydrateResourceIO, observabilityRevivers } from "workflow/observability"; // [!code highlight]
|
|
360
360
|
|
|
361
|
-
const world = getWorld();
|
|
361
|
+
const world = await getWorld();
|
|
362
362
|
const step = await world.steps.get(runId, stepId); // [!code highlight]
|
|
363
363
|
const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
|
|
364
364
|
console.log(hydrated.input, hydrated.output);
|
|
@@ -369,7 +369,7 @@ console.log(hydrated.input, hydrated.output);
|
|
|
369
369
|
```typescript lineNumbers
|
|
370
370
|
import { getWorld } from "workflow/runtime";
|
|
371
371
|
|
|
372
|
-
const world = getWorld();
|
|
372
|
+
const world = await getWorld();
|
|
373
373
|
await world.events.create(runId, { // [!code highlight]
|
|
374
374
|
eventType: "run_cancelled", // [!code highlight]
|
|
375
375
|
}); // [!code highlight]
|
|
@@ -380,7 +380,7 @@ await world.events.create(runId, { // [!code highlight]
|
|
|
380
380
|
```typescript lineNumbers
|
|
381
381
|
import { getWorld } from "workflow/runtime";
|
|
382
382
|
|
|
383
|
-
const world = getWorld();
|
|
383
|
+
const world = await getWorld();
|
|
384
384
|
const hook = await world.hooks.getByToken(token); // [!code highlight]
|
|
385
385
|
console.log(hook.runId, hook.metadata); // [!code highlight]
|
|
386
386
|
```
|
|
@@ -390,7 +390,7 @@ console.log(hook.runId, hook.metadata); // [!code highlight]
|
|
|
390
390
|
```typescript lineNumbers
|
|
391
391
|
import { getWorld } from "workflow/runtime";
|
|
392
392
|
|
|
393
|
-
const world = getWorld();
|
|
393
|
+
const world = await getWorld();
|
|
394
394
|
const events = await world.events.list({ runId }); // [!code highlight]
|
|
395
395
|
|
|
396
396
|
for (const event of events.data) {
|
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
title: Streams
|
|
3
3
|
description: Read, write, and manage real-time data streams for workflow runs.
|
|
4
4
|
type: reference
|
|
5
|
-
summary: "Methods:
|
|
5
|
+
summary: "Methods: streams.write(), streams.writeMulti(), streams.get(), streams.close(), streams.list(), streams.getChunks(), streams.getInfo(). Stream methods live on world.streams."
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/api-reference/workflow-api/get-world
|
|
8
8
|
related:
|
|
9
9
|
- /docs/foundations/streaming
|
|
10
10
|
- /docs/api-reference/workflow/get-writable
|
|
11
11
|
keywords:
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
12
|
+
- streams.write
|
|
13
|
+
- streams.writeMulti
|
|
14
|
+
- streams.get
|
|
15
|
+
- streams.close
|
|
16
|
+
- streams.list
|
|
17
|
+
- streams.getChunks
|
|
18
|
+
- streams.getInfo
|
|
19
19
|
- Streamer interface
|
|
20
20
|
- real-time streaming
|
|
21
21
|
- stream lifecycle
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
Stream methods live
|
|
24
|
+
Stream methods live on `world.streams` (the `streams` sub-object of the `World` instance returned by `await getWorld()`). Use them to write chunks, read streams, and manage stream lifecycle outside of the standard `getWritable()` pattern.
|
|
25
25
|
|
|
26
26
|
<Callout type="info">
|
|
27
27
|
For most streaming use cases, use [`getWritable()`](/docs/api-reference/workflow/get-writable) inside steps. Direct stream methods are for advanced scenarios like building custom stream consumers or managing streams from outside a workflow.
|
|
@@ -32,82 +32,83 @@ Stream methods live directly on the `world` object returned by `getWorld()`. Use
|
|
|
32
32
|
```typescript lineNumbers
|
|
33
33
|
import { getWorld } from "workflow/runtime";
|
|
34
34
|
|
|
35
|
-
const world = getWorld(); // [!code highlight]
|
|
36
|
-
// Stream methods are called
|
|
35
|
+
const world = await getWorld(); // [!code highlight]
|
|
36
|
+
// Stream methods are called on world.streams — e.g. world.streams.write()
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Methods
|
|
40
40
|
|
|
41
|
-
###
|
|
41
|
+
### write()
|
|
42
42
|
|
|
43
43
|
Write a data chunk to a named stream.
|
|
44
44
|
|
|
45
45
|
```typescript lineNumbers
|
|
46
|
-
await world.
|
|
46
|
+
await world.streams.write(runId, "default", chunk); // [!code highlight]
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
**Parameters:**
|
|
50
50
|
|
|
51
51
|
| Parameter | Type | Description |
|
|
52
52
|
|-----------|------|-------------|
|
|
53
|
-
| `name` | `string` | The stream name |
|
|
54
53
|
| `runId` | `string` | The workflow run ID |
|
|
54
|
+
| `name` | `string` | The stream name |
|
|
55
55
|
| `chunk` | `string \| Uint8Array` | Data to write |
|
|
56
56
|
|
|
57
|
-
###
|
|
57
|
+
### writeMulti()
|
|
58
58
|
|
|
59
|
-
Write multiple chunks in a single operation. Optional optimization — not all World implementations support it. Falls back to sequential `
|
|
59
|
+
Write multiple chunks in a single operation. Optional optimization — not all World implementations support it. Falls back to sequential `write()` calls if unavailable.
|
|
60
60
|
|
|
61
61
|
```typescript lineNumbers
|
|
62
|
-
await world.
|
|
62
|
+
await world.streams.writeMulti?.(runId, "default", [chunk1, chunk2]); // [!code highlight]
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
**Parameters:**
|
|
66
66
|
|
|
67
67
|
| Parameter | Type | Description |
|
|
68
68
|
|-----------|------|-------------|
|
|
69
|
-
| `name` | `string` | The stream name |
|
|
70
69
|
| `runId` | `string` | The workflow run ID |
|
|
70
|
+
| `name` | `string` | The stream name |
|
|
71
71
|
| `chunks` | `(string \| Uint8Array)[]` | Chunks to write, in order |
|
|
72
72
|
|
|
73
|
-
###
|
|
73
|
+
### get()
|
|
74
74
|
|
|
75
75
|
Read data from a named stream as a live `ReadableStream` that waits for new chunks in real time.
|
|
76
76
|
|
|
77
77
|
```typescript lineNumbers
|
|
78
|
-
const readable = await world.
|
|
78
|
+
const readable = await world.streams.get(runId, "default"); // [!code highlight]
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
**Parameters:**
|
|
82
82
|
|
|
83
83
|
| Parameter | Type | Description |
|
|
84
84
|
|-----------|------|-------------|
|
|
85
|
+
| `runId` | `string` | The workflow run ID |
|
|
85
86
|
| `name` | `string` | The stream name |
|
|
86
87
|
| `startIndex` | `number` | Optional. Positive values skip chunks from the start (0-based). Negative values read from the tail (e.g. `-3` starts 3 chunks from the end). Clamped to 0. |
|
|
87
88
|
|
|
88
89
|
**Returns:** `ReadableStream<Uint8Array>`
|
|
89
90
|
|
|
90
|
-
###
|
|
91
|
+
### close()
|
|
91
92
|
|
|
92
93
|
Close a stream when done writing.
|
|
93
94
|
|
|
94
95
|
```typescript lineNumbers
|
|
95
|
-
await world.
|
|
96
|
+
await world.streams.close(runId, "default"); // [!code highlight]
|
|
96
97
|
```
|
|
97
98
|
|
|
98
99
|
**Parameters:**
|
|
99
100
|
|
|
100
101
|
| Parameter | Type | Description |
|
|
101
102
|
|-----------|------|-------------|
|
|
102
|
-
| `name` | `string` | The stream name |
|
|
103
103
|
| `runId` | `string` | The workflow run ID |
|
|
104
|
+
| `name` | `string` | The stream name |
|
|
104
105
|
|
|
105
|
-
###
|
|
106
|
+
### list()
|
|
106
107
|
|
|
107
108
|
List all stream names associated with a workflow run.
|
|
108
109
|
|
|
109
110
|
```typescript lineNumbers
|
|
110
|
-
const streamNames = await world.
|
|
111
|
+
const streamNames = await world.streams.list(runId); // [!code highlight]
|
|
111
112
|
```
|
|
112
113
|
|
|
113
114
|
**Parameters:**
|
|
@@ -118,12 +119,12 @@ const streamNames = await world.listStreamsByRunId(runId); // [!code highlight]
|
|
|
118
119
|
|
|
119
120
|
**Returns:** `string[]`
|
|
120
121
|
|
|
121
|
-
###
|
|
122
|
+
### getChunks()
|
|
122
123
|
|
|
123
|
-
Fetch stream chunks with cursor-based pagination. Unlike `
|
|
124
|
+
Fetch stream chunks with cursor-based pagination. Unlike `get()` (which returns a live `ReadableStream`), this returns a snapshot of currently available chunks.
|
|
124
125
|
|
|
125
126
|
```typescript lineNumbers
|
|
126
|
-
const result = await world.
|
|
127
|
+
const result = await world.streams.getChunks(runId, "default", { // [!code highlight]
|
|
127
128
|
limit: 50,
|
|
128
129
|
}); // [!code highlight]
|
|
129
130
|
// result.data: StreamChunk[], result.cursor, result.hasMore, result.done
|
|
@@ -133,8 +134,8 @@ const result = await world.getStreamChunks("default", runId, { // [!code highlig
|
|
|
133
134
|
|
|
134
135
|
| Parameter | Type | Description |
|
|
135
136
|
|-----------|------|-------------|
|
|
136
|
-
| `name` | `string` | The stream name |
|
|
137
137
|
| `runId` | `string` | The workflow run ID |
|
|
138
|
+
| `name` | `string` | The stream name |
|
|
138
139
|
| `options.limit` | `number` | Max chunks per page (default: 100, max: 1000) |
|
|
139
140
|
| `options.cursor` | `string` | Cursor from a previous response |
|
|
140
141
|
|
|
@@ -147,12 +148,12 @@ const result = await world.getStreamChunks("default", runId, { // [!code highlig
|
|
|
147
148
|
| `hasMore` | `boolean` | Whether more pages of already-written chunks exist |
|
|
148
149
|
| `done` | `boolean` | Whether the stream is fully closed. When `false`, new chunks may appear in future requests even after `hasMore` is `false`. |
|
|
149
150
|
|
|
150
|
-
###
|
|
151
|
+
### getInfo()
|
|
151
152
|
|
|
152
153
|
Retrieve lightweight metadata about a stream without fetching chunks.
|
|
153
154
|
|
|
154
155
|
```typescript lineNumbers
|
|
155
|
-
const info = await world.
|
|
156
|
+
const info = await world.streams.getInfo(runId, "default"); // [!code highlight]
|
|
156
157
|
// info.tailIndex: last chunk index (-1 if empty), info.done: whether stream is closed
|
|
157
158
|
```
|
|
158
159
|
|
|
@@ -160,8 +161,8 @@ const info = await world.getStreamInfo("default", runId); // [!code highlight]
|
|
|
160
161
|
|
|
161
162
|
| Parameter | Type | Description |
|
|
162
163
|
|-----------|------|-------------|
|
|
163
|
-
| `name` | `string` | The stream name |
|
|
164
164
|
| `runId` | `string` | The workflow run ID |
|
|
165
|
+
| `name` | `string` | The stream name |
|
|
165
166
|
|
|
166
167
|
**Returns:** `StreamInfoResponse`
|
|
167
168
|
|
|
@@ -181,8 +182,9 @@ import { getWorld } from "workflow/runtime";
|
|
|
181
182
|
export async function GET(req: Request) {
|
|
182
183
|
const url = new URL(req.url);
|
|
183
184
|
const streamName = url.searchParams.get("name") ?? "default";
|
|
184
|
-
const
|
|
185
|
-
const
|
|
185
|
+
const runId = url.searchParams.get("runId")!;
|
|
186
|
+
const world = await getWorld();
|
|
187
|
+
const readable = await world.streams.get(runId, streamName); // [!code highlight]
|
|
186
188
|
|
|
187
189
|
return new Response(readable, {
|
|
188
190
|
headers: { "Content-Type": "application/octet-stream" },
|
|
@@ -195,11 +197,11 @@ export async function GET(req: Request) {
|
|
|
195
197
|
```typescript lineNumbers
|
|
196
198
|
import { getWorld } from "workflow/runtime";
|
|
197
199
|
|
|
198
|
-
const world = getWorld();
|
|
200
|
+
const world = await getWorld();
|
|
199
201
|
let cursor: string | undefined;
|
|
200
202
|
|
|
201
203
|
do {
|
|
202
|
-
const result = await world.
|
|
204
|
+
const result = await world.streams.getChunks(runId, "default", { cursor }); // [!code highlight]
|
|
203
205
|
for (const chunk of result.data) {
|
|
204
206
|
console.log(`Chunk ${chunk.index}:`, chunk.data);
|
|
205
207
|
}
|
|
@@ -11,7 +11,7 @@ related:
|
|
|
11
11
|
|
|
12
12
|
`WorkflowRunFailedError` is thrown when awaiting `run.returnValue` on a workflow run whose status is `'failed'`. This indicates that the workflow encountered a fatal error during execution and cannot produce a return value.
|
|
13
13
|
|
|
14
|
-
The `cause` property
|
|
14
|
+
The `cause` property holds the original thrown value, hydrated through the workflow serialization pipeline so its type identity (e.g. `FatalError`, `RetryableError`, custom `Error` subclasses), `cause` chain, and custom properties are preserved. Because any JavaScript value can be thrown, `cause` is typed as `unknown` — narrow it with `instanceof Error` (or a more specific check) before accessing fields like `message`. The high-level error classification is exposed as the top-level `errorCode` property.
|
|
15
15
|
|
|
16
16
|
```typescript lineNumbers
|
|
17
17
|
import { WorkflowRunFailedError } from "workflow/errors"
|
|
@@ -21,9 +21,11 @@ try {
|
|
|
21
21
|
const result = await run.returnValue;
|
|
22
22
|
} catch (error) {
|
|
23
23
|
if (WorkflowRunFailedError.is(error)) { // [!code highlight]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
if (error.cause instanceof Error) {
|
|
25
|
+
console.error(`Run ${error.runId} failed:`, error.cause.message);
|
|
26
|
+
}
|
|
27
|
+
if (error.errorCode) {
|
|
28
|
+
console.error("Error code:", error.errorCode);
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
}
|
|
@@ -38,8 +40,16 @@ definition={`
|
|
|
38
40
|
interface WorkflowRunFailedError {
|
|
39
41
|
/** The ID of the failed run. */
|
|
40
42
|
runId: string;
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
+
/**
|
|
44
|
+
* The original thrown value from the failed workflow run, hydrated through
|
|
45
|
+
* the workflow serialization pipeline. Preserves the original type identity
|
|
46
|
+
* (Error subclasses, FatalError, custom classes with WORKFLOW_SERIALIZE,
|
|
47
|
+
* etc.) and custom properties. Typed as \`unknown\` because any value can
|
|
48
|
+
* be thrown — narrow with \`instanceof Error\` before accessing fields.
|
|
49
|
+
*/
|
|
50
|
+
cause: unknown;
|
|
51
|
+
/** The high-level error category (e.g. \`USER_ERROR\`, \`RUNTIME_ERROR\`). */
|
|
52
|
+
errorCode?: string;
|
|
43
53
|
/** The error message. */
|
|
44
54
|
message: string;
|
|
45
55
|
}
|