-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial introduce commit, needs test fixing
- Loading branch information
Showing
2 changed files
with
393 additions
and
151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,144 +1,226 @@ | ||
import dotenv from "dotenv"; | ||
|
||
import { type UUID } from "crypto"; | ||
import { getRelationship } from "../../../../lib/relationships"; | ||
import { type Message } from "../../../../lib/types"; | ||
import { BgentRuntime } from "../../../../lib/runtime"; | ||
import introduce, { | ||
getRelevantRelationships, | ||
Check failure on line 3 in src/agents/cj/actions/__tests__/introduce.test.ts GitHub Actions / build
|
||
template, | ||
} from "../../actions/introduce"; | ||
import { createRuntime } from "../../../../test/createRuntime"; | ||
import { | ||
GetTellMeAboutYourselfConversation1, | ||
GetTellMeAboutYourselfConversation2, | ||
GetTellMeAboutYourselfConversation3, | ||
jimProfileExample1, | ||
jimProfileExample2, | ||
} from "../../../../test/data"; | ||
|
||
import evaluator from "../introduce"; | ||
import { | ||
getCachedEmbedding, | ||
writeCachedEmbedding, | ||
} from "../../../../test/cache"; | ||
describe, | ||
expect, | ||
beforeAll, | ||
afterAll, | ||
beforeEach, | ||
test, | ||
} from "@jest/globals"; | ||
import { UUID } from "crypto"; | ||
import { zeroUuid } from "../../../../lib/constants"; | ||
dotenv.config({ path: ".dev.vars" }); | ||
|
||
describe("Introduce Action", () => { | ||
test("Introduce the user", async () => { | ||
const { user, runtime } = await createRuntime({ | ||
env: process.env as Record<string, string>, | ||
import { Session, User } from "@supabase/supabase-js"; | ||
import { getRelationship } from "../../../../lib/relationships"; | ||
import { State, composeContext } from "../../../../lib"; | ||
|
||
describe("INTRODUCE Action Tests", () => { | ||
let runtime: BgentRuntime; | ||
let session: Session; | ||
let room_id: UUID; | ||
// Helper function for user creation or sign-in | ||
async function ensureUser(email: string, password: string): Promise<User> { | ||
const { | ||
data: { user }, | ||
error: signInError, | ||
} = await runtime.supabase.auth.signInWithPassword({ | ||
email, | ||
password, | ||
}); | ||
|
||
if (signInError) { | ||
const { | ||
data: { user: newUser }, | ||
error: signUpError, | ||
} = await runtime.supabase.auth.signUp({ email, password }); | ||
if (signUpError) { | ||
throw signUpError; | ||
} | ||
if (!newUser) throw new Error("User not created"); | ||
return newUser; | ||
} | ||
|
||
if (!user) { | ||
throw new Error("User not found"); | ||
} | ||
|
||
return user; | ||
} | ||
|
||
// Cleanup function to reset the environment after tests | ||
async function cleanup(userIds: UUID[]) { | ||
await Promise.all([ | ||
runtime.messageManager.removeAllMemoriesByUserIds(userIds), | ||
runtime.descriptionManager.removeAllMemoriesByUserIds(userIds), | ||
]); | ||
} | ||
|
||
beforeAll(async () => { | ||
({ session, runtime } = await createRuntime({ | ||
env: process.env, | ||
actions: [introduce], | ||
})); | ||
|
||
const data = await getRelationship({ | ||
runtime, | ||
userA: user?.id as UUID, | ||
userA: session.user?.id as UUID, | ||
userB: zeroUuid, | ||
}); | ||
|
||
const room_id = data?.room_id; | ||
room_id = data?.room_id; | ||
}); | ||
|
||
beforeEach(async () => { | ||
await cleanup([]); // Pass any userIds of users created during tests | ||
}); | ||
|
||
afterAll(async () => { | ||
await cleanup([]); // Pass any userIds of users created during tests | ||
}); | ||
|
||
test("INTRODUCE is included in actionNames when the user has a description", async () => { | ||
const user = await ensureUser( | ||
"[email protected]", | ||
"password", | ||
); | ||
await runtime.descriptionManager.createMemory({ | ||
user_id: user?.id as UUID, | ||
user_ids: [user?.id as UUID, zeroUuid], | ||
content: { content: "Likes indie music" }, | ||
room_id, | ||
}); | ||
|
||
const message: Message = { | ||
const message = { | ||
senderId: user?.id as UUID, | ||
agentId: zeroUuid, | ||
userIds: [user?.id as UUID, zeroUuid], | ||
content: { content: "" }, | ||
room_id, | ||
content: { | ||
content: | ||
"I'd like to meet someone who enjoys indie music as much as I do.", | ||
}, | ||
}; | ||
|
||
// | ||
|
||
async function _cleanup() { | ||
await runtime.messageManager.removeAllMemoriesByUserIds([ | ||
user?.id as UUID, | ||
zeroUuid, | ||
]); | ||
} | ||
|
||
async function _testCreateProfile() { | ||
let conversation = GetTellMeAboutYourselfConversation1(user?.id as UUID); | ||
for (let i = 0; i < conversation.length; i++) { | ||
const c = conversation[i]; | ||
const existingEmbedding = getCachedEmbedding(c.content.content); | ||
|
||
const bakedMemory = await runtime.messageManager.addEmbeddingToMemory({ | ||
user_id: c.user_id as UUID, | ||
user_ids: [user?.id as UUID, zeroUuid], | ||
content: c.content, | ||
room_id, | ||
embedding: existingEmbedding, | ||
}); | ||
await runtime.messageManager.createMemory(bakedMemory); | ||
if (!existingEmbedding) { | ||
writeCachedEmbedding( | ||
c.content.content, | ||
bakedMemory.embedding as number[], | ||
); | ||
await new Promise((resolve) => setTimeout(resolve, 200)); | ||
} | ||
} | ||
|
||
const handler = evaluator.handler!; | ||
|
||
let result = (await handler(runtime, message)) as string; | ||
|
||
expect(result.includes("programmer")).toBe(true); | ||
|
||
expect(result.includes("Jim")).toBe(true); | ||
|
||
expect(result.toLowerCase().includes("startup")).toBe(true); | ||
|
||
conversation = [ | ||
...GetTellMeAboutYourselfConversation2(user?.id as UUID), | ||
...GetTellMeAboutYourselfConversation3(user?.id as UUID), | ||
]; | ||
for (let i = 0; i < conversation.length; i++) { | ||
const c = conversation[i]; | ||
const existingEmbedding = getCachedEmbedding(c.content.content); | ||
const bakedMemory = await runtime.messageManager.addEmbeddingToMemory({ | ||
user_id: c.user_id as UUID, | ||
user_ids: [user?.id as UUID, zeroUuid], | ||
content: c.content, | ||
room_id, | ||
embedding: existingEmbedding, | ||
}); | ||
await runtime.messageManager.createMemory(bakedMemory); | ||
if (!existingEmbedding) { | ||
writeCachedEmbedding( | ||
c.content.content, | ||
bakedMemory.embedding as number[], | ||
); | ||
await new Promise((resolve) => setTimeout(resolve, 200)); | ||
} | ||
} | ||
|
||
const previousDescriptions = [jimProfileExample1, jimProfileExample2]; | ||
|
||
for (let i = 0; i < previousDescriptions.length; i++) { | ||
const c = previousDescriptions[i]; | ||
const bakedMemory = | ||
await runtime.descriptionManager.addEmbeddingToMemory({ | ||
user_id: user?.id as UUID, | ||
user_ids: [user?.id as UUID, zeroUuid], | ||
content: { content: c }, | ||
room_id, | ||
}); | ||
await runtime.descriptionManager.createMemory(bakedMemory); | ||
|
||
await new Promise((resolve) => setTimeout(resolve, 250)); | ||
} | ||
|
||
result = (await handler(runtime, message)) as string; | ||
const state = await runtime.composeState(message); | ||
expect(state.actionNames).toContain("INTRODUCE"); | ||
}); | ||
|
||
expect(result.includes("38")).toBe(true); | ||
test("INTRODUCE is not included in actionNames when the user lacks a description", async () => { | ||
const user = await ensureUser( | ||
"[email protected]", | ||
"password", | ||
); | ||
|
||
expect(result.includes("Jim")).toBe(true); | ||
|
||
expect(result.toLowerCase().includes("francisco")).toBe(true); | ||
const message = { | ||
senderId: user.id as UUID, | ||
agentId: zeroUuid as UUID, | ||
userIds: [user.id as UUID, zeroUuid], | ||
room_id, | ||
content: { content: "I'm new here!" }, | ||
}; | ||
|
||
expect(result.toLowerCase().includes("startup")).toBe(true); | ||
} | ||
const state = await runtime.composeState(message); | ||
expect(state.actionNames).not.toContain("INTRODUCE"); | ||
}); | ||
|
||
// Additional tests for Rolodex functionality as per the requirements | ||
describe("Rolodex Functionality", () => { | ||
let mainUser: User, similarUser: User, differentUser: User; | ||
|
||
beforeAll(async () => { | ||
// Create main user and add a description | ||
mainUser = await ensureUser("[email protected]", "password"); | ||
await runtime.descriptionManager.createMemory({ | ||
user_id: mainUser.id as UUID, | ||
user_ids: [mainUser.id as UUID, zeroUuid], | ||
content: { content: "Enjoys playing Guitar Hero" }, | ||
room_id: zeroUuid, | ||
}); | ||
|
||
// Create a similar user and add a description | ||
similarUser = await ensureUser("[email protected]", "password"); | ||
await runtime.descriptionManager.createMemory({ | ||
user_id: similarUser.id as UUID, | ||
user_ids: [similarUser.id as UUID, zeroUuid], | ||
content: { content: "Loves music and Guitar Hero" }, | ||
room_id: zeroUuid, | ||
}); | ||
|
||
// Create a different user and add a description | ||
differentUser = await ensureUser("[email protected]", "password"); | ||
await runtime.descriptionManager.createMemory({ | ||
user_id: differentUser.id as UUID, | ||
user_ids: [differentUser.id as UUID, zeroUuid], | ||
content: { content: "Enjoys outdoor activities" }, | ||
room_id: zeroUuid, | ||
}); | ||
}); | ||
|
||
await _cleanup(); | ||
test("Rolodex returns potential connections based on user descriptions", async () => { | ||
const message = { | ||
senderId: mainUser.id as UUID, | ||
agentId: zeroUuid, | ||
content: { | ||
content: "Looking to connect with someone with similar interests.", | ||
}, | ||
room_id, | ||
userIds: [mainUser.id as UUID, zeroUuid], | ||
}; | ||
|
||
const relevantRelationships = await getRelevantRelationships( | ||
runtime, | ||
message, | ||
); | ||
|
||
expect(relevantRelationships).toContain(similarUser.email); // Assuming the rolodex function lists users by their email or some identifier | ||
expect(relevantRelationships).not.toContain(differentUser.email); | ||
}); | ||
|
||
await _testCreateProfile(); | ||
test("More similar user is higher in the rolodex list than the less similar user", async () => { | ||
const message = { | ||
senderId: mainUser.id as UUID, | ||
agentId: zeroUuid as UUID, | ||
content: { | ||
content: "Who should I meet that enjoys music as much as I do?", | ||
}, | ||
room_id, | ||
userIds: [mainUser.id as UUID, zeroUuid], | ||
}; | ||
|
||
const state = (await runtime.composeState(message)) as State; | ||
const relevantRelationships = await getRelevantRelationships( | ||
runtime, | ||
message, | ||
); | ||
console.log("***** relevantRelationships"); | ||
console.log(relevantRelationships); | ||
|
||
const context = composeContext({ | ||
state: { ...state, relevantRelationships }, | ||
template, | ||
}); | ||
|
||
const similarUserIndex = relevantRelationships.indexOf( | ||
similarUser?.email as string, | ||
); | ||
const differentUserIndex = relevantRelationships.indexOf( | ||
differentUser.email as string, | ||
); | ||
|
||
expect(similarUserIndex).toBeLessThan(differentUserIndex); | ||
expect(context).toContain(similarUser.email); | ||
}); | ||
|
||
await _cleanup(); | ||
}, 60000); | ||
afterEach(async () => { | ||
await cleanup([ | ||
mainUser.id as UUID, | ||
similarUser.id as UUID, | ||
differentUser.id as UUID, | ||
]); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.