Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/data/nav/aitransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export default {
name: 'Vercel AI SDK',
link: '/docs/ai-transport/getting-started/vercel-ai-sdk',
},
{
name: 'Vercel WDK',
link: '/docs/ai-transport/getting-started/vercel-wdk',
},
{
name: 'Temporal',
link: '/docs/ai-transport/getting-started/temporal',
Expand Down Expand Up @@ -114,6 +118,10 @@ export default {
name: 'Vercel AI SDK Core',
link: '/docs/ai-transport/frameworks/vercel-ai-sdk-core',
},
{
name: 'Vercel WDK',
link: '/docs/ai-transport/frameworks/vercel-wdk',
},
Comment on lines +121 to +124

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets have this above "temporal" so that all the vercel stuff is grouped

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

{
name: 'Temporal',
link: '/docs/ai-transport/frameworks/temporal',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ Pipe a `ReadableStream` of outputs through the encoder to the channel. Returns w

Create a [`RunStep`](#step): a re-attemptable unit of agent work within this Run. Use it when a retry of the same logical unit must supersede the failed attempt's channel output rather than append beside it, typically inside a workflow-engine activity. Returns synchronously and does no I/O; [`RunStep.start`](#step-start) publishes the opening event.

`options.stepId` controls retry coalescing. Omit it for the common in-process case: the SDK assigns an invocation-scoped id, and an in-process retry after a `'failed'` close reuses that id. Supply an explicit `stepId` when the same logical Step re-attempts in a separate process. Source it from the workflow engine's own stable per-activity id (a [Temporal](/docs/ai-transport/frameworks/temporal) activity id, a Vercel Workflow DevKit step id). See [Durable execution](/docs/ai-transport/features/durable-execution).
`options.stepId` controls retry coalescing. Omit it for the common in-process case: the SDK assigns an invocation-scoped id, and an in-process retry after a `'failed'` close reuses that id. Supply an explicit `stepId` when the same logical Step re-attempts in a separate process. Source it from the workflow engine's own stable per-activity id (a [Temporal](/docs/ai-transport/frameworks/temporal) activity id, a [Vercel WDK](/docs/ai-transport/frameworks/vercel-wdk) step id). See [Durable execution](/docs/ai-transport/features/durable-execution).

<Code>
```javascript
Expand Down Expand Up @@ -422,7 +422,7 @@ The Step must be active (started, not ended). Rejects otherwise. A publish failu

<MethodSignature>{`end(params?: StepEndParams): Promise<void>`}</MethodSignature>

Publish `ai-step-end`, closing the Step. Idempotent; a second call is a no-op. Omit `params` to derive the reason from the Step's piped output: `'failed'` if any [`pipe`](#step-pipe) errored, otherwise `'complete'`. Pass an explicit `reason` to override.
Publish `ai-step-end`, closing the Step. Idempotent; a second call is a no-op. Omit `params` to derive the reason: `'cancelled'` if the Run was cancelled (its `abortSignal` fired), otherwise `'failed'` if any [`pipe`](#step-pipe) errored, otherwise `'complete'`. Pass an explicit `reason` to override.

A Step terminal is not a Run terminal. Drive the Run to [`suspend`](#run-suspend) or [`end`](#run-end) afterwards. If a Step is left open, `run.end()` auto-closes it so observers are never stranded, but an explicit `end()` is clearer and lets you set the reason.

Expand All @@ -440,7 +440,7 @@ A Step terminal is not a Run terminal. Drive the Run to [`suspend`](#run-suspend

| Property | Description | Type |
| --- | --- | --- |
| reason | The terminal reason. Omit to derive it from the Step's piped output: `'failed'` if any `pipe` errored, otherwise `'complete'`. Pass an explicit value to override. | `'complete' \| 'failed'` |
| reason | The terminal reason. Omit to derive it: `'cancelled'` if the Run was cancelled (its `abortSignal` fired), otherwise `'failed'` if any `pipe` errored, otherwise `'complete'`. Pass an explicit value to override. | `'complete' \| 'failed' \| 'cancelled'` |

</Table>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export async function POST(req: Request) {
await run.end(outcome);
}
} finally {
await session.close();
await session.end();
}

return Response.json({ invocationId: run.invocationId });
Expand Down
6 changes: 3 additions & 3 deletions src/pages/docs/ai-transport/concepts/connections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The two connection types differ in what they own and how long they live:
| `ClientSession` | Long-lived (the lifetime of the user's app or tab). | Channel subscription, the read path into the tree, default `view`, cancel publish path. | The channel itself, the Ably client, the conversation state. |
| `AgentSession` | Typically short-lived (one HTTP handler invocation). | Channel attach for cancel routing, the write path for Run lifecycle events and the streamed response. | Long-lived state, retry coordination across invocations. |

Both expose `connect()`, `close()`, and the SDK's lifecycle gate: methods that publish or subscribe throw `InvalidArgument` until `connect()` resolves.
Both expose `connect()` and the SDK's lifecycle gate: methods that publish or subscribe throw `InvalidArgument` until `connect()` resolves. They differ on teardown: a `ClientSession` disposes with `close()`, an `AgentSession` with `end()` (or `detach()` to hand an in-flight Run to another process).

## What the connection layer requires <a id="requires"/>

Expand All @@ -37,11 +37,11 @@ Both expose `connect()`, `close()`, and the SDK's lifecycle gate: methods that p
| Independence | Each connection has its own subscription, branch selections, and pagination window. A second `ClientSession` in another tab doesn't see the first one's branch state. |
| Cancel routing | Cancels are channel publishes that name a `runId`. Both `ClientSession.cancel(runId)` and the agent's `Run.abortSignal` rely on the connection being attached to the right channel. |
| Codec binding | The codec is wired into the connection at construction. Switching codecs means a new connection. |
| Clean teardown | `close()` releases the subscription and clears handlers locally. It does not end Runs on the wire. Active Runs on the channel keep running until the agent ends them. |
| Clean teardown | Disposal releases the subscription and clears handlers locally. `ClientSession.close()` and `AgentSession.detach()` do not end Runs on the wire; active Runs keep running until the agent ends them. `AgentSession.end()` first closes the agent's own open Runs as `'cancelled'`, then detaches. |

## Understand connection lifecycle <a id="lifecycle"/>

A connection moves through four stages. Construct it with `createClientSession` or `createAgentSession`. Call `connect()` to subscribe to the channel. On a `ClientSession`, write through `view.send`, `view.regenerate`, and `view.edit`, cancel through `cancel(runId)`, derive views with `createView()`, and subscribe to non-fatal errors with `on('error', ...)`. Tear it down with `close()`.
A connection moves through four stages. Construct it with `createClientSession` or `createAgentSession`. Call `connect()` to subscribe to the channel. On a `ClientSession`, write through `view.send`, `view.regenerate`, and `view.edit`, cancel through `cancel(runId)`, derive views with `createView()`, and subscribe to non-fatal errors with `on('error', ...)`. Tear it down with `close()` on a `ClientSession`, or `end()` (or `detach()`) on an `AgentSession`.

`connect()` is the gate. Every operation that touches the channel throws `InvalidArgument` until the connect promise resolves. `connect()` is also idempotent: subsequent calls return the same promise, useful when a component mounts twice or a retry path re-runs initialisation.

Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/ai-transport/concepts/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ A session contains many Runs. Runs coexist on the same session and have independ

A [Step](/docs/ai-transport/concepts/steps) is one re-attemptable unit of agent output inside a Run: a single inference, a single tool result, a single scheduled activity. A retry under the same `stepId` supersedes the failed attempt on the channel rather than appending beside it.

Steps are what make Runs safe to execute inside a durable workflow engine such as [Temporal](/docs/ai-transport/frameworks/temporal). See [Durable execution](/docs/ai-transport/features/durable-execution).
Steps are what make Runs safe to execute inside a durable workflow engine such as [Temporal](/docs/ai-transport/frameworks/temporal) or [Vercel WDK](/docs/ai-transport/frameworks/vercel-wdk). See [Durable execution](/docs/ai-transport/features/durable-execution).

## An Invocation triggers a Run <a id="invocation"/>

Expand Down
7 changes: 4 additions & 3 deletions src/pages/docs/ai-transport/concepts/steps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
title: "Steps"
meta_description: "Understand Steps in AI Transport: the sub-bracket within a Run that carries one publishable unit of agent output. Steps have their own start and end lifecycle, an addressable stepId, and supersede-on-retry semantics."
meta_keywords: "AI Transport, Step, RunStep, createStep, stepId, supersede, run structure, retry"
intro: "A Step is a bracket around one publishable unit of agent output inside a Run. It has its own start and end lifecycle on the channel, an addressable stepId, and a terminal reason of complete or failed."
intro: "A Step is a bracket around one publishable unit of agent output inside a Run. It has its own start and end lifecycle on the channel, an addressable stepId, and a terminal reason of complete, failed, or cancelled."
---

A [Run](/docs/ai-transport/concepts/runs) does not publish output directly. It publishes through Steps. A Step is the inner bracket a Run uses to group one contiguous unit of output: the tokens for one LLM inference, the payload for one tool result, or any other burst of channel writes the agent code frames as a single unit. Every output message an agent publishes carries a `step-id` that names the Step it belongs to.

A Step has its own lifecycle events on the channel (`ai-step-start` and `ai-step-end`), its own addressable identity (`stepId`), and its own terminal reason (`'complete'` or `'failed'`). It is to the Run what the Run is to the Session: a nested bracket with a stable identity and a defined start and end, carrying a portion of the outer bracket's output.
A Step has its own lifecycle events on the channel (`ai-step-start` and `ai-step-end`), its own addressable identity (`stepId`), and its own terminal reason (`'complete'`, `'failed'`, or `'cancelled'`). It is to the Run what the Run is to the Session: a nested bracket with a stable identity and a defined start and end, carrying a portion of the outer bracket's output.

Two properties of the Step layer sit on top of that structural role. Every Step in a Run is ordered relative to the others (exactly one Step is active on a Run at a time). And two `ai-step-start` events under the same `stepId` coalesce: the later one supersedes the earlier one's output rather than appending beside it, which is what makes a Step the safe boundary for a retry.

Expand Down Expand Up @@ -41,7 +41,7 @@ Two kinds of Steps sit on a Run:

| Property | Why it matters |
| --- | --- |
| Stable stepId | A retry's `ai-step-start` must land under the same `stepId` as the failed attempt. Otherwise the retry's output publishes under a fresh id and both attempts remain in the conversation. Supply the workflow engine's own stable id ([Temporal](/docs/ai-transport/frameworks/temporal) activity id, Vercel Workflow DevKit step id) on cross-process retries. |
| Stable stepId | A retry's `ai-step-start` must land under the same `stepId` as the failed attempt. Otherwise the retry's output publishes under a fresh id and both attempts remain in the conversation. Supply the workflow engine's own stable id ([Temporal](/docs/ai-transport/frameworks/temporal) activity id, [Vercel WDK](/docs/ai-transport/frameworks/vercel-wdk) step id) on cross-process retries. |
| Supersede on retry | When two attempts share a `stepId`, the message that was published later wins. The client's View surfaces only the winning attempt. |
| One Step at a time | Exactly one Step may be active on a Run. [`RunStep.start`](/docs/ai-transport/api/javascript/core/agent-session#step-start) rejects if another Step is still open. |
| Terminal auto-close | If agent code forgets to close a Step, [`AgentRun.end`](/docs/ai-transport/api/javascript/core/agent-session#run-end) auto-closes the open Step before publishing the Run terminal. No observer's UI is stranded on `streaming`. |
Expand Down Expand Up @@ -94,4 +94,5 @@ Omit `stepId` for the common in-process case. The SDK assigns an invocation-scop
- [Runs](/docs/ai-transport/concepts/runs): the outer bracket a Step lives in.
- [Durable execution](/docs/ai-transport/features/durable-execution): the pattern that makes cross-process Step retries safe.
- [Temporal](/docs/ai-transport/frameworks/temporal): the reference workflow-engine integration.
- [Vercel WDK](/docs/ai-transport/frameworks/vercel-wdk): the same pattern inside your Next.js app.
- [RunStep API reference](/docs/ai-transport/api/javascript/core/agent-session#step): the surface `createStep` returns.
2 changes: 1 addition & 1 deletion src/pages/docs/ai-transport/features/agent-presence.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ app.post('/api/chat', async (req, res) => {
await run.end({ reason });

await session.presence.leave();
await session.close();
await session.end();
res.json({ ok: true });
});
```
Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/ai-transport/features/branching.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ try {
await run.end({ reason: 'error' });
throw err;
} finally {
await session.close();
await session.end();
}
```
</Code>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/ai-transport/features/chain-of-thought.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ app.post('/api/chat', async (req, res) => {

const { reason } = await run.pipe(result.toUIMessageStream());
await run.end({ reason });
await session.close();
await session.end();
res.json({ ok: true });
});
```
Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/ai-transport/features/concurrent-turns.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ app.post('/api/chat', async (req, res) => {

const { reason } = await run.pipe(result.toUIMessageStream());
await run.end({ reason });
await session.close();
await session.end();
res.json({ ok: true });
});
```
Expand Down
Loading
Loading