Skip to content

Commit e858242

Browse files
committed
Use vercelRunOutcome in Vercel AI SDK Core framework guide
The agent route snippets piped the stream and called run.end({ reason }) directly, skipping vercelRunOutcome. This diverged from the getting started guide and the 0.2.0 blog post, and dropped tool-call suspension and the finishReason rejection guard. Align both snippets and the explanation with the canonical pattern. Fixes AIT-1034
1 parent 2611889 commit e858242

1 file changed

Lines changed: 15 additions & 8 deletions

File tree

src/pages/docs/ai-transport/frameworks/vercel-ai-sdk-core.mdx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ On the server, AI Transport replaces `createUIMessageStreamResponse()` with `Run
4646
return createUIMessageStreamResponse({ stream: result.toUIMessageStream() });
4747

4848
// After: Ably transport
49-
const { reason } = await run.pipe(result.toUIMessageStream());
50-
await run.end({ reason });
49+
const pipeResult = await run.pipe(result.toUIMessageStream());
50+
const outcome = await vercelRunOutcome(pipeResult, result.finishReason);
51+
await run.end(outcome);
52+
5153
return Response.json({ invocationId: run.invocationId });
5254
```
5355
</Code>
@@ -59,9 +61,9 @@ A full agent route:
5961
import { after } from 'next/server';
6062
import { streamText, convertToModelMessages } from 'ai';
6163
import { anthropic } from '@ai-sdk/anthropic';
62-
import Ably from 'ably';
64+
import * as Ably from 'ably';
6365
import { Invocation } from '@ably/ai-transport';
64-
import { createAgentSession } from '@ably/ai-transport/vercel';
66+
import { createAgentSession, vercelRunOutcome } from '@ably/ai-transport/vercel';
6567

6668
const ably = new Ably.Realtime({ key: process.env.ABLY_API_KEY });
6769

@@ -81,12 +83,17 @@ export async function POST(req) {
8183
abortSignal: run.abortSignal,
8284
});
8385

84-
const { reason } = await run.pipe(result.toUIMessageStream());
85-
await run.end({ reason });
86+
const pipeResult = await run.pipe(result.toUIMessageStream());
87+
const outcome = await vercelRunOutcome(pipeResult, result.finishReason);
88+
if (outcome.reason === 'suspend') {
89+
await run.suspend();
90+
} else {
91+
await run.end(outcome);
92+
}
8693
session.close();
8794
});
8895

89-
return Response.json({ invocationId: run.invocationId });
96+
return Response.json({ runId: run.runId, invocationId: run.invocationId });
9097
}
9198
```
9299
</Code>
@@ -95,7 +102,7 @@ The integration has three pieces:
95102

96103
1. The `UIMessageCodec` encodes Vercel's `UIMessageChunk` events as Ably messages. Every chunk type maps to an Ably operation with headers that track the metadata. The codec encodes on the agent and decodes on the client.
97104
2. `createAgentSession({ client, channelName })` from `@ably/ai-transport/vercel` constructs the agent session bound to the channel from the invocation. The default codec is `UIMessageCodec`.
98-
3. `run.pipe()` reads the model's `UIMessageChunk` stream, encodes each chunk, and publishes the resulting Ably messages. `run.abortSignal` wires cancellation through from the client.
105+
3. `run.pipe()` reads the model's `UIMessageChunk` stream, encodes each chunk, and publishes the resulting Ably messages. `run.abortSignal` wires cancellation through from the client. [`vercelRunOutcome()`](/docs/ai-transport/api/javascript/vercel/run-outcome) then maps the pipe result and Vercel's `finishReason` to the right lifecycle action: suspend the Run when the model requested tools the SDK did not auto-execute, otherwise end it with the matching reason.
99106

100107
## Scope and trade-offs <a id="scope"/>
101108

0 commit comments

Comments
 (0)