Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
8bd61a8
feat(js/plugins/vercel-ai-sdk): add @genkit-ai/vercel-ai-sdk plugin
chrisraygill Apr 10, 2026
ec9a856
style(js/plugins/vercel-ai-sdk): apply prettier formatting
chrisraygill Apr 10, 2026
661d609
fix(js/plugins/vercel-ai-sdk): close stream cleanly on objectHandler …
chrisraygill Apr 10, 2026
de7a06b
fix(testapps/vercel-ai-sdk-next): add missing schemas module, fix imp…
chrisraygill Apr 10, 2026
38ee1e0
refactor(js/plugins/vercel-ai-sdk): rename schemas for consistency
chrisraygill Apr 10, 2026
8701438
style(js/plugins/vercel-ai-sdk): apply prettier formatting
chrisraygill Apr 10, 2026
d0daa39
docs(js/plugins/vercel-ai-sdk): add README for plugin and testapp
chrisraygill Apr 10, 2026
9e883e0
docs(js/plugins/vercel-ai-sdk): add Vercel AI SDK doc links to JSDoc …
chrisraygill Apr 10, 2026
e78cb61
chore(js/plugins/vercel-ai-sdk): add .npmignore, fix repository URL
chrisraygill Apr 10, 2026
520b41f
feat(js/plugins/vercel-ai-sdk): add toStreamChunks() converter helper
chrisraygill Apr 10, 2026
6ed0cea
feat(js/plugins/vercel-ai-sdk): add toStreamChunks and toFlowOutput h…
chrisraygill Apr 10, 2026
f3db73b
refactor(js/plugins/vercel-ai-sdk): API cleanup and consistency impro…
chrisraygill Apr 10, 2026
d03ce3d
refactor(js/plugins/vercel-ai-sdk): public API cleanup
chrisraygill Apr 10, 2026
2778bf5
docs(js/plugins/vercel-ai-sdk): fix stale plain-string stream comment…
chrisraygill Apr 10, 2026
a514f14
refactor(js/plugins/vercel-ai-sdk): improve type safety and AI SDK v6…
chrisraygill Apr 10, 2026
724d36c
fix(js/plugins/vercel-ai-sdk): guard writer.close() against already-c…
chrisraygill Apr 10, 2026
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
3 changes: 3 additions & 0 deletions js/plugins/vercel-ai-sdk/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
tsconfig.json
tsup.config.ts
154 changes: 154 additions & 0 deletions js/plugins/vercel-ai-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# @genkit-ai/vercel-ai-sdk

