workflow 5.0.0-beta.5 → 5.0.0-beta.50
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 +68 -23
- package/dist/api-workflow.d.ts +1 -1
- package/dist/api-workflow.d.ts.map +1 -1
- package/dist/api-workflow.js +1 -1
- package/dist/api.d.ts +3 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +5 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/internal/builtins.d.ts +20 -3
- package/dist/internal/builtins.d.ts.map +1 -1
- package/dist/internal/builtins.js +68 -4
- package/dist/internal/errors.d.ts +1 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +2 -2
- package/dist/nest-builder.d.ts +2 -0
- package/dist/nest-builder.d.ts.map +1 -0
- package/dist/nest-builder.js +2 -0
- package/dist/nest-vercel-builder.d.ts +2 -0
- package/dist/nest-vercel-builder.d.ts.map +1 -0
- package/dist/nest-vercel-builder.js +2 -0
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -2
- package/dist/runtime.d.ts +2 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +4 -1
- package/docs/ai/chat-session-modeling.mdx +29 -26
- package/docs/ai/defining-tools.mdx +6 -7
- package/docs/ai/human-in-the-loop.mdx +11 -11
- package/docs/ai/index.mdx +50 -45
- package/docs/ai/message-queueing.mdx +16 -16
- package/docs/ai/meta.json +1 -0
- package/docs/ai/resumable-streams.mdx +40 -28
- package/docs/ai/sleep-and-delays.mdx +10 -10
- package/docs/ai/streaming-updates-from-tools.mdx +6 -6
- package/docs/api-reference/index.mdx +24 -0
- package/docs/api-reference/meta.json +8 -0
- package/docs/api-reference/vitest/index.mdx +9 -15
- package/docs/api-reference/workflow/create-hook.mdx +89 -10
- package/docs/api-reference/workflow/create-webhook.mdx +16 -15
- package/docs/api-reference/workflow/define-hook.mdx +35 -33
- package/docs/api-reference/workflow/fatal-error.mdx +30 -8
- package/docs/api-reference/workflow/fetch.mdx +14 -10
- 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 +4 -1
- package/docs/api-reference/workflow/retryable-error.mdx +1 -1
- package/docs/api-reference/workflow/set-attributes.mdx +61 -0
- package/docs/api-reference/workflow/sleep.mdx +4 -4
- package/docs/api-reference/workflow-ai/durable-agent.mdx +48 -86
- package/docs/api-reference/workflow-ai/index.mdx +3 -3
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +67 -24
- package/docs/api-reference/workflow-api/get-hook-by-token.mdx +26 -12
- package/docs/api-reference/workflow-api/get-run.mdx +43 -8
- package/docs/api-reference/workflow-api/index.mdx +6 -10
- package/docs/api-reference/workflow-api/resume-hook.mdx +73 -12
- package/docs/api-reference/workflow-api/resume-webhook.mdx +11 -9
- package/docs/api-reference/workflow-api/start.mdx +60 -13
- package/docs/api-reference/workflow-astro/index.mdx +18 -0
- package/docs/api-reference/workflow-astro/meta.json +4 -0
- package/docs/api-reference/workflow-astro/workflow.mdx +45 -0
- package/docs/api-reference/workflow-errors/entity-conflict-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
- package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
- package/docs/api-reference/workflow-errors/index.mdx +88 -0
- package/docs/api-reference/workflow-errors/meta.json +6 -0
- package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +68 -0
- package/docs/api-reference/workflow-errors/run-expired-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
- 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 +52 -0
- 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 +58 -0
- package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/workflow-world-error.mdx +8 -8
- package/docs/api-reference/workflow-globals.mdx +14 -10
- package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
- package/docs/api-reference/workflow-nest/index.mdx +31 -0
- package/docs/api-reference/workflow-nest/meta.json +9 -0
- package/docs/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
- package/docs/api-reference/workflow-nest/workflow-controller.mdx +40 -0
- package/docs/api-reference/workflow-nest/workflow-module.mdx +74 -0
- package/docs/api-reference/workflow-next/with-workflow.mdx +39 -17
- package/docs/api-reference/workflow-nitro/index.mdx +60 -0
- package/docs/api-reference/workflow-nuxt/index.mdx +48 -0
- package/docs/api-reference/workflow-observability/hydrate-data.mdx +35 -0
- package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
- package/docs/api-reference/workflow-observability/index.mdx +62 -0
- package/docs/api-reference/workflow-observability/meta.json +11 -0
- package/docs/api-reference/workflow-observability/observability-revivers.mdx +50 -0
- package/docs/api-reference/workflow-observability/parse-class-name.mdx +41 -0
- package/docs/api-reference/workflow-observability/parse-step-name.mdx +40 -0
- package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
- package/docs/api-reference/workflow-runtime/create-world.mdx +39 -0
- package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/get-world.mdx +11 -14
- package/docs/api-reference/workflow-runtime/health-check.mdx +50 -0
- package/docs/api-reference/workflow-runtime/index.mdx +41 -0
- package/docs/api-reference/workflow-runtime/meta.json +12 -0
- package/docs/api-reference/workflow-runtime/set-world.mdx +51 -0
- package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +43 -0
- package/docs/api-reference/workflow-runtime/world/analytics.mdx +315 -0
- package/docs/api-reference/workflow-runtime/world/index.mdx +60 -0
- package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
- package/docs/api-reference/workflow-runtime/world/queue.mdx +88 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +98 -34
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +8 -8
- package/docs/api-reference/workflow-serde/index.mdx +1 -2
- package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +3 -4
- package/docs/api-reference/workflow-serde/workflow-serialize.mdx +8 -8
- package/docs/api-reference/workflow-sveltekit/index.mdx +18 -0
- package/docs/api-reference/workflow-sveltekit/meta.json +4 -0
- package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
- package/docs/api-reference/workflow-vite/index.mdx +18 -0
- package/docs/api-reference/workflow-vite/meta.json +4 -0
- package/docs/api-reference/workflow-vite/workflow.mdx +48 -0
- package/docs/changelog/attributes-mvp.mdx +380 -0
- package/docs/changelog/batched-event-writes.mdx +79 -0
- package/docs/changelog/eager-processing.mdx +110 -436
- package/docs/changelog/index.mdx +4 -2
- package/docs/changelog/lazy-event-creation.md +127 -0
- package/docs/changelog/lazy-hook-resume.mdx +78 -0
- package/docs/changelog/meta.json +11 -1
- package/docs/changelog/resilient-resume.mdx +32 -0
- package/docs/changelog/resilient-start.mdx +33 -285
- package/docs/changelog/step-message-ownership.mdx +360 -0
- package/docs/changelog/turbo-mode.md +87 -0
- package/docs/comparisons/index.mdx +66 -0
- package/docs/comparisons/meta.json +11 -0
- package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +55 -0
- package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +111 -0
- package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +71 -0
- package/docs/comparisons/workflow-sdk-vs-inngest.mdx +102 -0
- package/docs/comparisons/workflow-sdk-vs-temporal.mdx +123 -0
- package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +104 -0
- package/docs/configuration/build-and-diagnostics.mdx +70 -0
- package/docs/configuration/cli-and-web-ui.mdx +241 -0
- package/docs/configuration/framework-options.mdx +165 -0
- package/docs/configuration/index.mdx +32 -0
- package/docs/configuration/meta.json +12 -0
- package/docs/configuration/runtime-tuning.mdx +376 -0
- package/docs/configuration/worlds.mdx +313 -0
- package/docs/cookbook/advanced/child-workflows.mdx +211 -264
- package/docs/cookbook/advanced/meta.json +6 -1
- package/docs/cookbook/advanced/publishing-libraries.mdx +65 -56
- package/docs/cookbook/advanced/serializable-steps.mdx +28 -20
- package/docs/cookbook/advanced/upgrading-workflows.mdx +199 -0
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +27 -19
- package/docs/cookbook/agent-patterns/durable-agent.mdx +14 -142
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +30 -22
- package/docs/cookbook/common-patterns/batching.mdx +18 -14
- package/docs/cookbook/common-patterns/idempotency.mdx +41 -53
- package/docs/cookbook/common-patterns/rate-limiting.mdx +8 -4
- package/docs/cookbook/common-patterns/saga.mdx +23 -19
- package/docs/cookbook/common-patterns/scheduling.mdx +34 -22
- package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +29 -25
- package/docs/cookbook/common-patterns/timeouts.mdx +26 -21
- package/docs/cookbook/common-patterns/webhooks.mdx +10 -6
- package/docs/cookbook/common-patterns/workflow-composition.mdx +30 -27
- package/docs/cookbook/index.mdx +22 -21
- package/docs/cookbook/integrations/ai-sdk.mdx +85 -47
- package/docs/cookbook/integrations/chat-sdk.mdx +50 -33
- package/docs/cookbook/integrations/sandbox.mdx +62 -45
- package/docs/deploying.mdx +95 -0
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +16 -12
- package/docs/errors/corrupted-event-log.mdx +29 -18
- package/docs/errors/deployment-mismatch.mdx +71 -0
- package/docs/errors/fetch-in-workflow.mdx +11 -7
- package/docs/errors/hook-conflict.mdx +69 -13
- package/docs/errors/index.mdx +2 -36
- package/docs/errors/node-js-module-in-workflow.mdx +9 -5
- package/docs/errors/replay-divergence.mdx +27 -0
- package/docs/errors/run-expired.mdx +85 -0
- package/docs/errors/runtime-decryption-failed.mdx +77 -0
- package/docs/errors/serialization-failed.mdx +44 -12
- package/docs/errors/start-invalid-workflow-function.mdx +9 -5
- package/docs/errors/step-executed-multiple-times.mdx +23 -0
- package/docs/errors/step-not-registered.mdx +6 -6
- package/docs/errors/timeout-in-workflow.mdx +12 -8
- package/docs/errors/webhook-invalid-respond-with-value.mdx +18 -18
- package/docs/errors/webhook-response-not-sent.mdx +20 -16
- package/docs/errors/workflow-not-registered.mdx +5 -5
- package/docs/foundations/cancellation.mdx +31 -32
- package/docs/foundations/errors-and-retries.mdx +42 -11
- package/docs/foundations/hooks.mdx +64 -35
- package/docs/foundations/idempotency.mdx +244 -12
- package/docs/foundations/index.mdx +1 -23
- package/docs/foundations/meta.json +2 -1
- package/docs/foundations/serialization.mdx +21 -22
- package/docs/foundations/starting-workflows.mdx +106 -30
- package/docs/foundations/streaming.mdx +107 -59
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/getting-started/astro.mdx +22 -18
- package/docs/getting-started/express.mdx +15 -11
- package/docs/getting-started/fastify.mdx +15 -11
- package/docs/getting-started/hono.mdx +15 -11
- package/docs/getting-started/index.mdx +10 -3
- package/docs/getting-started/meta.json +3 -1
- package/docs/getting-started/nestjs.mdx +87 -20
- package/docs/getting-started/next.mdx +22 -16
- package/docs/getting-started/nitro.mdx +22 -18
- package/docs/getting-started/nuxt.mdx +15 -11
- package/docs/getting-started/python.mdx +135 -40
- package/docs/getting-started/react-router/index.mdx +33 -0
- package/docs/getting-started/react-router/meta.json +5 -0
- package/docs/getting-started/react-router/v7.mdx +237 -0
- package/docs/getting-started/react-router/v8.mdx +232 -0
- package/docs/getting-started/sveltekit.mdx +20 -16
- package/docs/getting-started/tanstack-start.mdx +17 -13
- package/docs/getting-started/vite.mdx +15 -11
- package/docs/how-it-works/cancellation.mdx +63 -63
- package/docs/how-it-works/code-transform.mdx +83 -67
- package/docs/how-it-works/encryption.mdx +30 -26
- package/docs/how-it-works/event-sourcing.mdx +98 -34
- package/docs/how-it-works/framework-integrations.mdx +96 -337
- package/docs/how-it-works/understanding-directives.mdx +22 -22
- package/docs/internal/index.mdx +6 -4
- package/docs/internal/meta.json +6 -1
- package/docs/internal/nitro-native-build.mdx +38 -0
- package/docs/internal/nitro-web-ui.mdx +24 -0
- package/docs/internal/serializable-abort-controller.mdx +7 -7
- package/docs/meta.json +3 -2
- package/docs/observability/attributes.mdx +134 -0
- package/docs/observability/index.mdx +32 -10
- package/docs/observability/meta.json +1 -1
- package/docs/observability/retention.mdx +93 -0
- package/docs/observability/tracing.mdx +124 -0
- package/docs/testing/index.mdx +36 -36
- package/docs/testing/server-based.mdx +10 -10
- package/docs/whats-new.mdx +186 -0
- package/package.json +17 -14
- package/docs/api-reference/workflow-api/world/index.mdx +0 -58
- package/docs/api-reference/workflow-api/world/meta.json +0 -4
- package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
- package/docs/api-reference/workflow-api/world/queue.mdx +0 -86
- package/docs/deploying/building-a-world.mdx +0 -251
- package/docs/deploying/index.mdx +0 -95
- package/docs/deploying/meta.json +0 -4
- package/docs/deploying/world/local-world.mdx +0 -84
- package/docs/deploying/world/meta.json +0 -4
- package/docs/deploying/world/postgres-world.mdx +0 -224
- package/docs/deploying/world/vercel-world.mdx +0 -179
- package/docs/migration-guides/index.mdx +0 -34
- package/docs/migration-guides/meta.json +0 -9
- package/docs/migration-guides/migrating-from-aws-step-functions.mdx +0 -363
- package/docs/migration-guides/migrating-from-inngest.mdx +0 -314
- package/docs/migration-guides/migrating-from-temporal.mdx +0 -318
- package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -337
|
@@ -14,16 +14,15 @@ related:
|
|
|
14
14
|
|
|
15
15
|
This page covers the details for some common patterns when defining tools for AI agents using Workflow SDK.
|
|
16
16
|
|
|
17
|
-
Using
|
|
17
|
+
Using WorkflowAgent, we model most tools as steps. These can range from a single function call to an entire multi-day workflow.
|
|
18
18
|
|
|
19
19
|
## Accessing message context in tools
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
As with regular AI SDK tool definitions, tools in WorkflowAgent receive the tool's input parameters as the first argument and the tool call context as the second.
|
|
22
22
|
|
|
23
|
-
When
|
|
23
|
+
When your tool needs access to the full message history, you can access it via the `messages` property of the tool call context:
|
|
24
24
|
|
|
25
25
|
```typescript title="tools.ts" lineNumbers
|
|
26
|
-
import { Experimental_Agent as Agent } from "ai";
|
|
27
26
|
import type { ModelMessage } from "ai";
|
|
28
27
|
|
|
29
28
|
async function getWeather(
|
|
@@ -34,9 +33,9 @@ async function getWeather(
|
|
|
34
33
|
}
|
|
35
34
|
```
|
|
36
35
|
|
|
37
|
-
## Writing to
|
|
36
|
+
## Writing to streams
|
|
38
37
|
|
|
39
|
-
As discussed in [Streaming Updates from Tools](/docs/ai/streaming-updates-from-tools), it's common to use a step
|
|
38
|
+
As discussed in [Streaming Updates from Tools](/docs/ai/streaming-updates-from-tools), it's common to use a step only to call `getWritable()` for writing custom data parts to the stream.
|
|
40
39
|
|
|
41
40
|
This can be made generic, by creating a helper step function to write arbitrary data to the stream:
|
|
42
41
|
|
|
@@ -53,7 +52,7 @@ async function writeToStream(data: any) {
|
|
|
53
52
|
}
|
|
54
53
|
```
|
|
55
54
|
|
|
56
|
-
## Step-
|
|
55
|
+
## Step-level vs workflow-level tools
|
|
57
56
|
|
|
58
57
|
Tools can be implemented either at the step level or the workflow level, with different capabilities and constraints.
|
|
59
58
|
|
|
@@ -19,7 +19,7 @@ Workflow SDK's [webhook](/docs/api-reference/workflow/create-webhook) and [hook]
|
|
|
19
19
|
|
|
20
20
|
If you need to react to external events programmatically, see the [hooks](/docs/foundations/hooks) documentation for more information. This part of the guide will focus on the human-in-the-loop pattern, which is a subset of the more general hook pattern.
|
|
21
21
|
|
|
22
|
-
## How
|
|
22
|
+
## How it works
|
|
23
23
|
|
|
24
24
|
<Steps>
|
|
25
25
|
|
|
@@ -45,9 +45,9 @@ The workflow receives the approval data and resumes execution.
|
|
|
45
45
|
|
|
46
46
|
</Steps>
|
|
47
47
|
|
|
48
|
-
While this demo
|
|
48
|
+
While this demo uses a client-side button for human approval, you could instead create a webhook and send the approval link over email or Slack to resume the agent.
|
|
49
49
|
|
|
50
|
-
## Creating a
|
|
50
|
+
## Creating a booking approval tool
|
|
51
51
|
|
|
52
52
|
Add a tool that allows the agent to deliberately pause execution until a human approves or rejects a flight booking:
|
|
53
53
|
|
|
@@ -55,7 +55,7 @@ Add a tool that allows the agent to deliberately pause execution until a human a
|
|
|
55
55
|
|
|
56
56
|
<Step>
|
|
57
57
|
|
|
58
|
-
### Define the
|
|
58
|
+
### Define the hook
|
|
59
59
|
|
|
60
60
|
Create a typed hook with a Zod schema for validation:
|
|
61
61
|
|
|
@@ -78,7 +78,7 @@ export const bookingApprovalHook = defineHook({
|
|
|
78
78
|
|
|
79
79
|
<Step>
|
|
80
80
|
|
|
81
|
-
### Implement the
|
|
81
|
+
### Implement the tool
|
|
82
82
|
|
|
83
83
|
Create a tool that creates a hook instance using the tool call ID as the token. The UI will use this ID to submit the approval.
|
|
84
84
|
|
|
@@ -126,14 +126,14 @@ export const flightBookingTools = {
|
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
<Callout type="info">
|
|
129
|
-
|
|
129
|
+
Call `defineHook().create()` from within a workflow context, not from within a step. `executeBookingApproval` does not have `"use step"` because it runs in the workflow context where hooks are available.
|
|
130
130
|
</Callout>
|
|
131
131
|
|
|
132
132
|
</Step>
|
|
133
133
|
|
|
134
134
|
<Step>
|
|
135
135
|
|
|
136
|
-
### Create the API
|
|
136
|
+
### Create the API route
|
|
137
137
|
|
|
138
138
|
Create a new API endpoint that the UI will call to submit the approval decision:
|
|
139
139
|
|
|
@@ -158,7 +158,7 @@ export async function POST(request: Request) {
|
|
|
158
158
|
|
|
159
159
|
<Step>
|
|
160
160
|
|
|
161
|
-
### Create the
|
|
161
|
+
### Create the approval component
|
|
162
162
|
|
|
163
163
|
Build a new component that reacts to the tool call data, and allows the user to approve or reject the booking:
|
|
164
164
|
|
|
@@ -253,7 +253,7 @@ export function BookingApproval({ toolCallId, input, output }: BookingApprovalPr
|
|
|
253
253
|
|
|
254
254
|
<Step>
|
|
255
255
|
|
|
256
|
-
### Show the
|
|
256
|
+
### Show the tool status in the UI
|
|
257
257
|
|
|
258
258
|
Use the component we just created to render the tool call and approval controls in your chat interface:
|
|
259
259
|
|
|
@@ -332,7 +332,7 @@ export default function ChatPage() {
|
|
|
332
332
|
|
|
333
333
|
</Steps>
|
|
334
334
|
|
|
335
|
-
## Using
|
|
335
|
+
## Using webhooks directly
|
|
336
336
|
|
|
337
337
|
For simpler cases where you don't need type-safe validation or programmatic resumption, you can use [`createWebhook()`](/docs/api-reference/workflow/create-webhook) directly. This generates a unique URL that can be called to resume the workflow:
|
|
338
338
|
|
|
@@ -367,7 +367,7 @@ The webhook URL can be called directly with a POST request containing the approv
|
|
|
367
367
|
- Payment provider callbacks
|
|
368
368
|
- Email-based approval links
|
|
369
369
|
|
|
370
|
-
## Related
|
|
370
|
+
## Related documentation
|
|
371
371
|
|
|
372
372
|
- [Hooks & Webhooks](/docs/foundations/hooks) - Complete guide to hooks and webhooks
|
|
373
373
|
- [`createWebhook()` API Reference](/docs/api-reference/workflow/create-webhook) - Webhook configuration options
|
package/docs/ai/index.mdx
CHANGED
|
@@ -3,6 +3,7 @@ title: Building Durable AI Agents
|
|
|
3
3
|
description: Build AI agents that survive crashes, scale across requests, and maintain state with durable LLM tool-call loops.
|
|
4
4
|
type: overview
|
|
5
5
|
summary: Convert a basic AI chat app into a durable, resumable agent using Workflow SDK.
|
|
6
|
+
manualCards: true
|
|
6
7
|
related:
|
|
7
8
|
- /docs/foundations/workflows-and-steps
|
|
8
9
|
- /docs/foundations/streaming
|
|
@@ -21,7 +22,7 @@ Workflow SDK makes your agents production-ready, by turning them into durable, r
|
|
|
21
22
|
|
|
22
23
|
This guide walks you through converting a basic AI chat app into a durable AI agent using Workflow SDK.
|
|
23
24
|
|
|
24
|
-
## Why
|
|
25
|
+
## Why durable agents?
|
|
25
26
|
|
|
26
27
|
Aside from the usual challenges of getting your long-running tasks to be production-ready, building mature AI agents typically requires solving several **additional challenges**:
|
|
27
28
|
|
|
@@ -30,22 +31,22 @@ Aside from the usual challenges of getting your long-running tasks to be product
|
|
|
30
31
|
- **Resumability**: Resuming streams requires not just storing your messages, but also storing streams, and piping them across services.
|
|
31
32
|
- **Human-in-the-loop**: Your client, API, and async job orchestration need to work together to create, track, route to, and display human approval requests, or similar webhook operations.
|
|
32
33
|
|
|
33
|
-
Workflow SDK provides all of these capabilities
|
|
34
|
+
Workflow SDK provides all of these capabilities without additional infrastructure. Your agent becomes a workflow, your tools become steps, and the framework handles interplay with your existing infrastructure.
|
|
34
35
|
|
|
35
|
-
## Getting
|
|
36
|
+
## Getting started
|
|
36
37
|
|
|
37
38
|
To make an Agent durable, we first need an Agent, which we'll be setting up here. If you already have an app you'd like to follow along with, you can skip this section.
|
|
38
39
|
|
|
39
|
-
For our example, we'll need an app with a
|
|
40
|
+
For our example, we'll need an app with a basic chat interface and an API route calling an LLM, so that we can add Workflow SDK to it. We'll use the [Flight Booking Agent](https://github.com/vercel/workflow-examples/tree/main/flight-booking-app) example as a starting point, which comes with a chat interface built using Next.js, AI SDK, and Shadcn UI.
|
|
40
41
|
|
|
41
42
|
<Steps>
|
|
42
43
|
|
|
43
44
|
<Step>
|
|
44
45
|
### Clone example app
|
|
45
46
|
|
|
46
|
-
We'll need an app with a
|
|
47
|
+
We'll need an app with a basic chat interface and an API route calling an LLM, so that we can add Workflow SDK to it. For the follow-along steps, we'll use the [Flight Booking Agent](https://github.com/vercel/workflow-examples/tree/main/flight-booking-app) example as a starting point, which comes with a chat interface built using Next.js, AI SDK, and Shadcn UI.
|
|
47
48
|
|
|
48
|
-
If you have your own project,
|
|
49
|
+
If you have your own project, skip this step and apply the changes in the following steps to your project.
|
|
49
50
|
|
|
50
51
|
```bash
|
|
51
52
|
git clone https://github.com/vercel/workflow-examples -b plain-ai-sdk
|
|
@@ -58,12 +59,12 @@ cd workflow-examples/flight-booking-app
|
|
|
58
59
|
|
|
59
60
|
### Set up API keys
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
To connect to an LLM, set up an API key. You can use Vercel Gateway, which works with all providers at zero markup, or configure a custom provider.
|
|
62
63
|
<Tabs items={['Gateway', 'Custom Provider']}>
|
|
63
64
|
|
|
64
65
|
<Tab value="Gateway">
|
|
65
66
|
|
|
66
|
-
Get a Gateway API key from the [Vercel Gateway](https://vercel.com/docs/gateway/
|
|
67
|
+
Get a Gateway API key from the [Vercel Gateway](https://vercel.com/docs/ai-gateway/authentication) page.
|
|
67
68
|
|
|
68
69
|
Then add it to your `.env.local` file:
|
|
69
70
|
|
|
@@ -92,7 +93,7 @@ Then modify your API endpoint to use the OpenAI provider:
|
|
|
92
93
|
{/* @skip-typecheck: incomplete code sample */}
|
|
93
94
|
```typescript title="app/api/chat/route.ts" lineNumbers
|
|
94
95
|
// ...
|
|
95
|
-
import { openai } from "@
|
|
96
|
+
import { openai } from "@ai-sdk/openai"; // [!code highlight]
|
|
96
97
|
|
|
97
98
|
export async function POST(req: Request) {
|
|
98
99
|
// ...
|
|
@@ -112,24 +113,25 @@ export async function POST(req: Request) {
|
|
|
112
113
|
|
|
113
114
|
### Get familiar with the code
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
Run the app with `npm run dev` and open [http://localhost:3000](http://localhost:3000) in your browser. You should see a basic chat interface to test.
|
|
116
117
|
|
|
117
|
-
The
|
|
118
|
+
The following sections break down the core code. You don't need to make changes yet.
|
|
118
119
|
|
|
119
120
|
<Tabs items={['API Route', 'Tools', 'Client']}>
|
|
120
121
|
|
|
121
122
|
<Tab value="API Route">
|
|
122
123
|
|
|
123
|
-
Our API route
|
|
124
|
+
Our API route calls [AI SDK's `ToolLoopAgent` class](https://ai-sdk.dev/docs/agents/overview), which encapsulates the LLM call, tool execution loop, and stopping conditions on top of [AI SDK's `streamText` function](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text#streamtext). This is also where we pass tools to the agent.
|
|
124
125
|
|
|
125
126
|
```typescript title="app/api/chat/route.ts" lineNumbers
|
|
126
|
-
import {
|
|
127
|
-
import type {
|
|
127
|
+
import { ToolLoopAgent } from "ai";
|
|
128
|
+
import type { UIMessage } from "ai";
|
|
129
|
+
import { convertToModelMessages, createUIMessageStreamResponse } from "ai";
|
|
128
130
|
|
|
129
131
|
export async function POST(req: Request) {
|
|
130
132
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
131
|
-
const agent = new
|
|
132
|
-
model:
|
|
133
|
+
const agent = new ToolLoopAgent({ // [!code highlight]
|
|
134
|
+
model: "bedrock/claude-4-5-haiku-20251001-v1",
|
|
133
135
|
instructions: FLIGHT_ASSISTANT_PROMPT,
|
|
134
136
|
tools: flightBookingTools,
|
|
135
137
|
});
|
|
@@ -168,7 +170,7 @@ async function searchFlights({ from, to, date }: { from: string; to: string; dat
|
|
|
168
170
|
|
|
169
171
|
<Tab value="Client">
|
|
170
172
|
|
|
171
|
-
Our `ChatPage` component
|
|
173
|
+
Our `ChatPage` component contains logic for displaying chat messages, but its core responsibility is managing input and output for the [`useChat` hook](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat#usechat) from AI SDK.
|
|
172
174
|
|
|
173
175
|
```typescript title="app/chat.tsx" lineNumbers
|
|
174
176
|
"use client";
|
|
@@ -226,12 +228,12 @@ Now that we have a basic agent using AI SDK, we can modify it to make it durable
|
|
|
226
228
|
<Steps>
|
|
227
229
|
<Step>
|
|
228
230
|
|
|
229
|
-
### Install
|
|
231
|
+
### Install dependencies
|
|
230
232
|
|
|
231
233
|
Add the Workflow SDK packages to your project:
|
|
232
234
|
|
|
233
235
|
```package-install
|
|
234
|
-
npm i workflow @workflow
|
|
236
|
+
npm i workflow @ai-sdk/workflow
|
|
235
237
|
```
|
|
236
238
|
|
|
237
239
|
and extend the Next.js config to transform your workflow code (see [Getting Started](/docs/getting-started/next) for more details).
|
|
@@ -251,26 +253,26 @@ export default withWorkflow(nextConfig);
|
|
|
251
253
|
|
|
252
254
|
<Step>
|
|
253
255
|
|
|
254
|
-
### Create a
|
|
256
|
+
### Create a workflow function
|
|
255
257
|
|
|
256
258
|
Move the agent logic into a separate function, which will serve as our workflow definition.
|
|
257
259
|
|
|
258
260
|
{/* @skip-typecheck: Shows two mutually exclusive model options */}
|
|
259
261
|
```typescript title="workflows/chat/workflow.ts" lineNumbers
|
|
260
|
-
import {
|
|
262
|
+
import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow"; // [!code highlight]
|
|
261
263
|
import { getWritable } from "workflow"; // [!code highlight]
|
|
262
264
|
import { tools } from "@/ai/tools";
|
|
263
|
-
import { openai } from "@
|
|
264
|
-
import
|
|
265
|
+
import { openai } from "@ai-sdk/openai";
|
|
266
|
+
import { convertToModelMessages, type UIMessage } from "ai";
|
|
265
267
|
|
|
266
|
-
export async function chatWorkflow(messages:
|
|
268
|
+
export async function chatWorkflow(messages: UIMessage[]) {
|
|
267
269
|
"use workflow"; // [!code highlight]
|
|
268
270
|
|
|
269
|
-
const writable = getWritable<
|
|
271
|
+
const writable = getWritable<ModelCallStreamPart>(); // [!code highlight]
|
|
270
272
|
|
|
271
|
-
const agent = new
|
|
273
|
+
const agent = new WorkflowAgent({ // [!code highlight]
|
|
272
274
|
|
|
273
|
-
// If using AI Gateway,
|
|
275
|
+
// If using AI Gateway, specify the model name as a string:
|
|
274
276
|
model: "bedrock/claude-4-5-haiku-20251001-v1", // [!code highlight]
|
|
275
277
|
|
|
276
278
|
// ELSE if using a custom provider, pass the provider call as an argument:
|
|
@@ -280,8 +282,10 @@ export async function chatWorkflow(messages: ModelMessage[]) {
|
|
|
280
282
|
tools: flightBookingTools,
|
|
281
283
|
});
|
|
282
284
|
|
|
285
|
+
const modelMessages = await convertToModelMessages(messages); // [!code highlight]
|
|
286
|
+
|
|
283
287
|
await agent.stream({ // [!code highlight]
|
|
284
|
-
messages,
|
|
288
|
+
messages: modelMessages,
|
|
285
289
|
writable,
|
|
286
290
|
});
|
|
287
291
|
}
|
|
@@ -290,29 +294,29 @@ export async function chatWorkflow(messages: ModelMessage[]) {
|
|
|
290
294
|
Key changes:
|
|
291
295
|
|
|
292
296
|
- Add the `"use workflow"` directive to mark our Agent as a workflow function
|
|
293
|
-
-
|
|
294
|
-
-
|
|
297
|
+
- Replace the in-memory agent with [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) from `@ai-sdk/workflow`. This runs the agent loop inside a workflow, persists state across step boundaries, and lets tool executions marked with `"use step"` retry automatically.
|
|
298
|
+
- Convert AI SDK `UIMessage` values to model messages inside the workflow before calling `agent.stream()`.
|
|
299
|
+
- Use [`getWritable()`](/docs/api-reference/workflow/get-writable) to get a stream for agent output. `WorkflowAgent` writes `ModelCallStreamPart` chunks to this persistent stream, and API endpoints can read from a run's stream at any time.
|
|
295
300
|
</Step>
|
|
296
301
|
|
|
297
302
|
<Step>
|
|
298
|
-
### Update the API
|
|
303
|
+
### Update the API route
|
|
299
304
|
|
|
300
305
|
Remove the agent call that we just extracted, and replace it with a call to `start()` to run the workflow:
|
|
301
306
|
|
|
302
307
|
```typescript title="app/api/chat/route.ts" lineNumbers
|
|
303
|
-
import
|
|
304
|
-
import {
|
|
308
|
+
import { createModelCallToUIChunkTransform } from "@ai-sdk/workflow";
|
|
309
|
+
import { createUIMessageStreamResponse, type UIMessage } from "ai";
|
|
305
310
|
import { start } from "workflow/api";
|
|
306
311
|
import { chatWorkflow } from "@/workflows/chat/workflow";
|
|
307
312
|
|
|
308
313
|
export async function POST(req: Request) {
|
|
309
314
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
310
|
-
const modelMessages = await convertToModelMessages(messages);
|
|
311
315
|
|
|
312
|
-
const run = await start(chatWorkflow, [
|
|
316
|
+
const run = await start(chatWorkflow, [messages]); // [!code highlight]
|
|
313
317
|
|
|
314
318
|
return createUIMessageStreamResponse({
|
|
315
|
-
stream: run.readable, // [!code highlight]
|
|
319
|
+
stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()), // [!code highlight]
|
|
316
320
|
});
|
|
317
321
|
}
|
|
318
322
|
```
|
|
@@ -320,12 +324,13 @@ export async function POST(req: Request) {
|
|
|
320
324
|
Key changes:
|
|
321
325
|
|
|
322
326
|
- Call `start()` to run the workflow function. This returns a `Run` object, which contains the run ID and the readable stream (see [Starting Workflows](/docs/foundations/starting-workflows) for more details on the `Run` object).
|
|
323
|
-
- Pass the `writable` to `agent.stream()` instead of returning a stream directly, ensuring all the Agent output is written to
|
|
327
|
+
- Pass the `writable` to `agent.stream()` instead of returning a stream directly, ensuring all the Agent output is written to the run's stream.
|
|
328
|
+
- Pipe the readable stream through `createModelCallToUIChunkTransform()` so the raw model-call chunks become AI SDK UI message chunks before they are returned to the client.
|
|
324
329
|
|
|
325
330
|
</Step>
|
|
326
331
|
|
|
327
332
|
<Step>
|
|
328
|
-
### Convert
|
|
333
|
+
### Convert tools to steps
|
|
329
334
|
|
|
330
335
|
Mark all tool definitions with `"use step"` to make them durable. This enables automatic retries and observability for each tool call:
|
|
331
336
|
|
|
@@ -377,14 +382,14 @@ export async function checkBaggageAllowance(
|
|
|
377
382
|
|
|
378
383
|
With `"use step"`:
|
|
379
384
|
|
|
380
|
-
- The tool execution runs
|
|
385
|
+
- The tool execution runs as a durable step with full Node.js access. The combined runtime may execute it inline in the flow request or resume it through the workflow queue, and can scale queued work with your workload.
|
|
381
386
|
- Failed tool calls are automatically retried (up to 3 times by default). See [Errors and Retries](/docs/foundations/errors-and-retries) for more details.
|
|
382
387
|
- Each tool execution appears as a discrete step in observability tools. See [Observability](/docs/observability) for more details.
|
|
383
388
|
</Step>
|
|
384
389
|
|
|
385
390
|
</Steps>
|
|
386
391
|
|
|
387
|
-
|
|
392
|
+
Your basic AI SDK agent is now durable. Run your development server and send a chat message. The agent should respond as before, with added durability and observability.
|
|
388
393
|
|
|
389
394
|
## Observability
|
|
390
395
|
|
|
@@ -396,9 +401,9 @@ npx workflow web
|
|
|
396
401
|
|
|
397
402
|
This opens a local dashboard showing all workflow runs and their status, as well as a trace viewer to inspect the workflow in detail, including retry attempts, and the data being passed between steps.
|
|
398
403
|
|
|
399
|
-
## Next
|
|
404
|
+
## Next steps
|
|
400
405
|
|
|
401
|
-
Now that you have a basic durable agent, it's
|
|
406
|
+
Now that you have a basic durable agent, it's only a short step to add these additional features:
|
|
402
407
|
|
|
403
408
|
<Cards>
|
|
404
409
|
<Card title="Streaming Updates from Tools" href="/docs/ai/streaming-updates-from-tools">
|
|
@@ -415,14 +420,14 @@ Now that you have a basic durable agent, it's a only a short step to add these a
|
|
|
415
420
|
</Card>
|
|
416
421
|
</Cards>
|
|
417
422
|
|
|
418
|
-
## Complete
|
|
423
|
+
## Complete example
|
|
419
424
|
|
|
420
425
|
A complete example that includes all of the above, plus all of the "next steps" features is available on the main branch of the [Flight Booking Agent](https://github.com/vercel/workflow-examples/tree/main/flight-booking-app) example.
|
|
421
426
|
|
|
422
|
-
## Related
|
|
427
|
+
## Related documentation
|
|
423
428
|
|
|
424
429
|
- [Tools](/docs/ai/defining-tools) - Patterns for defining tools for your agent
|
|
425
|
-
- [`
|
|
430
|
+
- [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - AI SDK API for durable, resumable agents
|
|
426
431
|
- [Workflows and Steps](/docs/foundations/workflows-and-steps) - Core concepts
|
|
427
432
|
- [Streaming](/docs/foundations/streaming) - In-depth streaming guide
|
|
428
433
|
- [Errors and Retries](/docs/foundations/errors-and-retries) - Error handling patterns
|
|
@@ -13,9 +13,9 @@ related:
|
|
|
13
13
|
|
|
14
14
|
When using [multi-turn workflows](/docs/ai/chat-session-modeling#multi-turn-workflows), messages typically arrive between agent turns. The workflow waits at a hook, receives a message, then starts a new turn. But sometimes you need to inject messages *during* an agent's turn, before tool calls complete or while the model is reasoning.
|
|
15
15
|
|
|
16
|
-
`
|
|
16
|
+
`WorkflowAgent`'s `prepareStep` callback enables this by running before each step in the agent loop, giving you a chance to inject queued messages into the conversation. `prepareStep` also allows you to modify the model choice and existing messages mid-turn, see AI SDK's [prepareStep callback](https://ai-sdk.dev/docs/agents/loop-control#prepare-step) for more details.
|
|
17
17
|
|
|
18
|
-
## When to
|
|
18
|
+
## When to use this
|
|
19
19
|
|
|
20
20
|
Message queueing is useful when:
|
|
21
21
|
|
|
@@ -24,10 +24,10 @@ Message queueing is useful when:
|
|
|
24
24
|
- You want messages to influence the agent's next step rather than waiting for the current turn to complete
|
|
25
25
|
|
|
26
26
|
<Callout type="info">
|
|
27
|
-
If you
|
|
27
|
+
If you need basic multi-turn conversations where messages arrive between turns, see [Chat Session Modeling](/docs/ai/chat-session-modeling). This guide covers the more advanced case of injecting messages *during* turns.
|
|
28
28
|
</Callout>
|
|
29
29
|
|
|
30
|
-
## The `prepareStep`
|
|
30
|
+
## The `prepareStep` callback
|
|
31
31
|
|
|
32
32
|
The `prepareStep` callback runs before each step in the agent loop. It receives the current state and can modify the messages sent to the model:
|
|
33
33
|
|
|
@@ -47,25 +47,25 @@ interface PrepareStepResult {
|
|
|
47
47
|
}
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
## Injecting
|
|
50
|
+
## Injecting queued messages
|
|
51
51
|
|
|
52
52
|
Once you have a [multi-turn workflow](/docs/ai/chat-session-modeling#multi-turn-workflows), you can combine a message queue with `prepareStep` to inject messages that arrive during processing:
|
|
53
53
|
|
|
54
54
|
```typescript title="workflows/chat/index.ts" lineNumbers
|
|
55
|
-
import {
|
|
55
|
+
import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow";
|
|
56
56
|
import { getWritable, getWorkflowMetadata } from "workflow";
|
|
57
57
|
import { chatMessageHook } from "./hooks/chat-message";
|
|
58
58
|
import { flightBookingTools, FLIGHT_ASSISTANT_PROMPT } from "./steps/tools";
|
|
59
|
-
import type {
|
|
59
|
+
import type { ModelMessage } from "ai";
|
|
60
60
|
|
|
61
61
|
export async function chat(initialMessages: ModelMessage[]) {
|
|
62
62
|
"use workflow";
|
|
63
63
|
|
|
64
64
|
const { workflowRunId: runId } = getWorkflowMetadata();
|
|
65
|
-
const writable = getWritable<
|
|
65
|
+
const writable = getWritable<ModelCallStreamPart>();
|
|
66
66
|
const messageQueue: Array<{ role: "user"; content: string }> = []; // [!code highlight]
|
|
67
67
|
|
|
68
|
-
const agent = new
|
|
68
|
+
const agent = new WorkflowAgent({
|
|
69
69
|
model: "bedrock/claude-haiku-4-5-20251001-v1",
|
|
70
70
|
instructions: FLIGHT_ASSISTANT_PROMPT,
|
|
71
71
|
tools: flightBookingTools,
|
|
@@ -106,25 +106,25 @@ Messages sent via `chatMessageHook.resume()` accumulate in the queue and get inj
|
|
|
106
106
|
The `prepareStep` callback receives messages in `ModelMessage[]` format (with content arrays), which is the internal format used by the AI SDK.
|
|
107
107
|
</Callout>
|
|
108
108
|
|
|
109
|
-
## Combining with
|
|
109
|
+
## Combining with multi-turn sessions
|
|
110
110
|
|
|
111
111
|
You can also combine message queueing with the standard multi-turn pattern:
|
|
112
112
|
|
|
113
113
|
```typescript title="workflows/chat/index.ts" lineNumbers
|
|
114
|
-
import {
|
|
114
|
+
import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow";
|
|
115
115
|
import { getWritable, getWorkflowMetadata } from "workflow";
|
|
116
116
|
import { chatMessageHook } from "./hooks/chat-message";
|
|
117
|
-
import type {
|
|
117
|
+
import type { ModelMessage } from "ai";
|
|
118
118
|
|
|
119
119
|
export async function chat(initialMessages: ModelMessage[]) {
|
|
120
120
|
"use workflow";
|
|
121
121
|
|
|
122
122
|
const { workflowRunId: runId } = getWorkflowMetadata();
|
|
123
|
-
const writable = getWritable<
|
|
123
|
+
const writable = getWritable<ModelCallStreamPart>();
|
|
124
124
|
const messages: ModelMessage[] = [...initialMessages];
|
|
125
125
|
const messageQueue: Array<{ role: "user"; content: string }> = [];
|
|
126
126
|
|
|
127
|
-
const agent = new
|
|
127
|
+
const agent = new WorkflowAgent({ /* ... */ });
|
|
128
128
|
const hook = chatMessageHook.create({ token: runId });
|
|
129
129
|
|
|
130
130
|
while (true) {
|
|
@@ -169,9 +169,9 @@ export async function chat(initialMessages: ModelMessage[]) {
|
|
|
169
169
|
}
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
-
## Related
|
|
172
|
+
## Related documentation
|
|
173
173
|
|
|
174
174
|
- [Chat Session Modeling](/docs/ai/chat-session-modeling) - Single-turn vs multi-turn patterns
|
|
175
175
|
- [Building Durable AI Agents](/docs/ai) - Complete guide to creating durable agents
|
|
176
|
-
- [`
|
|
176
|
+
- [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - AI SDK API for durable, resumable agents
|
|
177
177
|
- [`defineHook()` API Reference](/docs/api-reference/workflow/define-hook) - Hook configuration options
|