@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 Connect AI SDK? Your agent, bridge, and project are already set up - jump to Minimal agent. Otherwise connect first, then come back here for adapter details.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:
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 conversation context into AI SDK ModelMessage[]. Pass ctx so a workflow-origin notification (ctx.notification) is prepended as an assistant row with capped notification text and the full JSON payload:
ctx.historyalready includes the current inbound message - do not append themessageargument on top of it.- When
ctx.notificationis set, it includesbody(capped outbound notification text) pluspayload,workflowId, and ids. - Tool approval cycles in history are mapped automatically, so auto-resume (below) works.
- Wrap
toModelMessages()inhydrateUnreachableAttachmentUrlsbeforegenerateText/streamText. Public HTTPS signed URLs stay as URLs; local or HTTP URLs (for example LocalStack) are fetched and inlined as bytes so hosted providers can read the file. - Pass
ctx.historyinstead ofctxto skip automatic origin injection when handling typed fields withisFromWorkflow:
toModelMessages(ctx) after a custom unshift — you would inject the origin twice.
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) 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.