diff --git a/src/pages/docs/ai-transport/frameworks/vercel-ai-sdk-core.mdx b/src/pages/docs/ai-transport/frameworks/vercel-ai-sdk-core.mdx index 7d66614ad9..841c2bfad2 100644 --- a/src/pages/docs/ai-transport/frameworks/vercel-ai-sdk-core.mdx +++ b/src/pages/docs/ai-transport/frameworks/vercel-ai-sdk-core.mdx @@ -46,8 +46,10 @@ On the server, AI Transport replaces `createUIMessageStreamResponse()` with `Run return createUIMessageStreamResponse({ stream: result.toUIMessageStream() }); // After: Ably transport -const { reason } = await run.pipe(result.toUIMessageStream()); -await run.end({ reason }); +const pipeResult = await run.pipe(result.toUIMessageStream()); +const outcome = await vercelRunOutcome(pipeResult, result.finishReason); +await run.end(outcome); + return Response.json({ invocationId: run.invocationId }); ``` @@ -59,9 +61,9 @@ A full agent route: import { after } from 'next/server'; import { streamText, convertToModelMessages } from 'ai'; import { anthropic } from '@ai-sdk/anthropic'; -import Ably from 'ably'; +import * as Ably from 'ably'; import { Invocation } from '@ably/ai-transport'; -import { createAgentSession } from '@ably/ai-transport/vercel'; +import { createAgentSession, vercelRunOutcome } from '@ably/ai-transport/vercel'; const ably = new Ably.Realtime({ key: process.env.ABLY_API_KEY }); @@ -81,12 +83,17 @@ export async function POST(req) { abortSignal: run.abortSignal, }); - const { reason } = await run.pipe(result.toUIMessageStream()); - await run.end({ reason }); + const pipeResult = await run.pipe(result.toUIMessageStream()); + const outcome = await vercelRunOutcome(pipeResult, result.finishReason); + if (outcome.reason === 'suspend') { + await run.suspend(); + } else { + await run.end(outcome); + } session.close(); }); - return Response.json({ invocationId: run.invocationId }); + return Response.json({ runId: run.runId, invocationId: run.invocationId }); } ``` @@ -95,7 +102,7 @@ The integration has three pieces: 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. 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`. -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. +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. ## Scope and trade-offs