mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
chore: merge latest stacked SDK fixes
This commit is contained in:
commit
80ccb5cc65
4 changed files with 68 additions and 20 deletions
|
|
@ -272,6 +272,8 @@ import { withSupermemory } from "@supermemory/tools/openai"
|
||||||
const openaiWithSupermemory = withSupermemory(openai, {
|
const openaiWithSupermemory = withSupermemory(openai, {
|
||||||
containerTag: "user-123", // Required: identifies the user/container
|
containerTag: "user-123", // Required: identifies the user/container
|
||||||
customId: "conversation-456", // Required: groups messages into the same document
|
customId: "conversation-456", // Required: groups messages into the same document
|
||||||
|
apiKey: process.env.SUPERMEMORY_API_KEY, // Optional env fallback
|
||||||
|
baseUrl: process.env.SUPERMEMORY_BASE_URL,
|
||||||
mode: "full",
|
mode: "full",
|
||||||
addMemory: "always", // Default: "always"
|
addMemory: "always", // Default: "always"
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
|
@ -296,6 +298,8 @@ The middleware supports the same configuration options as the AI SDK version:
|
||||||
const openaiWithSupermemory = withSupermemory(openai, {
|
const openaiWithSupermemory = withSupermemory(openai, {
|
||||||
containerTag: "user-123", // Required: identifies the user/container
|
containerTag: "user-123", // Required: identifies the user/container
|
||||||
customId: "conversation-456", // Required: groups messages for contextual memory
|
customId: "conversation-456", // Required: groups messages for contextual memory
|
||||||
|
apiKey: process.env.SUPERMEMORY_API_KEY, // Optional; captured per client
|
||||||
|
baseUrl: process.env.SUPERMEMORY_BASE_URL,
|
||||||
mode: "full", // "profile" | "query" | "full"
|
mode: "full", // "profile" | "query" | "full"
|
||||||
addMemory: "always", // "always" (default) | "never"
|
addMemory: "always", // "always" (default) | "never"
|
||||||
verbose: true, // Enable detailed logging
|
verbose: true, // Enable detailed logging
|
||||||
|
|
@ -320,6 +324,8 @@ export async function POST(req: Request) {
|
||||||
const openaiWithSupermemory = withSupermemory(openai, {
|
const openaiWithSupermemory = withSupermemory(openai, {
|
||||||
containerTag: "user-123",
|
containerTag: "user-123",
|
||||||
customId: conversationId,
|
customId: conversationId,
|
||||||
|
apiKey: process.env.SUPERMEMORY_API_KEY,
|
||||||
|
baseUrl: process.env.SUPERMEMORY_BASE_URL,
|
||||||
mode: "full",
|
mode: "full",
|
||||||
addMemory: "always",
|
addMemory: "always",
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ export interface AddConversationResponse {
|
||||||
status: string
|
status: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CONVERSATION_REQUEST_TIMEOUT_MS = 30_000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a conversation to Supermemory using the /v4/conversations endpoint
|
* Adds a conversation to Supermemory using the /v4/conversations endpoint
|
||||||
*
|
*
|
||||||
|
|
@ -89,6 +91,8 @@ export async function addConversation(
|
||||||
metadata: params.metadata,
|
metadata: params.metadata,
|
||||||
entityContext: params.entityContext,
|
entityContext: params.entityContext,
|
||||||
}),
|
}),
|
||||||
|
redirect: "error",
|
||||||
|
signal: AbortSignal.timeout(CONVERSATION_REQUEST_TIMEOUT_MS),
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
* @param options.verbose - Optional flag to enable detailed logging of memory search and injection process (default: false)
|
* @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.mode - Optional mode for memory search: "profile" (default), "query", or "full"
|
||||||
* @param options.addMemory - Optional mode for memory addition: "always" (default), "never"
|
* @param options.addMemory - Optional mode for memory addition: "always" (default), "never"
|
||||||
|
* @param options.apiKey - Optional Supermemory API key; falls back to SUPERMEMORY_API_KEY
|
||||||
*
|
*
|
||||||
* @returns An OpenAI client with SuperMemory middleware injected for both Chat Completions and Responses APIs
|
* @returns An OpenAI client with SuperMemory middleware injected for both Chat Completions and Responses APIs
|
||||||
*
|
*
|
||||||
|
|
@ -56,15 +57,17 @@ import {
|
||||||
* })
|
* })
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @throws {Error} When SUPERMEMORY_API_KEY environment variable is not set
|
* @throws {Error} When neither options.apiKey nor SUPERMEMORY_API_KEY is set
|
||||||
* @throws {Error} When supermemory API request fails
|
* @throws {Error} When supermemory API request fails
|
||||||
*/
|
*/
|
||||||
export function withSupermemory(
|
export function withSupermemory(
|
||||||
openaiClient: OpenAI,
|
openaiClient: OpenAI,
|
||||||
options: OpenAIMiddlewareOptions,
|
options: OpenAIMiddlewareOptions,
|
||||||
) {
|
) {
|
||||||
if (!process.env.SUPERMEMORY_API_KEY) {
|
if (!options.apiKey?.trim() && !process.env.SUPERMEMORY_API_KEY?.trim()) {
|
||||||
throw new Error("SUPERMEMORY_API_KEY is not set")
|
throw new Error(
|
||||||
|
"SUPERMEMORY_API_KEY is not set — provide it via options.apiKey or set the environment variable",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.containerTag) {
|
if (!options.containerTag) {
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,11 @@ import { convertProfileToMarkdown } from "../vercel/util"
|
||||||
|
|
||||||
const normalizeBaseUrl = (url?: string): string => {
|
const normalizeBaseUrl = (url?: string): string => {
|
||||||
const defaultUrl = "https://api.supermemory.ai"
|
const defaultUrl = "https://api.supermemory.ai"
|
||||||
if (!url) return defaultUrl
|
return url?.trim().replace(/\/+$/, "") || defaultUrl
|
||||||
return url.endsWith("/") ? url.slice(0, -1) : url
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PROFILE_REQUEST_TIMEOUT_MS = 30_000
|
||||||
|
|
||||||
export interface OpenAIMiddlewareOptions {
|
export interface OpenAIMiddlewareOptions {
|
||||||
/** Container tag/identifier for memory search (e.g., user ID, project ID). Required. */
|
/** Container tag/identifier for memory search (e.g., user ID, project ID). Required. */
|
||||||
containerTag: string
|
containerTag: string
|
||||||
|
|
@ -19,6 +20,8 @@ export interface OpenAIMiddlewareOptions {
|
||||||
verbose?: boolean
|
verbose?: boolean
|
||||||
mode?: "profile" | "query" | "full"
|
mode?: "profile" | "query" | "full"
|
||||||
addMemory?: "always" | "never"
|
addMemory?: "always" | "never"
|
||||||
|
/** Supermemory API key (falls back to SUPERMEMORY_API_KEY). */
|
||||||
|
apiKey?: string
|
||||||
baseUrl?: string
|
baseUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +93,7 @@ const getLastUserMessage = (
|
||||||
const supermemoryProfileSearch = async (
|
const supermemoryProfileSearch = async (
|
||||||
containerTag: string,
|
containerTag: string,
|
||||||
queryText: string,
|
queryText: string,
|
||||||
|
apiKey: string,
|
||||||
baseUrl: string,
|
baseUrl: string,
|
||||||
): Promise<SupermemoryProfileSearch> => {
|
): Promise<SupermemoryProfileSearch> => {
|
||||||
const payload = queryText
|
const payload = queryText
|
||||||
|
|
@ -106,9 +110,11 @@ const supermemoryProfileSearch = async (
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
|
Authorization: `Bearer ${apiKey}`,
|
||||||
},
|
},
|
||||||
body: payload,
|
body: payload,
|
||||||
|
redirect: "error",
|
||||||
|
signal: AbortSignal.timeout(PROFILE_REQUEST_TIMEOUT_MS),
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
@ -160,6 +166,7 @@ const addSystemPrompt = async (
|
||||||
containerTag: string,
|
containerTag: string,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
mode: "profile" | "query" | "full",
|
mode: "profile" | "query" | "full",
|
||||||
|
apiKey: string,
|
||||||
baseUrl: string,
|
baseUrl: string,
|
||||||
) => {
|
) => {
|
||||||
const systemPromptExists = messages.some((msg) => msg.role === "system")
|
const systemPromptExists = messages.some((msg) => msg.role === "system")
|
||||||
|
|
@ -169,6 +176,7 @@ const addSystemPrompt = async (
|
||||||
const memoriesResponse = await supermemoryProfileSearch(
|
const memoriesResponse = await supermemoryProfileSearch(
|
||||||
containerTag,
|
containerTag,
|
||||||
queryText,
|
queryText,
|
||||||
|
apiKey,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -400,8 +408,9 @@ const addMemoryTool = async (
|
||||||
* @param options.verbose - Enable detailed logging of memory operations (default: false)
|
* @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.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.addMemory - Automatic memory storage mode: "always" or "never" (default: "always")
|
||||||
|
* @param options.apiKey - Supermemory API key (falls back to SUPERMEMORY_API_KEY)
|
||||||
* @returns Object with `wrapClient` and `createClient` methods
|
* @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 SUPERMEMORY_API_KEY is set
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
|
|
@ -420,9 +429,16 @@ export function createOpenAIMiddleware(
|
||||||
options?: OpenAIMiddlewareOptions,
|
options?: OpenAIMiddlewareOptions,
|
||||||
) {
|
) {
|
||||||
const logger = createLogger(options?.verbose ?? false)
|
const logger = createLogger(options?.verbose ?? false)
|
||||||
|
const apiKey =
|
||||||
|
options?.apiKey?.trim() || process.env.SUPERMEMORY_API_KEY?.trim() || ""
|
||||||
|
if (!apiKey) {
|
||||||
|
throw new Error(
|
||||||
|
"SUPERMEMORY_API_KEY is not set — provide it via options.apiKey or set the environment variable",
|
||||||
|
)
|
||||||
|
}
|
||||||
const baseUrl = normalizeBaseUrl(options?.baseUrl)
|
const baseUrl = normalizeBaseUrl(options?.baseUrl)
|
||||||
const client = new Supermemory({
|
const client = new Supermemory({
|
||||||
apiKey: process.env.SUPERMEMORY_API_KEY,
|
apiKey,
|
||||||
...(baseUrl !== "https://api.supermemory.ai" ? { baseURL: baseUrl } : {}),
|
...(baseUrl !== "https://api.supermemory.ai" ? { baseURL: baseUrl } : {}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -456,6 +472,7 @@ export function createOpenAIMiddleware(
|
||||||
const memoriesResponse = await supermemoryProfileSearch(
|
const memoriesResponse = await supermemoryProfileSearch(
|
||||||
containerTag,
|
containerTag,
|
||||||
queryText,
|
queryText,
|
||||||
|
apiKey,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -523,6 +540,7 @@ export function createOpenAIMiddleware(
|
||||||
|
|
||||||
const createResponsesWithMemory = async (
|
const createResponsesWithMemory = async (
|
||||||
params: Parameters<typeof originalResponsesCreate>[0],
|
params: Parameters<typeof originalResponsesCreate>[0],
|
||||||
|
requestOptions?: OpenAI.RequestOptions,
|
||||||
) => {
|
) => {
|
||||||
if (!originalResponsesCreate) {
|
if (!originalResponsesCreate) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
@ -534,7 +552,11 @@ export function createOpenAIMiddleware(
|
||||||
|
|
||||||
if (mode !== "profile" && !input) {
|
if (mode !== "profile" && !input) {
|
||||||
logger.debug("No input found for Responses API, skipping memory search")
|
logger.debug("No input found for Responses API, skipping memory search")
|
||||||
return originalResponsesCreate.call(openaiClient.responses, params)
|
return originalResponsesCreate.call(
|
||||||
|
openaiClient.responses,
|
||||||
|
params,
|
||||||
|
requestOptions,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Starting memory search for Responses API", {
|
logger.info("Starting memory search for Responses API", {
|
||||||
|
|
@ -572,14 +594,19 @@ export function createOpenAIMiddleware(
|
||||||
? `${params.instructions || ""}\n\n${memories}`.trim()
|
? `${params.instructions || ""}\n\n${memories}`.trim()
|
||||||
: params.instructions
|
: params.instructions
|
||||||
|
|
||||||
return originalResponsesCreate.call(openaiClient.responses, {
|
return originalResponsesCreate.call(
|
||||||
...params,
|
openaiClient.responses,
|
||||||
instructions: enhancedInstructions,
|
{
|
||||||
})
|
...params,
|
||||||
|
instructions: enhancedInstructions,
|
||||||
|
},
|
||||||
|
requestOptions,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const createWithMemory = async (
|
const createWithMemory = async (
|
||||||
params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
|
params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
|
||||||
|
requestOptions?: OpenAI.RequestOptions,
|
||||||
) => {
|
) => {
|
||||||
const messages = Array.isArray(params.messages) ? params.messages : []
|
const messages = Array.isArray(params.messages) ? params.messages : []
|
||||||
|
|
||||||
|
|
@ -587,7 +614,11 @@ export function createOpenAIMiddleware(
|
||||||
const userMessage = getLastUserMessage(messages)
|
const userMessage = getLastUserMessage(messages)
|
||||||
if (!userMessage) {
|
if (!userMessage) {
|
||||||
logger.debug("No user message found, skipping memory search")
|
logger.debug("No user message found, skipping memory search")
|
||||||
return originalCreate.call(openaiClient.chat.completions, params)
|
return originalCreate.call(
|
||||||
|
openaiClient.chat.completions,
|
||||||
|
params,
|
||||||
|
requestOptions,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -615,7 +646,7 @@ export function createOpenAIMiddleware(
|
||||||
memoryCustomId,
|
memoryCustomId,
|
||||||
logger,
|
logger,
|
||||||
messages,
|
messages,
|
||||||
process.env.SUPERMEMORY_API_KEY,
|
apiKey,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -623,16 +654,20 @@ export function createOpenAIMiddleware(
|
||||||
}
|
}
|
||||||
|
|
||||||
operations.push(
|
operations.push(
|
||||||
addSystemPrompt(messages, containerTag, logger, mode, baseUrl),
|
addSystemPrompt(messages, containerTag, logger, mode, apiKey, baseUrl),
|
||||||
)
|
)
|
||||||
|
|
||||||
const results = await Promise.all(operations)
|
const results = await Promise.all(operations)
|
||||||
const enhancedMessages = results[results.length - 1] // Enhanced messages result is always last
|
const enhancedMessages = results[results.length - 1] // Enhanced messages result is always last
|
||||||
|
|
||||||
return originalCreate.call(openaiClient.chat.completions, {
|
return originalCreate.call(
|
||||||
...params,
|
openaiClient.chat.completions,
|
||||||
messages: enhancedMessages,
|
{
|
||||||
})
|
...params,
|
||||||
|
messages: enhancedMessages,
|
||||||
|
},
|
||||||
|
requestOptions,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
openaiClient.chat.completions.create =
|
openaiClient.chat.completions.create =
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue