mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-16 20:14:02 +00:00
feat(ai-sdk): re-export full Supermemory tool set from @supermemory/tools
Thin @supermemory/ai-sdk package now mirrors the canonical 7-tool surface with updated tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
d5937b8b26
commit
9c3f84b5cb
4 changed files with 58 additions and 163 deletions
|
|
@ -1,19 +1,21 @@
|
|||
{
|
||||
"name": "@supermemory/ai-sdk",
|
||||
"type": "module",
|
||||
"version": "1.0.8",
|
||||
"version": "1.0.9",
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"dev": "tsdown --watch --ignore-watch .turbo",
|
||||
"check-types": "tsc --noEmit",
|
||||
"test": "vitest",
|
||||
"test:unit": "vitest run src/tools.unit.test.ts",
|
||||
"test:watch": "vitest --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^2.0.22",
|
||||
"@ai-sdk/provider": "^2.0.0",
|
||||
"@supermemory/tools": "workspace:*",
|
||||
"ai": "^5.0.113",
|
||||
"supermemory": "^3.0.0-alpha.26"
|
||||
"supermemory": "^4.25.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@total-typescript/tsconfig": "^1.0.4",
|
||||
|
|
@ -24,7 +26,7 @@
|
|||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index-Dk1U5LBS.d.ts",
|
||||
"types": "./dist/index-B8qmWxBg.d.ts",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./package.json": "./package.json"
|
||||
|
|
|
|||
|
|
@ -5,19 +5,12 @@ 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")
|
||||
}
|
||||
describe.skipIf(
|
||||
!process.env.SUPERMEMORY_API_KEY || !process.env.OPENAI_API_KEY,
|
||||
)("supermemoryTools", () => {
|
||||
// Required API keys — suite is skipped in CI without them
|
||||
const testApiKey = process.env.SUPERMEMORY_API_KEY as string
|
||||
const testOpenAIKey = process.env.OPENAI_API_KEY as string
|
||||
|
||||
// Optional configuration with defaults
|
||||
const testBaseUrl = process.env.SUPERMEMORY_BASE_URL ?? undefined
|
||||
|
|
@ -39,6 +32,11 @@ describe("supermemoryTools", () => {
|
|||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.getProfile).toBeDefined()
|
||||
expect(tools.documentList).toBeDefined()
|
||||
expect(tools.documentDelete).toBeDefined()
|
||||
expect(tools.documentAdd).toBeDefined()
|
||||
expect(tools.memoryForget).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with custom baseUrl", () => {
|
||||
|
|
|
|||
|
|
@ -1,150 +1,17 @@
|
|||
import { jsonSchema, tool } from "ai"
|
||||
import Supermemory from "supermemory"
|
||||
|
||||
/**
|
||||
* Supermemory configuration
|
||||
* Only one of `projectId` or `containerTags` can be provided.
|
||||
* Re-export the canonical Supermemory AI SDK tools from @supermemory/tools.
|
||||
* Prefer @supermemory/tools for middleware, OpenAI, Mastra, and VoltAgent integrations.
|
||||
*/
|
||||
export interface SupermemoryToolsConfig {
|
||||
baseUrl?: string
|
||||
containerTags?: string[]
|
||||
projectId?: string
|
||||
}
|
||||
export {
|
||||
supermemoryTools,
|
||||
searchMemoriesTool,
|
||||
addMemoryTool,
|
||||
getProfileTool,
|
||||
documentListTool,
|
||||
documentDeleteTool,
|
||||
documentAddTool,
|
||||
memoryForgetTool,
|
||||
getContainerTags,
|
||||
} from "@supermemory/tools/ai-sdk"
|
||||
|
||||
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
|
||||
}
|
||||
export type { SupermemoryToolsConfig } from "@supermemory/tools"
|
||||
|
|
|
|||
28
packages/ai-sdk/src/tools.unit.test.ts
Normal file
28
packages/ai-sdk/src/tools.unit.test.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { describe, expect, it } from "vitest"
|
||||
import { getContainerTags } from "./tools"
|
||||
|
||||
describe("getContainerTags", () => {
|
||||
it("defaults to the default project when no config is provided", () => {
|
||||
expect(getContainerTags()).toEqual(["sm_project_default"])
|
||||
})
|
||||
|
||||
it("converts projectId into a project container tag", () => {
|
||||
expect(getContainerTags({ projectId: "abc" })).toEqual(["sm_project_abc"])
|
||||
})
|
||||
|
||||
it("uses explicit container tags", () => {
|
||||
expect(getContainerTags({ containerTags: ["tag-a", "tag-b"] })).toEqual([
|
||||
"tag-a",
|
||||
"tag-b",
|
||||
])
|
||||
})
|
||||
|
||||
it("rejects config with both projectId and containerTags", () => {
|
||||
expect(() =>
|
||||
getContainerTags({
|
||||
projectId: "abc",
|
||||
containerTags: ["tag-a"],
|
||||
}),
|
||||
).toThrow("either projectId or containerTags")
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue