Deepseek Harness: canceled recall marks undelivered memories as seen
Component
Plugin
Description
Summary
Canceling a DSH turn while automatic memory search is pending can mark returned memories as seen without delivering them to the model. Later automatic recall skips those memories in the same session, so the agent may answer without relevant stored information(if agent does not use search_memory).
Steps to Reproduce
- On the commit listed below, insert the inline test from the verification field into the existing
describe("Harness lifecycle", ...)block inintegrations/deepseek-plugin/tests/apply.test.ts. - From
integrations/deepseek-plugin, run the installation and test commands provided in that field.
The test cancels during a mocked memory search, lets it return successfully, then retries in the same session with the same memory ID. No API keys, live model, or running DSH server are required.
Expected Behavior
Canceling a turn should not make the agent forget a memory it never received. If a later search returns that memory, the plugin should include it in the model's context again.
Its ID should become “seen” only after successful delivery, not merely because search found it. Deduplication should still apply to memories previously delivered successfully.
Actual Behavior
The retry returns contexts: [] instead of a mem0:recall entry containing the retrieved memory. Its ID was marked as seen during the canceled turn, so the plugin filters it out. This test checks the recalled context, not a generated agent answer.
Environment
- Mem0 plugin:
@mem0/[email protected]at commit782fa392a5b76e3acf474478e7e22637c0e41575. - Mem0 SDK:
[email protected]. - DSH packages:
0.1.1-rc.2. - Node.js:
22.22.0. - OS: macOS.
How You Verified This
What I Ran
On commit 782fa392a5b76e3acf474478e7e22637c0e41575, inserted the following test as the first test inside the existing describe("Harness lifecycle", ...) block in integrations/deepseek-plugin/tests/apply.test.ts. Place it immediately after describe("Harness lifecycle", () => {, before the existing tests. It uses that file's existing helpers and mocks. No API keys, live model, DSH server, or separate download is needed.
it("recalls an undelivered memory after cancellation", async () => {
const response = { results: [{ id: "m1", memory: "A saved fact" }] };
const controller = new AbortController();
const hooks = applyAndCollectListeners({ apiKey: "test-key", userId: "u" });
const assemble = hooks.get("system-prompt/assemble")!;
const base = { sections: [], contexts: [], tools: [], variables: {} };
const agent = { session: { deriveMessages: () => [
{ role: "user", source: { kind: "user" }, content: "Recall my saved information" },
] } };
mockSearch.mockImplementationOnce(async () => {
controller.abort(); // Cancel during search, before returning the memory.
return response;
}).mockResolvedValue(response);
expect(await assemble(base, { agent, signal: controller.signal }, async () => base)).toBe(base);
const retried = await assemble(base, { agent, signal: new AbortController().signal }, async () => base);
expect(mockSearch).toHaveBeenCalledTimes(2);
console.log(JSON.stringify(retried));
expect(retried).toMatchObject({
contexts: [{ name: "mem0:recall", text: expect.stringContaining("A saved fact") }],
});
});From integrations/deepseek-plugin, install dependencies if needed, then run the Harness lifecycle group:
pnpm install --frozen-lockfile --config.auto-install-peers=false --ignore-scripts
./node_modules/.bin/vitest run tests/apply.test.ts -t "Harness lifecycle"What I Saw
Both searches returned the same memory: m1, containing A saved fact. After cancellation and retry:
| Expected output | Actual output |
|---|---|
The model's automatic memory context includes A saved fact. |
The automatic memory context is empty. The retrieved fact is not delivered. |
The rerun reports the test inside the requested group:
FAIL tests/apply.test.ts > Harness lifecycle > recalls an undelivered memory after cancellation
Tests 1 failed | 5 passed | 14 skipped (20)The five existing Harness lifecycle tests passed. The new regression failed with this expected-versus-actual diff:
- Expected
+ Received
{
- "contexts": [
- {
- "name": "mem0:recall",
- "text": StringContaining "A saved fact",
- },
- ],
+ "contexts": [],
}The failure is missing input to the agent; this offline test does not generate an agent answer. The package type check passed.
Why This Is a Bug
A memory never delivered to the model should remain eligible for automatic recall. Instead, the lifecycle marks the ID seen before the adapter checks cancellation and discards the text. Later recall therefore skips information the model never received.
What I Ruled Out
- Missing search results or API errors: both mocked searches successfully return the same memory.
- Prior delivery: the canceled assembly is unchanged and the existing prompt contains no memory text.
- Uncertain cancellation timing: the mock cancels inside search, before resolving its response.
- Model variability: this regression checks the plugin's recalled context without calling a model. It does not assert that every live agent answer must fail.
This behavior also exists before #7285; the report does not attribute its introduction to that PR.
AI Assistance
AI helped me find it, and I reproduced it myself afterwards
Source: mem0ai/mem0