workflow 5.0.0-beta.9 → 5.0.1
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 +3 -1
- package/dist/api-workflow.d.ts.map +1 -1
- package/dist/api-workflow.js +2 -1
- package/dist/api.d.ts +5 -4
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +6 -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 +4 -4
- package/dist/internal/builtins.js +6 -6
- 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/runtime.d.ts +2 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +4 -1
- package/docs/advanced/dynamic-workflows.mdx +227 -0
- package/docs/advanced/index.mdx +13 -0
- package/docs/advanced/meta.json +5 -0
- package/docs/ai/chat-session-modeling.mdx +176 -422
- package/docs/ai/defining-tools.mdx +6 -7
- package/docs/ai/human-in-the-loop.mdx +16 -12
- package/docs/ai/index.mdx +67 -72
- package/docs/ai/message-queueing.mdx +71 -110
- 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 +25 -1
- package/docs/api-reference/meta.json +8 -0
- package/docs/api-reference/vitest/index.mdx +68 -15
- package/docs/api-reference/workflow/create-hook.mdx +170 -10
- package/docs/api-reference/workflow/create-webhook.mdx +16 -15
- package/docs/api-reference/workflow/define-hook.mdx +41 -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 +3 -3
- package/docs/api-reference/workflow/retryable-error.mdx +1 -1
- package/docs/api-reference/workflow/set-attributes.mdx +63 -0
- package/docs/api-reference/workflow/sleep.mdx +4 -4
- package/docs/api-reference/workflow-ai/durable-agent.mdx +63 -101
- package/docs/api-reference/workflow-ai/index.mdx +5 -5
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +67 -24
- package/docs/api-reference/workflow-api/get-hook-by-token.mdx +37 -15
- package/docs/api-reference/workflow-api/get-run.mdx +43 -8
- package/docs/api-reference/workflow-api/index.mdx +8 -9
- package/docs/api-reference/workflow-api/register-lifecycle-hooks.mdx +87 -0
- package/docs/api-reference/workflow-api/resume-hook.mdx +77 -12
- package/docs/api-reference/workflow-api/resume-webhook.mdx +15 -9
- package/docs/api-reference/workflow-api/start.mdx +107 -12
- 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-force-claimed-error.mdx +70 -0
- package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
- package/docs/api-reference/workflow-errors/index.mdx +91 -0
- package/docs/api-reference/workflow-errors/meta.json +7 -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 +13 -6
- package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +12 -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 +19 -11
- package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +37 -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 +46 -0
- package/docs/api-reference/workflow-nest/workflow-module.mdx +134 -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 +51 -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 +133 -35
- 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 +53 -41
- 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 +89 -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 +424 -0
- package/docs/configuration/worlds.mdx +341 -0
- package/docs/cookbook/advanced/child-workflows.mdx +33 -25
- package/docs/cookbook/advanced/publishing-libraries.mdx +65 -56
- package/docs/cookbook/advanced/serializable-steps.mdx +48 -68
- package/docs/cookbook/advanced/upgrading-workflows.mdx +35 -31
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +78 -60
- package/docs/cookbook/agent-patterns/durable-agent.mdx +23 -135
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +180 -195
- package/docs/cookbook/common-patterns/batching.mdx +20 -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 +30 -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 +12 -7
- package/docs/cookbook/common-patterns/workflow-composition.mdx +27 -17
- package/docs/cookbook/index.mdx +22 -22
- package/docs/cookbook/integrations/ai-sdk.mdx +63 -48
- package/docs/cookbook/integrations/chat-sdk.mdx +46 -33
- package/docs/cookbook/integrations/sandbox.mdx +58 -45
- package/docs/deploying.mdx +106 -0
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +16 -12
- package/docs/errors/corrupted-event-log.mdx +39 -18
- package/docs/errors/deployment-mismatch.mdx +71 -0
- package/docs/errors/fetch-in-workflow.mdx +15 -14
- package/docs/errors/hook-conflict.mdx +38 -11
- package/docs/errors/hook-force-claimed.mdx +96 -0
- package/docs/errors/index.mdx +24 -37
- 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 +54 -11
- package/docs/foundations/hooks.mdx +187 -36
- package/docs/foundations/idempotency.mdx +267 -12
- package/docs/foundations/index.mdx +1 -26
- package/docs/foundations/serialization.mdx +22 -22
- package/docs/foundations/starting-workflows.mdx +104 -30
- package/docs/foundations/streaming.mdx +108 -60
- package/docs/foundations/versioning.mdx +4 -4
- package/docs/foundations/workflows-and-steps.mdx +10 -10
- 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 +264 -21
- package/docs/getting-started/next.mdx +18 -14
- package/docs/getting-started/nitro.mdx +22 -18
- package/docs/getting-started/nuxt.mdx +15 -11
- package/docs/getting-started/python.mdx +190 -41
- 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 +82 -66
- package/docs/how-it-works/encryption.mdx +30 -26
- package/docs/how-it-works/event-sourcing.mdx +132 -35
- 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 +4 -2
- package/docs/observability/attributes.mdx +91 -21
- package/docs/observability/index.mdx +29 -15
- package/docs/observability/lifecycle-hooks.mdx +95 -0
- package/docs/observability/meta.json +1 -1
- package/docs/observability/retention.mdx +95 -0
- package/docs/observability/tracing.mdx +124 -0
- package/docs/testing/index.mdx +118 -38
- package/docs/testing/server-based.mdx +10 -10
- package/docs/whats-new.mdx +196 -0
- package/docs/worlds/building-a-world.mdx +600 -0
- package/docs/worlds/local.mdx +129 -0
- package/docs/worlds/meta.json +10 -0
- package/docs/worlds/postgres.mdx +428 -0
- package/docs/worlds/upgrading-to-v5.mdx +183 -0
- package/docs/worlds/vercel.mdx +389 -0
- package/package.json +17 -14
- package/docs/api-reference/workflow/experimental-set-attributes.mdx +0 -63
- 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 -181
- 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 -358
- package/docs/migration-guides/migrating-from-inngest.mdx +0 -304
- package/docs/migration-guides/migrating-from-temporal.mdx +0 -313
- package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -328
|
@@ -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
|
|
|
@@ -154,11 +154,15 @@ export async function POST(request: Request) {
|
|
|
154
154
|
}
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
<Callout type="warn">
|
|
158
|
+
This route resumes whichever hook owns `toolCallId`, so anyone who learns the ID can submit a decision. In production, authenticate the request and check that the signed-in user may approve this booking before calling `resume()`. See [Hook and webhook security](/docs/foundations/hooks#security).
|
|
159
|
+
</Callout>
|
|
160
|
+
|
|
157
161
|
</Step>
|
|
158
162
|
|
|
159
163
|
<Step>
|
|
160
164
|
|
|
161
|
-
### Create the
|
|
165
|
+
### Create the approval component
|
|
162
166
|
|
|
163
167
|
Build a new component that reacts to the tool call data, and allows the user to approve or reject the booking:
|
|
164
168
|
|
|
@@ -253,7 +257,7 @@ export function BookingApproval({ toolCallId, input, output }: BookingApprovalPr
|
|
|
253
257
|
|
|
254
258
|
<Step>
|
|
255
259
|
|
|
256
|
-
### Show the
|
|
260
|
+
### Show the tool status in the UI
|
|
257
261
|
|
|
258
262
|
Use the component we just created to render the tool call and approval controls in your chat interface:
|
|
259
263
|
|
|
@@ -332,9 +336,9 @@ export default function ChatPage() {
|
|
|
332
336
|
|
|
333
337
|
</Steps>
|
|
334
338
|
|
|
335
|
-
## Using
|
|
339
|
+
## Using webhooks directly
|
|
336
340
|
|
|
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
|
|
341
|
+
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. Anyone with the URL can resume it, so avoid this for approvals that need to know who approved, unless you use the incoming payload for authorization. See [Hook and webhook security](/docs/foundations/hooks#security).
|
|
338
342
|
|
|
339
343
|
```typescript title="workflows/chat/steps/tools.ts" lineNumbers
|
|
340
344
|
import { createWebhook } from "workflow";
|
|
@@ -367,7 +371,7 @@ The webhook URL can be called directly with a POST request containing the approv
|
|
|
367
371
|
- Payment provider callbacks
|
|
368
372
|
- Email-based approval links
|
|
369
373
|
|
|
370
|
-
## Related
|
|
374
|
+
## Related documentation
|
|
371
375
|
|
|
372
376
|
- [Hooks & Webhooks](/docs/foundations/hooks) - Complete guide to hooks and webhooks
|
|
373
377
|
- [`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
|
|
@@ -56,55 +57,49 @@ cd workflow-examples/flight-booking-app
|
|
|
56
57
|
|
|
57
58
|
<Step>
|
|
58
59
|
|
|
59
|
-
###
|
|
60
|
+
### Configure model access
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
<Tabs items={['Gateway', 'Custom Provider']}>
|
|
62
|
+
<Tabs items={['AI Gateway', 'Provider package']}>
|
|
63
63
|
|
|
64
|
-
<Tab value="Gateway">
|
|
64
|
+
<Tab value="AI Gateway">
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
AI SDK uses [Vercel AI Gateway](https://vercel.com/docs/ai-gateway) as its default global provider, so plain `"provider/model"` strings need no provider-specific package. Vercel deployments authenticate with OIDC automatically. For local development, link the project and pull a short-lived OIDC token:
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
GATEWAY_API_KEY=...
|
|
68
|
+
```bash
|
|
69
|
+
vercel link
|
|
70
|
+
vercel env pull .env.local
|
|
72
71
|
```
|
|
73
72
|
|
|
73
|
+
You can alternatively set `AI_GATEWAY_API_KEY` from the [AI Gateway authentication](https://vercel.com/docs/ai-gateway/authentication) page.
|
|
74
|
+
|
|
74
75
|
</Tab>
|
|
75
76
|
|
|
76
|
-
<Tab value="
|
|
77
|
+
<Tab value="Provider package">
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
`WorkflowAgent` accepts any AI SDK provider. To use OpenAI, install its provider package:
|
|
79
80
|
|
|
80
81
|
```package-install
|
|
81
82
|
npm i @ai-sdk/openai
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
Set
|
|
85
|
+
Set the provider's API key:
|
|
85
86
|
|
|
86
87
|
```bash title=".env.local" lineNumbers
|
|
87
88
|
OPENAI_API_KEY=...
|
|
88
89
|
```
|
|
89
90
|
|
|
90
|
-
Then
|
|
91
|
+
Then construct the model with the provider package:
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// ...
|
|
95
|
-
import { openai } from "@workflow/ai/openai"; // [!code highlight]
|
|
93
|
+
```typescript
|
|
94
|
+
import { openai } from "@ai-sdk/openai";
|
|
96
95
|
|
|
97
|
-
|
|
98
|
-
// ...
|
|
99
|
-
const agent = new Agent({
|
|
100
|
-
// This uses the OPENAI_API_KEY environment variable by default, but you
|
|
101
|
-
// can also pass { apiKey: string } as an option.
|
|
102
|
-
model: openai("gpt-5.1"), // [!code highlight]
|
|
103
|
-
// ...
|
|
104
|
-
});
|
|
96
|
+
const model = openai("gpt-5.6-sol");
|
|
105
97
|
```
|
|
106
98
|
|
|
99
|
+
See the [AI SDK provider guide](https://ai-sdk.dev/providers/ai-sdk-providers) for Anthropic, Google, Amazon Bedrock, and other providers.
|
|
100
|
+
|
|
107
101
|
</Tab>
|
|
102
|
+
|
|
108
103
|
</Tabs>
|
|
109
104
|
</Step>
|
|
110
105
|
|
|
@@ -112,15 +107,15 @@ export async function POST(req: Request) {
|
|
|
112
107
|
|
|
113
108
|
### Get familiar with the code
|
|
114
109
|
|
|
115
|
-
|
|
110
|
+
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
111
|
|
|
117
|
-
The
|
|
112
|
+
The following sections break down the core code. You don't need to make changes yet.
|
|
118
113
|
|
|
119
114
|
<Tabs items={['API Route', 'Tools', 'Client']}>
|
|
120
115
|
|
|
121
116
|
<Tab value="API Route">
|
|
122
117
|
|
|
123
|
-
Our API route
|
|
118
|
+
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
119
|
|
|
125
120
|
```typescript title="app/api/chat/route.ts" lineNumbers
|
|
126
121
|
import { ToolLoopAgent } from "ai";
|
|
@@ -130,7 +125,7 @@ import { convertToModelMessages, createUIMessageStreamResponse } from "ai";
|
|
|
130
125
|
export async function POST(req: Request) {
|
|
131
126
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
132
127
|
const agent = new ToolLoopAgent({ // [!code highlight]
|
|
133
|
-
model: "
|
|
128
|
+
model: "spacexai/grok-4.6",
|
|
134
129
|
instructions: FLIGHT_ASSISTANT_PROMPT,
|
|
135
130
|
tools: flightBookingTools,
|
|
136
131
|
});
|
|
@@ -169,7 +164,7 @@ async function searchFlights({ from, to, date }: { from: string; to: string; dat
|
|
|
169
164
|
|
|
170
165
|
<Tab value="Client">
|
|
171
166
|
|
|
172
|
-
Our `ChatPage` component
|
|
167
|
+
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.
|
|
173
168
|
|
|
174
169
|
```typescript title="app/chat.tsx" lineNumbers
|
|
175
170
|
"use client";
|
|
@@ -227,12 +222,12 @@ Now that we have a basic agent using AI SDK, we can modify it to make it durable
|
|
|
227
222
|
<Steps>
|
|
228
223
|
<Step>
|
|
229
224
|
|
|
230
|
-
### Install
|
|
225
|
+
### Install dependencies
|
|
231
226
|
|
|
232
227
|
Add the Workflow SDK packages to your project:
|
|
233
228
|
|
|
234
229
|
```package-install
|
|
235
|
-
npm i workflow @workflow
|
|
230
|
+
npm i workflow @ai-sdk/workflow
|
|
236
231
|
```
|
|
237
232
|
|
|
238
233
|
and extend the Next.js config to transform your workflow code (see [Getting Started](/docs/getting-started/next) for more details).
|
|
@@ -252,68 +247,67 @@ export default withWorkflow(nextConfig);
|
|
|
252
247
|
|
|
253
248
|
<Step>
|
|
254
249
|
|
|
255
|
-
### Create a
|
|
250
|
+
### Create a workflow function
|
|
256
251
|
|
|
257
252
|
Move the agent logic into a separate function, which will serve as our workflow definition.
|
|
258
253
|
|
|
259
|
-
{/* @skip-typecheck: Shows two mutually exclusive model options */}
|
|
260
254
|
```typescript title="workflows/chat/workflow.ts" lineNumbers
|
|
261
|
-
import {
|
|
255
|
+
import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow"; // [!code highlight]
|
|
262
256
|
import { getWritable } from "workflow"; // [!code highlight]
|
|
263
|
-
import {
|
|
264
|
-
import {
|
|
265
|
-
import type { ModelMessage, UIMessageChunk } from "ai";
|
|
257
|
+
import { flightBookingTools, FLIGHT_ASSISTANT_PROMPT } from "@/ai/tools";
|
|
258
|
+
import { convertToModelMessages, type UIMessage } from "ai";
|
|
266
259
|
|
|
267
|
-
export async function chatWorkflow(messages:
|
|
260
|
+
export async function chatWorkflow(messages: UIMessage[]) {
|
|
268
261
|
"use workflow"; // [!code highlight]
|
|
269
262
|
|
|
270
|
-
const writable = getWritable<
|
|
271
|
-
|
|
272
|
-
const agent = new DurableAgent({ // [!code highlight]
|
|
273
|
-
|
|
274
|
-
// If using AI Gateway, just specify the model name as a string:
|
|
275
|
-
model: "bedrock/claude-4-5-haiku-20251001-v1", // [!code highlight]
|
|
276
|
-
|
|
277
|
-
// ELSE if using a custom provider, pass the provider call as an argument:
|
|
278
|
-
model: openai("gpt-5.1"), // [!code highlight]
|
|
263
|
+
const writable = getWritable<ModelCallStreamPart>(); // [!code highlight]
|
|
279
264
|
|
|
265
|
+
const agent = new WorkflowAgent({ // [!code highlight]
|
|
266
|
+
// Plain model strings use Vercel AI Gateway.
|
|
267
|
+
model: "spacexai/grok-4.6", // [!code highlight]
|
|
280
268
|
instructions: FLIGHT_ASSISTANT_PROMPT,
|
|
281
269
|
tools: flightBookingTools,
|
|
282
270
|
});
|
|
283
271
|
|
|
272
|
+
const modelMessages = await convertToModelMessages(messages); // [!code highlight]
|
|
273
|
+
|
|
284
274
|
await agent.stream({ // [!code highlight]
|
|
285
|
-
messages,
|
|
275
|
+
messages: modelMessages,
|
|
286
276
|
writable,
|
|
287
277
|
});
|
|
288
278
|
}
|
|
289
279
|
```
|
|
290
280
|
|
|
281
|
+
<Callout type="info">
|
|
282
|
+
`WorkflowAgent` accepts any AI SDK provider. Import the provider and pass its model instance, for example `model: openai("gpt-5.6-sol")` from `@ai-sdk/openai`. The rest of the integration is unchanged.
|
|
283
|
+
</Callout>
|
|
284
|
+
|
|
291
285
|
Key changes:
|
|
292
286
|
|
|
293
287
|
- Add the `"use workflow"` directive to mark our Agent as a workflow function
|
|
294
|
-
-
|
|
295
|
-
-
|
|
288
|
+
- 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.
|
|
289
|
+
- Convert AI SDK `UIMessage` values to model messages inside the workflow before calling `agent.stream()`.
|
|
290
|
+
- 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.
|
|
296
291
|
</Step>
|
|
297
292
|
|
|
298
293
|
<Step>
|
|
299
|
-
### Update the API
|
|
294
|
+
### Update the API route
|
|
300
295
|
|
|
301
296
|
Remove the agent call that we just extracted, and replace it with a call to `start()` to run the workflow:
|
|
302
297
|
|
|
303
298
|
```typescript title="app/api/chat/route.ts" lineNumbers
|
|
304
|
-
import
|
|
305
|
-
import {
|
|
299
|
+
import { createModelCallToUIChunkTransform } from "@ai-sdk/workflow";
|
|
300
|
+
import { createUIMessageStreamResponse, type UIMessage } from "ai";
|
|
306
301
|
import { start } from "workflow/api";
|
|
307
302
|
import { chatWorkflow } from "@/workflows/chat/workflow";
|
|
308
303
|
|
|
309
304
|
export async function POST(req: Request) {
|
|
310
305
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
311
|
-
const modelMessages = await convertToModelMessages(messages);
|
|
312
306
|
|
|
313
|
-
const run = await start(chatWorkflow, [
|
|
307
|
+
const run = await start(chatWorkflow, [messages]); // [!code highlight]
|
|
314
308
|
|
|
315
309
|
return createUIMessageStreamResponse({
|
|
316
|
-
stream: run.readable, // [!code highlight]
|
|
310
|
+
stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()), // [!code highlight]
|
|
317
311
|
});
|
|
318
312
|
}
|
|
319
313
|
```
|
|
@@ -321,12 +315,13 @@ export async function POST(req: Request) {
|
|
|
321
315
|
Key changes:
|
|
322
316
|
|
|
323
317
|
- 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).
|
|
324
|
-
- Pass the `writable` to `agent.stream()` instead of returning a stream directly, ensuring all the Agent output is written to
|
|
318
|
+
- Pass the `writable` to `agent.stream()` instead of returning a stream directly, ensuring all the Agent output is written to the run's stream.
|
|
319
|
+
- 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.
|
|
325
320
|
|
|
326
321
|
</Step>
|
|
327
322
|
|
|
328
323
|
<Step>
|
|
329
|
-
### Convert
|
|
324
|
+
### Convert tools to steps
|
|
330
325
|
|
|
331
326
|
Mark all tool definitions with `"use step"` to make them durable. This enables automatic retries and observability for each tool call:
|
|
332
327
|
|
|
@@ -378,14 +373,14 @@ export async function checkBaggageAllowance(
|
|
|
378
373
|
|
|
379
374
|
With `"use step"`:
|
|
380
375
|
|
|
381
|
-
- The tool execution runs
|
|
376
|
+
- 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.
|
|
382
377
|
- Failed tool calls are automatically retried (up to 3 times by default). See [Errors and Retries](/docs/foundations/errors-and-retries) for more details.
|
|
383
378
|
- Each tool execution appears as a discrete step in observability tools. See [Observability](/docs/observability) for more details.
|
|
384
379
|
</Step>
|
|
385
380
|
|
|
386
381
|
</Steps>
|
|
387
382
|
|
|
388
|
-
|
|
383
|
+
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.
|
|
389
384
|
|
|
390
385
|
## Observability
|
|
391
386
|
|
|
@@ -397,9 +392,9 @@ npx workflow web
|
|
|
397
392
|
|
|
398
393
|
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.
|
|
399
394
|
|
|
400
|
-
## Next
|
|
395
|
+
## Next steps
|
|
401
396
|
|
|
402
|
-
Now that you have a basic durable agent, it's
|
|
397
|
+
Now that you have a basic durable agent, it's only a short step to add these additional features:
|
|
403
398
|
|
|
404
399
|
<Cards>
|
|
405
400
|
<Card title="Streaming Updates from Tools" href="/docs/ai/streaming-updates-from-tools">
|
|
@@ -416,14 +411,14 @@ Now that you have a basic durable agent, it's a only a short step to add these a
|
|
|
416
411
|
</Card>
|
|
417
412
|
</Cards>
|
|
418
413
|
|
|
419
|
-
## Complete
|
|
414
|
+
## Complete example
|
|
420
415
|
|
|
421
416
|
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.
|
|
422
417
|
|
|
423
|
-
## Related
|
|
418
|
+
## Related documentation
|
|
424
419
|
|
|
425
420
|
- [Tools](/docs/ai/defining-tools) - Patterns for defining tools for your agent
|
|
426
|
-
- [`
|
|
421
|
+
- [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - AI SDK API for durable, resumable agents
|
|
427
422
|
- [Workflows and Steps](/docs/foundations/workflows-and-steps) - Core concepts
|
|
428
423
|
- [Streaming](/docs/foundations/streaming) - In-depth streaming guide
|
|
429
424
|
- [Errors and Retries](/docs/foundations/errors-and-retries) - Error handling patterns
|