This commit is contained in:
Agnik Paul 2026-09-26 20:20:52 +00:00 • committed by GitHub
commit be90889594
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 108 additions and 1 deletions

View file

@ -970,13 +970,22 @@ export function createOpenAIMiddleware(
: ""
}
// Sending `instructions` at all tells the Responses API to drop whatever a
// `previous_response_id` turn carried over, so an empty result must leave
// the caller's own field untouched rather than blank it. Matches the
// no-input early return above.
const instructionsOverride =
enhancedInstructions || typeof params.instructions === "string"
? { instructions: enhancedInstructions }
: {}
return {
request: originalResponsesCreate.call(
openaiClient.responses,
{
...params,
input: cleanedInput,
instructions: enhancedInstructions,
...instructionsOverride,
},
requestOptions,
),

View file

@ -63,3 +63,101 @@ describe("OpenAI middleware memory context", () => {
).toHaveLength(1)
})
})
describe("OpenAI Responses middleware instructions", () => {
const originalApiKey = process.env.SUPERMEMORY_API_KEY
beforeEach(() => {
process.env.SUPERMEMORY_API_KEY = "sm_test_key"
})
afterEach(() => {
if (originalApiKey === undefined) delete process.env.SUPERMEMORY_API_KEY
else process.env.SUPERMEMORY_API_KEY = originalApiKey
vi.unstubAllGlobals()
})
const stubMemoryFetch = (staticMemories: string[]) => {
vi.stubGlobal(
"fetch",
vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
profile: {
static: staticMemories.map((memory) => ({ memory })),
dynamic: [],
},
searchResults: { results: [] },
}),
}),
)
}
const wrapResponsesClient = () => {
const originalCreate = vi.fn(() =>
Object.assign(Promise.resolve({ output: [] }), {
asResponse: async () => new Response(),
}),
)
const client = {
chat: { completions: { create: vi.fn() } },
responses: { create: originalCreate },
} as unknown as OpenAI
const wrapped = withSupermemory(client, {
containerTag: "user-a",
customId: "conversation-a",
mode: "profile",
addMemory: "never",
})
return { originalCreate, wrapped }
}
it("leaves instructions absent when the caller sent none and there is nothing to inject", async () => {
stubMemoryFetch([])
const { originalCreate, wrapped } = wrapResponsesClient()
await wrapped.responses.create({
model: "gpt-4o-mini",
input: "What do you remember?",
previous_response_id: "resp_123",
})
// An empty `instructions` still counts as present, and the Responses API
// drops the previous turn's instructions whenever the field is sent.
const forwarded = originalCreate.mock.calls[0]?.[0]
expect("instructions" in forwarded).toBe(false)
expect(forwarded.previous_response_id).toBe("resp_123")
})
it("still injects memories as instructions when the caller sent none", async () => {
stubMemoryFetch(["Fresh profile fact"])
const { originalCreate, wrapped } = wrapResponsesClient()
await wrapped.responses.create({
model: "gpt-4o-mini",
input: "What do you remember?",
})
const forwarded = originalCreate.mock.calls[0]?.[0]
expect(String(forwarded.instructions)).toContain("Fresh profile fact")
})
it("keeps caller instructions and strips stale context when there is nothing to inject", async () => {
stubMemoryFetch([])
const { originalCreate, wrapped } = wrapResponsesClient()
await wrapped.responses.create({
model: "gpt-4o-mini",
input: "What do you remember?",
instructions: [
"Be helpful.",
'<supermemory context="user-memories" readonly>',
"Stale profile fact",
"</supermemory>",
].join("\n"),
})
const forwarded = originalCreate.mock.calls[0]?.[0]
expect(String(forwarded.instructions)).toBe("Be helpful.")
})
})