Adapter helpers that connect [Genkit](https://genkit.dev) streaming flows to the [Vercel AI SDK](https://sdk.vercel.ai) UI hooks: `useChat()`, `useCompletion()`, and `useObject()`.

Each handler returns a standard `(req: Request) => Promise<Response>` compatible with any Fetch API framework — Next.js App Router, Hono, SvelteKit, Cloudflare Workers, etc.

## Installation

```bash
npm install @genkit-ai/vercel-ai-sdk
```

**Peer dependencies:** `ai >= 6.0.0`, `genkit`, `zod`

## Handlers

### `chatHandler` — `useChat()`

Wraps a flow that takes `MessagesSchema` as input and emits `StreamChunkSchema` stream chunks.

```ts
// src/app/api/chat/route.ts
import { chatHandler } from '@genkit-ai/vercel-ai-sdk';
import { chatFlow } from '@/genkit/chat';

export const POST = chatHandler(chatFlow);
```

```ts
// src/genkit/chat.ts
import {
FlowOutputSchema, MessagesSchema, StreamChunkSchema,
toFlowOutput, toStreamChunks,
} from '@genkit-ai/vercel-ai-sdk';

export const chatFlow = ai.defineFlow(
{
name: 'chat',
inputSchema: MessagesSchema,
outputSchema: FlowOutputSchema,
streamSchema: StreamChunkSchema,
},
async (input, { sendChunk }) => {
const { stream, response } = ai.generateStream({
messages: input.messages,
});
for await (const chunk of stream) {
for (const c of toStreamChunks(chunk)) sendChunk(c);
}
return toFlowOutput(await response);
}
);
```

### `completionHandler` — `useCompletion()`

Wraps a flow that takes `z.string()` as input and uses `StreamChunkSchema` as `streamSchema`. Supports both SSE (`'data'`) and plain text (`'text'`) stream protocols — in text mode only `{ type: 'text', delta }` chunks are forwarded; all other chunk types are skipped.

```ts
// src/app/api/completion/route.ts
import { completionHandler } from '@genkit-ai/vercel-ai-sdk';
import { completionFlow } from '@/genkit/completion';

export const POST = completionHandler(completionFlow);
// Or for streamProtocol: 'text':
// export const POST = completionHandler(completionFlow, { streamProtocol: 'text' });
```

### `objectHandler` — `useObject()`

Wraps a flow that streams raw JSON text fragments. `useObject` reassembles them into a typed partial object in real time.

```ts
// src/app/api/notifications/route.ts
import { objectHandler } from '@genkit-ai/vercel-ai-sdk';
import { notificationsFlow } from '@/genkit/notifications';

export const POST = objectHandler(notificationsFlow);
```

## StreamChunkSchema

A discriminated union flows can use as `streamSchema` to drive the full UI Message Stream protocol:

| Chunk type | Wire events emitted |
|---|---|
| `{ type: 'text', delta }` | `text-start` (lazy) + `text-delta` |
| `{ type: 'reasoning', delta }` | `reasoning-start` (lazy) + `reasoning-delta` |
| `{ type: 'tool-request', toolCallId, toolName, inputDelta? \| input? }` | `tool-input-start` + `tool-input-delta` or `tool-input-available` |
| `{ type: 'tool-result', toolCallId, output }` | `tool-output-available` |
| `{ type: 'tool-input-error', toolCallId, toolName, input, errorText }` | `tool-input-start` + `tool-input-error` |
| `{ type: 'tool-output-error', toolCallId, errorText }` | `tool-output-error` |
| `{ type: 'tool-output-denied', toolCallId }` | `tool-output-denied` |
| `{ type: 'tool-approval-request', approvalId, toolCallId }` | `tool-approval-request` |
| `{ type: 'file', url, mediaType }` | `file` |
| `{ type: 'source-url', sourceId, url, title? }` | `source-url` |
| `{ type: 'source-document', sourceId, mediaType, title, filename? }` | `source-document` |
| `{ type: 'data', id, value }` | `data-${id}` |
| `{ type: 'step-start' }` | `start-step` |
| `{ type: 'step-end' }` | `finish-step` + closes open blocks |

In `completionHandler` with `streamProtocol: 'text'`, only `{ type: 'text', delta }` chunks are forwarded; all other chunk types are skipped.

## Auth / Context

All three handlers accept a `contextProvider` to extract server-side context (e.g. from auth headers) and forward it to the flow:

```ts
export const POST = chatHandler(chatFlow, {
contextProvider: async ({ headers }) => {
const token = headers['authorization']?.slice(7);
if (!token) throw Object.assign(new Error('Unauthorized'), { status: 401 });
return { userId: await verifyToken(token) };
},
});
```

## Client-supplied context

### `useChat` body passthrough

Extra fields sent by the client via `useChat({ body: { ... } })` are forwarded to the flow as `input.body`:

```ts
// Client
const { messages } = useChat({ api: '/api/chat', body: { sessionId: 'abc' } });

// Flow receives: { messages: [...], body: { sessionId: 'abc' } }
```

### `useCompletion` body passthrough

Extra fields sent via `useCompletion({ body: { ... } })` are available in `contextProvider`. Place anything the flow needs into the returned context object — Genkit stores it in async-local storage so `ai.generate()` calls and tools within the flow can access it automatically:

```ts
export const POST = completionHandler(completionFlow, {
contextProvider: async ({ headers, input }) => {
const token = headers['authorization']?.slice(7);
return { userId: await verifyToken(token), sessionId: input.sessionId };
},
});
```

## Framework compatibility

Handlers return a standard Fetch API `Response` and work in any runtime that supports the Web Platform APIs:

- **Next.js** App Router (Node.js and Edge)
- **Hono**, **SvelteKit**, **Remix**, **Astro**
- **Cloudflare Workers**, **Deno**, **Bun**

## License

Apache 2.0
58 changes: 58 additions & 0 deletions js/plugins/vercel-ai-sdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@genkit-ai/vercel-ai-sdk",
"description": "Genkit adapters for the Vercel AI SDK UI hooks (useChat, useCompletion, useObject)",
"keywords": [
"genkit",
"genkit-plugin",
"ai",
"genai",
"generative-ai",
"vercel",
"ai-sdk",
"useChat",
"useCompletion",
"useObject"
],
"version": "1.0.0",
"type": "commonjs",
"scripts": {
"check": "tsc",
"compile": "tsup-node",
"build:clean": "rimraf ./lib",
"build": "npm-run-all build:clean check compile",
"build:watch": "tsup-node --watch",
"test": "node --import tsx --test tests/*_test.ts"
},
"repository": {
"type": "git",
"url": "https://github.com/genkit-ai/genkit.git",
"directory": "js/plugins/vercel-ai-sdk"
},
"author": "genkit",
"license": "Apache-2.0",
"peerDependencies": {
"ai": ">=6.0.0",
"genkit": "workspace:^",
"zod": "^3.24.1"
},
"devDependencies": {
"@types/node": "^20.11.16",
"ai": "^6.0.156",
"genkit": "workspace:^",
"npm-run-all": "^4.1.5",
"rimraf": "^6.0.1",
"tsup": "^8.3.5",
"tsx": "^4.19.2",
"typescript": "^5.9.3",
"zod": "^3.24.1"
},
"types": "./lib/index.d.ts",
"exports": {
".": {
"require": "./lib/index.js",
"default": "./lib/index.js",
"import": "./lib/index.mjs",
"types": "./lib/index.d.ts"
}
}
}
Loading
Loading