diff --git a/packages/core/src/tests/generation.test.ts b/packages/core/src/tests/generation.test.ts index 5d2c8720342..fe8f035913d 100644 --- a/packages/core/src/tests/generation.test.ts +++ b/packages/core/src/tests/generation.test.ts @@ -129,6 +129,23 @@ describe("Generation", () => { }); describe("trimTokens", () => { + let mockRuntime: IAgentRuntime; + + beforeEach(() => { + mockRuntime = { + getSetting: vi.fn().mockImplementation((key: string) => { + switch (key) { + case "TOKENIZER_MODEL": + return "gpt-4"; + case "TOKENIZER_TYPE": + return "tiktoken"; + default: + return undefined; + } + }), + } as unknown as IAgentRuntime; + }); + it("should return empty string for empty input", async () => { const result = await trimTokens("", 100, mockRuntime); expect(result).toBe(""); @@ -169,10 +186,10 @@ describe("Generation", () => { it("should handle multiline text", async () => { const multilineText = `Line 1 - Line 2 - Line 3 - Line 4 - Line 5`; +Line 2 +Line 3 +Line 4 +Line 5`; const result = await trimTokens(multilineText, 5, mockRuntime); expect(result.length).toBeGreaterThan(0); expect(result.length).toBeLessThan(multilineText.length); diff --git a/packages/core/src/tests/goals.test.ts b/packages/core/src/tests/goals.test.ts index f66461cc863..180b0aa3377 100644 --- a/packages/core/src/tests/goals.test.ts +++ b/packages/core/src/tests/goals.test.ts @@ -247,8 +247,15 @@ const sampleGoal: Goal = { }; describe("getGoals", () => { + let runtime: IAgentRuntime; + beforeEach(() => { - vi.clearAllMocks(); + runtime = { + agentId: "test-agent-id" as UUID, + databaseAdapter: { + getGoals: vi.fn().mockResolvedValue([]), + } as any, + } as IAgentRuntime; }); it("retrieves goals successfully", async () => { @@ -274,6 +281,26 @@ describe("getGoals", () => { }) ).rejects.toThrow("Failed to retrieve goals"); }); + + it("should handle empty goals list", async () => { + const mockRuntime = { + agentId: "test-agent-id" as UUID, + databaseAdapter: { + getGoals: vi.fn().mockResolvedValue([]), + }, + } as unknown as IAgentRuntime; + + const roomId = "test-room" as UUID; + + await getGoals({ runtime: mockRuntime, roomId }); + + expect(mockRuntime.databaseAdapter.getGoals).toHaveBeenCalledWith({ + agentId: "test-agent-id", + roomId, + onlyInProgress: true, + count: 5, + }); + }); }); describe("formatGoalsAsString", () => { @@ -292,6 +319,53 @@ describe("formatGoalsAsString", () => { const formatted = formatGoalsAsString({ goals: [] }); expect(formatted).toBe(""); }); + + it("should format goals as string correctly", () => { + const goals: Goal[] = [ + { + id: "1" as UUID, + name: "Goal 1", + status: GoalStatus.IN_PROGRESS, + objectives: [ + { + id: "obj1" as UUID, + description: "Objective 1", + completed: true, + }, + { + id: "obj2" as UUID, + description: "Objective 2", + completed: false, + }, + ], + roomId: "test-room" as UUID, + userId: "test-user" as UUID, + }, + { + id: "2" as UUID, + name: "Goal 2", + status: GoalStatus.DONE, + objectives: [ + { + id: "obj3" as UUID, + description: "Objective 3", + completed: true, + }, + ], + roomId: "test-room" as UUID, + userId: "test-user" as UUID, + }, + ]; + + const formattedGoals = formatGoalsAsString({ goals }); + expect(formattedGoals).toContain("Goal: Goal 1"); + expect(formattedGoals).toContain("id: 1"); + expect(formattedGoals).toContain("- [x] Objective 1 (DONE)"); + expect(formattedGoals).toContain("- [ ] Objective 2 (IN PROGRESS)"); + expect(formattedGoals).toContain("Goal: Goal 2"); + expect(formattedGoals).toContain("id: 2"); + expect(formattedGoals).toContain("- [x] Objective 3 (DONE)"); + }); }); describe("updateGoal", () => { @@ -318,6 +392,138 @@ describe("updateGoal", () => { updateGoal({ runtime: mockRuntime, goal: sampleGoal }) ).rejects.toThrow("Failed to update goal"); }); + + it("should update goal status correctly", async () => { + const goalId = "test-goal" as UUID; + const mockRuntime = { + databaseAdapter: { updateGoal: vi.fn() }, + agentId: "test-agent-id" as UUID, + } as unknown as IAgentRuntime; + + const updatedGoal: Goal = { + id: goalId, + name: "Test Goal", + objectives: [ + { + description: "Objective 1", + completed: false, + }, + { + description: "Objective 2", + completed: true, + }, + ], + roomId: "room-id" as UUID, + userId: "user-id" as UUID, + status: GoalStatus.DONE, + }; + + await updateGoal({ + runtime: mockRuntime, + goal: updatedGoal, + }); + + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + }); + + it("should handle failed goal update", async () => { + const goalId = "test-goal" as UUID; + const mockRuntime = { + databaseAdapter: { updateGoal: vi.fn() }, + agentId: "test-agent-id" as UUID, + } as unknown as IAgentRuntime; + + const updatedGoal: Goal = { + id: goalId, + name: "Test Goal", + objectives: [ + { + description: "Objective 1", + completed: false, + }, + { + description: "Objective 2", + completed: true, + }, + ], + roomId: "room-id" as UUID, + userId: "user-id" as UUID, + status: GoalStatus.FAILED, + }; + + await updateGoal({ + runtime: mockRuntime, + goal: updatedGoal, + }); + + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + }); + + it("should handle in-progress goal update", async () => { + const goalId = "test-goal" as UUID; + const mockRuntime = { + databaseAdapter: { updateGoal: vi.fn() }, + agentId: "test-agent-id" as UUID, + } as unknown as IAgentRuntime; + + const updatedGoal: Goal = { + id: goalId, + name: "Test Goal", + objectives: [ + { + description: "Objective 1", + completed: false, + }, + { + description: "Objective 2", + completed: true, + }, + ], + roomId: "room-id" as UUID, + userId: "user-id" as UUID, + status: GoalStatus.IN_PROGRESS, + }; + + await updateGoal({ + runtime: mockRuntime, + goal: updatedGoal, + }); + + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + }); + + it("should handle goal priority updates", async () => { + const goalId = "test-goal" as UUID; + const mockRuntime = { + databaseAdapter: { updateGoal: vi.fn() }, + agentId: "test-agent-id" as UUID, + } as unknown as IAgentRuntime; + + const updatedGoal: Goal = { + id: goalId, + name: "Test Goal", + objectives: [ + { + description: "Objective 1", + completed: false, + }, + { + description: "Objective 2", + completed: true, + }, + ], + roomId: "room-id" as UUID, + userId: "user-id" as UUID, + status: GoalStatus.IN_PROGRESS, + }; + + await updateGoal({ + runtime: mockRuntime, + goal: updatedGoal, + }); + + expect(mockRuntime.databaseAdapter.updateGoal).toHaveBeenCalledWith(updatedGoal); + }); }); describe("createGoal", () => { @@ -344,4 +550,57 @@ describe("createGoal", () => { createGoal({ runtime: mockRuntime, goal: sampleGoal }) ).rejects.toThrow("Failed to create goal"); }); + + it("should create new goal with correct properties", async () => { + const newGoal: Goal = { + name: "New Goal", + roomId: "room-id" as UUID, + userId: "user-id" as UUID, + status: GoalStatus.IN_PROGRESS, + objectives: [] + }; + + const mockRuntime = { + databaseAdapter: { createGoal: vi.fn() }, + agentId: "test-agent-id" as UUID, + } as unknown as IAgentRuntime; + + await createGoal({ + runtime: mockRuntime, + goal: newGoal, + }); + + expect(mockRuntime.databaseAdapter.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ + name: "New Goal", + roomId: "room-id", + userId: "user-id", + status: GoalStatus.IN_PROGRESS, + objectives: [] + }) + ); + }); + + it("should create a new goal", async () => { + const mockRuntime = { + databaseAdapter: { createGoal: vi.fn() }, + agentId: "test-agent-id" as UUID, + } as unknown as IAgentRuntime; + + const newGoal = { + id: "new-goal" as UUID, + name: "New Goal", + objectives: [], + roomId: "test-room" as UUID, + userId: "test-user" as UUID, + status: GoalStatus.IN_PROGRESS, + }; + + await createGoal({ + runtime: mockRuntime, + goal: newGoal, + }); + + expect(mockRuntime.databaseAdapter.createGoal).toHaveBeenCalledWith(newGoal); + }); }); diff --git a/packages/core/src/tests/memory.test.ts b/packages/core/src/tests/memory.test.ts new file mode 100644 index 00000000000..d146cebf7f2 --- /dev/null +++ b/packages/core/src/tests/memory.test.ts @@ -0,0 +1,132 @@ +import { MemoryManager } from "../memory"; +import { CacheManager, MemoryCacheAdapter } from "../cache"; +import { describe, expect, it, vi, beforeEach } from "vitest"; +import { IAgentRuntime, Memory, UUID } from "../types"; + +describe("MemoryManager", () => { + let memoryManager: MemoryManager; + let mockDatabaseAdapter: any; + let mockRuntime: IAgentRuntime; + + beforeEach(() => { + mockDatabaseAdapter = { + getMemories: vi.fn(), + createMemory: vi.fn(), + removeMemory: vi.fn(), + removeAllMemories: vi.fn(), + countMemories: vi.fn(), + getCachedEmbeddings: vi.fn(), + searchMemories: vi.fn(), + getMemoriesByRoomIds: vi.fn(), + getMemoryById: vi.fn(), + }; + + mockRuntime = { + databaseAdapter: mockDatabaseAdapter, + cacheManager: new CacheManager(new MemoryCacheAdapter()), + agentId: "test-agent-id" as UUID, + } as unknown as IAgentRuntime; + + memoryManager = new MemoryManager({ + tableName: "test_memories", + runtime: mockRuntime, + }); + }); + + describe("addEmbeddingToMemory", () => { + it("should preserve existing embedding if present", async () => { + const existingEmbedding = [0.1, 0.2, 0.3]; + const memory: Memory = { + id: "test-id" as UUID, + userId: "user-id" as UUID, + agentId: "agent-id" as UUID, + roomId: "room-id" as UUID, + content: { text: "test content" }, + embedding: existingEmbedding, + }; + + const result = await memoryManager.addEmbeddingToMemory(memory); + expect(result.embedding).toBe(existingEmbedding); + }); + + it("should throw error for empty content", async () => { + const memory: Memory = { + id: "test-id" as UUID, + userId: "user-id" as UUID, + agentId: "agent-id" as UUID, + roomId: "room-id" as UUID, + content: { text: "" }, + }; + + await expect(memoryManager.addEmbeddingToMemory(memory)).rejects.toThrow( + "Cannot generate embedding: Memory content is empty" + ); + }); + }); + + describe("searchMemoriesByEmbedding", () => { + it("should use default threshold and count when not provided", async () => { + const embedding = [0.1, 0.2, 0.3]; + const roomId = "test-room" as UUID; + + mockDatabaseAdapter.searchMemories = vi.fn().mockResolvedValue([]); + + await memoryManager.searchMemoriesByEmbedding(embedding, { roomId }); + + expect(mockDatabaseAdapter.searchMemories).toHaveBeenCalledWith({ + embedding, + match_threshold: 0.1, + match_count: 10, + roomId, + tableName: "test_memories", + agentId: "test-agent-id", + unique: false, + }); + }); + + it("should respect custom threshold and count", async () => { + const embedding = [0.1, 0.2, 0.3]; + const roomId = "test-room" as UUID; + const match_threshold = 0.5; + const count = 5; + + mockDatabaseAdapter.searchMemories = vi.fn().mockResolvedValue([]); + + await memoryManager.searchMemoriesByEmbedding(embedding, { + roomId, + match_threshold, + count, + }); + + expect(mockDatabaseAdapter.searchMemories).toHaveBeenCalledWith({ + embedding, + match_threshold, + match_count: count, + roomId, + tableName: "test_memories", + agentId: "test-agent-id", + unique: false, + }); + }); + }); + + describe("getMemories", () => { + it("should handle pagination parameters", async () => { + const roomId = "test-room" as UUID; + const start = 0; + const end = 5; + + await memoryManager.getMemories({ roomId, start, end }); + + expect(mockDatabaseAdapter.getMemories).toHaveBeenCalledWith({ + roomId, + count: 10, + unique: true, + tableName: "test_memories", + agentId: "test-agent-id", + start: 0, + end: 5, + }); + }); + }); +}); diff --git a/packages/core/src/tests/providers.test.ts b/packages/core/src/tests/providers.test.ts index 62171f631a3..152cac053b0 100644 --- a/packages/core/src/tests/providers.test.ts +++ b/packages/core/src/tests/providers.test.ts @@ -172,4 +172,68 @@ describe("getProviders", () => { getProviders(runtime, message, {} as State) ).rejects.toThrow("Provider error"); }); + + it("should handle empty provider list", async () => { + runtime.providers = []; + const message: Memory = { + userId: "00000000-0000-0000-0000-000000000001", + content: { text: "" }, + roomId, + agentId: "00000000-0000-0000-0000-000000000002", + }; + + const responses = await getProviders(runtime, message); + expect(responses).toBe(""); + }); + + it("should filter out null and undefined responses", async () => { + const MockProviderWithMixedResponses: Provider = { + get: async ( + _runtime: IAgentRuntime, + _message: Memory, + _state?: State + ) => { + return null; + }, + }; + + runtime.providers = [ + MockProvider1, + MockProviderWithMixedResponses, + MockProvider2, + ]; + + const message: Memory = { + userId: "00000000-0000-0000-0000-000000000001", + content: { text: "" }, + roomId, + agentId: "00000000-0000-0000-0000-000000000002", + }; + + const responses = await getProviders(runtime, message); + expect(responses).toBe("Response from Provider 1\nResponse from Provider 2"); + }); + + it("should handle provider throwing an error", async () => { + const MockProviderWithError: Provider = { + get: async ( + _runtime: IAgentRuntime, + _message: Memory, + _state?: State + ) => { + throw new Error("Provider error"); + }, + }; + + runtime.providers = [MockProvider1, MockProviderWithError, MockProvider2]; + + const message: Memory = { + userId: "00000000-0000-0000-0000-000000000001", + content: { text: "" }, + roomId, + agentId: "00000000-0000-0000-0000-000000000002", + }; + + await expect(getProviders(runtime, message)).rejects.toThrow("Provider error"); + }); });