fix(ts-oss): return snake_case entity ids from the redis and valkey stores (#6902)

This commit is contained in:
Kartik
2026-08-14 16:56:27 +05:30
committed by GitHub
parent 0f172c2890
commit 956bf4f88e
8 changed files with 225 additions and 73 deletions
+2 -8
View File
@@ -269,9 +269,7 @@ describe("Memory - add()", () => {
"runId",
"actor_id",
]) {
if (key !== canonicalKey) {
expect(stored!.metadata).not.toHaveProperty(key);
}
expect(stored!.metadata).not.toHaveProperty(key);
}
},
);
@@ -307,10 +305,7 @@ describe("Memory - add()", () => {
}
}
expect(stored!.metadata).toEqual(
expect.objectContaining({
[filterKey]: filterValue,
ordinary: "preserved",
}),
expect.objectContaining({ ordinary: "preserved" }),
);
for (const key of [
"user_id",
@@ -321,7 +316,6 @@ describe("Memory - add()", () => {
"runId",
"actor_id",
]) {
if (key === filterKey) continue;
expect(stored!.metadata).not.toHaveProperty(key);
}
},
+10
View File
@@ -128,6 +128,16 @@ describe("Memory - get()", () => {
expect(item!.createdAt).toBeDefined();
expect(new Date(item!.createdAt!).toString()).not.toBe("Invalid Date");
});
test("does not duplicate the entity id inside metadata", async () => {
const addResult: SearchResult = await memory.add("Metadata leak test", {
userId,
});
const item: any = await memory.get(addResult.results[0].id);
expect(item.user_id).toBe(userId);
expect(item.metadata).not.toHaveProperty("user_id");
expect(item.metadata).not.toHaveProperty("userId");
});
});
// ─── update() ────────────────────────────────────────────
+84
View File
@@ -125,4 +125,88 @@ describe("RedisDB – entity payload handling", () => {
expect(entry.created_at).toBeGreaterThan(0);
expect(Number.isNaN(entry.created_at)).toBe(false);
});
test("search returns entity ids as snake_case", async () => {
mockClient.ft.search.mockResolvedValue({
total: 1,
documents: [
{
id: "mem0:test:mem-1",
value: {
memory_id: "mem-1",
hash: "h1",
memory: "likes coffee",
created_at: "1700000000000",
agent_id: "agent-1",
run_id: "run-1",
user_id: "user-1",
metadata: "{}",
__vector_score: 0.1,
},
},
],
});
const results = await store.search([0.1, 0.2, 0.3, 0.4], 5);
expect(results[0].payload.user_id).toBe("user-1");
expect(results[0].payload.agent_id).toBe("agent-1");
expect(results[0].payload.run_id).toBe("run-1");
expect(results[0].payload).not.toHaveProperty("userId");
expect(results[0].payload).not.toHaveProperty("agentId");
expect(results[0].payload).not.toHaveProperty("runId");
});
test("get returns entity ids as snake_case", async () => {
mockClient.exists.mockResolvedValue(1);
mockClient.hGetAll.mockResolvedValue({
memory_id: "mem-1",
hash: "h1",
memory: "likes coffee",
created_at: "1700000000000",
agent_id: "agent-1",
run_id: "run-1",
user_id: "user-1",
metadata: "{}",
});
const result = await store.get("mem-1");
expect(result?.payload.user_id).toBe("user-1");
expect(result?.payload.agent_id).toBe("agent-1");
expect(result?.payload.run_id).toBe("run-1");
expect(result?.payload).not.toHaveProperty("userId");
expect(result?.payload).not.toHaveProperty("agentId");
expect(result?.payload).not.toHaveProperty("runId");
});
test("list returns entity ids as snake_case", async () => {
mockClient.ft.search.mockResolvedValue({
total: 1,
documents: [
{
id: "mem0:test:mem-1",
value: {
memory_id: "mem-1",
hash: "h1",
memory: "likes coffee",
created_at: "1700000000000",
agent_id: "agent-1",
run_id: "run-1",
user_id: "user-1",
metadata: "{}",
},
},
],
});
const [items] = await store.list();
expect(items[0].payload.user_id).toBe("user-1");
expect(items[0].payload.agent_id).toBe("agent-1");
expect(items[0].payload.run_id).toBe("run-1");
expect(items[0].payload).not.toHaveProperty("userId");
expect(items[0].payload).not.toHaveProperty("agentId");
expect(items[0].payload).not.toHaveProperty("runId");
});
});
+86 -1
View File
@@ -166,7 +166,7 @@ describe("Valkey – mocked iovalkey client", () => {
const result = await store.get("mem-1");
expect(result?.id).toBe("mem-1");
expect(result?.payload.data).toBe("hello valkey");
expect(result?.payload.userId).toBe("alice");
expect(result?.payload.user_id).toBe("alice");
// created_at is persisted as unix seconds and rendered back to its ISO instant.
expect(result?.payload.createdAt).toBe("2024-01-01T00:00:00.000Z");
});
@@ -244,6 +244,91 @@ describe("Valkey – mocked iovalkey client", () => {
expect(searchCall[2]).toContain("@user_id:{a\\|b\\ c}");
});
it("get returns entity ids as snake_case", async () => {
const store = new ValkeyDB({
collectionName: "test",
embeddingModelDims: 4,
valkeyUrl: "valkey://localhost:6379",
});
await store.initialize();
await store.insert(
[[0.1, 0.2, 0.3, 0.4]],
["mem-ids"],
[
{
data: "likes tea",
user_id: "user-1",
agent_id: "agent-1",
run_id: "run-1",
},
],
);
const result = await store.get("mem-ids");
expect(result?.payload.user_id).toBe("user-1");
expect(result?.payload.agent_id).toBe("agent-1");
expect(result?.payload.run_id).toBe("run-1");
expect(result?.payload).not.toHaveProperty("userId");
expect(result?.payload).not.toHaveProperty("agentId");
expect(result?.payload).not.toHaveProperty("runId");
});
it("search and list return entity ids as snake_case", async () => {
const store = new ValkeyDB({
collectionName: "test",
embeddingModelDims: 4,
valkeyUrl: "valkey://localhost:6379",
});
await store.initialize();
const iovalkey = require("iovalkey");
const mockClient = iovalkey.__mockClient;
mockClient.call.mockImplementation(async (...args: any[]) => {
if (args[0] === "FT.SEARCH") {
return [
1,
"mem0:test:mem-search",
[
"memory_id",
"mem-search",
"hash",
"h1",
"memory",
"likes tea",
"created_at",
"1700000000",
"agent_id",
"agent-1",
"run_id",
"run-1",
"user_id",
"user-1",
"metadata",
"{}",
"vector_score",
"0.1",
],
];
}
return "OK";
});
const results = await store.search([0.1, 0.2, 0.3, 0.4], 5);
expect(results[0].payload.user_id).toBe("user-1");
expect(results[0].payload.agent_id).toBe("agent-1");
expect(results[0].payload.run_id).toBe("run-1");
expect(results[0].payload).not.toHaveProperty("userId");
expect(results[0].payload).not.toHaveProperty("agentId");
expect(results[0].payload).not.toHaveProperty("runId");
const [listed] = await store.list();
expect(listed[0].payload.user_id).toBe("user-1");
expect(listed[0].payload.agent_id).toBe("agent-1");
expect(listed[0].payload.run_id).toBe("run-1");
expect(listed[0].payload).not.toHaveProperty("userId");
});
it("does not raise an unhandled rejection when initialization fails", async () => {
const iovalkey = require("iovalkey");
iovalkey.__mockClient.call.mockImplementationOnce(async () => {