mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
feat(tools): apiKey option, type re-exports, and two reliability fixes (#1594)
Some checks failed
Publish Tools / publish (push) Has been cancelled
Some checks failed
Publish Tools / publish (push) Has been cancelled
Cherry-picks four contributor PRs for `@supermemory/tools` onto one branch, and bumps the package to 2.2.0. - #1244 (@rajarshidattapy): `withSupermemory` accepts `options.apiKey` instead of only reading `SUPERMEMORY_API_KEY`, matching the Vercel, Mastra and Voltagent integrations. Unblocks secrets managers, edge runtimes and per-request keys. - #1574 (@Agnik47): re-exports `PromptTemplate`, `MemoryPromptData` and `WithSupermemoryOptions` from `ai-sdk`. `./vercel` is not a published subpath, so the documented custom-template example did not compile. - #1488 (@abhinav7x94): malformed tool-call JSON returns an error result instead of throwing out of the request. - #1507 (@abhinav7x94): VoltAgent `onEnd` awaits the conversation save, which was fire-and-forget and could be dropped when a serverless runtime tore down. Dropped the `middleware.test.ts` added by #1244. Note that editing `packages/tools/package.json` triggers the npm publish workflow on merge. Co-Authored-By: rajarshidattapy <138959719+rajarshidattapy@users.noreply.github.com> Co-Authored-By: Agnik47 <140933190+Agnik47@users.noreply.github.com> Co-Authored-By: abhinav7x94 <204053250+abhinav7x94@users.noreply.github.com>
This commit is contained in:
parent
f051af098e
commit
e4afc770be
8 changed files with 53 additions and 22 deletions
2
bun.lock
2
bun.lock
|
|
@ -336,7 +336,7 @@
|
|||
},
|
||||
"packages/tools": {
|
||||
"name": "@supermemory/tools",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.0",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^2.0.25",
|
||||
"@ai-sdk/openai": "^2.0.23",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@supermemory/tools",
|
||||
"type": "module",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.0",
|
||||
"description": "Memory tools for AI SDK, OpenAI, Voltagent and Mastra with supermemory",
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
|
|
|
|||
|
|
@ -372,4 +372,10 @@ export function supermemoryTools(
|
|||
}
|
||||
}
|
||||
|
||||
export { withSupermemory } from "./vercel"
|
||||
// `./vercel` is not a published subpath, so this is the only way consumers reach the middleware types.
|
||||
export {
|
||||
withSupermemory,
|
||||
type WithSupermemoryOptions,
|
||||
type PromptTemplate,
|
||||
type MemoryPromptData,
|
||||
} from "./vercel"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type OpenAI from "openai"
|
||||
import { validateApiKey } from "../shared"
|
||||
import {
|
||||
createOpenAIMiddleware,
|
||||
type OpenAIMiddlewareOptions,
|
||||
|
|
@ -21,6 +22,7 @@ import {
|
|||
* @param options.verbose - Optional flag to enable detailed logging of memory search and injection process (default: false)
|
||||
* @param options.mode - Optional mode for memory search: "profile" (default), "query", or "full"
|
||||
* @param options.addMemory - Optional mode for memory addition: "always" (default), "never"
|
||||
* @param options.apiKey - Optional Supermemory API key to use instead of the SUPERMEMORY_API_KEY environment variable
|
||||
*
|
||||
* @returns An OpenAI client with SuperMemory middleware injected for both Chat Completions and Responses APIs
|
||||
*
|
||||
|
|
@ -56,16 +58,14 @@ import {
|
|||
* })
|
||||
* ```
|
||||
*
|
||||
* @throws {Error} When SUPERMEMORY_API_KEY environment variable is not set
|
||||
* @throws {Error} When neither `options.apiKey` nor `process.env.SUPERMEMORY_API_KEY` are set
|
||||
* @throws {Error} When supermemory API request fails
|
||||
*/
|
||||
export function withSupermemory(
|
||||
openaiClient: OpenAI,
|
||||
options: OpenAIMiddlewareOptions,
|
||||
) {
|
||||
if (!process.env.SUPERMEMORY_API_KEY) {
|
||||
throw new Error("SUPERMEMORY_API_KEY is not set")
|
||||
}
|
||||
validateApiKey(options.apiKey)
|
||||
|
||||
if (!options.containerTag) {
|
||||
throw new Error(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type OpenAI from "openai"
|
||||
import Supermemory from "supermemory"
|
||||
import { addConversation } from "../conversations-client"
|
||||
import { validateApiKey } from "../shared"
|
||||
import { deduplicateMemoriesForMode } from "../tools-shared"
|
||||
import { createLogger, type Logger } from "../vercel/logger"
|
||||
import { convertProfileToMarkdown } from "../vercel/util"
|
||||
|
|
@ -20,6 +21,7 @@ export interface OpenAIMiddlewareOptions {
|
|||
mode?: "profile" | "query" | "full"
|
||||
addMemory?: "always" | "never"
|
||||
baseUrl?: string
|
||||
apiKey?: string
|
||||
}
|
||||
|
||||
interface SupermemoryProfileSearch {
|
||||
|
|
@ -75,22 +77,25 @@ const getLastUserMessage = (
|
|||
*
|
||||
* @param containerTag - The container tag/identifier for memory search (e.g., user ID, project ID)
|
||||
* @param queryText - Optional query text to search for specific memories. If empty, returns all profile memories
|
||||
* @param baseUrl - The Supermemory API base URL
|
||||
* @param apiKey - The Supermemory API key used to authenticate the request
|
||||
* @returns Promise that resolves to the SuperMemory profile search response
|
||||
* @throws {Error} When the API request fails or returns an error status
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Search with query
|
||||
* const results = await supermemoryProfileSearch("user-123", "favorite programming language")
|
||||
* const results = await supermemoryProfileSearch("user-123", "favorite programming language", baseUrl, apiKey)
|
||||
*
|
||||
* // Get all profile memories
|
||||
* const profile = await supermemoryProfileSearch("user-123", "")
|
||||
* const profile = await supermemoryProfileSearch("user-123", "", baseUrl, apiKey)
|
||||
* ```
|
||||
*/
|
||||
const supermemoryProfileSearch = async (
|
||||
containerTag: string,
|
||||
queryText: string,
|
||||
baseUrl: string,
|
||||
apiKey: string,
|
||||
): Promise<SupermemoryProfileSearch> => {
|
||||
const payload = queryText
|
||||
? JSON.stringify({
|
||||
|
|
@ -106,7 +111,7 @@ const supermemoryProfileSearch = async (
|
|||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
body: payload,
|
||||
})
|
||||
|
|
@ -138,6 +143,8 @@ const supermemoryProfileSearch = async (
|
|||
* @param containerTag - The container tag/identifier for memory search
|
||||
* @param logger - Logger instance for debugging and info output
|
||||
* @param mode - Memory search mode: "profile" (all memories), "query" (search-based), or "full" (both)
|
||||
* @param baseUrl - The Supermemory API base URL
|
||||
* @param apiKey - The Supermemory API key used to authenticate the request
|
||||
* @returns Promise that resolves to enhanced messages with memory-injected system prompt
|
||||
*
|
||||
* @example
|
||||
|
|
@ -150,7 +157,9 @@ const supermemoryProfileSearch = async (
|
|||
* messages,
|
||||
* "user-123",
|
||||
* logger,
|
||||
* "full"
|
||||
* "full",
|
||||
* baseUrl,
|
||||
* apiKey
|
||||
* )
|
||||
* // Returns messages with system prompt containing relevant memories
|
||||
* ```
|
||||
|
|
@ -161,6 +170,7 @@ const addSystemPrompt = async (
|
|||
logger: Logger,
|
||||
mode: "profile" | "query" | "full",
|
||||
baseUrl: string,
|
||||
apiKey: string,
|
||||
) => {
|
||||
const systemPromptExists = messages.some((msg) => msg.role === "system")
|
||||
|
||||
|
|
@ -170,6 +180,7 @@ const addSystemPrompt = async (
|
|||
containerTag,
|
||||
queryText,
|
||||
baseUrl,
|
||||
apiKey,
|
||||
)
|
||||
|
||||
const memoryCountStatic = memoriesResponse.profile.static?.length || 0
|
||||
|
|
@ -400,8 +411,9 @@ const addMemoryTool = async (
|
|||
* @param options.verbose - Enable detailed logging of memory operations (default: false)
|
||||
* @param options.mode - Memory search mode: "profile" (all memories), "query" (search-based), or "full" (both) (default: "profile")
|
||||
* @param options.addMemory - Automatic memory storage mode: "always" or "never" (default: "always")
|
||||
* @param options.apiKey - Supermemory API key to use instead of the SUPERMEMORY_API_KEY environment variable
|
||||
* @returns Object with `wrapClient` and `createClient` methods
|
||||
* @throws {Error} When SUPERMEMORY_API_KEY environment variable is not set
|
||||
* @throws {Error} When neither `options.apiKey` nor `process.env.SUPERMEMORY_API_KEY` are set
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
|
|
@ -421,8 +433,9 @@ export function createOpenAIMiddleware(
|
|||
) {
|
||||
const logger = createLogger(options?.verbose ?? false)
|
||||
const baseUrl = normalizeBaseUrl(options?.baseUrl)
|
||||
const apiKey = validateApiKey(options?.apiKey)
|
||||
const client = new Supermemory({
|
||||
apiKey: process.env.SUPERMEMORY_API_KEY,
|
||||
apiKey,
|
||||
...(baseUrl !== "https://api.supermemory.ai" ? { baseURL: baseUrl } : {}),
|
||||
})
|
||||
|
||||
|
|
@ -457,6 +470,7 @@ export function createOpenAIMiddleware(
|
|||
containerTag,
|
||||
queryText,
|
||||
baseUrl,
|
||||
apiKey,
|
||||
)
|
||||
|
||||
const memoryCountStatic = memoriesResponse.profile.static?.length || 0
|
||||
|
|
@ -615,7 +629,7 @@ export function createOpenAIMiddleware(
|
|||
memoryCustomId,
|
||||
logger,
|
||||
messages,
|
||||
process.env.SUPERMEMORY_API_KEY,
|
||||
apiKey,
|
||||
baseUrl,
|
||||
),
|
||||
)
|
||||
|
|
@ -623,7 +637,7 @@ export function createOpenAIMiddleware(
|
|||
}
|
||||
|
||||
operations.push(
|
||||
addSystemPrompt(messages, containerTag, logger, mode, baseUrl),
|
||||
addSystemPrompt(messages, containerTag, logger, mode, baseUrl, apiKey),
|
||||
)
|
||||
|
||||
const results = await Promise.all(operations)
|
||||
|
|
|
|||
|
|
@ -552,6 +552,14 @@ export function getToolDefinitions(): OpenAI.Chat.Completions.ChatCompletionTool
|
|||
]
|
||||
}
|
||||
|
||||
function parseToolArguments(argumentsJson: string) {
|
||||
try {
|
||||
return { success: true as const, value: JSON.parse(argumentsJson) }
|
||||
} catch {
|
||||
return { success: false as const }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a tool call based on the function name and arguments
|
||||
*/
|
||||
|
|
@ -565,7 +573,14 @@ export function createToolCallExecutor(
|
|||
toolCall: OpenAI.Chat.Completions.ChatCompletionMessageToolCall,
|
||||
): Promise<string> {
|
||||
const functionName = toolCall.function.name
|
||||
const args = JSON.parse(toolCall.function.arguments)
|
||||
const parsed = parseToolArguments(toolCall.function.arguments)
|
||||
if (!parsed.success) {
|
||||
return JSON.stringify({
|
||||
success: false,
|
||||
error: `Invalid JSON arguments for ${functionName}`,
|
||||
})
|
||||
}
|
||||
const args = parsed.value
|
||||
|
||||
switch (functionName) {
|
||||
case "searchMemories":
|
||||
|
|
|
|||
|
|
@ -129,11 +129,7 @@ export function createSupermemoryHooks(
|
|||
return
|
||||
}
|
||||
|
||||
saveConversation(messages, ctx).catch((error) => {
|
||||
ctx.logger.error("Background conversation save failed", {
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
})
|
||||
})
|
||||
await saveConversation(messages, ctx)
|
||||
} catch (error) {
|
||||
ctx.logger.error("Error in onEnd", {
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ const convertToConversationMessages = (
|
|||
}
|
||||
|
||||
/**
|
||||
* Saves conversation to Supermemory (fire-and-forget).
|
||||
* Saves conversation to Supermemory.
|
||||
*/
|
||||
export const saveConversation = async (
|
||||
messages: VoltAgentMessage[],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue