workflow 4.2.0-beta.75 → 4.2.0-beta.77
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 +2 -2
- package/docs/api-reference/workflow-ai/durable-agent.mdx +86 -1
- package/docs/api-reference/workflow-api/get-world.mdx +59 -14
- package/docs/api-reference/workflow-api/start.mdx +5 -0
- package/docs/api-reference/workflow-api/world/index.mdx +5 -14
- package/docs/api-reference/workflow-api/world/meta.json +1 -9
- package/docs/api-reference/workflow-api/world/observability.mdx +14 -139
- package/docs/api-reference/workflow-api/world/queue.mdx +26 -67
- package/docs/api-reference/workflow-api/world/storage.mdx +408 -0
- package/docs/api-reference/workflow-api/world/streams.mdx +89 -27
- package/docs/api-reference/workflow-next/with-workflow.mdx +51 -0
- package/docs/changelog/meta.json +1 -1
- package/docs/changelog/resilient-start.mdx +327 -0
- package/docs/deploying/building-a-world.mdx +16 -6
- package/docs/deploying/index.mdx +2 -2
- package/docs/deploying/world/vercel-world.mdx +30 -1
- package/docs/errors/hook-conflict.mdx +1 -1
- package/docs/errors/node-js-module-in-workflow.mdx +1 -1
- package/docs/errors/start-invalid-workflow-function.mdx +83 -58
- package/docs/foundations/serialization.mdx +3 -3
- package/docs/foundations/starting-workflows.mdx +1 -1
- package/docs/foundations/streaming.mdx +1 -1
- package/docs/getting-started/astro.mdx +18 -1
- package/docs/getting-started/express.mdx +18 -1
- package/docs/getting-started/fastify.mdx +18 -1
- package/docs/getting-started/hono.mdx +18 -1
- package/docs/getting-started/nestjs.mdx +84 -6
- package/docs/getting-started/next.mdx +17 -2
- package/docs/getting-started/nitro.mdx +18 -1
- package/docs/getting-started/nuxt.mdx +18 -1
- package/docs/getting-started/sveltekit.mdx +18 -1
- package/docs/getting-started/vite.mdx +18 -1
- package/docs/how-it-works/encryption.mdx +39 -2
- package/docs/how-it-works/event-sourcing.mdx +19 -2
- package/docs/how-it-works/framework-integrations.mdx +68 -11
- package/docs/how-it-works/understanding-directives.mdx +3 -3
- package/docs/observability/index.mdx +1 -1
- package/docs/testing/index.mdx +1 -1
- package/docs/testing/server-based.mdx +59 -16
- package/package.json +10 -10
- package/docs/api-reference/workflow-api/world/events.mdx +0 -227
- package/docs/api-reference/workflow-api/world/hooks.mdx +0 -181
- package/docs/api-reference/workflow-api/world/runs.mdx +0 -223
- package/docs/api-reference/workflow-api/world/steps.mdx +0 -216
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<img alt="Workflow SDK logo" src="https://useworkflow.dev/workflow-circle-symbol-light.svg" height="128">
|
|
6
6
|
</picture>
|
|
7
7
|
</a>
|
|
8
|
-
<h1>Workflow
|
|
8
|
+
<h1>Workflow SDK</h1>
|
|
9
9
|
|
|
10
10
|
<a href="https://vercel.com"><img alt="Vercel logo" src="https://img.shields.io/badge/MADE%20BY%20Vercel-000000.svg?style=for-the-badge&logo=Vercel&labelColor=000"></a>
|
|
11
11
|
<a href="https://www.npmjs.com/package/workflow"><img alt="NPM version" src="https://img.shields.io/npm/v/workflow?style=for-the-badge&labelColor=000000"></a>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
## Getting Started
|
|
18
18
|
|
|
19
|
-
The **Workflow
|
|
19
|
+
The **Workflow SDK** lets you easily add durability, reliability, and observability to async JavaScript. Build apps and AI agents that can suspend, resume, and maintain state with ease.
|
|
20
20
|
|
|
21
21
|
Visit [https://useworkflow.dev](https://useworkflow.dev) to view the full documentation.
|
|
22
22
|
|
|
@@ -213,7 +213,7 @@ export default OutputSpecification;`}
|
|
|
213
213
|
- Tools can use core library features like `sleep()` and Hooks within their `execute` functions
|
|
214
214
|
- The agent processes tool calls iteratively until completion or `maxSteps` is reached
|
|
215
215
|
- **Default `maxSteps` is unlimited** - set a value to limit the number of LLM calls
|
|
216
|
-
- The `stream()` method returns `{ messages, steps, experimental_output, uiMessages }` containing the full conversation history, step details, optional structured output, and optionally accumulated UI messages
|
|
216
|
+
- The `stream()` method returns `{ messages, steps, toolCalls, toolResults, experimental_output, uiMessages }` containing the full conversation history, step details, tool call details, optional structured output, and optionally accumulated UI messages
|
|
217
217
|
- Use `collectUIMessages: true` to accumulate `UIMessage[]` during streaming, useful for persisting conversation state without re-reading the stream
|
|
218
218
|
- The `prepareStep` callback runs before each step and can modify model, messages, generation settings, tool choice, and context
|
|
219
219
|
- Generation settings (temperature, maxOutputTokens, etc.) can be set on the constructor and overridden per-stream call
|
|
@@ -842,6 +842,91 @@ async function saveConversation(messages: UIMessage[]) {
|
|
|
842
842
|
The `uiMessages` property is only available when `collectUIMessages` is set to `true`. When disabled, `uiMessages` is `undefined`.
|
|
843
843
|
</Callout>
|
|
844
844
|
|
|
845
|
+
### Machine-Readable Tool Results
|
|
846
|
+
|
|
847
|
+
`stream()` returns tool call information you can inspect programmatically. Compare `toolCalls` with `toolResults` to find unresolved tool calls that need client-side handling:
|
|
848
|
+
|
|
849
|
+
```typescript lineNumbers
|
|
850
|
+
import { DurableAgent } from "@workflow/ai/agent";
|
|
851
|
+
import { getWritable } from "workflow";
|
|
852
|
+
import { z } from "zod";
|
|
853
|
+
import type { UIMessageChunk } from "ai";
|
|
854
|
+
|
|
855
|
+
async function checkOrderStatus({ orderId }: { orderId: string }) {
|
|
856
|
+
"use step";
|
|
857
|
+
return `Order ${orderId}: shipped`;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
async function agentWithToolInspection(userMessage: string) {
|
|
861
|
+
"use workflow";
|
|
862
|
+
|
|
863
|
+
const agent = new DurableAgent({
|
|
864
|
+
model: "anthropic/claude-haiku-4.5",
|
|
865
|
+
tools: {
|
|
866
|
+
checkOrderStatus: {
|
|
867
|
+
description: "Check order status",
|
|
868
|
+
inputSchema: z.object({ orderId: z.string() }),
|
|
869
|
+
execute: checkOrderStatus,
|
|
870
|
+
},
|
|
871
|
+
},
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
const result = await agent.stream({
|
|
875
|
+
messages: [{ role: "user", content: userMessage }],
|
|
876
|
+
writable: getWritable<UIMessageChunk>(),
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
const unresolved = result.toolCalls.filter( // [!code highlight]
|
|
880
|
+
(tc) => !result.toolResults.some((tr) => tr.toolCallId === tc.toolCallId) // [!code highlight]
|
|
881
|
+
); // [!code highlight]
|
|
882
|
+
|
|
883
|
+
if (unresolved.length > 0) {
|
|
884
|
+
return {
|
|
885
|
+
status: "needs-client-tools",
|
|
886
|
+
unresolved,
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
return {
|
|
891
|
+
status: "complete",
|
|
892
|
+
messages: result.messages,
|
|
893
|
+
toolResults: result.toolResults,
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
<Callout type="info">
|
|
899
|
+
`toolCalls` and `toolResults` reflect the *last step* of the agent loop. Tools without an `execute` function will appear in `toolCalls` but not in `toolResults`, which is how you detect calls that need client-side handling.
|
|
900
|
+
</Callout>
|
|
901
|
+
|
|
902
|
+
### Aborting Long-Running Streams
|
|
903
|
+
|
|
904
|
+
Use `timeout` to abort a stream automatically after a fixed duration:
|
|
905
|
+
|
|
906
|
+
<Callout type="warn">
|
|
907
|
+
`abortSignal` is not yet supported and will be available in a future release. Use `timeout` for now.
|
|
908
|
+
</Callout>
|
|
909
|
+
|
|
910
|
+
```typescript lineNumbers
|
|
911
|
+
import { DurableAgent } from "@workflow/ai/agent";
|
|
912
|
+
import { getWritable } from "workflow";
|
|
913
|
+
import type { UIMessageChunk } from "ai";
|
|
914
|
+
|
|
915
|
+
async function agentWithTimeout(userMessage: string) {
|
|
916
|
+
"use workflow";
|
|
917
|
+
|
|
918
|
+
const agent = new DurableAgent({
|
|
919
|
+
model: "anthropic/claude-haiku-4.5",
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
await agent.stream({
|
|
923
|
+
messages: [{ role: "user", content: userMessage }],
|
|
924
|
+
writable: getWritable<UIMessageChunk>(),
|
|
925
|
+
timeout: 30_000, // [!code highlight]
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
```
|
|
929
|
+
|
|
845
930
|
## See Also
|
|
846
931
|
|
|
847
932
|
- [Building Durable AI Agents](/docs/ai) - Complete guide to creating durable agents
|
|
@@ -39,23 +39,17 @@ showSections={["returns"]}
|
|
|
39
39
|
The World object provides access to several entity interfaces. See the [World SDK](/docs/api-reference/workflow-api/world) reference for complete documentation:
|
|
40
40
|
|
|
41
41
|
<Cards>
|
|
42
|
-
<Card href="/docs/api-reference/workflow-api/world/
|
|
43
|
-
|
|
42
|
+
<Card href="/docs/api-reference/workflow-api/world/storage" title="Storage">
|
|
43
|
+
Query runs, steps, hooks, and the underlying event log.
|
|
44
44
|
</Card>
|
|
45
|
-
<Card href="/docs/api-reference/workflow-api/world/
|
|
46
|
-
List and inspect step execution data.
|
|
47
|
-
</Card>
|
|
48
|
-
<Card href="/docs/api-reference/workflow-api/world/hooks" title="world.hooks">
|
|
49
|
-
Look up hooks by ID or token.
|
|
50
|
-
</Card>
|
|
51
|
-
<Card href="/docs/api-reference/workflow-api/world/events" title="world.events">
|
|
52
|
-
Query the append-only event log.
|
|
53
|
-
</Card>
|
|
54
|
-
<Card href="/docs/api-reference/workflow-api/world/streams" title="world.streams">
|
|
45
|
+
<Card href="/docs/api-reference/workflow-api/world/streams" title="Streams">
|
|
55
46
|
Read, write, and manage data streams.
|
|
56
47
|
</Card>
|
|
57
|
-
<Card href="/docs/api-reference/workflow-api/world/queue" title="
|
|
58
|
-
|
|
48
|
+
<Card href="/docs/api-reference/workflow-api/world/queue" title="Queue">
|
|
49
|
+
Low-level queue dispatch (internal SDK infrastructure).
|
|
50
|
+
</Card>
|
|
51
|
+
<Card href="/docs/api-reference/workflow-api/world/observability" title="Observability">
|
|
52
|
+
Hydrate step I/O, parse display names, decrypt data.
|
|
59
53
|
</Card>
|
|
60
54
|
</Cards>
|
|
61
55
|
|
|
@@ -72,6 +66,57 @@ const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highl
|
|
|
72
66
|
|
|
73
67
|
See [Observability Utilities](/docs/api-reference/workflow-api/world/observability) for the full hydration, parsing, and encryption API.
|
|
74
68
|
|
|
69
|
+
### List Workflow Runs (Display Names)
|
|
70
|
+
|
|
71
|
+
List workflow runs and derive human-readable names from the `workflowName` field:
|
|
72
|
+
|
|
73
|
+
```typescript lineNumbers
|
|
74
|
+
import { getWorld } from "workflow/runtime";
|
|
75
|
+
import { parseWorkflowName } from "@workflow/utils/parse-name"; // [!code highlight]
|
|
76
|
+
|
|
77
|
+
export async function GET(req: Request) {
|
|
78
|
+
const url = new URL(req.url);
|
|
79
|
+
const cursor = url.searchParams.get("cursor") ?? undefined;
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const world = getWorld(); // [!code highlight]
|
|
83
|
+
const runs = await world.runs.list({
|
|
84
|
+
pagination: { cursor },
|
|
85
|
+
resolveData: "none",
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return Response.json({
|
|
89
|
+
data: runs.data.map((run) => {
|
|
90
|
+
const parsed = parseWorkflowName(run.workflowName); // [!code highlight]
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
runId: run.runId,
|
|
94
|
+
// Use shortName for UI display (e.g., "processOrder") // [!code highlight]
|
|
95
|
+
displayName: parsed?.shortName ?? run.workflowName, // [!code highlight]
|
|
96
|
+
// Module info available for debugging // [!code highlight]
|
|
97
|
+
module: parsed?.moduleSpecifier, // [!code highlight]
|
|
98
|
+
status: run.status,
|
|
99
|
+
startedAt: run.startedAt,
|
|
100
|
+
completedAt: run.completedAt,
|
|
101
|
+
};
|
|
102
|
+
}),
|
|
103
|
+
cursor: runs.cursor,
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return Response.json(
|
|
107
|
+
{ error: "Failed to list workflow runs" },
|
|
108
|
+
{ status: 500 }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
<Callout type="info">
|
|
115
|
+
The `workflowName` field contains a machine-readable identifier like `workflow//./src/workflows/order//processOrder`.
|
|
116
|
+
Use `parseWorkflowName()` from `@workflow/utils/parse-name` to extract the `shortName` (e.g., `"processOrder"`)
|
|
117
|
+
and `moduleSpecifier` for display in your UI.
|
|
118
|
+
</Callout>
|
|
119
|
+
|
|
75
120
|
## Related Functions
|
|
76
121
|
|
|
77
122
|
- [`getRun()`](/docs/api-reference/workflow-api/get-run) - Higher-level API for working with individual runs by ID.
|
|
@@ -54,6 +54,11 @@ Learn more about [`WorkflowReadableStreamOptions`](/docs/api-reference/workflow-
|
|
|
54
54
|
* This is different from calling workflow functions directly, which is the typical pattern in Next.js applications.
|
|
55
55
|
* The function returns immediately after enqueuing the workflow - it doesn't wait for the workflow to complete.
|
|
56
56
|
* All arguments must be [serializable](/docs/foundations/serialization).
|
|
57
|
+
* 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.
|
|
58
|
+
|
|
59
|
+
<Callout type="info">
|
|
60
|
+
If `start()` throws `'start' received an invalid workflow function. Ensure the Workflow Development Kit 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
|
+
</Callout>
|
|
57
62
|
|
|
58
63
|
## Examples
|
|
59
64
|
|
|
@@ -22,26 +22,17 @@ import { getWorld } from "workflow/runtime";
|
|
|
22
22
|
const world = getWorld(); // [!code highlight]
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Interfaces
|
|
26
26
|
|
|
27
27
|
<Cards>
|
|
28
|
-
<Card href="/docs/api-reference/workflow-api/world/
|
|
29
|
-
|
|
30
|
-
</Card>
|
|
31
|
-
<Card href="/docs/api-reference/workflow-api/world/steps" title="world.steps">
|
|
32
|
-
List and inspect step execution data including input/output hydration.
|
|
33
|
-
</Card>
|
|
34
|
-
<Card href="/docs/api-reference/workflow-api/world/hooks" title="world.hooks">
|
|
35
|
-
Look up hooks by ID or token for webhook resume flows.
|
|
36
|
-
</Card>
|
|
37
|
-
<Card href="/docs/api-reference/workflow-api/world/events" title="world.events">
|
|
38
|
-
Query the append-only event log — the source of truth for all workflow state changes.
|
|
28
|
+
<Card href="/docs/api-reference/workflow-api/world/storage" title="Storage">
|
|
29
|
+
Query runs, steps, hooks, and the underlying event log.
|
|
39
30
|
</Card>
|
|
40
31
|
<Card href="/docs/api-reference/workflow-api/world/streams" title="Streams">
|
|
41
32
|
Read, write, and manage real-time data streams for workflow runs.
|
|
42
33
|
</Card>
|
|
43
|
-
<Card href="/docs/api-reference/workflow-api/world/queue" title="
|
|
44
|
-
|
|
34
|
+
<Card href="/docs/api-reference/workflow-api/world/queue" title="Queue">
|
|
35
|
+
Low-level queue dispatch (internal SDK infrastructure).
|
|
45
36
|
</Card>
|
|
46
37
|
<Card href="/docs/api-reference/workflow-api/world/observability" title="Observability Utilities">
|
|
47
38
|
Hydrate step I/O, parse display names, and decrypt workflow data.
|
|
@@ -6,8 +6,7 @@ summary: "Functions: hydrateResourceIO(), parseStepName(), parseWorkflowName(),
|
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/api-reference/workflow-api/get-world
|
|
8
8
|
related:
|
|
9
|
-
- /docs/api-reference/workflow-api/world/
|
|
10
|
-
- /docs/api-reference/workflow-api/world/runs
|
|
9
|
+
- /docs/api-reference/workflow-api/world/storage
|
|
11
10
|
keywords:
|
|
12
11
|
- workflow/observability
|
|
13
12
|
- hydrateResourceIO
|
|
@@ -41,18 +40,14 @@ import { // [!code highlight]
|
|
|
41
40
|
|
|
42
41
|
### hydrateResourceIO()
|
|
43
42
|
|
|
44
|
-
Deserialize step or run data that was serialized using the [devalue](https://github.com/Rich-Harris/devalue) format.
|
|
43
|
+
Deserialize step or run data that was serialized using the [devalue](https://github.com/Rich-Harris/devalue) format. Required to display step input/output in your UI.
|
|
45
44
|
|
|
46
45
|
```typescript lineNumbers
|
|
47
46
|
import { hydrateResourceIO, observabilityRevivers } from "workflow/observability"; // [!code highlight]
|
|
48
|
-
import { getWorld } from "workflow/runtime";
|
|
49
47
|
|
|
50
|
-
const world = getWorld();
|
|
51
48
|
const step = await world.steps.get(runId, stepId);
|
|
52
|
-
|
|
53
49
|
const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
|
|
54
|
-
console.log(hydrated.input);
|
|
55
|
-
console.log(hydrated.output); // Deserialized output data
|
|
50
|
+
console.log(hydrated.input, hydrated.output);
|
|
56
51
|
```
|
|
57
52
|
|
|
58
53
|
**Parameters:**
|
|
@@ -68,77 +63,41 @@ console.log(hydrated.output); // Deserialized output data
|
|
|
68
63
|
|
|
69
64
|
A set of reviver functions that handle standard workflow serialization types (Date, Map, Set, Error, etc.).
|
|
70
65
|
|
|
71
|
-
```typescript lineNumbers
|
|
72
|
-
import { observabilityRevivers } from "workflow/observability";
|
|
73
|
-
```
|
|
74
|
-
|
|
75
66
|
## Name Parsing
|
|
76
67
|
|
|
77
|
-
Workflow and step names are stored as machine-readable identifiers. These utilities extract display-friendly names.
|
|
68
|
+
Workflow and step names are stored as machine-readable identifiers. These utilities extract display-friendly names. All return `{ shortName: string, moduleSpecifier: string } | null`.
|
|
78
69
|
|
|
79
70
|
### parseStepName()
|
|
80
71
|
|
|
81
|
-
Parse a machine-readable step name into its components.
|
|
82
|
-
|
|
83
72
|
```typescript lineNumbers
|
|
84
73
|
import { parseStepName } from "workflow/observability"; // [!code highlight]
|
|
85
74
|
|
|
86
75
|
const parsed = parseStepName("step//./src/workflows/order//processPayment"); // [!code highlight]
|
|
87
|
-
// parsed
|
|
88
|
-
// parsed
|
|
76
|
+
// parsed?.shortName → "processPayment"
|
|
77
|
+
// parsed?.moduleSpecifier → "./src/workflows/order"
|
|
89
78
|
```
|
|
90
79
|
|
|
91
|
-
**Parameters:**
|
|
92
|
-
|
|
93
|
-
| Parameter | Type | Description |
|
|
94
|
-
|-----------|------|-------------|
|
|
95
|
-
| `stepName` | `string` | The machine-readable step name |
|
|
96
|
-
|
|
97
|
-
**Returns:** `{ shortName: string, moduleSpecifier: string } | null`
|
|
98
|
-
|
|
99
80
|
### parseWorkflowName()
|
|
100
81
|
|
|
101
|
-
Parse a machine-readable workflow name into its components.
|
|
102
|
-
|
|
103
82
|
```typescript lineNumbers
|
|
104
83
|
import { parseWorkflowName } from "workflow/observability"; // [!code highlight]
|
|
105
84
|
|
|
106
85
|
const parsed = parseWorkflowName("workflow//./src/workflows/order//processOrder"); // [!code highlight]
|
|
107
|
-
// parsed
|
|
108
|
-
// parsed.moduleSpecifier → "./src/workflows/order"
|
|
86
|
+
// parsed?.shortName → "processOrder"
|
|
109
87
|
```
|
|
110
88
|
|
|
111
|
-
**Parameters:**
|
|
112
|
-
|
|
113
|
-
| Parameter | Type | Description |
|
|
114
|
-
|-----------|------|-------------|
|
|
115
|
-
| `workflowName` | `string` | The machine-readable workflow name |
|
|
116
|
-
|
|
117
|
-
**Returns:** `{ shortName: string, moduleSpecifier: string } | null`
|
|
118
|
-
|
|
119
89
|
### parseClassName()
|
|
120
90
|
|
|
121
|
-
Parse a machine-readable class name into its components.
|
|
122
|
-
|
|
123
91
|
```typescript lineNumbers
|
|
124
92
|
import { parseClassName } from "workflow/observability"; // [!code highlight]
|
|
125
93
|
|
|
126
94
|
const parsed = parseClassName("class//./src/models//User"); // [!code highlight]
|
|
127
|
-
// parsed
|
|
128
|
-
// parsed.moduleSpecifier → "./src/models"
|
|
95
|
+
// parsed?.shortName → "User"
|
|
129
96
|
```
|
|
130
97
|
|
|
131
|
-
**Parameters:**
|
|
132
|
-
|
|
133
|
-
| Parameter | Type | Description |
|
|
134
|
-
|-----------|------|-------------|
|
|
135
|
-
| `className` | `string` | The machine-readable class name |
|
|
136
|
-
|
|
137
|
-
**Returns:** `{ shortName: string, moduleSpecifier: string } | null`
|
|
138
|
-
|
|
139
98
|
## Encryption
|
|
140
99
|
|
|
141
|
-
For workflows with encrypted step data,
|
|
100
|
+
For workflows with encrypted step data, decrypt before hydrating.
|
|
142
101
|
|
|
143
102
|
### getEncryptionKeyForRun()
|
|
144
103
|
|
|
@@ -165,10 +124,7 @@ Hydrate step or run data using a decryption key. Use this instead of `hydrateRes
|
|
|
165
124
|
|
|
166
125
|
{/* @expect-error:2305,2724 */}
|
|
167
126
|
```typescript lineNumbers
|
|
168
|
-
import { // [!code highlight]
|
|
169
|
-
getEncryptionKeyForRun, // [!code highlight]
|
|
170
|
-
hydrateResourceIOWithKey, // [!code highlight]
|
|
171
|
-
} from "workflow/observability"; // [!code highlight]
|
|
127
|
+
import { getEncryptionKeyForRun, hydrateResourceIOWithKey } from "workflow/observability"; // [!code highlight]
|
|
172
128
|
|
|
173
129
|
const key = await getEncryptionKeyForRun(runId); // [!code highlight]
|
|
174
130
|
const hydrated = hydrateResourceIOWithKey(step, key); // [!code highlight]
|
|
@@ -185,105 +141,24 @@ const hydrated = hydrateResourceIOWithKey(step, key); // [!code highlight]
|
|
|
185
141
|
|
|
186
142
|
## Examples
|
|
187
143
|
|
|
188
|
-
### Hydrate Step Input and Output Data
|
|
189
|
-
|
|
190
|
-
```typescript lineNumbers
|
|
191
|
-
// app/api/workflow-steps/hydrate/route.ts
|
|
192
|
-
import { getWorld } from "workflow/runtime";
|
|
193
|
-
import { // [!code highlight]
|
|
194
|
-
hydrateResourceIO, // [!code highlight]
|
|
195
|
-
observabilityRevivers, // [!code highlight]
|
|
196
|
-
parseStepName, // [!code highlight]
|
|
197
|
-
} from "workflow/observability"; // [!code highlight]
|
|
198
|
-
|
|
199
|
-
export async function GET(req: Request) {
|
|
200
|
-
const url = new URL(req.url);
|
|
201
|
-
const runId = url.searchParams.get("runId");
|
|
202
|
-
const stepId = url.searchParams.get("stepId");
|
|
203
|
-
|
|
204
|
-
if (!runId || !stepId) {
|
|
205
|
-
return Response.json({ error: "runId and stepId required" }, { status: 400 });
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const world = getWorld();
|
|
209
|
-
const step = await world.steps.get(runId, stepId);
|
|
210
|
-
|
|
211
|
-
const hydrated = hydrateResourceIO(step, observabilityRevivers); // [!code highlight]
|
|
212
|
-
const parsed = parseStepName(step.stepName);
|
|
213
|
-
|
|
214
|
-
return Response.json({
|
|
215
|
-
displayName: parsed?.shortName ?? step.stepName,
|
|
216
|
-
input: hydrated.input, // [!code highlight]
|
|
217
|
-
output: hydrated.output, // [!code highlight]
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Decrypt and Hydrate Encrypted Step Data
|
|
223
|
-
|
|
224
|
-
For teams with encryption enabled, step data must be decrypted before hydration:
|
|
225
|
-
|
|
226
|
-
{/* @expect-error:2305,2724 */}
|
|
227
|
-
```typescript lineNumbers
|
|
228
|
-
// app/api/workflow-steps/decrypt/route.ts
|
|
229
|
-
import { getWorld } from "workflow/runtime";
|
|
230
|
-
import { // [!code highlight]
|
|
231
|
-
getEncryptionKeyForRun, // [!code highlight]
|
|
232
|
-
hydrateResourceIOWithKey, // [!code highlight]
|
|
233
|
-
parseStepName, // [!code highlight]
|
|
234
|
-
} from "workflow/observability"; // [!code highlight]
|
|
235
|
-
|
|
236
|
-
export async function GET(req: Request) {
|
|
237
|
-
const url = new URL(req.url);
|
|
238
|
-
const runId = url.searchParams.get("runId");
|
|
239
|
-
const stepId = url.searchParams.get("stepId");
|
|
240
|
-
|
|
241
|
-
if (!runId || !stepId) {
|
|
242
|
-
return Response.json({ error: "runId and stepId required" }, { status: 400 });
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const world = getWorld();
|
|
246
|
-
const step = await world.steps.get(runId, stepId);
|
|
247
|
-
|
|
248
|
-
// Decrypt then hydrate // [!code highlight]
|
|
249
|
-
const key = await getEncryptionKeyForRun(runId); // [!code highlight]
|
|
250
|
-
const hydrated = hydrateResourceIOWithKey(step, key); // [!code highlight]
|
|
251
|
-
|
|
252
|
-
const parsed = parseStepName(step.stepName);
|
|
253
|
-
|
|
254
|
-
return Response.json({
|
|
255
|
-
displayName: parsed?.shortName ?? step.stepName,
|
|
256
|
-
input: hydrated.input,
|
|
257
|
-
output: hydrated.output,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
144
|
### Parse Display Names for a Run's Steps
|
|
263
145
|
|
|
264
|
-
Build a progress dashboard with human-readable step names:
|
|
265
|
-
|
|
266
146
|
```typescript lineNumbers
|
|
267
147
|
import { getWorld } from "workflow/runtime";
|
|
268
148
|
import { parseStepName, parseWorkflowName } from "workflow/observability"; // [!code highlight]
|
|
269
149
|
|
|
270
150
|
const world = getWorld();
|
|
271
|
-
|
|
272
|
-
// Parse workflow name
|
|
273
151
|
const run = await world.runs.get(runId, { resolveData: "none" });
|
|
274
|
-
|
|
275
|
-
console.log("Workflow:", workflowDisplay?.shortName); // [!code highlight]
|
|
152
|
+
console.log("Workflow:", parseWorkflowName(run.workflowName)?.shortName); // [!code highlight]
|
|
276
153
|
|
|
277
|
-
// Parse step names
|
|
278
154
|
const steps = await world.steps.list({ runId, resolveData: "none" });
|
|
279
155
|
for (const step of steps.data) {
|
|
280
|
-
const
|
|
281
|
-
console.log(` ${
|
|
156
|
+
const parsed = parseStepName(step.stepName); // [!code highlight]
|
|
157
|
+
console.log(` ${parsed?.shortName}: ${step.status}`); // [!code highlight]
|
|
282
158
|
}
|
|
283
159
|
```
|
|
284
160
|
|
|
285
161
|
## Related
|
|
286
162
|
|
|
287
|
-
- [
|
|
288
|
-
- [world.runs](/docs/api-reference/workflow-api/world/runs) — Query run data to hydrate
|
|
163
|
+
- [Storage](/docs/api-reference/workflow-api/world/storage) — Query runs, steps, hooks, and events
|
|
289
164
|
- [Serialization](/docs/foundations/serialization) — How workflow data is serialized
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description:
|
|
2
|
+
title: Queue
|
|
3
|
+
description: Low-level queue interface for dispatching workflow and step invocations.
|
|
4
4
|
type: reference
|
|
5
|
-
summary: "Methods: getDeploymentId(), queue(), createQueueHandler().
|
|
5
|
+
summary: "Methods: getDeploymentId(), queue(), createQueueHandler(). Internal queue dispatch — normally handled by the SDK."
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/api-reference/workflow-api/get-world
|
|
8
8
|
related:
|
|
@@ -13,115 +13,74 @@ keywords:
|
|
|
13
13
|
- getDeploymentId
|
|
14
14
|
- queue
|
|
15
15
|
- createQueueHandler
|
|
16
|
-
- background processing
|
|
17
|
-
- enqueue workflow
|
|
18
16
|
- ValidQueueName
|
|
17
|
+
- queue dispatch
|
|
19
18
|
---
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
Queue methods live directly on the `world` object (not nested). They dispatch internal workflow and step invocations to the queue backend.
|
|
21
|
+
|
|
22
|
+
<Callout type="warn">
|
|
23
|
+
These methods are used internally by the Workflow SDK to dispatch execution. You do not need to call them in normal operations — use [`start()`](/docs/api-reference/workflow-api/start) to trigger workflows instead. Direct queue access is only needed if you programmatically create a run via `world.events.create()` with a `run_created` event and need to kick off its initial execution, or for debugging resumption of a flow or step route.
|
|
24
|
+
</Callout>
|
|
22
25
|
|
|
23
26
|
## Import
|
|
24
27
|
|
|
25
28
|
```typescript lineNumbers
|
|
26
29
|
import { getWorld } from "workflow/runtime";
|
|
27
30
|
|
|
28
|
-
const world = getWorld();
|
|
29
|
-
|
|
31
|
+
const world = getWorld(); // [!code highlight]
|
|
32
|
+
// Queue methods are called directly on world — e.g. world.queue()
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
## Methods
|
|
33
36
|
|
|
34
37
|
### getDeploymentId()
|
|
35
38
|
|
|
36
|
-
Get the current deployment ID.
|
|
39
|
+
Get the current deployment ID. Used internally for routing queue messages to the correct deployment.
|
|
37
40
|
|
|
38
41
|
```typescript lineNumbers
|
|
39
|
-
const deploymentId = await world.
|
|
42
|
+
const deploymentId = await world.getDeploymentId(); // [!code highlight]
|
|
40
43
|
```
|
|
41
44
|
|
|
42
45
|
**Returns:** `string` — The current deployment ID
|
|
43
46
|
|
|
44
47
|
### queue()
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
Dispatch a message to a named queue. The message payload is an internal SDK type (`WorkflowInvokePayload`, `StepInvokePayload`, or `HealthCheckPayload`).
|
|
47
50
|
|
|
48
51
|
```typescript lineNumbers
|
|
49
|
-
const messageId = await world.queue
|
|
52
|
+
const { messageId } = await world.queue(queueName, payload, opts); // [!code highlight]
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
**Parameters:**
|
|
53
56
|
|
|
54
57
|
| Parameter | Type | Description |
|
|
55
58
|
|-----------|------|-------------|
|
|
56
|
-
| `
|
|
57
|
-
| `message` | `
|
|
58
|
-
| `opts` | `
|
|
59
|
+
| `queueName` | `ValidQueueName` | The queue name (branded string) |
|
|
60
|
+
| `message` | `QueuePayload` | Internal SDK payload |
|
|
61
|
+
| `opts` | `QueueOptions` | Optional — `deploymentId`, `idempotencyKey`, `delaySeconds`, `headers` |
|
|
59
62
|
|
|
60
|
-
**Returns:** `MessageId`
|
|
63
|
+
**Returns:** `{ messageId: MessageId | null }`
|
|
61
64
|
|
|
62
65
|
### createQueueHandler()
|
|
63
66
|
|
|
64
|
-
Create
|
|
67
|
+
Create an HTTP handler that processes messages from a queue. Used to set up the queue consumer endpoint.
|
|
65
68
|
|
|
66
69
|
```typescript lineNumbers
|
|
67
|
-
const handler = world.
|
|
70
|
+
const handler = world.createQueueHandler(prefix, callback); // [!code highlight]
|
|
68
71
|
```
|
|
69
72
|
|
|
70
73
|
**Parameters:**
|
|
71
74
|
|
|
72
75
|
| Parameter | Type | Description |
|
|
73
76
|
|-----------|------|-------------|
|
|
74
|
-
| `prefix` | `
|
|
75
|
-
| `callback` | `
|
|
76
|
-
|
|
77
|
-
**Returns:** Queue handler function
|
|
78
|
-
|
|
79
|
-
## Examples
|
|
80
|
-
|
|
81
|
-
### Enqueue a Workflow Run for Background Processing
|
|
82
|
-
|
|
83
|
-
```typescript lineNumbers
|
|
84
|
-
// app/api/workflow-queue/route.ts
|
|
85
|
-
import { getWorld } from "workflow/runtime";
|
|
86
|
-
|
|
87
|
-
export async function POST(req: Request) {
|
|
88
|
-
const { workflowName, input } = await req.json();
|
|
89
|
-
|
|
90
|
-
const world = getWorld();
|
|
91
|
-
const messageId = await world.queue.queue(workflowName, { // [!code highlight]
|
|
92
|
-
input,
|
|
93
|
-
priority: "normal",
|
|
94
|
-
}); // [!code highlight]
|
|
95
|
-
|
|
96
|
-
return Response.json({ messageId });
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Create a Queue Handler for Processing
|
|
77
|
+
| `prefix` | `QueuePrefix` | Queue name prefix to match |
|
|
78
|
+
| `callback` | `(message, meta) => Promise<void \| { timeoutSeconds: number }>` | Handler called for each message. `meta` contains `attempt`, `queueName`, `messageId`, `requestId`. |
|
|
101
79
|
|
|
102
|
-
|
|
103
|
-
import { getWorld } from "workflow/runtime";
|
|
104
|
-
|
|
105
|
-
const world = getWorld();
|
|
106
|
-
|
|
107
|
-
const handler = world.queue.createQueueHandler("my-workflows", async (message) => { // [!code highlight]
|
|
108
|
-
console.log("Processing:", message);
|
|
109
|
-
// Handle the queued workflow message
|
|
110
|
-
}); // [!code highlight]
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Get Current Deployment ID
|
|
114
|
-
|
|
115
|
-
```typescript lineNumbers
|
|
116
|
-
import { getWorld } from "workflow/runtime";
|
|
117
|
-
|
|
118
|
-
const world = getWorld();
|
|
119
|
-
const deploymentId = await world.queue.getDeploymentId(); // [!code highlight]
|
|
120
|
-
console.log("Running on deployment:", deploymentId);
|
|
121
|
-
```
|
|
80
|
+
**Returns:** `(req: Request) => Promise<Response>`
|
|
122
81
|
|
|
123
82
|
## Related
|
|
124
83
|
|
|
125
|
-
- [start()](/docs/api-reference/workflow-api/start) —
|
|
84
|
+
- [start()](/docs/api-reference/workflow-api/start) — The standard way to start workflow runs
|
|
126
85
|
- [Starting Workflows](/docs/foundations/starting-workflows) — Core concepts for workflow invocation
|
|
127
|
-
- [
|
|
86
|
+
- [Storage](/docs/api-reference/workflow-api/world/storage) — Create events that trigger queue dispatch
|