fix(tools): deduplicate @supermemory/ai-sdk into @supermemory/tools/ai-sdk

Fixes #1247
This commit is contained in:
Param 2026-07-12 22:04:28 +05:30
parent 2cebe81512
commit 6cdf8451b7
4 changed files with 12 additions and 339 deletions

View file

@ -1,7 +1,7 @@
{
"name": "@supermemory/ai-sdk",
"type": "module",
"version": "1.0.8",
"version": "2.0.0",
"scripts": {
"build": "tsdown",
"dev": "tsdown --watch --ignore-watch .turbo",
@ -10,10 +10,8 @@
"test:watch": "vitest --watch"
},
"dependencies": {
"@ai-sdk/openai": "^2.0.22",
"@ai-sdk/provider": "^2.0.0",
"ai": "^5.0.113",
"supermemory": "^3.0.0-alpha.26"
"@ai-sdk/provider": "^1.0.0",
"@supermemory/tools": "workspace:*"
},
"devDependencies": {
"@total-typescript/tsconfig": "^1.0.4",
@ -24,7 +22,7 @@
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index-Dk1U5LBS.d.ts",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./package.json": "./package.json"
@ -38,5 +36,7 @@
"sdk",
"supermemory",
"memory"
]
],
"author": "Supermemory Team",
"license": "MIT"
}

View file

@ -1 +1,5 @@
export * from "./tools"
/**
* @deprecated Use `@supermemory/tools/ai-sdk` directly.
* This package is now a re-export of `@supermemory/tools/ai-sdk` to prevent code drift.
*/
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
}