Wrap any Vercel AI SDK model with one line and get persistent, per-user memory on every call.Documentation Index
Fetch the complete documentation index at: https://docs.maximem.ai/llms.txt
Use this file to discover all available pages before exploring further.
generateText, streamText, and generateObject all keep working — the middleware just makes them memory-aware.
Overview
This guide shows how to add Synap to a Vercel AI SDK application to build apps that:- Inject relevant memory before every
generateText/streamText/generateObjectcall - Record completed turns back to Synap automatically
- Work with any provider — OpenAI, Anthropic, Google, etc. — without per-provider plumbing
| Export | Purpose |
|---|---|
createSynap | Async factory that initializes the Synap provider |
SynapProvider | Provider class with wrap and listen methods |
Setup
Install the package:.env
createSynap initializes the underlying Synap SDK internally — you don’t need to manage the SDK lifecycle separately. See SDK Initialization for the full lifecycle if you’d rather construct the SDK directly.
Basic integration
The smallest useful integration wraps a model withsynap.wrap and uses it like any other Vercel AI SDK model:
Core concepts
synap.wrap
synap.wrap(model, options) returns a standard Vercel AI SDK LanguageModel. Drop it anywhere you’d use the underlying model — generateText, streamText, generateObject, agentic loops, structured output, etc.
wrap — the model only ever sees the messages, never userId/customerId. This means prompt injection cannot spoof scope.
The middleware loop
On every call to the wrapped model:- Before — fetches the user’s Synap context and injects it as a system message.
- Generates — proxies the request to the wrapped model unchanged.
- After — ingests the completed user + assistant turn into Synap asynchronously.
Provider-agnostic
Wrap any Vercel AI SDK-compatible model:Streaming
streamText and streamObject work without any code changes — the middleware injects context before the stream starts and ingests the turn when the stream ends:
Complete example: chat route with per-request scoping
The pattern below is a typical Next.js (Node runtime) chat route. Each request gets its own scope baked into a freshly-wrapped model, so multiple concurrent users cannot leak into each other’s memory:- The provider is module-scoped, the model is request-scoped.
createSynapruns once;synap.wrapruns per request with the rightuserId. - Streaming is unchanged. No special integration needed —
streamTextand the middleware co-exist transparently. - The
runtime = "nodejs"pin matters. Edge Runtime would break the Python-subprocess dependency.
Advanced patterns
Per-request scoping
For multi-tenant services, build the wrapped model per request and never cache it across users:Anticipation stream
synap.listen() opens a gRPC stream that pre-fetches context speculatively before the user’s next request arrives. This reduces perceived latency in long-lived server processes where you can predict who will message next:
Multi-tenant scoping
synap.wrap accepts the standard scoping triple — userId (required), optional customerId, optional conversationId. customerId is required on B2B Synap instances and ignored on single-tenant ones. See Memory Scopes.
Failure semantics
The middleware follows the Synap-wide contract:- Context fetch degrades gracefully — empty context is injected and the error logged if Synap is unreachable.
- Turn ingestion surfaces failures — write failures raise
SynapIntegrationErrorso callers know if persistence failed.
Next steps
Mastra
SynapMemory and tools for the Mastra ADK.Claude Agent SDK
Hooks and MCP server for the Claude Agent SDK.
Context Fetch
The retrieval API behind
synap.wrap — modes, scopes, and response shapes.Memory Scopes
How
userId, customerId, and conversationId interact across reads.