New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@contextq/ai-sdk-memory

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@contextq/ai-sdk-memory

Vercel AI SDK memory tools (searchMemories, addMemory) backed by ContextQ -- a tool-provider adapter for the AI SDK memory page

latest
Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
4
-76.47%
Maintainers
1
Weekly downloads
 
Created
Source

@contextq/ai-sdk-memory

Vercel AI SDK memory tools -- searchMemories and addMemory -- backed by ContextQ. This is a tool provider, the same integration shape the AI SDK's own memory page documents for Supermemory (addMemory/searchMemories), not a language-model middleware or provider wrapper -- there is no documented AI SDK extension point for "read memory before generation, write after," so this package hands the model two ordinary tools instead. Background: .contextq/tasks/tasks/T726.md ("Decisions" section) is the design record this package implements.

Install

npm install @contextq/ai-sdk-memory ai @contextq/sdk

ai and @contextq/sdk are peer dependencies -- bring your own versions (tested against ai@^7.0.90, the version current when this package was built; @contextq/sdk@^0.2.0).

Quick start

import { generateText } from 'ai';
import { contextQMemoryTools } from '@contextq/ai-sdk-memory';

const memory = contextQMemoryTools({
  apiKey: process.env.CONTEXT_API_KEY!, // sk_live_<40 hex>
  subjectId: 'user-42',                 // the end-user this conversation is with
});

// Turn 1: the model decides to remember something.
await generateText({
  model: yourModel,
  tools: memory,
  prompt: 'Remember that I prefer dark mode, then confirm it.',
});

// Turn 2 (later, same subject): the model decides to recall it.
const { text } = await generateText({
  model: yourModel,
  tools: memory,
  prompt: 'What UI theme do I prefer?',
});
console.log(text);

contextQMemoryTools(options) returns a plain ToolSet ({ searchMemories, addMemory }) -- pass it straight to tools on generateText/streamText, or spread it into a larger tool set alongside your own tools.

Options

OptionDefaultNotes
subjectId--Required. ContextQ's end-user scoping id (the same field POST /api/retrieve/POST /api/memory already accept). Fixed at factory time, not a tool input -- the model can never read or write another subject's memories.
apiKeyprocess.env.CONTEXT_API_KEYContextQ API key, sk_live_<40 hex>. Required (one of this, client, or the env var).
baseUrlprocess.env.CONTEXT_API_URL || http://localhost:38200ContextQ API base URL. Ignored when client is given.
client--A pre-configured @contextq/sdk ContextQ instance. Use this instead of apiKey/baseUrl to control retries, timeouts, extra headers (e.g. a gateway auth header), or a custom fetch.
workspacetenant default (global when none set)ContextQ workspace slug both tools are scoped to.
defaultLimit8Default top_k for searchMemories when the model omits limit.

The two tools

searchMemories

Input: { query: string, limit?: number }.

Calls client.retrieve.query() (POST /api/retrieve) and flattens all three response arrays -- passages (workspace/tenant context chunks), memories (this subject's own extracted facts), and groupMemories (T414 shared account/group facts the subject belongs to) -- into one list sorted by score, plus a single citedText block:

{
  citedText: "[1] (memory, score 0.812) The user's preferred identifier is ...\n\n[2] ...",
  hits: [{ ref: 1, source: 'memory', text: '...', score: 0.812, contextId: 42, title: '...' }],
  empty: false,
}

addMemory

Input: { content: string } -- a plain-language statement to remember.

Calls client.memory.add([{ role: 'user', content }], { subjectId, workspace }) (POST /api/memory), ContextQ's real LLM-extraction pipeline (Mem0-parity): it is not a raw append log -- ContextQ extracts durable atomic facts from the text and dedupes/updates/archives against what it already knows. A short, test-artifact-shaped string (e.g. a bare UUID with no first-person framing) can legitimately extract zero facts; write real statements ("My preferred X is Y") for this to do anything.

Two possible outputs, depending on the server's sync/async threshold:

{ status: 'written', created: [...], updated: [...], extractedClaims: 1 }
// or, for a long conversation the server queues:
{ status: 'queued', jobId: 99, statusUrl: '/api/memory/jobs/99' }

Why subjectId is a factory option, not a tool argument

The AI SDK memory page's Mem0 row configures the equivalent (user_id) the same way -- once, at setup, not per tool call. Exposing it as a tool argument instead would let a model (or a prompt-injected instruction) read or write an arbitrary subject's memories by just naming a different id in its tool call. searchMemories/addMemory's execute closures capture subjectId from the factory call and never read it from the model's input, so the wire request always carries the id the calling application chose.

Development

npm install
npm test          # unit tests against @contextq/sdk with a fake `fetch` -- no real ContextQ needed
npm run typecheck # typecheck (src + scripts)
npm run build     # emit dist/ (src only, tests excluded)

@contextq/sdk is not published to npm yet (see "What 'publishable' means here" below), so local development resolves it via a file:../../sdk devDependency instead of the registry. That only works when this repository's own sdk/ directory sits two levels up, which is always true inside a clone of this repo but NOT inside a container that mounts only this package's own directory -- sdk/ must be built (cd ../../sdk && npm ci && npm run build) and reachable on disk before npm ci/npm install here can resolve it.

Live e2e

scripts/e2e-live.ts proves the full loop against a real, running local ContextQ instance -- no fakes, no mocks:

  • addMemory writes a real fact through the server's real LLM-extraction pipeline, verified independently via GET /api/contexts (not just "the tool didn't throw").
  • A second, separate searchMemories call retrieves that same fact via the server's real embedding-backed retrieval.

Unlike the sibling adapters/anthropic-memory-tool/scripts/e2e-live.ts, this script never calls a real LLM API itself -- this package is a tool provider, so calling tool.execute() directly is exactly what the AI SDK's own tool-calling runtime does once a model decides to invoke a tool. The ContextQ round trip on the other end (the part this package actually wraps) is real.

Requires:

  • The local ContextQ dev stack already running and reachable (default http://localhost:38200), with both an LLM and an embedding provider configured -- check curl $CONTEXT_API_URL/health/deep shows llm.status and embedding.status both "ok". Without an LLM configured, addMemory still returns 200 but extracts zero facts (server-side policy, not an adapter bug) and the script fails loudly with a message pointing at this check rather than a confusing downstream assertion.
  • Docker access to the shared-context-postgres container (used to create a throwaway tenant + owner user and mint an API key for them by direct INSERT -- see the script's own doc comments; same sanctioned local-dev pattern the sibling adapter's e2e-live.ts uses).
CONTEXT_API_URL=http://localhost:38200 npm run e2e:live

Every write is confined to a throwaway tenant + workspace created at the start; cleanup runs in the script's finally block regardless of pass/fail (the throwaway tenant row itself is left in place only if it already owns a chained activity_logs row -- the same accepted trade-off src/test-helpers/tenant-cleanup.ts documents, to avoid forking the global audit hash chain).

What "publishable" means here

This package is built and tested to be published, but publishing itself (npm publish) is deliberately out of scope -- see the repo's task tracker (T679) for the user-owned release flow this hands off to. Note that @contextq/sdk itself is not published to npm yet either, so a real npm install of this package by an external user is blocked until that release lands; the peer dependency range is set for that future state.

Keywords

contextq

FAQs

Package last updated on 15 Sep 2026

Related posts