workflow 5.0.0-beta.43 → 5.0.0-beta.44
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 +6 -4
- package/dist/internal/builtins.d.ts +4 -4
- package/dist/internal/builtins.js +6 -6
- package/docs/ai/chat-session-modeling.mdx +23 -24
- package/docs/ai/defining-tools.mdx +5 -6
- package/docs/ai/human-in-the-loop.mdx +11 -11
- package/docs/ai/index.mdx +20 -20
- package/docs/ai/message-queueing.mdx +6 -6
- package/docs/ai/meta.json +1 -0
- package/docs/ai/resumable-streams.mdx +28 -28
- package/docs/ai/sleep-and-delays.mdx +9 -9
- package/docs/ai/streaming-updates-from-tools.mdx +4 -4
- package/docs/api-reference/vitest/index.mdx +8 -8
- package/docs/api-reference/workflow/create-hook.mdx +15 -15
- package/docs/api-reference/workflow/create-webhook.mdx +15 -15
- package/docs/api-reference/workflow/define-hook.mdx +10 -10
- package/docs/api-reference/workflow/fatal-error.mdx +2 -2
- package/docs/api-reference/workflow/fetch.mdx +7 -7
- package/docs/api-reference/workflow/get-step-metadata.mdx +2 -2
- package/docs/api-reference/workflow/get-workflow-metadata.mdx +3 -3
- package/docs/api-reference/workflow/get-writable.mdx +7 -7
- package/docs/api-reference/workflow/index.mdx +1 -1
- package/docs/api-reference/workflow/retryable-error.mdx +1 -1
- package/docs/api-reference/workflow/set-attributes.mdx +2 -2
- package/docs/api-reference/workflow/sleep.mdx +3 -3
- package/docs/api-reference/workflow-ai/durable-agent.mdx +42 -42
- package/docs/api-reference/workflow-ai/index.mdx +3 -3
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +28 -28
- package/docs/api-reference/workflow-api/get-hook-by-token.mdx +11 -11
- package/docs/api-reference/workflow-api/get-run.mdx +10 -10
- package/docs/api-reference/workflow-api/index.mdx +2 -4
- package/docs/api-reference/workflow-api/resume-hook.mdx +14 -14
- package/docs/api-reference/workflow-api/resume-webhook.mdx +3 -3
- package/docs/api-reference/workflow-api/start.mdx +16 -15
- package/docs/api-reference/workflow-astro/workflow.mdx +3 -3
- package/docs/api-reference/workflow-errors/entity-conflict-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
- package/docs/api-reference/workflow-errors/index.mdx +6 -6
- package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +9 -9
- package/docs/api-reference/workflow-errors/run-expired-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/step-not-registered-error.mdx +5 -5
- package/docs/api-reference/workflow-errors/throttle-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/too-early-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/workflow-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-not-registered-error.mdx +5 -6
- package/docs/api-reference/workflow-errors/workflow-run-cancelled-error.mdx +6 -6
- package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +5 -5
- package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/workflow-world-error.mdx +8 -8
- package/docs/api-reference/workflow-globals.mdx +12 -11
- package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +2 -2
- package/docs/api-reference/workflow-nest/nest-local-builder.mdx +4 -4
- package/docs/api-reference/workflow-nest/workflow-controller.mdx +1 -1
- package/docs/api-reference/workflow-nest/workflow-module.mdx +4 -4
- package/docs/api-reference/workflow-next/with-workflow.mdx +16 -16
- package/docs/api-reference/workflow-nitro/index.mdx +6 -6
- package/docs/api-reference/workflow-nuxt/index.mdx +4 -4
- package/docs/api-reference/workflow-observability/hydrate-data.mdx +5 -5
- package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +4 -4
- package/docs/api-reference/workflow-observability/index.mdx +6 -8
- package/docs/api-reference/workflow-observability/observability-revivers.mdx +2 -2
- package/docs/api-reference/workflow-observability/parse-class-name.mdx +3 -3
- package/docs/api-reference/workflow-observability/parse-step-name.mdx +4 -4
- package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +4 -4
- package/docs/api-reference/workflow-runtime/create-world.mdx +8 -8
- package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +6 -6
- package/docs/api-reference/workflow-runtime/get-world.mdx +4 -4
- package/docs/api-reference/workflow-runtime/health-check.mdx +1 -1
- package/docs/api-reference/workflow-runtime/index.mdx +2 -4
- package/docs/api-reference/workflow-runtime/set-world.mdx +15 -13
- package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +6 -5
- package/docs/api-reference/workflow-runtime/world/analytics.mdx +9 -9
- package/docs/api-reference/workflow-runtime/world/index.mdx +5 -3
- package/docs/api-reference/workflow-runtime/world/queue.mdx +11 -11
- package/docs/api-reference/workflow-runtime/world/storage.mdx +62 -28
- package/docs/api-reference/workflow-runtime/world/streams.mdx +7 -7
- package/docs/api-reference/workflow-serde/index.mdx +1 -1
- package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +2 -2
- package/docs/api-reference/workflow-serde/workflow-serialize.mdx +7 -7
- package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +3 -3
- package/docs/api-reference/workflow-vite/workflow.mdx +5 -5
- package/docs/changelog/attributes-mvp.mdx +39 -39
- package/docs/changelog/batched-event-writes.mdx +12 -12
- package/docs/changelog/eager-processing.mdx +63 -63
- package/docs/changelog/index.mdx +3 -3
- package/docs/changelog/lazy-event-creation.md +27 -27
- package/docs/changelog/resilient-resume.mdx +5 -5
- package/docs/changelog/resilient-start.mdx +14 -14
- package/docs/changelog/step-message-ownership.mdx +47 -47
- package/docs/changelog/turbo-mode.md +20 -20
- package/docs/comparisons/index.mdx +13 -13
- package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +15 -15
- package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +12 -12
- package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +11 -11
- package/docs/comparisons/workflow-sdk-vs-inngest.mdx +19 -19
- package/docs/comparisons/workflow-sdk-vs-temporal.mdx +23 -23
- package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +18 -17
- package/docs/configuration/build-and-diagnostics.mdx +5 -5
- package/docs/configuration/cli-and-web-ui.mdx +4 -4
- package/docs/configuration/runtime-tuning.mdx +86 -23
- package/docs/configuration/worlds.mdx +28 -14
- package/docs/cookbook/advanced/child-workflows.mdx +25 -25
- package/docs/cookbook/advanced/publishing-libraries.mdx +40 -40
- package/docs/cookbook/advanced/serializable-steps.mdx +21 -21
- package/docs/cookbook/advanced/upgrading-workflows.mdx +31 -31
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +20 -20
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +22 -22
- package/docs/cookbook/common-patterns/batching.mdx +14 -14
- package/docs/cookbook/common-patterns/idempotency.mdx +9 -9
- package/docs/cookbook/common-patterns/rate-limiting.mdx +3 -3
- package/docs/cookbook/common-patterns/saga.mdx +19 -19
- package/docs/cookbook/common-patterns/scheduling.mdx +23 -23
- package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +26 -26
- package/docs/cookbook/common-patterns/timeouts.mdx +23 -23
- package/docs/cookbook/common-patterns/webhooks.mdx +6 -6
- package/docs/cookbook/common-patterns/workflow-composition.mdx +19 -19
- package/docs/cookbook/index.mdx +22 -22
- package/docs/cookbook/integrations/ai-sdk.mdx +43 -41
- package/docs/cookbook/integrations/chat-sdk.mdx +34 -34
- package/docs/cookbook/integrations/sandbox.mdx +46 -46
- package/docs/deploying.mdx +15 -15
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +12 -12
- package/docs/errors/corrupted-event-log.mdx +11 -11
- package/docs/errors/deployment-mismatch.mdx +14 -14
- package/docs/errors/fetch-in-workflow.mdx +8 -8
- package/docs/errors/hook-conflict.mdx +11 -11
- package/docs/errors/index.mdx +1 -1
- package/docs/errors/node-js-module-in-workflow.mdx +5 -5
- package/docs/errors/replay-divergence.mdx +2 -2
- package/docs/errors/runtime-decryption-failed.mdx +12 -12
- package/docs/errors/serialization-failed.mdx +40 -12
- package/docs/errors/start-invalid-workflow-function.mdx +5 -5
- package/docs/errors/step-executed-multiple-times.mdx +2 -2
- package/docs/errors/step-not-registered.mdx +5 -5
- package/docs/errors/timeout-in-workflow.mdx +8 -8
- package/docs/errors/webhook-invalid-respond-with-value.mdx +18 -18
- package/docs/errors/webhook-response-not-sent.mdx +16 -16
- package/docs/errors/workflow-not-registered.mdx +5 -5
- package/docs/foundations/cancellation.mdx +31 -31
- package/docs/foundations/errors-and-retries.mdx +42 -11
- package/docs/foundations/hooks.mdx +35 -35
- package/docs/foundations/idempotency.mdx +9 -9
- package/docs/foundations/serialization.mdx +21 -22
- package/docs/foundations/starting-workflows.mdx +36 -37
- package/docs/foundations/streaming.mdx +46 -41
- package/docs/foundations/versioning.mdx +3 -3
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/getting-started/astro.mdx +16 -16
- package/docs/getting-started/express.mdx +8 -8
- package/docs/getting-started/fastify.mdx +8 -8
- package/docs/getting-started/hono.mdx +8 -8
- package/docs/getting-started/nestjs.mdx +18 -17
- package/docs/getting-started/next.mdx +11 -11
- package/docs/getting-started/nitro.mdx +16 -16
- package/docs/getting-started/nuxt.mdx +8 -8
- package/docs/getting-started/python.mdx +4 -4
- package/docs/getting-started/react-router/v7.mdx +1 -1
- package/docs/getting-started/react-router/v8.mdx +1 -1
- package/docs/getting-started/sveltekit.mdx +14 -14
- package/docs/getting-started/tanstack-start.mdx +12 -12
- package/docs/getting-started/vite.mdx +8 -8
- package/docs/how-it-works/cancellation.mdx +62 -62
- package/docs/how-it-works/code-transform.mdx +66 -54
- package/docs/how-it-works/encryption.mdx +25 -21
- package/docs/how-it-works/event-sourcing.mdx +53 -35
- package/docs/how-it-works/framework-integrations.mdx +12 -12
- package/docs/how-it-works/understanding-directives.mdx +21 -21
- package/docs/internal/index.mdx +6 -6
- package/docs/internal/nitro-native-build.mdx +2 -2
- package/docs/internal/nitro-web-ui.mdx +4 -4
- package/docs/internal/serializable-abort-controller.mdx +7 -7
- package/docs/observability/attributes.mdx +3 -3
- package/docs/observability/index.mdx +14 -10
- package/docs/observability/tracing.mdx +10 -10
- package/docs/testing/index.mdx +33 -33
- package/docs/testing/server-based.mdx +10 -10
- package/docs/whats-new.mdx +185 -0
- package/package.json +12 -12
|
@@ -13,14 +13,14 @@ related:
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
<Callout type="warn">
|
|
16
|
-
`WorkflowChatTransport` now ships in AI SDK as a 1:1 port
|
|
16
|
+
`WorkflowChatTransport` now ships in AI SDK as a 1:1 port, so import it from `@ai-sdk/workflow` (the `@workflow/ai` export is deprecated). See [Resumable Streaming with `WorkflowChatTransport`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) for the full reference.
|
|
17
17
|
</Callout>
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Network interruptions, page refreshes, or Vercel Functions timeouts can break a chat interface's connection to an in-progress agent.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Workflow runs and their attached streams are durable, so users can resume a stream without resending a message or waiting for the entire response again. The client can optionally sync only the data missed since the last connection.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Workflow SDK supports resumable streams, but the client must identify the stream and the position from which to reconnect. The [`WorkflowChatTransport`](/docs/api-reference/workflow-ai/workflow-chat-transport) helper is a drop-in AI SDK transport that handles this client-side resumption logic.
|
|
24
24
|
|
|
25
25
|
<Callout type="info">
|
|
26
26
|
When deploying a streaming route to Vercel, enable request cancellation so a browser disconnect terminates that route's abandoned stream reader instead of letting the function run until `FUNCTION_INVOCATION_TIMEOUT`. See [Avoiding Function Timeouts After Client Disconnects](/docs/foundations/streaming#avoiding-function-timeouts-after-client-disconnects).
|
|
@@ -28,15 +28,15 @@ When deploying a streaming route to Vercel, enable request cancellation so a bro
|
|
|
28
28
|
|
|
29
29
|
## Implementing stream resumption
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Add stream resumption to the Flight Booking Agent from the [Building Durable AI Agents](/docs/ai) guide.
|
|
32
32
|
|
|
33
33
|
<Steps>
|
|
34
34
|
|
|
35
35
|
<Step>
|
|
36
36
|
|
|
37
|
-
### Return the
|
|
37
|
+
### Return the run ID from your API
|
|
38
38
|
|
|
39
|
-
Modify your chat endpoint to include the workflow run ID in a response header. The
|
|
39
|
+
Modify your chat endpoint to include the workflow run ID in a response header. The run ID uniquely identifies the stream so the client knows which stream to reconnect to.
|
|
40
40
|
|
|
41
41
|
{/*@skip-typecheck: incomplete code sample*/}
|
|
42
42
|
|
|
@@ -62,9 +62,9 @@ export async function POST(req: Request) {
|
|
|
62
62
|
|
|
63
63
|
<Step>
|
|
64
64
|
|
|
65
|
-
### Add a
|
|
65
|
+
### Add a stream reconnection endpoint
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
Create an API route that returns the stream for an existing run. The current endpoint always creates a new run.
|
|
68
68
|
|
|
69
69
|
```typescript title="app/api/chat/[id]/stream/route.ts" lineNumbers
|
|
70
70
|
import { createUIMessageStreamResponse } from "ai";
|
|
@@ -100,16 +100,16 @@ export async function GET(
|
|
|
100
100
|
}
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
The `startIndex` parameter
|
|
103
|
+
The `startIndex` parameter lets the client choose where to resume the stream. For example, if the function times out during streaming, the chat transport uses `startIndex` to resume from the last token it received. Negative values are also supported. A value of `-5` starts 5 chunks before the end, which is useful for custom stream consumers that show recent output without replaying the full stream.
|
|
104
104
|
|
|
105
|
-
When using a negative `startIndex`, your stream endpoint must return
|
|
105
|
+
When using a negative `startIndex`, your stream endpoint must return an `x-workflow-stream-tail-index` header for relative resumption. If the header is missing, the transport replays the entire stream.
|
|
106
106
|
</Step>
|
|
107
107
|
|
|
108
108
|
<Step>
|
|
109
109
|
|
|
110
|
-
### Use `WorkflowChatTransport` in the
|
|
110
|
+
### Use `WorkflowChatTransport` in the client
|
|
111
111
|
|
|
112
|
-
Replace the default transport in AI
|
|
112
|
+
Replace the default transport in AI SDK's `useChat` with [`WorkflowChatTransport`](
|
|
113
113
|
/docs/api-reference/workflow-ai/workflow-chat-transport
|
|
114
114
|
), and update the callbacks to store and use the latest run ID. For now, we'll store the run ID in localStorage. For your own app, this would be stored wherever you store session information.
|
|
115
115
|
|
|
@@ -166,23 +166,23 @@ export default function ChatPage() {
|
|
|
166
166
|
|
|
167
167
|
</Steps>
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
Open the flight booking example in another tab or refresh the page repeatedly. The client reconnects to the same chat stream each time.
|
|
170
170
|
|
|
171
|
-
## How
|
|
171
|
+
## How it works
|
|
172
172
|
|
|
173
|
-
1. When the user sends a message, `WorkflowChatTransport` makes a POST to `/api/chat
|
|
174
|
-
2. The API starts a workflow and returns the run ID in the `x-workflow-run-id` header
|
|
175
|
-
3. `onChatSendMessage` stores this run ID in localStorage
|
|
176
|
-
4. If the stream is interrupted before receiving a
|
|
177
|
-
5. `prepareReconnectToStreamRequest` builds the reconnection URL using the stored run ID
|
|
178
|
-
6. The reconnection endpoint returns the stream from where the client left off
|
|
179
|
-
7. When the stream completes, `onChatEnd` clears the stored run ID
|
|
173
|
+
1. When the user sends a message, `WorkflowChatTransport` makes a `POST` request to `/api/chat`.
|
|
174
|
+
2. The API starts a workflow and returns the run ID in the `x-workflow-run-id` header.
|
|
175
|
+
3. `onChatSendMessage` stores this run ID in `localStorage`.
|
|
176
|
+
4. If the stream is interrupted before receiving a `finish` chunk, the transport automatically reconnects.
|
|
177
|
+
5. `prepareReconnectToStreamRequest` builds the reconnection URL using the stored run ID and points to `/api/chat/{runId}/stream`.
|
|
178
|
+
6. The reconnection endpoint returns the stream from where the client left off.
|
|
179
|
+
7. When the stream completes, `onChatEnd` clears the stored run ID.
|
|
180
180
|
|
|
181
|
-
This approach also handles page refreshes, as the client will automatically reconnect to the stream from the last known position when the UI loads with a stored run ID, following the behavior of [AI SDK's stream resumption](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-resume-streams#chatbot-resume-streams).
|
|
181
|
+
This approach also handles page refreshes, as the client will automatically reconnect to the stream from the last known position when the user interface (UI) loads with a stored run ID, following the behavior of [AI SDK's stream resumption](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-resume-streams#chatbot-resume-streams).
|
|
182
182
|
|
|
183
183
|
### Resuming from the end of the stream
|
|
184
184
|
|
|
185
|
-
By default, reconnecting replays the entire stream from the beginning (`startIndex: 0`). If you only need to show recent output
|
|
185
|
+
By default, reconnecting replays the entire stream from the beginning (`startIndex: 0`). If you only need to show recent output (for example, when resuming a long conversation after a page refresh), you can set `initialStartIndex` to a negative value to read from the end of the stream instead:
|
|
186
186
|
|
|
187
187
|
{/*@skip-typecheck: incomplete code sample*/}
|
|
188
188
|
|
|
@@ -206,8 +206,8 @@ When using a negative `initialStartIndex`, the reconnection endpoint **must** re
|
|
|
206
206
|
|
|
207
207
|
A workflow stream is a flat sequence of chunks, but the AI SDK's UI protocol groups chunks into logical parts (`text-*`, `reasoning-*`, `tool-input-*`) that must be opened with a `*-start` before any `*-delta` or `*-end`. A non-zero `startIndex` can land in the middle of an open part. See [`WorkflowChatTransport` → Mid-part resumes](/docs/api-reference/workflow-ai/workflow-chat-transport#mid-part-resumes) for how this is handled and an example of rewinding to a step boundary on the server.
|
|
208
208
|
|
|
209
|
-
## Related
|
|
209
|
+
## Related documentation
|
|
210
210
|
|
|
211
|
-
- [`WorkflowChatTransport` API
|
|
212
|
-
- [Streaming](/docs/foundations/streaming)
|
|
213
|
-
- [`getRun()` API
|
|
211
|
+
- [`WorkflowChatTransport` API reference](/docs/api-reference/workflow-ai/workflow-chat-transport): Full configuration options
|
|
212
|
+
- [Streaming](/docs/foundations/streaming): Understanding workflow streams
|
|
213
|
+
- [`getRun()` API reference](/docs/api-reference/workflow-api/get-run): Retrieving existing runs
|
|
@@ -12,7 +12,7 @@ related:
|
|
|
12
12
|
- /docs/api-reference/workflow/sleep
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
AI agents sometimes need to pause execution
|
|
15
|
+
AI agents sometimes need to pause execution to schedule recurring or future actions, wait before retrying an operation (e.g. for rate limiting), or wait for external state to be available.
|
|
16
16
|
|
|
17
17
|
Workflow SDK's `sleep` function enables Agents to pause execution without consuming resources, and resume at a specified time, after a specified duration, or in response to an external event. Workflow operation that suspend will survive restarts, new deploys, and infrastructure changes, independent of whether the suspense takes seconds or months.
|
|
18
18
|
|
|
@@ -20,15 +20,15 @@ Workflow SDK's `sleep` function enables Agents to pause execution without consum
|
|
|
20
20
|
See the [`sleep()` API Reference](/docs/api-reference/workflow/sleep) for the full list of supported duration formats and detailed API documentation, and see the [hooks](/docs/foundations/hooks) documentation for more information on how to resume in response to external events.
|
|
21
21
|
</Callout>
|
|
22
22
|
|
|
23
|
-
## Adding a
|
|
23
|
+
## Adding a sleep tool
|
|
24
24
|
|
|
25
|
-
Sleep is a built-in function in Workflow SDK
|
|
25
|
+
Sleep is a built-in function in Workflow SDK. To expose it as a tool, wrap it in a tool definition. Learn more about how to define tools in [Patterns for Defining Tools](/docs/ai/defining-tools).
|
|
26
26
|
|
|
27
27
|
<Steps>
|
|
28
28
|
|
|
29
29
|
<Step>
|
|
30
30
|
|
|
31
|
-
### Define the
|
|
31
|
+
### Define the tool
|
|
32
32
|
|
|
33
33
|
Add a new "sleep" tool to the `tools` defined in `workflows/chat/steps/tools.ts`:
|
|
34
34
|
|
|
@@ -60,7 +60,7 @@ export const flightBookingTools = {
|
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
<Callout type="info">
|
|
63
|
-
|
|
63
|
+
Call `sleep()` from within a workflow context, not from within a step. `executeSleep` does not have `"use step"` because it runs in the workflow context where `sleep()` is available.
|
|
64
64
|
</Callout>
|
|
65
65
|
|
|
66
66
|
This already makes the full sleep functionality available to the Agent!
|
|
@@ -71,7 +71,7 @@ export const flightBookingTools = {
|
|
|
71
71
|
|
|
72
72
|
### Show the tool status in the UI
|
|
73
73
|
|
|
74
|
-
To round it off, extend the UI to display the tool call status. This can be done either by displaying the tool call information directly, or by emitting custom data parts to the stream (see [Streaming Updates from Tools](/docs/ai/streaming-updates-from-tools) for more details).
|
|
74
|
+
To round it off, extend the UI to display the tool call status. This can be done either by displaying the tool call information directly, or by emitting custom data parts to the stream (see [Streaming Updates from Tools](/docs/ai/streaming-updates-from-tools) for more details). Since there aren't any fine-grained progress updates to show, we'll display the tool call information directly:
|
|
75
75
|
|
|
76
76
|
{/*@skip-typecheck: incomplete code sample*/}
|
|
77
77
|
|
|
@@ -153,11 +153,11 @@ function renderToolOutput(part: any) {
|
|
|
153
153
|
|
|
154
154
|
Now, try out the Flight Booking Agent again, and ask it to sleep for 10 seconds before checking any flight. You'll see the agent pause, and the UI reflect the tool call status.
|
|
155
155
|
|
|
156
|
-
## Use
|
|
156
|
+
## Use cases
|
|
157
157
|
|
|
158
158
|
Aside from providing `sleep()` as a tool, there are other use cases for Agents that commonly call for suspension and resumption.
|
|
159
159
|
|
|
160
|
-
### Rate
|
|
160
|
+
### Rate limiting
|
|
161
161
|
|
|
162
162
|
When hitting API rate limits, use `RetryableError` with a delay:
|
|
163
163
|
|
|
@@ -180,7 +180,7 @@ async function callRateLimitedAPI(endpoint: string) {
|
|
|
180
180
|
}
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
## Related
|
|
183
|
+
## Related documentation
|
|
184
184
|
|
|
185
185
|
- [`sleep()` API Reference](/docs/api-reference/workflow/sleep) - Full API documentation with all duration formats
|
|
186
186
|
- [Workflows and Steps](/docs/foundations/workflows-and-steps) - Understanding workflow context
|
|
@@ -22,7 +22,7 @@ As an example, we'll extend out Flight Booking Agent to use emit more granular p
|
|
|
22
22
|
|
|
23
23
|
<Step>
|
|
24
24
|
|
|
25
|
-
### Define
|
|
25
|
+
### Define your data part type
|
|
26
26
|
|
|
27
27
|
First, define a TypeScript type for your custom data part. This ensures type safety across your tool and client code:
|
|
28
28
|
|
|
@@ -44,7 +44,7 @@ The `type` field must be a string starting with `data-` followed by your custom
|
|
|
44
44
|
|
|
45
45
|
<Step>
|
|
46
46
|
|
|
47
|
-
### Emit
|
|
47
|
+
### Emit updates from your tool
|
|
48
48
|
|
|
49
49
|
Use [`getWritable()`](/docs/api-reference/workflow/get-writable) inside a step function to get a handle to the stream. This is the same stream that the LLM and other tools calls are writing to, so we can inject out own data packets directly.
|
|
50
50
|
|
|
@@ -95,7 +95,7 @@ Key points:
|
|
|
95
95
|
</Step>
|
|
96
96
|
|
|
97
97
|
<Step>
|
|
98
|
-
### Handle
|
|
98
|
+
### Handle data parts in the client
|
|
99
99
|
|
|
100
100
|
Update your chat component to detect and render the custom data parts. Data parts are stored in the message's `parts` array alongside text and tool invocation parts:
|
|
101
101
|
|
|
@@ -143,7 +143,7 @@ The pattern is:
|
|
|
143
143
|
|
|
144
144
|
Now, when you run the agent to search for flights, you'll see the flight results pop up one after another. This will be most useful if you have tool calls that take minutes to complete, and you need to show granular progress updates to the user.
|
|
145
145
|
|
|
146
|
-
## Related
|
|
146
|
+
## Related documentation
|
|
147
147
|
|
|
148
148
|
- [Building Durable AI Agents](/docs/ai) - Complete guide to durable agents
|
|
149
149
|
- [`getWritable()` API Reference](/docs/api-reference/workflow/get-writable) - Stream API details
|
|
@@ -3,7 +3,7 @@ title: "@workflow/vitest"
|
|
|
3
3
|
description: Vitest plugin and test helpers for integration testing workflows in-process.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
The `@workflow/vitest` package provides a Vitest plugin and test helpers for running full workflow integration tests in-process
|
|
6
|
+
The `@workflow/vitest` package provides a Vitest plugin and test helpers for running full workflow integration tests in-process, no server required.
|
|
7
7
|
|
|
8
8
|
## Plugin
|
|
9
9
|
|
|
@@ -21,7 +21,7 @@ export default defineConfig({
|
|
|
21
21
|
});
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Pass a [`WorkflowTestOptions`](#workflowtestoptions) object when your project uses a non-standard layout
|
|
24
|
+
Pass a [`WorkflowTestOptions`](#workflowtestoptions) object when your project uses a non-standard layout, for example, a monorepo where `workflows/` does not live at the Vitest config's directory, or when the default `.workflow-data` / `.workflow-vitest` output locations need to move. The plugin forwards these paths to `buildWorkflowTests()` and `setupWorkflowTests()` through Vitest's per-project provided context, so each Vitest workspace project stays isolated.
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
@@ -46,7 +46,7 @@ export default defineConfig({
|
|
|
46
46
|
|
|
47
47
|
**Returns:** `Plugin[]`
|
|
48
48
|
|
|
49
|
-
## Setup
|
|
49
|
+
## Setup functions
|
|
50
50
|
|
|
51
51
|
### `buildWorkflowTests()`
|
|
52
52
|
|
|
@@ -108,11 +108,11 @@ Tears down the workflow test world. Clears the global world and closes the Local
|
|
|
108
108
|
| `dataDir` | `string` | `<rootDir>/.workflow-data` | Directory for workflow runtime data written by the test world. Relative paths resolve against `cwd`. |
|
|
109
109
|
| `outDir` | `string` | `<rootDir>/.workflow-vitest` | Directory for generated workflow and step bundles. Relative paths resolve against `cwd`. |
|
|
110
110
|
|
|
111
|
-
## Test
|
|
111
|
+
## Test helpers
|
|
112
112
|
|
|
113
113
|
### `waitForSleep()`
|
|
114
114
|
|
|
115
|
-
Polls the event log until the workflow has a pending `sleep()` call
|
|
115
|
+
Polls the event log until the workflow has a pending `sleep()` call, one with a `wait_created` event but no corresponding `wait_completed` event. Returns the correlation ID of the pending sleep, which can be passed to [`wakeUp()`](/docs/api-reference/workflow-api/get-run) to target a specific sleep.
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
```typescript
|
|
@@ -131,9 +131,9 @@ await getRun(run.runId).wakeUp({ correlationIds: [sleepId] }); // [!code highlig
|
|
|
131
131
|
| `run` | `Run<any>` | The workflow run to monitor |
|
|
132
132
|
| `options?` | `WaitOptions` | Polling and timeout configuration |
|
|
133
133
|
|
|
134
|
-
**Returns:** `Promise<string
|
|
134
|
+
**Returns:** `Promise<string>`, the correlation ID of the first pending sleep. Pass this to `wakeUp({ correlationIds: [id] })` to target a specific sleep.
|
|
135
135
|
|
|
136
|
-
#### Behavior with
|
|
136
|
+
#### Behavior with multiple sleeps
|
|
137
137
|
|
|
138
138
|
- **Sequential sleeps**: `waitForSleep()` returns each sleep as the workflow reaches it. After waking one, call `waitForSleep()` again for the next.
|
|
139
139
|
- **Parallel sleeps**: `waitForSleep()` returns whichever pending sleep is found first. After waking it, call `waitForSleep()` again to get the next one.
|
|
@@ -159,7 +159,7 @@ await resumeHook(hook.token, { approved: true }); // [!code highlight]
|
|
|
159
159
|
| `run` | `Run<any>` | The workflow run to monitor |
|
|
160
160
|
| `options?` | `WaitOptions & { token?: string }` | Polling, timeout, and optional token filter |
|
|
161
161
|
|
|
162
|
-
**Returns:** `Promise<Hook
|
|
162
|
+
**Returns:** `Promise<Hook>`, the first pending hook matching the filter. The hook object includes `token`, `hookId`, and `runId`.
|
|
163
163
|
|
|
164
164
|
### `WaitOptions`
|
|
165
165
|
|
|
@@ -26,7 +26,7 @@ export async function hookWorkflow() {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
## API
|
|
29
|
+
## API signature
|
|
30
30
|
|
|
31
31
|
### Parameters
|
|
32
32
|
|
|
@@ -66,11 +66,11 @@ export default Hook;`}
|
|
|
66
66
|
|
|
67
67
|
The returned `Hook` object also implements `AsyncIterable<T>`, which allows you to iterate over incoming payloads using `for await...of` syntax.
|
|
68
68
|
|
|
69
|
-
Use `hook.getConflict()` to check whether the hook token is already claimed by another hook, including one kept reserved after its run ends, without waiting for hook payload data. Calling `createHook()` on its own does not register the hook
|
|
69
|
+
Use `hook.getConflict()` to check whether the hook token is already claimed by another hook, including one kept reserved after its run ends, without waiting for hook payload data. Calling `createHook()` on its own does not register the hook: registration is only committed when the workflow suspends. Awaiting `hook.getConflict()` suspends the workflow to commit the registration, then resolves with `null` once `hook_created` is recorded, or with the conflicting [`Run`](/docs/api-reference/workflow-api/get-run).
|
|
70
70
|
|
|
71
71
|
## Examples
|
|
72
72
|
|
|
73
|
-
### Basic
|
|
73
|
+
### Basic usage
|
|
74
74
|
|
|
75
75
|
When creating a hook, you can specify a payload type for automatic type safety:
|
|
76
76
|
|
|
@@ -91,7 +91,7 @@ export async function approvalWorkflow() {
|
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
### Customizing
|
|
94
|
+
### Customizing tokens
|
|
95
95
|
|
|
96
96
|
Tokens are used to identify a specific hook. You can customize the token to be more specific to a use case.
|
|
97
97
|
|
|
@@ -115,7 +115,7 @@ export async function slackBotWorkflow(channelId: string) {
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
### Detecting
|
|
118
|
+
### Detecting token conflicts
|
|
119
119
|
|
|
120
120
|
Use `hook.getConflict()` when the workflow needs to claim a hook token before doing other work, but does not need a payload yet:
|
|
121
121
|
|
|
@@ -141,7 +141,7 @@ async function processOrder(orderId: string) {
|
|
|
141
141
|
}
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
Because `createHook()` alone does not suspend the workflow, awaiting `hook.getConflict()` is what actually suspends the run and commits the hook registration. It only waits for registration
|
|
144
|
+
Because `createHook()` alone does not suspend the workflow, awaiting `hook.getConflict()` is what actually suspends the run and commits the hook registration. It only waits for registration. To receive payload data from a future `resumeHook()` call, await the hook itself or iterate it with `for await...of`.
|
|
145
145
|
|
|
146
146
|
On a conflict, the resolved value is a `Run` handle for the run that owns the token, with durable step-backed accessors. The duplicate run can decide in code how to handle it: return or log `conflict.runId`, inspect `await conflict.status`, wait on `await conflict.returnValue`, or cancel the owner with `await conflict.cancel()` and continue in the current run. See [Run idempotency](/docs/foundations/idempotency#run-idempotency) for these strategies in context.
|
|
147
147
|
|
|
@@ -149,7 +149,7 @@ On a conflict, the resolved value is a `Run` handle for the run that owns the to
|
|
|
149
149
|
Custom hook tokens are the recommended way to coordinate active workflow runs. Use a deterministic token from your domain, such as an order ID or conversation ID, create the hook near the beginning of the workflow, and check `await hook.getConflict()` before work that depends on owning the token. See [Run idempotency](/docs/foundations/idempotency#run-idempotency).
|
|
150
150
|
</Callout>
|
|
151
151
|
|
|
152
|
-
### Keep a
|
|
152
|
+
### Keep a token unavailable after the run ends
|
|
153
153
|
|
|
154
154
|
By default, another Hook can use the token after its workflow ends. Set `experimental_minRetention` to keep the token unavailable for at least a specific time after `createHook()` runs:
|
|
155
155
|
|
|
@@ -190,7 +190,7 @@ After the workflow ends, [`getHookByToken()`](/docs/api-reference/workflow-api/g
|
|
|
190
190
|
This option is experimental. Worlds can limit how long tokens are retained; see [World configuration](/docs/configuration/worlds) for each World's limit. If the configured World does not support minimum retention, the workflow fails when registering the Hook. `createWebhook()` does not accept this option.
|
|
191
191
|
</Callout>
|
|
192
192
|
|
|
193
|
-
### Waiting for
|
|
193
|
+
### Waiting for multiple payloads
|
|
194
194
|
|
|
195
195
|
You can also wait for multiple payloads by using the `for await...of` syntax.
|
|
196
196
|
|
|
@@ -213,7 +213,7 @@ export async function collectHookWorkflow() {
|
|
|
213
213
|
}
|
|
214
214
|
```
|
|
215
215
|
|
|
216
|
-
### Disposing
|
|
216
|
+
### Disposing hooks early
|
|
217
217
|
|
|
218
218
|
You can dispose a hook early to release its token for reuse by another workflow. This is useful for handoff patterns where one workflow needs to transfer a hook token to another workflow while still running.
|
|
219
219
|
|
|
@@ -242,7 +242,7 @@ export async function handoffWorkflow(channelId: string) {
|
|
|
242
242
|
|
|
243
243
|
After calling `dispose()`, the hook will no longer receive events and its token becomes available for other workflows to use.
|
|
244
244
|
|
|
245
|
-
### Automatic
|
|
245
|
+
### Automatic disposal with `using`
|
|
246
246
|
|
|
247
247
|
Hooks implement the [TC39 Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management) proposal, allowing automatic disposal with the `using` keyword:
|
|
248
248
|
|
|
@@ -268,9 +268,9 @@ export async function scopedHookWorkflow(channelId: string) {
|
|
|
268
268
|
|
|
269
269
|
This is equivalent to manually calling `dispose()` but ensures the hook is always cleaned up, even if an error occurs.
|
|
270
270
|
|
|
271
|
-
## Related
|
|
271
|
+
## Related functions
|
|
272
272
|
|
|
273
|
-
- [`defineHook()`](/docs/api-reference/workflow/define-hook)
|
|
274
|
-
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook)
|
|
275
|
-
- [`createWebhook()`](/docs/api-reference/workflow/create-webhook)
|
|
276
|
-
- [Idempotency](/docs/foundations/idempotency)
|
|
273
|
+
- [`defineHook()`](/docs/api-reference/workflow/define-hook): Type-safe hook helper
|
|
274
|
+
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook): Resume a hook with a payload
|
|
275
|
+
- [`createWebhook()`](/docs/api-reference/workflow/create-webhook): Higher-level HTTP webhook abstraction
|
|
276
|
+
- [Idempotency](/docs/foundations/idempotency): Deduplicate step side effects and workflow starts
|
|
@@ -14,7 +14,7 @@ Creates a webhook that can be used to suspend and resume a workflow run upon rec
|
|
|
14
14
|
Webhooks provide a way for external systems to send HTTP requests directly to your workflow. Unlike hooks which accept arbitrary payloads, webhooks work with standard HTTP `Request` objects and can return HTTP `Response` objects.
|
|
15
15
|
|
|
16
16
|
<Callout type="warn">
|
|
17
|
-
`createWebhook()` creates a public endpoint at `/.well-known/workflow/v1/webhook/:token`, and the token in that URL is the only authorization performed for incoming requests resuming that webhook. This is convenient for prototypes and
|
|
17
|
+
`createWebhook()` creates a public endpoint at `/.well-known/workflow/v1/webhook/:token`, and the token in that URL is the only authorization performed for incoming requests resuming that webhook. This is convenient for prototypes and basic resume links because it avoids creating another route, but if you need stronger security, prefer [`createHook()`](/docs/api-reference/workflow/create-hook) behind your own route and authorize the request before calling [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) to avoid unauthenticated workflow resumptions.
|
|
18
18
|
</Callout>
|
|
19
19
|
|
|
20
20
|
```ts lineNumbers
|
|
@@ -31,7 +31,7 @@ export async function webhookWorkflow() {
|
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
## API
|
|
34
|
+
## API signature
|
|
35
35
|
|
|
36
36
|
### Parameters
|
|
37
37
|
|
|
@@ -63,22 +63,22 @@ When using `createWebhook({ respondWith: 'manual' })`, the resolved request type
|
|
|
63
63
|
<Callout type="info">
|
|
64
64
|
Use the simplest option that satisfies the prompt:
|
|
65
65
|
|
|
66
|
-
- `createWebhook()
|
|
67
|
-
- `createWebhook({ respondWith: 'manual' })
|
|
68
|
-
- `createHook()` + `resumeHook()
|
|
66
|
+
- `createWebhook()`: generated callback URL, and the default `202 Accepted` response is fine
|
|
67
|
+
- `createWebhook({ respondWith: 'manual' })`: generated callback URL, but you must send a custom body, status, or headers
|
|
68
|
+
- `createHook()` + `resumeHook()`: the app resumes from server-side code with a deterministic business token instead of a generated callback URL
|
|
69
69
|
</Callout>
|
|
70
70
|
|
|
71
71
|
<details>
|
|
72
72
|
<summary>Common wrong turns</summary>
|
|
73
73
|
|
|
74
|
-
-
|
|
74
|
+
- A callback URL alone does not require `respondWith: 'manual'`.
|
|
75
75
|
- Do not use `RequestWithResponse` unless you chose manual mode.
|
|
76
76
|
- Do not invent a custom callback route when `webhook.url` is the intended callback surface.
|
|
77
77
|
</details>
|
|
78
78
|
|
|
79
79
|
## Examples
|
|
80
80
|
|
|
81
|
-
### Basic
|
|
81
|
+
### Basic usage
|
|
82
82
|
|
|
83
83
|
Create a webhook that receives HTTP requests and logs the request details:
|
|
84
84
|
|
|
@@ -101,11 +101,11 @@ export async function basicWebhookWorkflow() {
|
|
|
101
101
|
}
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
### Responding to
|
|
104
|
+
### Responding to webhook requests (manual mode)
|
|
105
105
|
|
|
106
106
|
Use this section only when the caller requires a non-default HTTP response. If `202 Accepted` is acceptable, use `createWebhook()` without `respondWith: "manual"`.
|
|
107
107
|
|
|
108
|
-
Pass `{ respondWith: "manual" }` to get a `RequestWithResponse` object with a `respondWith()` method.
|
|
108
|
+
Pass `{ respondWith: "manual" }` to get a `RequestWithResponse` object with a `respondWith()` method. Call `respondWith()` from within a step function:
|
|
109
109
|
|
|
110
110
|
```typescript lineNumbers
|
|
111
111
|
import { createWebhook, type RequestWithResponse } from "workflow"
|
|
@@ -143,7 +143,7 @@ async function processData(data: any): Promise<void> {
|
|
|
143
143
|
}
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
### Waiting for
|
|
146
|
+
### Waiting for multiple requests
|
|
147
147
|
|
|
148
148
|
You can also wait for multiple requests by using the `for await...of` syntax.
|
|
149
149
|
|
|
@@ -182,9 +182,9 @@ export async function eventCollectorWorkflow() {
|
|
|
182
182
|
}
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
-
## Related
|
|
185
|
+
## Related functions
|
|
186
186
|
|
|
187
|
-
- [`createHook()`](/docs/api-reference/workflow/create-hook)
|
|
188
|
-
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook)
|
|
189
|
-
- [`defineHook()`](/docs/api-reference/workflow/define-hook)
|
|
190
|
-
- [`resumeWebhook()`](/docs/api-reference/workflow-api/resume-webhook)
|
|
187
|
+
- [`createHook()`](/docs/api-reference/workflow/create-hook): Use when the app resumes from server-side code with a deterministic business token.
|
|
188
|
+
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook): Pairs with `createHook()` for deterministic server-side resume.
|
|
189
|
+
- [`defineHook()`](/docs/api-reference/workflow/define-hook): Type-safe hook helper.
|
|
190
|
+
- [`resumeWebhook()`](/docs/api-reference/workflow-api/resume-webhook): Low-level runtime API. Most integrations should call `webhook.url` directly instead of adding a custom callback route.
|
|
@@ -33,7 +33,7 @@ export async function nameWorkflow() {
|
|
|
33
33
|
}
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
## API
|
|
36
|
+
## API signature
|
|
37
37
|
|
|
38
38
|
### Parameters
|
|
39
39
|
|
|
@@ -59,11 +59,11 @@ interface TypedHook<TInput, TOutput> {
|
|
|
59
59
|
export default TypedHook;`}
|
|
60
60
|
/>
|
|
61
61
|
|
|
62
|
-
`create()` is called inside a `"use workflow"` function to create the hook; `resume()` is called from runtime code (an API route or server action). When a `schema` is provided, `resume()` accepts the raw input type (`TInput`) and the workflow receives the validated and possibly transformed output type (`TOutput`); without a schema, `TOutput` defaults to `TInput`. `resume()` throws [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error) if the token does not match an active hook
|
|
62
|
+
`create()` is called inside a `"use workflow"` function to create the hook; `resume()` is called from runtime code (an API route or server action). When a `schema` is provided, `resume()` accepts the raw input type (`TInput`) and the workflow receives the validated and possibly transformed output type (`TOutput`); without a schema, `TOutput` defaults to `TInput`. `resume()` throws [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error) if the token does not match an active hook. It does not return `null`.
|
|
63
63
|
|
|
64
64
|
## Examples
|
|
65
65
|
|
|
66
|
-
### Basic
|
|
66
|
+
### Basic type-safe hook definition
|
|
67
67
|
|
|
68
68
|
By defining the hook once with a specific payload type, you can reuse it in multiple workflows and API routes with automatic type safety.
|
|
69
69
|
|
|
@@ -88,7 +88,7 @@ export async function workflowWithApproval() {
|
|
|
88
88
|
}
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
### Resuming with
|
|
91
|
+
### Resuming with type safety
|
|
92
92
|
|
|
93
93
|
Hooks can be resumed using the same defined hook and a token. By using the same hook, you can ensure that the payload matches the defined type when resuming a hook. `resume()` resolves to the resumed hook and throws [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error) if the token does not match an active hook.
|
|
94
94
|
|
|
@@ -116,7 +116,7 @@ export async function POST(request: Request) {
|
|
|
116
116
|
}
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
### Validate and
|
|
119
|
+
### Validate and transform with schema
|
|
120
120
|
|
|
121
121
|
You can provide runtime validation and transformation of hook payloads using the `schema` option. This option accepts any validator that conforms to the [Standard Schema v1](https://standardschema.dev) specification.
|
|
122
122
|
|
|
@@ -174,7 +174,7 @@ export async function POST(request: Request) {
|
|
|
174
174
|
}
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
-
#### Using
|
|
177
|
+
#### Using other Standard Schema libraries
|
|
178
178
|
|
|
179
179
|
The same pattern works with any Standard Schema v1 compliant library. Here's an example with [Valibot](https://valibot.dev):
|
|
180
180
|
|
|
@@ -190,7 +190,7 @@ export const approvalHook = defineHook({
|
|
|
190
190
|
});
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
-
### Customizing
|
|
193
|
+
### Customizing tokens
|
|
194
194
|
|
|
195
195
|
Tokens are used to identify a specific hook and for resuming a hook. You can customize the token to be more specific to a use case.
|
|
196
196
|
|
|
@@ -211,7 +211,7 @@ export async function slackBotWorkflow(channelId: string) {
|
|
|
211
211
|
}
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
## Related
|
|
214
|
+
## Related functions
|
|
215
215
|
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
- [`createHook()`](/docs/api-reference/workflow/create-hook): Create a hook in a workflow.
|
|
217
|
+
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook): Resume a hook with a payload.
|
|
@@ -27,7 +27,7 @@ async function fallibleStep() {
|
|
|
27
27
|
}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
## API
|
|
30
|
+
## API signature
|
|
31
31
|
|
|
32
32
|
### Constructor
|
|
33
33
|
|
|
@@ -50,7 +50,7 @@ interface FatalError {
|
|
|
50
50
|
export default FatalError;`}
|
|
51
51
|
/>
|
|
52
52
|
|
|
53
|
-
### Static
|
|
53
|
+
### Static methods
|
|
54
54
|
|
|
55
55
|
#### `FatalError.is(value)`
|
|
56
56
|
|
|
@@ -34,7 +34,7 @@ async function apiWorkflow() {
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
## API
|
|
37
|
+
## API signature
|
|
38
38
|
|
|
39
39
|
### Parameters
|
|
40
40
|
|
|
@@ -60,9 +60,9 @@ showSections={['returns']}
|
|
|
60
60
|
|
|
61
61
|
## Examples
|
|
62
62
|
|
|
63
|
-
### Basic
|
|
63
|
+
### Basic usage
|
|
64
64
|
|
|
65
|
-
Here's
|
|
65
|
+
Here's an example of how you can use `fetch` inside your workflow.
|
|
66
66
|
|
|
67
67
|
```typescript lineNumbers
|
|
68
68
|
import { fetch } from "workflow"
|
|
@@ -87,13 +87,13 @@ async function apiWorkflow() {
|
|
|
87
87
|
}
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
We call `fetch()` with a URL and optional request options,
|
|
90
|
+
We call `fetch()` with a URL and optional request options, like the standard fetch API. The workflow runtime automatically handles the response serialization.
|
|
91
91
|
|
|
92
|
-
This API
|
|
92
|
+
This API lets you use `fetch` in a workflow. You can also implement a custom fetch for different error handling and retry logic.
|
|
93
93
|
|
|
94
|
-
### Customizing
|
|
94
|
+
### Customizing fetch behavior
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
The following custom fetch wrapper provides more advanced error handling with custom retry logic. Call `globalThis.fetch` inside your own `"use step"` function because calling the workflow `fetch` imported from `workflow` would nest a step inside a step:
|
|
97
97
|
|
|
98
98
|
```typescript lineNumbers
|
|
99
99
|
import { FatalError, RetryableError } from "workflow"
|
|
@@ -34,7 +34,7 @@ async function logStepId() {
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
### Example:
|
|
37
|
+
### Example: use `stepId` as an idempotency key
|
|
38
38
|
|
|
39
39
|
```typescript lineNumbers
|
|
40
40
|
import { getStepMetadata } from "workflow";
|
|
@@ -61,7 +61,7 @@ async function chargeUser(userId: string, amount: number) {
|
|
|
61
61
|
<a href="/docs/foundations/idempotency">Idempotency</a> guide.
|
|
62
62
|
</Callout>
|
|
63
63
|
|
|
64
|
-
## API
|
|
64
|
+
## API signature
|
|
65
65
|
|
|
66
66
|
### Parameters
|
|
67
67
|
|