AI SDKs

Vercel AI SDK

Spectron memory for the Vercel AI SDK, via language-model middleware and a tool set.

@surrealdb/vercel-ai integrates Spectron with the Vercel AI SDK. Keep using your own model provider (@ai-sdk/openai, @ai-sdk/anthropic, and so on) with generateText / streamText, and let Spectron transparently:

  • inject relevant long-term memory (and the user's profile) into the prompt before generation, and

  • store each user and assistant exchange afterwards,

plus an optional tool set so the model can query memory on demand mid-generation.

The API is createSpectron().middleware() / .tools().

npm i @surrealdb/vercel-ai ai @surrealdb/spectron
# plus your model provider, e.g.
npm i @ai-sdk/openai

ai (v7) is a peer dependency; you bring your own model provider.

createSpectron() reads credentials from the environment by default:

VariableDescription
SPECTRON_ENDPOINTAPI endpoint origin
SPECTRON_API_KEYBearer API key
SPECTRON_CONTEXTContext id
import { createSpectron } from "@surrealdb/vercel-ai";

// From the environment, bound to one user by default.
const spectron = createSpectron({ defaultScopes: "user/tobie" });

// Or pass config / a preconstructed client explicitly:
import { Spectron } from "@surrealdb/vercel-ai";
const spectron = createSpectron({
    client: new Spectron({ endpoint, apiKey, context }),
});

Wrap your model with wrapLanguageModel. The middleware fetches memory for the latest user message, injects it as a system message, then stores the exchange after generation:

import { openai } from "@ai-sdk/openai";
import { generateText, wrapLanguageModel } from "ai";
import { createSpectron } from "@surrealdb/vercel-ai";

const spectron = createSpectron({ defaultScopes: "user/tobie" });

const model = wrapLanguageModel({
    model: openai("gpt-4o"),
    middleware: spectron.middleware({ sessionId: "session-123" }),
});

const { text } = await generateText({
    model,
    prompt: "What should I focus on today?",
});

streamText works identically. The middleware wraps the stream, accumulates the reply, and stores it once the stream finishes.

OptionDefaultDescription
scopesdefaultScopesDNF scope selector for reads and writes, for example "user/tobie".
sessionIdn/aSession to attach retrieved context and stored turns to.
injectHistorytrueInject retrieved memory before generation.
storetrueStore the user and assistant exchange after generation.
retrieval"context""context" (server-formatted), "recall" (raw hits), or false.
k8Max hits / context breadth to retrieve.
includeProfiletrueInject the user's profile.
onErrorno-opCalled on memory errors; generation still proceeds.
Note

Memory operations are fail-open: if Spectron is unreachable, the middleware falls back to a plain LLM call rather than throwing.

When you already pass a full messages array, turn store off (or set retrieval: false / injectHistory: false) to avoid duplicating history.

spectron.tools() returns a Vercel AI SDK ToolSet the model can call during generation, bound to the same scope and session you pass:

import { generateText, stepCountIs } from "ai";

const { text } = await generateText({
    model,
    tools: spectron.tools({ sessionId: "session-123" }),
    stopWhen: stepCountIs(3),
    prompt: "Based on our past conversations, what do I care about most?",
});
ToolWhat it does
spectron_recallSemantic recall of facts and passages for a query.
spectron_contextServer-formatted context text for a query.
spectron_reflectSynthesise over memory, optionally persisting the conclusion.
spectron_rememberPersist a fact or observation for future recall.
spectron_forgetForget memories matching a query.
spectron_profileThe user's attributes, preferences, and instructions.
spectron_inspectResolve an entity, attribute, relation, or trace reference.

Scopes bind reads and writes to a region of memory (a DNF selector). A bare string is a single path:

spectron.middleware({ scopes: "user/tobie" });           // one user
spectron.middleware({ scopes: ["team/eng", "user/x"] }); // OR of two

spectron.client is the underlying @surrealdb/spectron client for anything not wrapped here: documents, sessions, entities, chat, and so on. See the JavaScript SDK for the full surface.

Was this page helpful?