@novu/framework/ai-sdk lets you write agent handlers with the Vercel AI SDK. Return an AI SDK result straight from onMessage and Novu delivers the text — including tool loops and approval gating — to the conversation.
Before you start
Completed the Quickstart? Your agent, bridge, and project are already set up — jump to Minimal agent. Otherwise start with the Quickstart first. All three onboarding paths (dashboard, CLI, AI assistant) walk you through creating the agent and wiring the bridge. This page covers only what’s specific to the AI SDK adapter.Prerequisites
Install the framework, the AI SDK, and a model provider:@novu/framework and ai are required; pick one provider package. Examples on this page use OpenAI — see the AI SDK providers list for others.
Minimal agent
Importagent and toModelMessages from @novu/framework/ai-sdk, then return generateText() from onMessage:
'support-bot') matches the Identifier in your dashboard, and that this handler is registered on your bridge route — see Connecting your app.
For handlers, replies, signals, typing, and tool approval, see Building blocks. The sections below cover what’s specific to the AI SDK adapter.
Returning from onMessage
On the AI SDK path, onMessage (and onToolApproval) can return an AI SDK result in addition to the usual reply types:
| Return | Behavior |
|---|---|
generateText(...) | Novu delivers the generated text |
streamText(...) | Novu waits for the full response, then delivers the final text (same outcome as generateText) |
string / JSX Card | Delivered as a normal reply — see Reply |
| nothing | After you call ctx.reply() yourself |
Returning
streamText(...) behaves the same as returning generateText(...) — Novu waits for the full response, then posts the completed text.streamText() inside the handler without returning it. Post a reply, then update it as chunks arrive with ReplyHandle.edit():
onMessage: pass the handler directly.
toModelMessages()
Convert ctx.history into AI SDK ModelMessage[]:
ctx.historyalready includes the current inbound message — do not append themessageargument on top of it.- Tool approval cycles in history are mapped automatically, so auto-resume (below) works.
Automatic tool approval
SetneedsApproval: true on an AI SDK tool(). When the model calls it, Novu posts the Approve / Deny card and pauses the turn. After the user decides, Novu re-runs onMessage — toModelMessages(ctx.history) now includes the decision, so the tool loop continues with no extra code from you.
onToolApproval when you need a hook after the click. See Tool approval for the full API.
Turn failures and onError
When a returned generateText() / streamText() result rejects — for example the provider errors or stream consumption fails — the failure propagates to the same dispatch boundary as a thrown handler error. Register onError on the agent to log, suppress user notification, send custom copy, or fall back to Novu’s generic message.
tool-error parts inside a multi-step AI SDK flow do not end the turn by themselves — only failures that reject the result or throw from your handler trigger onError. See Handlers and context — onError for the full pipeline.
MCP tools
Self-hosted agents do not use the dashboard MCP server configuration — that OAuth flow and token vault are for managed agents only. On the custom code path, you wire external MCP servers yourself with the AI SDK MCP client:ctx. Resolve tokens in your handler — for example, look up a per-subscriber token you stored after your own OAuth flow using ctx.subscriber?.subscriberId.
Related
Typing indicator
Show a Thinking… or custom status while your handler runs.
Reply
Markdown, attachments, and interactive cards.
Tool approval
The shared Approve / Deny primitive.
LangChain
Return LangChain agent configs with automatic tool approval resume.
Other frameworks
Wire handlers without a Novu runtime adapter.