diff --git a/packages/ai-sdk/package.json b/packages/ai-sdk/package.json index 30ff931b7..84404de72 100644 --- a/packages/ai-sdk/package.json +++ b/packages/ai-sdk/package.json @@ -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" } diff --git a/packages/ai-sdk/src/index.ts b/packages/ai-sdk/src/index.ts index e419075c8..7a8268e75 100644 --- a/packages/ai-sdk/src/index.ts +++ b/packages/ai-sdk/src/index.ts @@ -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"; diff --git a/packages/ai-sdk/src/tools.test.ts b/packages/ai-sdk/src/tools.test.ts deleted file mode 100644 index 0acfc7ed7..000000000 --- a/packages/ai-sdk/src/tools.test.ts +++ /dev/null @@ -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") - }) - }) -}) diff --git a/packages/ai-sdk/src/tools.ts b/packages/ai-sdk/src/tools.ts deleted file mode 100644 index 7d0b837cb..000000000 --- a/packages/ai-sdk/src/tools.ts +++ /dev/null @@ -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({ - 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({ - 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 = {} - - 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 -}