import { createOpenAI } from "@ai-sdk/openai"; import { generateText } from "ai"; import { describe, expect, it } from "vitest"; import * as aiSdk from "./ai-sdk"; import * as openAi from "./openai"; import type { SupermemoryToolsConfig } from "./types"; import "dotenv/config"; describe("@supermemory/tools", () => { // 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-4o-mini"; describe("aiSdk module", () => { describe("client initialization", () => { it("should create tools with default configuration", () => { const config: SupermemoryToolsConfig = {}; const tools = aiSdk.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 = aiSdk.supermemoryTools(testApiKey, config); expect(tools).toBeDefined(); expect(tools.searchMemories).toBeDefined(); expect(tools.addMemory).toBeDefined(); }); it("should create individual tools", () => { const searchTool = aiSdk.searchMemoriesTool(testApiKey, { projectId: "test-project-123", }); const addTool = aiSdk.addMemoryTool(testApiKey, { projectId: "test-project-123", }); expect(searchTool).toBeDefined(); expect(addTool).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: "What do you remember about my preferences?", }, ], tools: { ...aiSdk.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 = aiSdk.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(); }); }); }); describe("openAi module", () => { describe("function-based tools", () => { it("should create function-based tools", () => { const tools = openAi.supermemoryTools(testApiKey, { projectId: "test-openai-functions", }); expect(tools).toBeDefined(); expect(tools.searchMemories).toBeDefined(); expect(tools.addMemory).toBeDefined(); }); it("should create individual tool functions", () => { const searchFunction = openAi.createSearchMemoriesFunction(testApiKey, { projectId: "test-individual", }); const addFunction = openAi.createAddMemoryFunction(testApiKey, { projectId: "test-individual", }); expect(searchFunction).toBeDefined(); expect(addFunction).toBeDefined(); expect(typeof searchFunction).toBe("function"); expect(typeof addFunction).toBe("function"); }); }); describe("tool definitions", () => { it("should return proper OpenAI function definitions", () => { const definitions = openAi.getToolDefinitions(); expect(definitions).toBeDefined(); expect(definitions.length).toBe(2); // Check searchMemories const searchTool = definitions.find( (d) => d.function.name === "searchMemories", ); expect(searchTool).toBeDefined(); expect(searchTool!.type).toBe("function"); expect(searchTool!.function.parameters?.required).toContain( "informationToGet", ); // Check addMemory const addTool = definitions.find( (d) => d.function.name === "addMemory", ); expect(addTool).toBeDefined(); expect(addTool!.type).toBe("function"); expect(addTool!.function.parameters?.required).toContain("memory"); }); }); describe("tool execution", () => { it("should create tool call executor", () => { const executor = openAi.createToolCallExecutor(testApiKey, { containerTags: ["test-executor"], baseUrl: testBaseUrl, }); expect(executor).toBeDefined(); expect(typeof executor).toBe("function"); }); it("should create tool calls executor", () => { const executor = openAi.createToolCallsExecutor(testApiKey, { containerTags: ["test-executors"], baseUrl: testBaseUrl, }); expect(executor).toBeDefined(); expect(typeof executor).toBe("function"); }); }); describe("individual tool creators", () => { it("should create individual search tool", () => { const searchTool = openAi.createSearchMemoriesTool(testApiKey, { projectId: "test-individual", }); expect(searchTool).toBeDefined(); expect(searchTool.definition).toBeDefined(); expect(searchTool.execute).toBeDefined(); expect(searchTool.definition.function.name).toBe("searchMemories"); }); it("should create individual add tool", () => { const addTool = openAi.createAddMemoryTool(testApiKey, { projectId: "test-individual", }); expect(addTool).toBeDefined(); expect(addTool.definition).toBeDefined(); expect(addTool.execute).toBeDefined(); expect(addTool.definition.function.name).toBe("addMemory"); }); }); describe("memory operations", () => { it("should search memories", async () => { const searchFunction = openAi.createSearchMemoriesFunction(testApiKey, { projectId: "test-search", baseUrl: testBaseUrl, }); const result = await searchFunction({ informationToGet: "test preferences", limit: 5, }); expect(result).toBeDefined(); expect(result.success).toBeDefined(); expect(typeof result.success).toBe("boolean"); if (result.success) { expect(result.results).toBeDefined(); expect(result.count).toBeDefined(); expect(typeof result.count).toBe("number"); } else { expect(result.error).toBeDefined(); } }); it("should add memory", async () => { const addFunction = openAi.createAddMemoryFunction(testApiKey, { containerTags: ["test-add-memory"], baseUrl: testBaseUrl, }); const result = await addFunction({ memory: "User prefers dark roast coffee in the morning - test memory", }); expect(result).toBeDefined(); expect(result.success).toBeDefined(); expect(typeof result.success).toBe("boolean"); if (result.success) { expect(result.memory).toBeDefined(); } else { expect(result.error).toBeDefined(); } }); }); }); });