This commit is contained in:
abhinav7x94 2026-10-05 11:20:01 -07:00 • committed by GitHub
commit fd22ee45b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 17 deletions

View file

@ -263,7 +263,7 @@ The `MemoryPromptData` object provides:
#### OpenAI Middleware with Supermemory #### OpenAI Middleware with Supermemory
The `withSupermemory` function creates an OpenAI client with SuperMemory middleware automatically injected: The `withSupermemory` function creates an isolated middleware facade around an OpenAI client. It does not mutate the supplied client, so a shared base client can safely be wrapped with different user or conversation options:
```typescript ```typescript
import { withSupermemory } from "@supermemory/tools/openai" import { withSupermemory } from "@supermemory/tools/openai"

View file

@ -23,7 +23,7 @@ import {
* @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 * @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 A distinct OpenAI middleware facade for Chat Completions and Responses APIs. The supplied client is not mutated.
* *
* @example * @example
* ```typescript * ```typescript

View file

@ -16,6 +16,34 @@ import { deduplicateMemoriesForMode } from "../tools-shared"
import { createLogger, type Logger } from "../vercel/logger" import { createLogger, type Logger } from "../vercel/logger"
import { convertProfileToMarkdown } from "../vercel/util" import { convertProfileToMarkdown } from "../vercel/util"
// Keep canonicalization stable across duplicate package copies and hot reloads.
const BASE_CLIENT_SYMBOL = Symbol.for("@supermemory/tools/openai/base-client")
const baseClientByWrapper = new WeakMap<OpenAI, OpenAI>()
const getBaseClient = (client: OpenAI) =>
(Reflect.get(client, BASE_CLIENT_SYMBOL) as OpenAI | undefined) ??
baseClientByWrapper.get(client) ??
client
const cloneWithOverrides = <T extends object>(
source: T,
overrides: Partial<T>,
): T => {
const descriptors = Object.getOwnPropertyDescriptors(source)
for (const key of Reflect.ownKeys(overrides) as Array<keyof T>) {
const current = Object.getOwnPropertyDescriptor(source, key)
Reflect.set(descriptors, key, {
configurable: current?.configurable ?? true,
enumerable: current?.enumerable ?? false,
value: overrides[key],
writable: current && "writable" in current ? current.writable : true,
})
}
return Object.create(Object.getPrototypeOf(source), descriptors) as T
}
const normalizeBaseUrl = (url?: string): string => { const normalizeBaseUrl = (url?: string): string => {
const defaultUrl = "https://api.supermemory.ai" const defaultUrl = "https://api.supermemory.ai"
return url?.trim().replace(/\/+$/, "") || defaultUrl return url?.trim().replace(/\/+$/, "") || defaultUrl
@ -761,6 +789,11 @@ export function createOpenAIMiddleware(
containerTag: string, containerTag: string,
options?: OpenAIMiddlewareOptions, options?: OpenAIMiddlewareOptions,
) { ) {
const baseClient = getBaseClient(openaiClient)
const baseChat = baseClient.chat
const baseCompletions = baseChat.completions
const baseResponses = baseClient.responses
const logger = createLogger(options?.verbose ?? false) const logger = createLogger(options?.verbose ?? false)
const apiKey = const apiKey =
options?.apiKey?.trim() || process.env.SUPERMEMORY_API_KEY?.trim() || "" options?.apiKey?.trim() || process.env.SUPERMEMORY_API_KEY?.trim() || ""
@ -779,8 +812,8 @@ export function createOpenAIMiddleware(
const mode = options?.mode ?? "profile" const mode = options?.mode ?? "profile"
const addMemory = options?.addMemory ?? "always" const addMemory = options?.addMemory ?? "always"
const originalCreate = openaiClient.chat.completions.create const originalCreate = baseCompletions.create
const originalResponsesCreate = openaiClient.responses?.create const originalResponsesCreate = baseResponses?.create
/** /**
* Searches for memories and formats them for injection into API calls. * Searches for memories and formats them for injection into API calls.
@ -920,7 +953,7 @@ export function createOpenAIMiddleware(
} }
return { return {
request: originalResponsesCreate.call( request: originalResponsesCreate.call(
openaiClient.responses, baseResponses,
cleanedParams, cleanedParams,
requestOptions, requestOptions,
), ),
@ -972,7 +1005,7 @@ export function createOpenAIMiddleware(
return { return {
request: originalResponsesCreate.call( request: originalResponsesCreate.call(
openaiClient.responses, baseResponses,
{ {
...params, ...params,
input: cleanedInput, input: cleanedInput,
@ -1023,7 +1056,7 @@ export function createOpenAIMiddleware(
logger.debug("No textual user message found, skipping memory search") logger.debug("No textual user message found, skipping memory search")
return { return {
request: originalCreate.call( request: originalCreate.call(
openaiClient.chat.completions, baseCompletions,
{ {
...params, ...params,
messages: updateChatMemoryContexts(messages), messages: updateChatMemoryContexts(messages),
@ -1078,7 +1111,7 @@ export function createOpenAIMiddleware(
return { return {
request: originalCreate.call( request: originalCreate.call(
openaiClient.chat.completions, baseCompletions,
{ {
...params, ...params,
messages: enhancedMessages, messages: enhancedMessages,
@ -1093,14 +1126,26 @@ export function createOpenAIMiddleware(
requestOptions?: OpenAI.RequestOptions, requestOptions?: OpenAI.RequestOptions,
) => deferAPIPromise(() => prepareCreateWithMemory(params, requestOptions)) ) => deferAPIPromise(() => prepareCreateWithMemory(params, requestOptions))
openaiClient.chat.completions.create = const wrappedCompletions = cloneWithOverrides(baseCompletions, {
createWithMemory as typeof originalCreate create: createWithMemory as typeof originalCreate,
})
const wrappedChat = cloneWithOverrides(baseChat, {
completions: wrappedCompletions,
})
const wrappedResponses =
baseResponses && originalResponsesCreate
? cloneWithOverrides(baseResponses, {
create: createResponsesWithMemory as typeof originalResponsesCreate,
})
: undefined
const wrappedClient = cloneWithOverrides(baseClient, {
chat: wrappedChat,
...(wrappedResponses ? { responses: wrappedResponses } : {}),
})
// Wrap Responses API if available Object.defineProperty(wrappedClient, BASE_CLIENT_SYMBOL, {
if (originalResponsesCreate) { value: baseClient,
openaiClient.responses.create = })
createResponsesWithMemory as typeof originalResponsesCreate baseClientByWrapper.set(wrappedClient, baseClient)
} return wrappedClient
return openaiClient
} }