workflow 5.0.0-beta.4 → 5.0.0-beta.41

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.
Files changed (227) hide show
  1. package/README.md +63 -20
  2. package/dist/api-workflow.d.ts +1 -1
  3. package/dist/api-workflow.d.ts.map +1 -1
  4. package/dist/api-workflow.js +1 -1
  5. package/dist/api.d.ts +5 -1
  6. package/dist/api.d.ts.map +1 -1
  7. package/dist/api.js +12 -2
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +6 -1
  11. package/dist/internal/builtins.d.ts +17 -0
  12. package/dist/internal/builtins.d.ts.map +1 -1
  13. package/dist/internal/builtins.js +65 -1
  14. package/dist/internal/errors.d.ts +1 -1
  15. package/dist/internal/errors.d.ts.map +1 -1
  16. package/dist/internal/errors.js +2 -2
  17. package/dist/nest-builder.d.ts +2 -0
  18. package/dist/nest-builder.d.ts.map +1 -0
  19. package/dist/nest-builder.js +2 -0
  20. package/dist/nest-vercel-builder.d.ts +2 -0
  21. package/dist/nest-vercel-builder.d.ts.map +1 -0
  22. package/dist/nest-vercel-builder.js +2 -0
  23. package/dist/observability.d.ts +1 -1
  24. package/dist/observability.js +2 -2
  25. package/dist/runtime.d.ts +2 -1
  26. package/dist/runtime.d.ts.map +1 -1
  27. package/dist/runtime.js +5 -2
  28. package/docs/ai/chat-session-modeling.mdx +7 -3
  29. package/docs/ai/defining-tools.mdx +2 -2
  30. package/docs/ai/index.mdx +30 -25
  31. package/docs/ai/message-queueing.mdx +10 -10
  32. package/docs/ai/resumable-streams.mdx +9 -1
  33. package/docs/api-reference/index.mdx +24 -0
  34. package/docs/api-reference/meta.json +8 -0
  35. package/docs/api-reference/vitest/index.mdx +28 -7
  36. package/docs/api-reference/workflow/create-hook.mdx +79 -0
  37. package/docs/api-reference/workflow/create-webhook.mdx +1 -0
  38. package/docs/api-reference/workflow/define-hook.mdx +26 -24
  39. package/docs/api-reference/workflow/fatal-error.mdx +29 -7
  40. package/docs/api-reference/workflow/fetch.mdx +8 -4
  41. package/docs/api-reference/workflow/index.mdx +3 -0
  42. package/docs/api-reference/workflow/set-attributes.mdx +61 -0
  43. package/docs/api-reference/workflow/sleep.mdx +1 -1
  44. package/docs/api-reference/workflow-ai/durable-agent.mdx +7 -45
  45. package/docs/api-reference/workflow-ai/index.mdx +2 -2
  46. package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +44 -1
  47. package/docs/api-reference/workflow-api/get-hook-by-token.mdx +9 -0
  48. package/docs/api-reference/workflow-api/get-run.mdx +25 -0
  49. package/docs/api-reference/workflow-api/index.mdx +6 -8
  50. package/docs/api-reference/workflow-api/resume-hook.mdx +60 -1
  51. package/docs/api-reference/workflow-api/resume-webhook.mdx +6 -4
  52. package/docs/api-reference/workflow-api/start.mdx +39 -6
  53. package/docs/api-reference/workflow-astro/index.mdx +18 -0
  54. package/docs/api-reference/workflow-astro/meta.json +4 -0
  55. package/docs/api-reference/workflow-astro/workflow.mdx +45 -0
  56. package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
  57. package/docs/api-reference/workflow-errors/index.mdx +88 -0
  58. package/docs/api-reference/workflow-errors/meta.json +6 -0
  59. package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +68 -0
  60. package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
  61. package/docs/api-reference/workflow-errors/workflow-error.mdx +52 -0
  62. package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +16 -6
  63. package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
  64. package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
  65. package/docs/api-reference/workflow-globals.mdx +4 -1
  66. package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
  67. package/docs/api-reference/workflow-nest/index.mdx +31 -0
  68. package/docs/api-reference/workflow-nest/meta.json +9 -0
  69. package/docs/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
  70. package/docs/api-reference/workflow-nest/workflow-controller.mdx +40 -0
  71. package/docs/api-reference/workflow-nest/workflow-module.mdx +74 -0
  72. package/docs/api-reference/workflow-next/with-workflow.mdx +56 -2
  73. package/docs/api-reference/workflow-nitro/index.mdx +60 -0
  74. package/docs/api-reference/workflow-nuxt/index.mdx +48 -0
  75. package/docs/api-reference/workflow-observability/hydrate-data.mdx +35 -0
  76. package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
  77. package/docs/api-reference/workflow-observability/index.mdx +64 -0
  78. package/docs/api-reference/workflow-observability/meta.json +11 -0
  79. package/docs/api-reference/workflow-observability/observability-revivers.mdx +50 -0
  80. package/docs/api-reference/workflow-observability/parse-class-name.mdx +41 -0
  81. package/docs/api-reference/workflow-observability/parse-step-name.mdx +40 -0
  82. package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
  83. package/docs/api-reference/workflow-runtime/create-world.mdx +39 -0
  84. package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
  85. package/docs/api-reference/{workflow-api → workflow-runtime}/get-world.mdx +7 -10
  86. package/docs/api-reference/workflow-runtime/health-check.mdx +50 -0
  87. package/docs/api-reference/workflow-runtime/index.mdx +43 -0
  88. package/docs/api-reference/workflow-runtime/meta.json +12 -0
  89. package/docs/api-reference/workflow-runtime/set-world.mdx +49 -0
  90. package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +42 -0
  91. package/docs/api-reference/workflow-runtime/world/analytics.mdx +138 -0
  92. package/docs/api-reference/{workflow-api → workflow-runtime}/world/index.mdx +10 -10
  93. package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
  94. package/docs/api-reference/{workflow-api → workflow-runtime}/world/queue.mdx +8 -6
  95. package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +24 -7
  96. package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +2 -2
  97. package/docs/api-reference/workflow-serde/index.mdx +0 -1
  98. package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +1 -2
  99. package/docs/api-reference/workflow-serde/workflow-serialize.mdx +2 -2
  100. package/docs/api-reference/workflow-sveltekit/index.mdx +18 -0
  101. package/docs/api-reference/workflow-sveltekit/meta.json +4 -0
  102. package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
  103. package/docs/api-reference/workflow-vite/index.mdx +18 -0
  104. package/docs/api-reference/workflow-vite/meta.json +4 -0
  105. package/docs/api-reference/workflow-vite/workflow.mdx +48 -0
  106. package/docs/changelog/attributes-mvp.mdx +380 -0
  107. package/docs/changelog/eager-processing.mdx +269 -0
  108. package/docs/changelog/index.mdx +3 -1
  109. package/docs/changelog/lazy-event-creation.md +127 -0
  110. package/docs/changelog/meta.json +9 -1
  111. package/docs/changelog/resilient-resume.mdx +22 -0
  112. package/docs/changelog/resilient-start.mdx +31 -283
  113. package/docs/changelog/step-message-ownership.mdx +360 -0
  114. package/docs/changelog/turbo-mode.md +87 -0
  115. package/docs/comparisons/index.mdx +66 -0
  116. package/docs/comparisons/meta.json +11 -0
  117. package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +55 -0
  118. package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +111 -0
  119. package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +71 -0
  120. package/docs/comparisons/workflow-sdk-vs-inngest.mdx +102 -0
  121. package/docs/comparisons/workflow-sdk-vs-temporal.mdx +123 -0
  122. package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +103 -0
  123. package/docs/configuration/build-and-diagnostics.mdx +70 -0
  124. package/docs/configuration/cli-and-web-ui.mdx +182 -0
  125. package/docs/configuration/framework-options.mdx +165 -0
  126. package/docs/configuration/index.mdx +32 -0
  127. package/docs/configuration/meta.json +12 -0
  128. package/docs/configuration/runtime-tuning.mdx +281 -0
  129. package/docs/configuration/worlds.mdx +283 -0
  130. package/docs/cookbook/advanced/child-workflows.mdx +203 -256
  131. package/docs/cookbook/advanced/meta.json +1 -1
  132. package/docs/cookbook/advanced/publishing-libraries.mdx +33 -24
  133. package/docs/cookbook/advanced/serializable-steps.mdx +12 -4
  134. package/docs/cookbook/advanced/upgrading-workflows.mdx +199 -0
  135. package/docs/cookbook/agent-patterns/agent-cancellation.mdx +34 -75
  136. package/docs/cookbook/agent-patterns/durable-agent.mdx +14 -142
  137. package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +11 -3
  138. package/docs/cookbook/common-patterns/batching.mdx +4 -0
  139. package/docs/cookbook/common-patterns/idempotency.mdx +40 -52
  140. package/docs/cookbook/common-patterns/rate-limiting.mdx +5 -1
  141. package/docs/cookbook/common-patterns/saga.mdx +6 -2
  142. package/docs/cookbook/common-patterns/scheduling.mdx +12 -0
  143. package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +4 -0
  144. package/docs/cookbook/common-patterns/timeouts.mdx +6 -1
  145. package/docs/cookbook/common-patterns/webhooks.mdx +4 -0
  146. package/docs/cookbook/common-patterns/workflow-composition.mdx +19 -16
  147. package/docs/cookbook/index.mdx +3 -3
  148. package/docs/cookbook/integrations/ai-sdk.mdx +64 -28
  149. package/docs/cookbook/integrations/chat-sdk.mdx +17 -0
  150. package/docs/cookbook/integrations/sandbox.mdx +17 -0
  151. package/docs/{deploying/index.mdx → deploying.mdx} +7 -7
  152. package/docs/errors/abort-signal-timeout-in-workflow.mdx +84 -0
  153. package/docs/errors/corrupted-event-log.mdx +11 -8
  154. package/docs/errors/deployment-mismatch.mdx +71 -0
  155. package/docs/errors/fetch-in-workflow.mdx +4 -0
  156. package/docs/errors/hook-conflict.mdx +60 -4
  157. package/docs/errors/index.mdx +1 -35
  158. package/docs/errors/node-js-module-in-workflow.mdx +4 -0
  159. package/docs/errors/replay-divergence.mdx +27 -0
  160. package/docs/errors/runtime-decryption-failed.mdx +77 -0
  161. package/docs/errors/serialization-failed.mdx +4 -0
  162. package/docs/errors/start-invalid-workflow-function.mdx +4 -0
  163. package/docs/errors/step-executed-multiple-times.mdx +23 -0
  164. package/docs/errors/step-not-registered.mdx +1 -1
  165. package/docs/errors/timeout-in-workflow.mdx +4 -0
  166. package/docs/errors/webhook-response-not-sent.mdx +4 -0
  167. package/docs/foundations/cancellation.mdx +459 -0
  168. package/docs/foundations/errors-and-retries.mdx +7 -3
  169. package/docs/foundations/hooks.mdx +29 -0
  170. package/docs/foundations/idempotency.mdx +243 -11
  171. package/docs/foundations/index.mdx +1 -23
  172. package/docs/foundations/meta.json +3 -1
  173. package/docs/foundations/serialization.mdx +77 -41
  174. package/docs/foundations/starting-workflows.mdx +79 -2
  175. package/docs/foundations/streaming.mdx +14 -23
  176. package/docs/foundations/versioning.mdx +263 -0
  177. package/docs/getting-started/astro.mdx +12 -2
  178. package/docs/getting-started/express.mdx +6 -2
  179. package/docs/getting-started/fastify.mdx +6 -2
  180. package/docs/getting-started/hono.mdx +6 -2
  181. package/docs/getting-started/index.mdx +16 -10
  182. package/docs/getting-started/meta.json +4 -1
  183. package/docs/getting-started/nestjs.mdx +77 -3
  184. package/docs/getting-started/next.mdx +12 -6
  185. package/docs/getting-started/nitro.mdx +28 -2
  186. package/docs/getting-started/nuxt.mdx +6 -2
  187. package/docs/getting-started/python.mdx +24 -18
  188. package/docs/getting-started/react-router/index.mdx +33 -0
  189. package/docs/getting-started/react-router/meta.json +5 -0
  190. package/docs/getting-started/react-router/v7.mdx +237 -0
  191. package/docs/getting-started/react-router/v8.mdx +232 -0
  192. package/docs/getting-started/sveltekit.mdx +12 -2
  193. package/docs/getting-started/tanstack-start.mdx +245 -0
  194. package/docs/getting-started/vite.mdx +6 -2
  195. package/docs/how-it-works/cancellation.mdx +287 -0
  196. package/docs/how-it-works/code-transform.mdx +21 -17
  197. package/docs/how-it-works/encryption.mdx +5 -5
  198. package/docs/how-it-works/event-sourcing.mdx +17 -9
  199. package/docs/how-it-works/framework-integrations.mdx +96 -337
  200. package/docs/how-it-works/meta.json +2 -1
  201. package/docs/internal/index.mdx +21 -0
  202. package/docs/internal/meta.json +10 -0
  203. package/docs/internal/nitro-native-build.mdx +38 -0
  204. package/docs/internal/nitro-web-ui.mdx +24 -0
  205. package/docs/internal/serializable-abort-controller.mdx +148 -0
  206. package/docs/meta.json +2 -2
  207. package/docs/observability/attributes.mdx +112 -0
  208. package/docs/observability/index.mdx +20 -1
  209. package/docs/observability/meta.json +1 -1
  210. package/docs/observability/tracing.mdx +124 -0
  211. package/docs/testing/index.mdx +2 -2
  212. package/package.json +17 -13
  213. package/docs/api-reference/workflow-api/world/meta.json +0 -4
  214. package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
  215. package/docs/cookbook/advanced/distributed-abort-controller.mdx +0 -318
  216. package/docs/deploying/building-a-world.mdx +0 -251
  217. package/docs/deploying/meta.json +0 -4
  218. package/docs/deploying/world/local-world.mdx +0 -84
  219. package/docs/deploying/world/meta.json +0 -4
  220. package/docs/deploying/world/postgres-world.mdx +0 -222
  221. package/docs/deploying/world/vercel-world.mdx +0 -179
  222. package/docs/migration-guides/index.mdx +0 -34
  223. package/docs/migration-guides/meta.json +0 -9
  224. package/docs/migration-guides/migrating-from-aws-step-functions.mdx +0 -363
  225. package/docs/migration-guides/migrating-from-inngest.mdx +0 -314
  226. package/docs/migration-guides/migrating-from-temporal.mdx +0 -318
  227. package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -337
