refactor(ai-sdk)!: re-export @supermemory/tools/ai-sdk (#1247) — the ! marks the breaking default-scope change.

This commit is contained in:
rajashidattapy 2026-07-12 12:58:08 +05:30
parent 2cebe81512
commit b73b4cb53e
9 changed files with 39 additions and 352 deletions

View file

@ -56,7 +56,8 @@ jobs:
- name: Build
if: steps.version-check.outputs.changed == 'true'
run: bun run build
working-directory: .
run: bunx turbo run build --filter='@supermemory/ai-sdk'
- name: Publish
if: steps.version-check.outputs.changed == 'true'

View file

@ -242,19 +242,16 @@
},
"packages/ai-sdk": {
"name": "@supermemory/ai-sdk",
"version": "1.0.8",
"version": "2.0.0",
"dependencies": {
"@ai-sdk/openai": "^2.0.22",
"@ai-sdk/provider": "^2.0.0",
"ai": "^5.0.113",
"supermemory": "^3.0.0-alpha.26",
"@supermemory/tools": "^2.1.0",
},
"devDependencies": {
"@total-typescript/tsconfig": "^1.0.4",
"@types/bun": "^1.2.21",
"tsdown": "^0.14.2",
"typescript": "^5.9.2",
"vitest": "^3.2.4",
},
},
"packages/docs-test": {
@ -320,7 +317,7 @@
},
"packages/tools": {
"name": "@supermemory/tools",
"version": "2.0.0",
"version": "2.1.0",
"dependencies": {
"@ai-sdk/anthropic": "^2.0.25",
"@ai-sdk/openai": "^2.0.23",

View file

@ -1,5 +1,18 @@
# supermemory AI SDK Utilities
> **Deprecated.** Use [`@supermemory/tools`](../tools) instead:
>
> ```ts
> import { supermemoryTools } from "@supermemory/tools/ai-sdk"
> ```
>
> As of 2.0.0 this package is a thin re-export of `@supermemory/tools/ai-sdk`, so it
> inherits that package's container-scoping semantics. **This is a behavior change:**
>
> - Passing both `projectId` and `containerTags` now throws instead of silently ignoring `containerTags`.
> - With no config, calls are scoped to `["sm_project_default"]`. Previously they were **unscoped**, i.e. searching and writing across every project. If you relied on that, pass `containerTags` explicitly.
> - `limit` is coerced, so a model emitting `"5"` is accepted rather than rejected.
Vercel AI SDK utilities for supermemory
## Installation

View file

@ -1,30 +1,26 @@
{
"name": "@supermemory/ai-sdk",
"type": "module",
"version": "1.0.8",
"version": "2.0.0",
"description": "Deprecated: re-exports @supermemory/tools/ai-sdk",
"scripts": {
"build": "tsdown",
"dev": "tsdown --watch --ignore-watch .turbo",
"check-types": "tsc --noEmit",
"test": "vitest",
"test:watch": "vitest --watch"
"check-types": "tsc --noEmit"
},
"dependencies": {
"@ai-sdk/openai": "^2.0.22",
"@ai-sdk/provider": "^2.0.0",
"ai": "^5.0.113",
"supermemory": "^3.0.0-alpha.26"
"@supermemory/tools": "^2.1.0"
},
"devDependencies": {
"@total-typescript/tsconfig": "^1.0.4",
"@types/bun": "^1.2.21",
"tsdown": "^0.14.2",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
"typescript": "^5.9.2"
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index-Dk1U5LBS.d.ts",
"types": "./dist/index-iQkOjAt3.d.ts",
"exports": {
".": "./dist/index.js",
"./package.json": "./package.json"

View file

@ -1 +1,12 @@
export * from "./tools"
/**
* @deprecated Use `@supermemory/tools/ai-sdk` instead. This package is now a
* thin re-export of it and will not receive further changes.
*
* Behavior change in 2.0.0 (inherited from `@supermemory/tools`):
* - Passing both `projectId` and `containerTags` now throws instead of silently
* ignoring `containerTags`.
* - With no config, calls are scoped to `["sm_project_default"]` instead of being
* unscoped across every project.
* - `limit`/`offset` are coerced, so a model emitting `"5"` is accepted.
*/
export * from "@supermemory/tools/ai-sdk"

View file

@ -1,181 +0,0 @@
import { createOpenAI } from "@ai-sdk/openai"
import { generateText } from "ai"
import { describe, expect, it } from "vitest"
import { type SupermemoryToolsConfig, supermemoryTools } from "./tools"
import "dotenv/config"
describe("supermemoryTools", () => {
// Required API keys - tests will fail if not provided
const testApiKey = process.env.SUPERMEMORY_API_KEY
const testOpenAIKey = process.env.OPENAI_API_KEY
if (!testApiKey) {
throw new Error(
"SUPERMEMORY_API_KEY environment variable is required for tests",
)
}
if (!testOpenAIKey) {
throw new Error("OPENAI_API_KEY environment variable is required for tests")
}
// Optional configuration with defaults
const testBaseUrl = process.env.SUPERMEMORY_BASE_URL ?? undefined
const testModelName = process.env.MODEL_NAME || "gpt-5-nano"
const testPrompts = [
"What do you remember about my preferences?",
"Help me plan my day based on what you know about me",
"What are my current projects?",
"Remind me of my interests and hobbies",
"What should I focus on today?",
]
describe("client initialization", () => {
it("should create tools with default configuration", () => {
const config: SupermemoryToolsConfig = {}
const tools = supermemoryTools(testApiKey, config)
expect(tools).toBeDefined()
expect(tools.searchMemories).toBeDefined()
expect(tools.addMemory).toBeDefined()
})
it("should create tools with custom baseUrl", () => {
const config: SupermemoryToolsConfig = {
baseUrl: testBaseUrl,
}
const tools = supermemoryTools(testApiKey, config)
expect(tools).toBeDefined()
expect(tools.searchMemories).toBeDefined()
expect(tools.addMemory).toBeDefined()
})
it("should create tools with projectId configuration", () => {
const config: SupermemoryToolsConfig = {
projectId: "test-project-123",
}
const tools = supermemoryTools(testApiKey, config)
expect(tools).toBeDefined()
expect(tools.searchMemories).toBeDefined()
expect(tools.addMemory).toBeDefined()
})
it("should create tools with custom container tags", () => {
const config: SupermemoryToolsConfig = {
containerTags: ["custom-tag-1", "custom-tag-2"],
}
const tools = supermemoryTools(testApiKey, config)
expect(tools).toBeDefined()
expect(tools.searchMemories).toBeDefined()
expect(tools.addMemory).toBeDefined()
})
})
describe("AI SDK integration", () => {
it("should work with AI SDK generateText", async () => {
const openai = createOpenAI({
apiKey: testOpenAIKey,
})
const result = await generateText({
model: openai(testModelName),
messages: [
{
role: "system",
content:
"You are a helpful assistant with access to user memories. Use the search tool when the user asks about preferences or past information.",
},
{
role: "user",
content: testPrompts[0]!,
},
],
tools: {
...supermemoryTools(testApiKey, {
projectId: "test-ai-integration",
baseUrl: testBaseUrl,
}),
},
})
expect(result).toBeDefined()
expect(result.text).toBeDefined()
expect(typeof result.text).toBe("string")
})
it("should use tools when prompted", async () => {
const openai = createOpenAI({
apiKey: testOpenAIKey,
})
const tools = supermemoryTools(testApiKey, {
projectId: "test-tool-usage",
baseUrl: testBaseUrl,
})
const result = await generateText({
model: openai(testModelName),
messages: [
{
role: "system",
content:
"You are a helpful assistant. When the user asks you to remember something, use the addMemory tool.",
},
{
role: "user",
content: "Please remember that I prefer dark roast coffee",
},
],
tools: {
addMemory: tools.addMemory,
},
})
expect(result).toBeDefined()
expect(result.text).toBeDefined()
expect(result.toolCalls).toBeDefined()
if (result.toolCalls && result.toolCalls.length > 0) {
const addMemoryCall = result.toolCalls.find(
(call) => call.toolName === "addMemory",
)
expect(addMemoryCall).toBeDefined()
}
})
it("should handle multiple tool types", async () => {
const openai = createOpenAI({
apiKey: testOpenAIKey,
})
const result = await generateText({
model: openai(testModelName),
messages: [
{
role: "system",
content:
"You are a helpful assistant with access to user memories. Use search when asked about preferences, and addMemory when told to remember something.",
},
{
role: "user",
content:
"Search for my preferences and then remember that I also like green tea",
},
],
tools: {
...supermemoryTools(testApiKey, {
containerTags: ["test-multi-tools"],
}),
},
})
expect(result).toBeDefined()
expect(result.text).toBeDefined()
expect(typeof result.text).toBe("string")
})
})
})

View file

@ -1,150 +0,0 @@
import { jsonSchema, tool } from "ai"
import Supermemory from "supermemory"
/**
* Supermemory configuration
* Only one of `projectId` or `containerTags` can be provided.
*/
export interface SupermemoryToolsConfig {
baseUrl?: string
containerTags?: string[]
projectId?: string
}
type SearchMemoriesInput = {
informationToGet: string
includeFullDocs: boolean
limit: number
}
type AddMemoryInput = {
memory: string
}
/**
* Create Supermemory tools for AI SDK
*/
export function supermemoryTools(
apiKey: string,
config?: SupermemoryToolsConfig,
) {
const client = new Supermemory({
apiKey,
...(config?.baseUrl ? { baseURL: config.baseUrl } : {}),
})
const containerTags = config?.projectId
? [`sm_project_${config?.projectId}`]
: config?.containerTags
const searchMemories = tool({
description:
"Search (recall) memories/details/information about the user or other facts or entities. Run when explicitly asked or when context about user's past choices would be helpful.",
inputSchema: jsonSchema<SearchMemoriesInput>({
type: "object",
properties: {
informationToGet: {
type: "string",
description: "Terms to search for in the user's memories",
},
includeFullDocs: {
type: "boolean",
description:
"Whether to include the full document content in the response. Defaults to true for better AI context.",
default: true,
},
limit: {
type: "number",
description: "Maximum number of results to return",
default: 10,
},
},
required: ["informationToGet"],
}),
execute: async ({
informationToGet,
includeFullDocs = true,
limit = 10,
}) => {
try {
const response = await client.search.execute({
q: informationToGet,
containerTags,
limit,
chunkThreshold: 0.6,
includeFullDocs,
})
return {
success: true,
results: response.results,
count: response.results?.length || 0,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
}
}
},
})
const addMemory = tool({
description:
"Add (remember) memories/details/information about the user or other facts or entities. Run when explicitly asked or when the user mentions any information generalizable beyond the context of the current conversation.",
inputSchema: jsonSchema<AddMemoryInput>({
type: "object",
properties: {
memory: {
type: "string",
description:
"The text content of the memory to add. This should be a single sentence or a short paragraph.",
},
},
required: ["memory"],
}),
execute: async ({ memory }) => {
try {
const metadata: Record<string, string | number | boolean> = {}
const response = await client.add({
content: memory,
containerTags,
...(Object.keys(metadata).length > 0 && { metadata }),
})
return {
success: true,
memory: response,
}
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
}
}
},
})
return {
searchMemories,
addMemory,
}
}
// Export individual tool creators for more flexibility
export const searchMemoriesTool = (
apiKey: string,
config?: SupermemoryToolsConfig,
) => {
const { searchMemories } = supermemoryTools(apiKey, config)
return searchMemories
}
export const addMemoryTool = (
apiKey: string,
config?: SupermemoryToolsConfig,
) => {
const { addMemory } = supermemoryTools(apiKey, config)
return addMemory
}

View file

@ -51,8 +51,8 @@
"./ai-sdk": "./dist/ai-sdk.js",
"./claude-memory": "./dist/claude-memory.js",
"./mastra": "./dist/mastra.js",
"./openai": "./dist/openai/index.js",
"./voltagent": "./dist/voltagent/index.js",
"./openai\\index": "./dist/openai\\index.js",
"./voltagent\\index": "./dist/voltagent\\index.js",
"./package.json": "./package.json"
},
"repository": {

View file

@ -11,7 +11,7 @@
"dependsOn": ["^lint"]
},
"check-types": {
"dependsOn": ["^check-types"]
"dependsOn": ["^build"]
},
"dev": {
"cache": false,