Added Mem0 TS Library (#2270)

This commit is contained in:
Saket Aryan
2025-02-28 04:49:17 +05:30
committed by GitHub
parent ecff6315e7
commit d200691e9b
44 changed files with 5142 additions and 0 deletions

View File

@@ -0,0 +1,391 @@
import { MemoryClient } from "../mem0";
import dotenv from "dotenv";
dotenv.config();
const apiKey = process.env.MEM0_API_KEY || "";
// const client = new MemoryClient({ apiKey, host: 'https://api.mem0.ai', organizationId: "org_gRNd1RrQa4y52iK4tG8o59hXyVbaULikgq4kethC", projectId: "proj_7RfMkWs0PMgXYweGUNKqV9M9mgIRNt5XcupE7mSP" });
// const client = new MemoryClient({ apiKey, host: 'https://api.mem0.ai', organizationName: "saket-default-org", projectName: "default-project" });
const client = new MemoryClient({ apiKey, host: "https://api.mem0.ai" });
// Generate a random string
const randomString = () => {
return (
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15)
);
};
describe("MemoryClient API", () => {
let userId: string, memoryId: string;
beforeAll(() => {
userId = randomString();
});
const messages1 = [
{ role: "user", content: "Hey, I am Alex. I'm now a vegetarian." },
{ role: "assistant", content: "Hello Alex! Glad to hear!" },
];
it("should add messages successfully", async () => {
const res = await client.add(messages1, { user_id: userId || "" });
// Validate the response contains an iterable list
expect(Array.isArray(res)).toBe(true);
// Validate the fields of the first message in the response
const message = res[0];
expect(typeof message.id).toBe("string");
expect(typeof message.data?.memory).toBe("string");
expect(typeof message.event).toBe("string");
// Store the memory ID for later use
memoryId = message.id;
});
it("should retrieve the specific memory by ID", async () => {
const memory = await client.get(memoryId);
// Validate that the memory fields have the correct types and values
// Should be a string (memory id)
expect(typeof memory.id).toBe("string");
// Should be a string (the actual memory content)
expect(typeof memory.memory).toBe("string");
// Should be a string and equal to the userId
expect(typeof memory.user_id).toBe("string");
expect(memory.user_id).toBe(userId);
// Should be null or any object (metadata)
expect(
memory.metadata === null || typeof memory.metadata === "object",
).toBe(true);
// Should be an array of strings or null (categories)
expect(Array.isArray(memory.categories) || memory.categories === null).toBe(
true,
);
if (Array.isArray(memory.categories)) {
memory.categories.forEach((category) => {
expect(typeof category).toBe("string");
});
}
// Should be a valid date (created_at)
expect(new Date(memory.created_at || "").toString()).not.toBe(
"Invalid Date",
);
// Should be a valid date (updated_at)
expect(new Date(memory.updated_at || "").toString()).not.toBe(
"Invalid Date",
);
});
it("should retrieve all users successfully", async () => {
const allUsers = await client.users();
// Validate the number of users is a number
expect(typeof allUsers.count).toBe("number");
// Validate the structure of the first user
const firstUser = allUsers.results[0];
expect(typeof firstUser.id).toBe("string");
expect(typeof firstUser.name).toBe("string");
expect(typeof firstUser.created_at).toBe("string");
expect(typeof firstUser.updated_at).toBe("string");
expect(typeof firstUser.total_memories).toBe("number");
expect(typeof firstUser.type).toBe("string");
// Find the user with the name matching userId
const entity = allUsers.results.find((user) => user.name === userId);
expect(entity).not.toBeUndefined();
// Store the entity ID for later use
const entity_id = entity?.id;
expect(typeof entity_id).toBe("string");
});
it("should retrieve all memories for the user", async () => {
const res3 = await client.getAll({ user_id: userId });
// Validate that res3 is an iterable list (array)
expect(Array.isArray(res3)).toBe(true);
if (res3.length > 0) {
// Iterate through the first memory for validation (you can loop through all if needed)
const memory = res3[0];
// Should be a string (memory id)
expect(typeof memory.id).toBe("string");
// Should be a string (the actual memory content)
expect(typeof memory.memory).toBe("string");
// Should be a string and equal to the userId
expect(typeof memory.user_id).toBe("string");
expect(memory.user_id).toBe(userId);
// Should be null or an object (metadata)
expect(
memory.metadata === null || typeof memory.metadata === "object",
).toBe(true);
// Should be an array of strings or null (categories)
expect(
Array.isArray(memory.categories) || memory.categories === null,
).toBe(true);
if (Array.isArray(memory.categories)) {
memory.categories.forEach((category) => {
expect(typeof category).toBe("string");
});
}
// Should be a valid date (created_at)
expect(new Date(memory.created_at || "").toString()).not.toBe(
"Invalid Date",
);
// Should be a valid date (updated_at)
expect(new Date(memory.updated_at || "").toString()).not.toBe(
"Invalid Date",
);
} else {
// If there are no memories, assert that the list is empty
expect(res3.length).toBe(0);
}
});
it("should search and return results based on provided query and filters (API version 2)", async () => {
const searchOptionsV2 = {
query: "What do you know about me?",
filters: {
OR: [{ user_id: userId }, { agent_id: "shopping-assistant" }],
},
threshold: 0.1,
api_version: "v2",
};
const searchResultV2 = await client.search(
"What do you know about me?",
searchOptionsV2,
);
// Validate that searchResultV2 is an iterable list (array)
expect(Array.isArray(searchResultV2)).toBe(true);
if (searchResultV2.length > 0) {
// Iterate through the first search result for validation (you can loop through all if needed)
const memory = searchResultV2[0];
// Should be a string (memory id)
expect(typeof memory.id).toBe("string");
// Should be a string (the actual memory content)
expect(typeof memory.memory).toBe("string");
if (memory.user_id) {
// Should be a string and equal to userId
expect(typeof memory.user_id).toBe("string");
expect(memory.user_id).toBe(userId);
}
if (memory.agent_id) {
// Should be a string (agent_id)
expect(typeof memory.agent_id).toBe("string");
expect(memory.agent_id).toBe("shopping-assistant");
}
// Should be null or an object (metadata)
expect(
memory.metadata === null || typeof memory.metadata === "object",
).toBe(true);
// Should be an array of strings or null (categories)
expect(
Array.isArray(memory.categories) || memory.categories === null,
).toBe(true);
if (Array.isArray(memory.categories)) {
memory.categories.forEach((category) => {
expect(typeof category).toBe("string");
});
}
// Should be a valid date (created_at)
expect(new Date(memory.created_at || "").toString()).not.toBe(
"Invalid Date",
);
// Should be a valid date (updated_at)
expect(new Date(memory.updated_at || "").toString()).not.toBe(
"Invalid Date",
);
// Should be a number (score)
expect(typeof memory.score).toBe("number");
} else {
// If no search results, assert that the list is empty
expect(searchResultV2.length).toBe(0);
}
});
it("should search and return results based on provided query (API version 1)", async () => {
const searchResultV1 = await client.search("What is my name?", {
user_id: userId,
});
// Validate that searchResultV1 is an iterable list (array)
expect(Array.isArray(searchResultV1)).toBe(true);
if (searchResultV1.length > 0) {
// Iterate through the first search result for validation (you can loop through all if needed)
const memory = searchResultV1[0];
// Should be a string (memory id)
expect(typeof memory.id).toBe("string");
// Should be a string (the actual memory content)
expect(typeof memory.memory).toBe("string");
// Should be a string and equal to userId
expect(typeof memory.user_id).toBe("string");
expect(memory.user_id).toBe(userId);
// Should be null or an object (metadata)
expect(
memory.metadata === null || typeof memory.metadata === "object",
).toBe(true);
// Should be an array of strings or null (categories)
expect(
Array.isArray(memory.categories) || memory.categories === null,
).toBe(true);
if (Array.isArray(memory.categories)) {
memory.categories.forEach((category) => {
expect(typeof category).toBe("string");
});
}
// Should be a valid date (created_at)
expect(new Date(memory.created_at || "").toString()).not.toBe(
"Invalid Date",
);
// Should be a valid date (updated_at)
expect(new Date(memory.updated_at || "").toString()).not.toBe(
"Invalid Date",
);
// Should be a number (score)
expect(typeof memory.score).toBe("number");
} else {
// If no search results, assert that the list is empty
expect(searchResultV1.length).toBe(0);
}
});
it("should retrieve history of a specific memory and validate the fields", async () => {
const res22 = await client.history(memoryId);
// Validate that res22 is an iterable list (array)
expect(Array.isArray(res22)).toBe(true);
if (res22.length > 0) {
// Iterate through the first history entry for validation (you can loop through all if needed)
const historyEntry = res22[0];
// Should be a string (history entry id)
expect(typeof historyEntry.id).toBe("string");
// Should be a string (memory id related to the history entry)
expect(typeof historyEntry.memory_id).toBe("string");
// Should be a string and equal to userId
expect(typeof historyEntry.user_id).toBe("string");
expect(historyEntry.user_id).toBe(userId);
// Should be a string or null (old memory)
expect(
historyEntry.old_memory === null ||
typeof historyEntry.old_memory === "string",
).toBe(true);
// Should be a string or null (new memory)
expect(
historyEntry.new_memory === null ||
typeof historyEntry.new_memory === "string",
).toBe(true);
// Should be an array of strings or null (categories)
expect(
Array.isArray(historyEntry.categories) ||
historyEntry.categories === null,
).toBe(true);
if (Array.isArray(historyEntry.categories)) {
historyEntry.categories.forEach((category) => {
expect(typeof category).toBe("string");
});
}
// Should be a valid date (created_at)
expect(new Date(historyEntry.created_at).toString()).not.toBe(
"Invalid Date",
);
// Should be a valid date (updated_at)
expect(new Date(historyEntry.updated_at).toString()).not.toBe(
"Invalid Date",
);
// Should be a string, one of: ADD, UPDATE, DELETE, NOOP
expect(["ADD", "UPDATE", "DELETE", "NOOP"]).toContain(historyEntry.event);
// Validate conditions based on event type
if (historyEntry.event === "ADD") {
expect(historyEntry.old_memory).toBeNull();
expect(historyEntry.new_memory).not.toBeNull();
} else if (historyEntry.event === "UPDATE") {
expect(historyEntry.old_memory).not.toBeNull();
expect(historyEntry.new_memory).not.toBeNull();
} else if (historyEntry.event === "DELETE") {
expect(historyEntry.old_memory).not.toBeNull();
expect(historyEntry.new_memory).toBeNull();
}
// Should be a list of objects or null (input)
expect(
Array.isArray(historyEntry.input) || historyEntry.input === null,
).toBe(true);
if (Array.isArray(historyEntry.input)) {
historyEntry.input.forEach((input) => {
// Each input should be an object
expect(typeof input).toBe("object");
// Should have string content
expect(typeof input.content).toBe("string");
// Should have a role that is either 'user' or 'assistant'
expect(["user", "assistant"]).toContain(input.role);
});
}
} else {
// If no history entries, assert that the list is empty
expect(res22.length).toBe(0);
}
});
it("should delete the user successfully", async () => {
const allUsers = await client.users();
const entity = allUsers.results.find((user) => user.name === userId);
if (entity) {
const deletedUser = await client.deleteUser(entity.id);
// Validate the deletion message
expect(deletedUser.message).toBe("Entity deleted successfully!");
}
});
});