@@ -7,12 +7,17 @@ prerequisites:
7
7
  - /docs/foundations/workflows-and-steps
8
8
  related:
9
9
  - /docs/errors/fetch-in-workflow
10
+ - /docs/foundations/idempotency
10
11
  ---
11
12
 
12
13
  Makes HTTP requests from within a workflow. This is a special step function that wraps the standard `fetch` API, automatically handling serialization and providing retry semantics.
13
14
 
14
15
  This is useful when you need to call external APIs or services from within your workflow.
15
16
 
17
+ <Callout type="warn">
18
+ Because workflow `fetch()` has retry semantics, use idempotency keys when the request mutates an external system, such as creating a charge, sending an email, or enqueueing work. See [Idempotency](/docs/foundations/idempotency).
19
+ </Callout>
20
+
16
21
  <Callout>
17
22
  `fetch` is a *special* type of step function provided and should be called directly inside workflow functions.
18
23
  </Callout>
@@ -88,7 +93,7 @@ This API is provided as a convenience to easily use `fetch` in workflow, but oft
88
93
 
89
94
  ### Customizing Fetch Behavior
90
95
 
91
- Here's an example of a custom fetch wrapper that provides more sophisticated error handling with custom retry logic:
96
+ Here's an example of a custom fetch wrapper that provides more sophisticated error handling with custom retry logic. Call `globalThis.fetch` inside your own `"use step"` function — calling the workflow `fetch` imported from `workflow` would nest a step inside a step:
92
97
 
93
98
  ```typescript lineNumbers
94
99
  import { FatalError, RetryableError } from "workflow"
@@ -99,7 +104,7 @@ export async function customFetch(
99
104
  ) {
100
105
  "use step"
101
106
 
102
- const response = await fetch(url, init)
107
+ const response = await globalThis.fetch(url, init)
103
108
 
104
109
  // Handle client errors (4xx) - don't retry
105
110
  if (response.status >= 400 && response.status < 500) {
@@ -140,7 +145,6 @@ export async function customFetch(
140
145
 
141
146
  This example demonstrates:
142
147
 
143
- - Setting custom `maxRetries` to 5 retries (6 total attempts including the initial attempt).
144
148
  - Throwing [`FatalError`](/docs/api-reference/workflow/fatal-error) for client errors (400-499) to prevent retries.
145
149
  - Handling 429 rate limiting by reading the `Retry-After` header and using [`RetryableError`](/docs/api-reference/workflow/retryable-error).
146
- - Allowing automatic retries for server errors (5xx).
150
+ - Allowing automatic retries for server errors (5xx) by throwing a plain `Error`.
@@ -47,6 +47,9 @@ Workflow SDK contains the following functions you can use inside your workflow f
47
47
  <Card href="/docs/api-reference/workflow/get-writable" title="getWritable()">
48
48
  Access the current workflow run's default stream.
49
49
  </Card>
50
+ <Card href="/docs/api-reference/workflow/set-attributes" title="setAttributes()">
51
+ Attach string metadata to the current workflow run.
52
+ </Card>
50
53
  </Cards>
51
54
 
52
55
  ## Error Classes
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: setAttributes
3
+ description: Attach string metadata to workflow run for observability.
4
+ type: reference
5
+ summary: Use setAttributes inside a workflow or step function to set run attributes.
6
+ prerequisites:
7
+ - /docs/foundations/workflows-and-steps
8
+ related:
9
+ - /docs/observability/attributes
10
+ - /docs/api-reference/workflow/fatal-error
11
+ ---
12
+
13
+ Attaches string metadata to the current workflow run.
14
+
15
+ ```typescript lineNumbers
16
+ import { setAttributes } from "workflow"
17
+
18
+ export async function orderWorkflow(orderId: string) {
19
+ "use workflow"
20
+
21
+ await setAttributes({
22
+ phase: "received",
23
+ orderId,
24
+ })
25
+ }
26
+ ```
27
+
28
+ ## API Signature
29
+
30
+ ### Parameters
31
+
32
+ <TSDoc
33
+ definition={`
34
+ import { setAttributes } from "workflow";
35
+ export default setAttributes;`}
36
+ showSections={['parameters']}
37
+ />
38
+
39
+ ## Usage
40
+
41
+ Call `setAttributes` from a `"use workflow"` function or a `"use step"` function. Calling it from plain application code is not supported because there is no active workflow run.
42
+
43
+ Attribute values must be strings. Pass `undefined` to remove an attribute:
44
+
45
+ ```typescript lineNumbers
46
+ import { setAttributes } from "workflow"
47
+
48
+ export async function cleanupAttributes() {
49
+ "use workflow"
50
+
51
+ await setAttributes({ staleKey: undefined })
52
+ }
53
+ ```
54
+
55
+ Attribute keys must be 1-256 characters, values must be strings up to 256 bytes, and each run can have up to 64 attributes. Keys that start with `$` are reserved for framework and library code.
56
+
57
+ Validation errors throw [`FatalError`](/docs/api-reference/workflow/fatal-error) and fail the run before an attribute write is attempted.
58
+
59
+ Calls from both workflow and step bodies append a native `attr_set` event, which the World materializes onto `run.attributes`. Workflow-originated events record a workflow writer; step-originated events record the originating step ID and attempt.
60
+
61
+ Native attributes require spec version 4 or later. Step-body storage errors throw from `setAttributes`; catch them inside the step if the write should be best-effort. Workflow-body writes are committed when the workflow suspends: transient storage errors are retried with the suspension, while a write the World rejects as invalid — such as exceeding the per-run attribute cap across multiple calls — fails the run with the validation error.
@@ -14,7 +14,7 @@ Suspends a workflow for a specified duration or until an end date without consum
14
14
  This is useful when you want to resume a workflow after some duration or date.
15
15
 
16
16
  <Callout>
17
- `sleep` is a *special* type of step function and should be called directly inside workflow functions.
17
+ `sleep` is a built-in workflow runtime function (backed by a timer event in the event log, not a step) and should be called directly inside workflow functions.
18
18
  </Callout>
19
19
 
20
20
  ```typescript lineNumbers
