392 lines
13 KiB
TypeScript
392 lines
13 KiB
TypeScript
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!");
|
|
}
|
|
});
|
|
});
|