fix(tools): route Responses API memory saves through /v4/conversations - #1286
fix(tools): route Responses API memory saves through /v4/conversations#1286abhay-codes07 wants to merge 3 commits into
Conversation
When a customId is configured, the chat-completions path hands addMemoryTool the messages plus API credentials, so the save routes through /v4/conversations with the internal "conversation:" prefix stripped back off. The Responses path built the same prefixed memoryCustomId but passed neither messages nor credentials, so the conversation branch never ran and the save fell through to client.add() with "conversation:<id>" as the stored customId — a value customId validation rejects (alphanumeric/hyphen/underscore only). The error is swallowed by design (memory saves must not break the user's API call), which means every Responses API call with a customId silently saved nothing. Hand the input over as a single user message together with the credentials, mirroring the chat path, so conversation grouping works for the Responses API too. Also strip the internal prefix in the client.add fallback so the routing marker can never leak into a stored customId on any path (previously the chat path had the same leak whenever SUPERMEMORY_API_KEY was unset). Covered with mocked-SDK middleware tests: a customId save routes through addConversation with the un-prefixed conversation id and never touches client.add; the fallback stores the user's configured id, not the prefixed marker; and the no-customId path is unchanged. Two of the three tests fail against the previous implementation.
ved015
left a comment
There was a problem hiding this comment.
hi @abhay-codes07 thanks for the PR.
The routing idea is valid, but I think it requires some changes
-
Our current backedn accepts conversation:, so previous saves may already exist under that ID. Switching to unprefixed would create a second document and split existing conversation history.
-
OpenAI Responses also supports structured input like
input: [{
role: "user",
content: [
{ type: "input_text", text: "Hi" },
{ type: "input_image", image_url: "..." }
]
}]
and this PR does this
const input = typeof params.input === "string" ? params.input : ""
so basically this implementation converts non-string input to "", so those requests still skip memory search and saving.
…ds stable Addresses review feedback on the Responses API memory routing: - The wrapper collapsed any non-string `input` to "" (`typeof input === "string" ? input : ""`), so structured or multi-modal Responses requests skipped both memory search and saving. Add extractResponsesInput to flatten string or structured array input into a text query plus role-tagged messages, and route the reconstructed messages through /v4/conversations. - Stop rewriting the stored customId in the client.add fallback. The backend already stores conversation memories under the "conversation:" id, so stripping the prefix would orphan a conversation's earlier turns. Unit tests cover string, empty, structured multi-part, multi-turn, role normalization, and text-less items.
|
Thanks @ved015, both are fair. Pushed a follow-up:
Added unit tests covering string, empty, structured multi-part, multi-turn, role normalization, and text-less items ( |
What
Responses API memory saves silently failed whenever a
customIdwas configured.The chat-completions path hands
addMemoryToolthe messages plus API credentials, so a configuredcustomIdroutes the save through/v4/conversations(with the internalconversation:routing prefix stripped back off). The Responses path built the same prefixedmemoryCustomIdbut passed neither messages nor credentials:So the conversation branch never ran and the save fell through to
client.add()withconversation:<id>as the stored customId — a value customId validation rejects (alphanumeric/hyphen/underscore only). Since save errors are swallowed by design (memory persistence must never break the user's API call), everyresponses.createcall with acustomIdsaved nothing, invisibly.Fix
client.addfallback strips the internalconversation:prefix so the routing marker can never leak into a stored customId on any path (the chat path had the same leak wheneverSUPERMEMORY_API_KEYwas unset)Testing
src/openai/middleware.test.ts): a customId save routes throughaddConversationwith the un-prefixed conversation id and never touchesclient.add; the fallback stores the user's configured id, not the prefixed marker; the no-customId path is unchanged — two of the three tests fail against the previous implementationvitest run— 3 passtsc --noEmiterror count unchanged vsmain(148 pre-existing),biome checkcleancc @MaheshtheDev