@@ -1,59 +1,21 @@
1
1
  ---
2
2
  title: DurableAgent
3
- description: Create AI agents that maintain state, call tools, and handle interruptions gracefully.
3
+ description: Deprecated DurableAgent API reference; use WorkflowAgent for new durable agents.
4
4
  type: reference
5
- summary: Use DurableAgent to build AI agents that maintain state across steps and survive interruptions.
5
+ summary: "Deprecated: use AI SDK's WorkflowAgent instead of DurableAgent."
6
6
  prerequisites:
7
7
  - /docs/ai
8
8
  related:
9
9
  - /docs/ai/defining-tools
10
10
  ---
11
11
 
12
- The `DurableAgent` class enables you to create AI-powered agents that can maintain state across workflow steps, call tools, and gracefully handle interruptions and resumptions.
13
-
14
- Tool calls can be implemented as workflow steps for automatic retries, or as regular workflow-level logic utilizing core library features such as [`sleep()`](/docs/api-reference/workflow/sleep) and [Hooks](/docs/foundations/hooks).
15
-
16
- ```typescript lineNumbers
17
- import { DurableAgent } from "@workflow/ai/agent";
18
- import { getWritable } from "workflow";
19
- import { z } from "zod";
20
- import type { UIMessageChunk } from "ai";
21
-
22
- async function getWeather({ city }: { city: string }) {
23
- "use step";
24
-
25
- return `Weather in ${city} is sunny`;
26
- }
27
-
28
- async function myAgent() {
29
- "use workflow";
30
-
31
- const agent = new DurableAgent({
32
- model: "anthropic/claude-haiku-4.5",
33
- instructions: "You are a helpful weather assistant.",
34
- temperature: 0.7,
35
- tools: {
36
- getWeather: {
37
- description: "Get weather for a city",
38
- inputSchema: z.object({ city: z.string() }),
39
- execute: getWeather,
40
- },
41
- },
42
- });
43
-
44
- // The agent will stream its output to the workflow
45
- // run's default output stream
46
- const writable = getWritable<UIMessageChunk>();
12
+ <Callout type="warn">
13
+ `DurableAgent` is deprecated. Use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) for new durable agents — see the [migration guide](https://ai-sdk.dev/v7/docs/agents/workflow-agent#migrating-from-durableagent).
14
+ </Callout>
47
15
 
48
- const result = await agent.stream({
49
- messages: [{ role: "user", content: "How is the weather in San Francisco?" }],
50
- writable,
51
- });
16
+ This reference is kept for existing applications that still import `DurableAgent` from `@workflow/ai/agent`. Do not use `DurableAgent` for new code.
52
17
 
53
- // result contains messages, steps, and optional structured output
54
- console.log(result.messages);
55
- }
56
- ```
18
+ For current examples and implementation guidance, see AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) docs. For legacy code, the API surface below documents the existing `DurableAgent` exports.
57
19
 
58
20
  ## API Signature
59
21
 
@@ -13,9 +13,9 @@ Helpers for integrating AI SDK for building AI-powered workflows.
13
13
 
14
14
  <Cards>
15
15
  <Card title="DurableAgent" href="/docs/api-reference/workflow-ai/durable-agent">
16
- A class for building durable AI agents that maintain state across workflow steps and handle tool execution with automatic retries.
16
+ Deprecated use AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent). Reference kept for existing `@workflow/ai/agent` imports.
17
17
  </Card>
18
18
  <Card title="WorkflowChatTransport" href="/docs/api-reference/workflow-ai/workflow-chat-transport">
19
- A drop-in transport for the AI SDK for automatic reconnection in interrupted streams.
19
+ Deprecated use AI SDK's [`WorkflowChatTransport`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) from `@ai-sdk/workflow`. Reference kept for existing `@workflow/ai` imports.
20
20
  </Card>
21
21
  </Cards>
