Skip to content

Commit 9f77da4

Browse files
refactor: migrate memory middleware to use SystemMessage (#178)
* refactor(deepagents): migrate memory middleware to use SystemMessage Update memory middleware to use SystemMessage class instead of string-based systemPrompt. This change aligns the middleware with the updated request interface and provides better type safety. - Replace systemPrompt string with SystemMessage object in memory.ts - Use SystemMessage.concat() method for combining memory section with existing system message - Update all test cases to use SystemMessage constructor and .text property for assertions * add changeset --------- Co-authored-by: Christian Bromann <git@bromann.dev>
1 parent 3cc5326 commit 9f77da4

File tree

3 files changed

+51
-25
lines changed

3 files changed

+51
-25
lines changed

.changeset/stale-pugs-hammer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"deepagents": patch
3+
---
4+
5+
refactor: migrate memory middleware to use SystemMessage

libs/deepagents/src/middleware/memory.test.ts

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ describe("createMemoryMiddleware", () => {
152152

153153
const mockHandler = vi.fn().mockReturnValue({ response: "ok" });
154154
const request = {
155-
systemPrompt: "Base prompt",
155+
systemMessage: new SystemMessage("Base prompt"),
156156
state: {
157157
memoryContents: {
158158
"~/.deepagents/AGENTS.md": "User memory content",
@@ -165,13 +165,23 @@ describe("createMemoryMiddleware", () => {
165165

166166
expect(mockHandler).toHaveBeenCalled();
167167
const modifiedRequest = mockHandler.mock.calls[0][0];
168-
expect(modifiedRequest.systemPrompt).toContain("<agent_memory>");
169-
expect(modifiedRequest.systemPrompt).toContain("</agent_memory>");
170-
expect(modifiedRequest.systemPrompt).toContain("<memory_guidelines>");
171-
expect(modifiedRequest.systemPrompt).toContain("User memory content");
172-
expect(modifiedRequest.systemPrompt).toContain("Project memory content");
173-
expect(modifiedRequest.systemPrompt).toContain("~/.deepagents/AGENTS.md");
174-
expect(modifiedRequest.systemPrompt).toContain("./.deepagents/AGENTS.md");
168+
expect(modifiedRequest.systemMessage.text).toContain("<agent_memory>");
169+
expect(modifiedRequest.systemMessage.text).toContain("</agent_memory>");
170+
expect(modifiedRequest.systemMessage.text).toContain(
171+
"<memory_guidelines>",
172+
);
173+
expect(modifiedRequest.systemMessage.text).toContain(
174+
"User memory content",
175+
);
176+
expect(modifiedRequest.systemMessage.text).toContain(
177+
"Project memory content",
178+
);
179+
expect(modifiedRequest.systemMessage.text).toContain(
180+
"~/.deepagents/AGENTS.md",
181+
);
182+
expect(modifiedRequest.systemMessage.text).toContain(
183+
"./.deepagents/AGENTS.md",
184+
);
175185
});
176186

177187
it("should show (No memory loaded) when no content", () => {
@@ -182,14 +192,16 @@ describe("createMemoryMiddleware", () => {
182192

183193
const mockHandler = vi.fn().mockReturnValue({ response: "ok" });
184194
const request = {
185-
systemPrompt: "Base prompt",
195+
systemMessage: new SystemMessage("Base prompt"),
186196
state: { memoryContents: {} },
187197
};
188198

189199
middleware.wrapModelCall!(request as any, mockHandler);
190200

191201
const modifiedRequest = mockHandler.mock.calls[0][0];
192-
expect(modifiedRequest.systemPrompt).toContain("(No memory loaded)");
202+
expect(modifiedRequest.systemMessage.text).toContain(
203+
"(No memory loaded)",
204+
);
193205
});
194206

195207
it("should prepend memory section to existing system prompt", () => {
@@ -200,16 +212,17 @@ describe("createMemoryMiddleware", () => {
200212

201213
const mockHandler = vi.fn().mockReturnValue({ response: "ok" });
202214
const request = {
203-
systemPrompt: "Original system prompt content",
215+
systemMessage: new SystemMessage("Original system prompt content"),
204216
state: { memoryContents: {} },
205217
};
206218

207219
middleware.wrapModelCall!(request as any, mockHandler);
208220

209221
const modifiedRequest = mockHandler.mock.calls[0][0];
210222
// Memory section should come before the original prompt
211-
const memoryIndex = modifiedRequest.systemPrompt.indexOf("Agent Memory");
212-
const originalIndex = modifiedRequest.systemPrompt.indexOf(
223+
const memoryIndex =
224+
modifiedRequest.systemMessage.text.indexOf("Agent Memory");
225+
const originalIndex = modifiedRequest.systemMessage.text.indexOf(
213226
"Original system prompt content",
214227
);
215228
expect(memoryIndex).toBeLessThan(originalIndex);
@@ -223,14 +236,16 @@ describe("createMemoryMiddleware", () => {
223236

224237
const mockHandler = vi.fn().mockReturnValue({ response: "ok" });
225238
const request = {
226-
systemPrompt: "Base prompt",
239+
systemMessage: new SystemMessage("Base prompt"),
227240
state: {},
228241
};
229242

230243
middleware.wrapModelCall!(request as any, mockHandler);
231244

232245
const modifiedRequest = mockHandler.mock.calls[0][0];
233-
expect(modifiedRequest.systemPrompt).toContain("(No memory loaded)");
246+
expect(modifiedRequest.systemMessage.text).toContain(
247+
"(No memory loaded)",
248+
);
234249
});
235250
});
236251

@@ -255,16 +270,20 @@ describe("createMemoryMiddleware", () => {
255270
// Step 2: Use loaded memory in wrapModelCall
256271
const mockHandler = vi.fn().mockReturnValue({ response: "ok" });
257272
const request: any = {
258-
systemPrompt: "You are a helpful assistant.",
273+
systemMessage: new SystemMessage("You are a helpful assistant."),
259274
state: stateUpdate,
260275
};
261276

262277
middleware.wrapModelCall!(request, mockHandler);
263278

264279
const modifiedRequest = mockHandler.mock.calls[0][0];
265-
expect(modifiedRequest.systemPrompt).toContain("I prefer TypeScript");
266-
expect(modifiedRequest.systemPrompt).toContain("This is a React project");
267-
expect(modifiedRequest.systemPrompt).toContain(
280+
expect(modifiedRequest.systemMessage.text).toContain(
281+
"I prefer TypeScript",
282+
);
283+
expect(modifiedRequest.systemMessage.text).toContain(
284+
"This is a React project",
285+
);
286+
expect(modifiedRequest.systemMessage.text).toContain(
268287
"You are a helpful assistant",
269288
);
270289
});

libs/deepagents/src/middleware/memory.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import { z } from "zod";
5252
import {
5353
createMiddleware,
54+
SystemMessage,
5455
/**
5556
* required for type inference
5657
*/
@@ -310,13 +311,14 @@ export function createMemoryMiddleware(options: MemoryMiddlewareOptions) {
310311
formattedContents,
311312
);
312313

313-
// Prepend memory section to system prompt
314-
const currentSystemPrompt = request.systemPrompt || "";
315-
const newSystemPrompt = currentSystemPrompt
316-
? `${memorySection}\n\n${currentSystemPrompt}`
317-
: memorySection;
314+
// Concat memory section to system prompt
315+
const memoryMessage = new SystemMessage(memorySection);
316+
const newSystemMessage = memoryMessage.concat(request.systemMessage);
318317

319-
return handler({ ...request, systemPrompt: newSystemPrompt });
318+
return handler({
319+
...request,
320+
systemMessage: newSystemMessage,
321+
});
320322
},
321323
});
322324
}

0 commit comments

Comments
 (0)