@@ -9,6 +9,10 @@ related:
9
9
  - /docs/ai/resumable-streams
10
10
  ---
11
11
 
12
+ <Callout type="warn">
13
+ `WorkflowChatTransport` from `@workflow/ai` is deprecated. AI SDK ships a 1:1 port — use [`WorkflowChatTransport` from `@ai-sdk/workflow`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#resumable-streaming-with-workflowchattransport) instead. This reference is kept for existing applications that still import it from `@workflow/ai`.
14
+ </Callout>
15
+
12
16
  A chat transport implementation for the AI SDK that provides reliable message streaming with automatic reconnection to interrupted streams. This transport is a drop-in replacement for the default AI SDK transport, enabling seamless recovery from network issues, page refreshes, or Vercel Function timeouts.
13
17
 
14
18
  <Callout>
@@ -250,9 +254,48 @@ export default function ChatWithCustomConfig() {
250
254
  }
251
255
  ```
252
256
 
257
+ ## Mid-part resumes
258
+
259
+ A workflow stream is a flat sequence of chunks, but the AI SDK's UI protocol groups chunks into logical parts: a `text-start` opens a text part that subsequent `text-delta`s extend and a `text-end` closes, and the same shape applies to `reasoning-*` and `tool-input-*`. The AI SDK client enforces that grammar — a `reasoning-delta` whose `reasoning-start` was never seen throws and breaks the chat.
260
+
261
+ A non-zero `startIndex` (in particular a negative `initialStartIndex`) resolves to a chunk offset with no awareness of those part boundaries, so it can land in the middle of an open part. When that happens, `WorkflowChatTransport` will **drop chunks that reference a part it didn't see a start for** and log a one-time warning. The chat keeps working, but any partial part overlapping the resume cursor is discarded. Tool calls are an exception: `tool-input-available` / `tool-input-error` chunks are self-contained (they carry the full input), so a tool call is recovered as soon as one of those chunks appears in the resumed window — only its streamed input deltas are lost.
262
+
263
+ To preserve those partial parts, rewind to a step boundary on the server before returning the readable. `start-step` / `finish-step` chunks are the natural seams — no UI part is ever open across them. Sketch:
264
+
265
+ {/*@skip-typecheck: incomplete code sample*/}
266
+
267
+ ```typescript title="app/api/chat/[id]/stream/route.ts"
268
+ const run = getRun(id);
269
+ const tailIndex = await run.getReadable().getTailIndex();
270
+
271
+ let resolved = startIndex < 0
272
+ ? Math.max(0, tailIndex + 1 + startIndex)
273
+ : startIndex;
274
+
275
+ if (startIndex !== 0) {
276
+ // Walk back from `resolved` to the most recent start-step (or chunk 0),
277
+ // capping the lookback so a single huge step can't trigger an unbounded scan.
278
+ const LOOKBACK = 200;
279
+ const probe = run.getReadable({ startIndex: Math.max(0, resolved - LOOKBACK) });
280
+ let i = Math.max(0, resolved - LOOKBACK);
281
+ let lastBoundary = i;
282
+ for await (const chunk of probe as unknown as AsyncIterable<{ type: string }>) {
283
+ if (i >= resolved) break;
284
+ if (chunk.type === "start-step") lastBoundary = i;
285
+ i++;
286
+ }
287
+ resolved = lastBoundary;
288
+ }
289
+
290
+ return createUIMessageStreamResponse({
291
+ stream: run.getReadable({ startIndex: resolved }),
292
+ headers: { "x-workflow-stream-tail-index": String(tailIndex) },
293
+ });
294
+ ```
295
+
253
296
  ## See Also
254
297
 
255
- - [DurableAgent](/docs/api-reference/workflow-ai/durable-agent) - Building durable AI agents within workflows
298
+ - [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) - Building durable, resumable AI agents (replaces `DurableAgent`)
256
299
  - [AI SDK `useChat` Documentation](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat) - Using `useChat` with custom transports
257
300
  - [Workflows and Steps](/docs/foundations/workflows-and-steps) - Understanding workflow fundamentals
258
301
  - ["flight-booking-app" Example](https://github.com/vercel/workflow-examples/tree/main/flight-booking-app) - An example application which uses `WorkflowChatTransport`
@@ -5,14 +5,22 @@ type: reference
5
5
  summary: Use getHookByToken to look up a hook's metadata and associated workflow run before resuming it.
6
6
  prerequisites:
7
7
  - /docs/foundations/hooks
8
+ related:
9
+ - /docs/foundations/idempotency
8
10
  ---
9
11
 
10
12
  Retrieves a hook by its unique token, returning the associated workflow run information and any metadata that was set when the hook was created. This function is useful for inspecting hook details before deciding whether to resume a workflow.
11
13
 
14
+ When `experimental_minRetention` is set, this function continues to return the Hook after its workflow ends until retention ends. That Hook cannot be resumed. Use `getRun(hook.runId)` to inspect the finished run.
15
+
12
16
  <Callout type="warn">
13
17
  `getHookByToken` is a runtime function that must be called from outside a workflow function.
14
18
  </Callout>
15
19
 
20
+ <Callout type="info">
21
+ Looking up a deterministic hook token is useful in hook-based idempotency flows, but it is only an advisory check. If no hook exists yet, another request can still start the same workflow before your `start()` call registers its hook. Use the lookup to avoid obvious duplicate starts, and handle the race inside the workflow by checking `await hook.getConflict()` before duplicate-sensitive work — on a conflict it resolves with the run that owns the token, so the duplicate can route the caller to the active owner. If duplicates must be rejected before a workflow body runs, keep a durable request record until native atomic start-and-hook registration exists. See [Run idempotency](/docs/foundations/idempotency#run-idempotency).
22
+ </Callout>
23
+
16
24
  ```typescript lineNumbers
17
25
  import { getHookByToken } from "workflow/api";
18
26
 
@@ -178,3 +186,4 @@ export async function POST(request: Request) {
178
186
  - [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) - Resume a hook with a payload.
179
187
  - [`createHook()`](/docs/api-reference/workflow/create-hook) - Create a hook in a workflow.
180
188
  - [`defineHook()`](/docs/api-reference/workflow/define-hook) - Type-safe hook helper.
189
+ - [Idempotency](/docs/foundations/idempotency) - Deduplicate step side effects and workflow starts.
@@ -5,12 +5,18 @@ type: reference
5
5
  summary: Use getRun to check a workflow run's status and metadata without blocking on completion.
6
6
  prerequisites:
7
7
  - /docs/foundations/starting-workflows
8
+ related:
9
+ - /docs/foundations/idempotency
8
10
  ---
9
11
 
10
12
  Retrieves the workflow run metadata and status information for a given run ID. This function provides immediate access to workflow run details without waiting for completion, making it ideal for status checking and monitoring.
11
13
 
12
14
  Use this function when you need to check workflow status, get timing information, or access workflow metadata without blocking on workflow completion.
13
15
 
16
+ <Callout type="info">
17
+ `getRun()` retrieves a run when you already have its `runId`. It does not look up runs by a business key. For retried requests that should route to one active workflow, use a deterministic hook token and [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token). After a hook conflict, `HookConflictError.conflictingRunId` can be passed to `getRun()` to inspect, stream, or return the active owner. See [Run idempotency](/docs/foundations/idempotency#run-idempotency).
18
+ </Callout>
19
+
14
20
  ```typescript lineNumbers
15
21
  import { getRun } from "workflow/api";
16
22
 
@@ -164,6 +170,25 @@ const { stoppedCount } = await run.wakeUp({
164
170
  });
165
171
  ```
166
172
 
173
+ ### Cancel a Run
174
+
175
+ Cancel a workflow run. You can pass an optional free-text `cancelReason` (up to 512 characters) that is recorded on the run's cancellation event and shown in the run detail view:
176
+
177
+ ```typescript lineNumbers
178
+ import { getRun } from "workflow/api";
179
+
180
+ export async function POST(req: Request) {
181
+ const { runId } = await req.json();
182
+ const run = getRun(runId);
183
+
184
+ await run.cancel({ cancelReason: "Superseded by a newer submission" }); // [!code highlight]
185
+
186
+ return Response.json({ cancelled: true });
187
+ }
188
+ ```
189
+
190
+ The options object is optional — `await run.cancel()` cancels the run without recording a reason.
191
+
167
192
  ## Related Functions
168
193
 
169
194
  - [`start()`](/docs/api-reference/workflow-api/start) - Start a new workflow and get its run ID.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "workflow/api"
3
- description: Runtime functions to inspect runs, start workflows, and access world data.
3
+ description: Runtime functions to inspect runs, start workflows, and manage hooks.
4
4
  type: overview
5
5
  summary: Explore runtime functions for starting workflows, inspecting runs, and managing hooks.
6
6
  ---
@@ -9,7 +9,7 @@ API reference for runtime functions from the `workflow/api` package.
9
9
 
10
10
  ## Functions
11
11
 
12
- The API package is for access and introspection of workflow data to inspect runs, start new runs, or access anything else directly accessible by the world.
12
+ The API package is for access and introspection of workflow data to inspect runs, start new runs, and manage hooks.
13
13
 
14
14
  <Cards>
15
15
  <Card href="/docs/api-reference/workflow-api/start" title="start()">
@@ -27,10 +27,8 @@ The API package is for access and introspection of workflow data to inspect runs
27
27
  <Card href="/docs/api-reference/workflow-api/get-run" title="getRun()">
28
28
  Get workflow run status and metadata without waiting for completion.
29
29
  </Card>
30
- <Card href="/docs/api-reference/workflow-api/get-world" title="getWorld()">
31
- Async: resolve the World instance for storage, queuing, and streaming backends.
32
- </Card>
33
- <Card href="/docs/api-reference/workflow-api/world" title="World SDK">
34
- Low-level API for inspecting runs, steps, events, hooks, streams, and queues.
35
- </Card>
36
30
  </Cards>
31
+
32
+ <Callout type="info">
33
+ Looking for `getWorld()` and the World SDK? They are exported from `workflow/runtime` — see the [`workflow/runtime` reference](/docs/api-reference/workflow-runtime).
34
+ </Callout>
@@ -7,12 +7,15 @@ prerequisites:
7
7
  - /docs/foundations/hooks
8
8
  related:
9
9
  - /docs/api-reference/workflow-api/resume-webhook
10
+ - /docs/foundations/idempotency
10
11
  ---
11
12
 
12
13
  Resumes a workflow run by sending a payload to a hook identified by its token.
13
14
 
14
15
  It creates a `hook_received` event and re-triggers the workflow to continue execution.
15
16
 
17
+ A Hook kept by `experimental_minRetention` after its workflow ends cannot be resumed. `resumeHook()` throws `HookNotFoundError` in that case.
18
+
16
19
  <Callout type="warn">
17
20
  `resumeHook` is a runtime function that must be called from outside a workflow function.
18
21
  </Callout>
@@ -47,7 +50,7 @@ showSections={["parameters"]}
47
50
 
48
51
  ### Returns
49
52
 
50
- Returns a `Promise<Hook>` that resolves to:
53
+ Returns a `Promise<ResumedHook>` a `Hook` extended with an optional `resilientResume` flag. Resolving means the resume was accepted and the workflow will continue, whether the `hook_received` event was written directly or, on the parallel fast path, delivered through the workflow queue for the runtime to materialize (see the [lazy hook resume changelog](/docs/changelog/resilient-resume)). `resilientResume` is `true` only when the direct event write failed transiently and the resume was recovered through the queue; on the happy path it is absent. The resolved hook:
51
54
 
52
55
  <TSDoc
53
56
  definition={`
@@ -155,8 +158,64 @@ export async function POST(request: Request) {
155
158
  }
156
159
  ```
157
160
 
161
+ ### Resume or Start
162
+
163
+ A common endpoint shape is "resume or start": one route that resumes the active workflow run for a business key if one exists, or starts a new run otherwise. This comes up when the workflow uses a deterministic hook token as its idempotency key — for example, one active run per order or conversation.
164
+
165
+ `resumeHook()` is the resume half of that flow. Try it first; if it throws `HookNotFoundError`, no active run owns the token yet, so start the workflow. One subtlety: `start()` returns before the new run executes and registers its hook, so you cannot resume immediately after starting. Retry the resume until the hook is registered — if you drop the payload and only start the workflow, the data from this request is lost.
166
+
167
+ ```typescript lineNumbers
168
+ import { resumeHook, start } from "workflow/api";
169
+ import { HookNotFoundError } from "workflow/errors";
170
+ import { processOrder } from "./workflows/process-order";
171
+
172
+ type OrderRequest = { confirmed: boolean };
173
+
174
+ async function resumeWithRetry(token: string, payload: OrderRequest) {
175
+ for (let attempt = 0; attempt < 5; attempt++) {
176
+ try {
177
+ return await resumeHook(token, payload); // [!code highlight]
178
+ } catch (error) {
179
+ if (!HookNotFoundError.is(error)) throw error;
180
+ await new Promise((resolve) => setTimeout(resolve, 100));
181
+ }
182
+ }
183
+
184
+ throw new Error("Workflow did not register its hook in time");
185
+ }
186
+
187
+ export async function POST(request: Request) {
188
+ const { orderId, confirmed } = await request.json();
189
+ const token = `order:${orderId}`;
190
+ const payload = { confirmed };
191
+
192
+ try {
193
+ // An active run already owns this token: resume it.
194
+ const hook = await resumeHook(token, payload); // [!code highlight]
195
+ return Response.json({ runId: hook.runId, reused: true });
196
+ } catch (error) {
197
+ if (!HookNotFoundError.is(error)) throw error;
198
+ }
199
+
200
+ // No hook yet: start a new run, then retry the resume so this
201
+ // request's payload still reaches the workflow.
202
+ const run = await start(processOrder, [orderId]); // [!code highlight]
203
+ const resumed = await resumeWithRetry(token, payload);
204
+
205
+ // A concurrent request can win the race between `start()` and hook
206
+ // registration; the resume always reaches the actual active owner.
207
+ return Response.json({
208
+ runId: resumed.runId,
209
+ reused: resumed.runId !== run.runId,
210
+ });
211
+ }
212
+ ```
213
+
214
+ See [Run idempotency](/docs/foundations/idempotency#run-idempotency) for the full pattern, including how the workflow claims the token with `hook.getConflict()` and how concurrent starts converge on one active owner.
215
+
158
216
  ## Related Functions
159
217
 
160
218
  - [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token) - Get hook details before resuming.
161
219
  - [`createHook()`](/docs/api-reference/workflow/create-hook) - Create a hook in a workflow.
162
220
  - [`defineHook()`](/docs/api-reference/workflow/define-hook) - Type-safe hook helper.
221
+ - [Idempotency](/docs/foundations/idempotency) - Deduplicate step side effects and workflow starts.
@@ -50,11 +50,13 @@ showSections={['parameters']}
50
50
 
51
51
  ### Returns
52
52
 
53
- Returns a `Promise<Response>` that resolves to:
53
+ Returns a `Promise<Response>` that resolves to one of:
54
54
 
55
- - `Response`: The HTTP response from the workflow's `respondWith()` call
55
+ - A `202 Accepted` response when the webhook was created in the default mode (no `respondWith` option).
56
+ - The exact `Response` object configured via `createWebhook({ respondWith: new Response(...) })`.
57
+ - The workflow's manual `Response` when the webhook was created with `createWebhook({ respondWith: "manual" })` and a step calls `request.respondWith(response)`.
56
58
 
57
- Throws an error if the webhook token is not found or invalid.
59
+ Throws [`HookNotFoundError`](/docs/api-reference/workflow-errors/hook-not-found-error) if the token does not match an active webhook.
58
60
 
59
61
  ## Usage Note
60
62
 
@@ -81,7 +83,7 @@ export async function POST(request: Request) {
81
83
 
82
84
  try {
83
85
  const response = await resumeWebhook(token, request); // [!code highlight]
84
- return response; // Returns the workflow's custom response
86
+ return response; // 202 Accepted, a configured static Response, or a manual workflow response
85
87
  } catch (error) {
86
88
  return new Response("Webhook not found", { status: 404 });
87
89
  }
@@ -2,9 +2,11 @@
2
2
  title: start
3
3
  description: Start and enqueue a new workflow run.
4
4
  type: reference
5
- summary: Use start to programmatically enqueue a new workflow run from outside a workflow function.
5
+ summary: Use start to programmatically enqueue a new workflow run.
6
6
  prerequisites:
7
7
  - /docs/foundations/starting-workflows
8
+ related:
9
+ - /docs/foundations/idempotency
8
10
  ---
9
11
 
10
12
  Start/enqueue a new workflow run.
@@ -50,14 +52,17 @@ Learn more about [`WorkflowReadableStreamOptions`](/docs/api-reference/workflow-
50
52
 
51
53
  ## Good to Know
52
54
 
53
- * The `start()` function is used in runtime/non-workflow contexts to programmatically trigger workflow executions.
55
+ * The `start()` function is used in runtime contexts to programmatically trigger workflow executions.
56
+ * In v5, `start()` can also be called directly from a workflow function to spawn a child run or continue work in a new run. See [Workflow Composition](/cookbook/common-patterns/workflow-composition) and [Versioning](/docs/foundations/versioning).
54
57
  * This is different from calling workflow functions directly, which is the typical pattern in Next.js applications.
55
58
  * The function returns immediately after enqueuing the workflow - it doesn't wait for the workflow to complete.
59
+ * Each call to `start()` creates a new workflow run. If retried requests must route to one active workflow, have the workflow create a deterministic hook token and use [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token) to reuse an already-registered active hook. The lookup is not atomic with `start()`, so concurrent callers can still create extra runs before the hook is registered; handle that race inside the workflow by checking `await hook.getConflict()` before duplicate-sensitive work — on a conflict it resolves with the run that owns the token, so the duplicate can return the active owner to the caller. If duplicates must be rejected before a workflow body runs, keep a durable request record until native atomic start-and-hook registration exists. See [Idempotency](/docs/foundations/idempotency#run-idempotency).
56
60
  * All arguments must be [serializable](/docs/foundations/serialization).
57
61
  * When `deploymentId` is provided, the argument types and return type become `unknown` since there is no guarantee the workflow function's types will be consistent across different deployments.
62
+ * `attributes` seeds plaintext run metadata as part of creation and requires a World implementing spec version 4 or later. Keys that start with `$` are reserved for framework and library code; framework-level callers can pass `allowReservedAttributes: true` to seed reserved keys, with the same semantics as the [`setAttributes`](/docs/api-reference/workflow/set-attributes) option of the same name.
58
63
 
59
64
  <Callout type="info">
60
- If `start()` throws `'start' received an invalid workflow function. Ensure the Workflow Development Kit is configured correctly and the function includes a 'use workflow' directive.`, the passed function was not transformed as a workflow. The two most common causes are a missing `"use workflow"` directive or missing framework integration. See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function).
65
+ If `start()` throws `'start' received an invalid workflow function. Ensure the Workflow SDK is configured correctly and the function includes a 'use workflow' directive.`, the passed function was not transformed as a workflow. The two most common causes are a missing `"use workflow"` directive or missing framework integration. See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function).
61
66
  </Callout>
62
67
 
63
68
  ## Examples
@@ -78,13 +83,14 @@ import { start } from "workflow/api";
78
83
  import { myWorkflow } from "./workflows/my-workflow";
79
84
 
80
85
  const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
81
- deploymentId: "custom-deployment-id" // [!code highlight]
86
+ deploymentId: "custom-deployment-id", // [!code highlight]
87
+ attributes: { source: "checkout" } // [!code highlight]
82
88
  }); // [!code highlight]
83
89
  ```
84
90
 
85
91
  ### Using `deploymentId: "latest"`
86
92
 
87
- Set `deploymentId` to `"latest"` to automatically resolve the most recent deployment for the current environment. This is useful when you want to ensure a workflow run targets the latest deployed version of your application rather than the deployment that initiated the call.
93
+ Set `deploymentId` to `"latest"` to automatically resolve the most recent deployment for the current environment. This is useful when you want to ensure a workflow run targets the latest deployed version of your application rather than the deployment that initiated the call. For when to use this and how it fits with default run pinning, see [Versioning](/docs/foundations/versioning).
88
94
 
89
95
  ```typescript
90
96
  import { start } from "workflow/api";
@@ -96,7 +102,9 @@ const run = await start(myWorkflow, ["arg1", "arg2"], { // [!code highlight]
96
102
  ```
97
103
 
98
104
  <Callout type="info">
99
- The `deploymentId` option is currently a Vercel-specific feature. The `"latest"` value resolves to the most recent deployment matching your current environment — the same production target for production deployments, or the same git branch for preview deployments.
105
+ The `deploymentId` option is currently a Vercel-specific feature. Other Worlds may implement this option differently to match their own deployment runtimes, and the World spec may rename it from `deploymentId` to `version` in a future SDK version. On Vercel, `"latest"` resolves to the most recent deployment matching your current environment — the same production target for production deployments, or the same git branch for preview deployments.
106
+
107
+ In Worlds without atomic, immutable deployments (such as local development or self-hosted Postgres), there is no notion of multiple deployments to resolve between, so `deploymentId: "latest"` has no effect: the SDK logs a warning and the run targets the current deployment. This means a workflow that opts into `"latest"` on Vercel still runs unchanged in local development.
100
108
  </Callout>
101
109
 
102
110
  <Callout type="warn">
@@ -105,3 +113,28 @@ When using `deploymentId: "latest"`, the workflow run will execute on a potentia
105
113
  - **Workflow identity**: The workflow ID is derived from the function name and file path. If the latest deployment has renamed the workflow function or moved it to a different directory, the workflow ID will no longer match and the run will fail to start.
106
114
  - **Input and output compatibility**: The arguments passed to `start()` are serialized by the calling deployment but deserialized by the target deployment. Similarly, the workflow's return value is serialized by the target deployment but deserialized by the caller. If the workflow's expected arguments or return type have changed (e.g. added required fields, removed fields, or changed types), the run may fail or behave unexpectedly. Ensure that input and output schemas remain backward-compatible across deployments.
107
115
  </Callout>
116
+
117
+ ### Inside a Workflow Function
118
+
119
+ `start()` can be called directly from a workflow function to spawn a child run. It is step-backed, so the spawn records a deterministic step boundary in the parent's event log.
120
+
121
+ ```typescript
122
+ import { start } from "workflow/api";
123
+ import { childWorkflow } from "./workflows/child";
124
+
125
+ export async function parentWorkflow(value: number) {
126
+ "use workflow";
127
+
128
+ const childRun = await start(childWorkflow, [value]); // [!code highlight]
129
+ const result = await childRun.returnValue; // [!code highlight]
130
+ return { childRunId: childRun.runId, result };
131
+ }
132
+ ```
133
+
134
+ <Callout type="info">
135
+ The returned `Run` object is fully functional inside a workflow. Each property access or method call (`.status`, `.returnValue`, `.cancel()`) executes as a separate step. See [Workflow Composition](/cookbook/common-patterns/workflow-composition) for choosing between spawning a child run and awaiting a workflow function directly.
136
+ </Callout>
137
+
138
+ <Callout type="warn">
139
+ `returnValue` polls the child run every second and holds the polling step's worker slot open for as long as the child takes to finish. For long-running children, spawn without awaiting `returnValue` and have the child resume a [hook](/docs/foundations/hooks) when it completes — see the [`startAndWait()` pattern](/cookbook/advanced/child-workflows).
140
+ </Callout>
@@ -0,0 +1,18 @@
1
+ ---
2
+ title: "workflow/astro"
3
+ description: Astro integration for automatic workflow bundling and route registration.
4
+ type: overview
5
+ summary: Explore the Astro integration for automatic workflow bundling and runtime support.
6
+ related:
7
+ - /docs/getting-started/astro
8
+ ---
9
+
10
+ Astro integration for Workflow SDK that transforms workflow code and builds the workflow bundles.
11
+
12
+ ## Functions
13
+
14
+ <Cards>
15
+ <Card title="workflow()" href="/docs/api-reference/workflow-astro/workflow">
16
+ Astro integration that transforms workflow code (`"use step"`/`"use workflow"` directives)
17
+ </Card>
18
+ </Cards>
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "workflow/astro",
3
+ "pages": ["workflow"]
4
+ }