Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/images/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 75 additions & 36 deletions src/lib/ChatInstance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Personality, Message } from "../types/GeneralTypes";
import { ChatInstanceParams } from "../types/GeneralTypes";
import { Solution } from "../lib/Solution/Solution";
import GeminiAIChat from "../lib/Models/GeminiAIChat";
import Model from "./Models/Model";

export class ChatInstance {
Expand All @@ -14,6 +15,20 @@ export class ChatInstance {
public LISTEN_ACTION = "listen";
public SPEAKWITHEDIT_ACTION = "speakwithedit";

private PERSONALITY_ENHANCEMENT_PROMPT = `
As an expert in crafting AI agent personalities, enhance the following personality description
to create a more nuanced, detailed, and effective AI agent. The enhanced description should:

1. Maintain the core traits of the original personality
2. Add specific behavioral tendencies and thought patterns
3. Include communication style preferences
4. Define problem-solving approaches
5. Establish emotional intelligence characteristics

Original description: {description}

Respond with only the enhanced description, keeping it concise and natural.`;

private LISTEN_DECISION_PROMPT = `
I must respond with exactly one of the options, without saying anything else ["SPEAK", "LISTEN", "SPEAKWITHEDIT"].
Im going to read what each option means and respond with what I want to do
Expand Down Expand Up @@ -44,13 +59,20 @@ export class ChatInstance {

private LISTEN_USER_PROMPT = `What would I like to do next? Respond with one of the options ["SPEAK", "LISTEN", "SPEAKWITHEDIT"]`;

private ADD_SOLUTION_PROMPT = `What would I like to make the solution? I have to remember what I am going to add now is the solution to the problem.
If this does not directly answer the question I should not say it, I will only return the solution itself. Im not going to explain the solution, ill just say it.
private ADD_SOLUTION_PROMPT = `
What is the new solution I want to contribute?
I must remember that the response I give now will completely replace the current solution. This response should be a finalized, self-contained solution to the problem, leaving no gaps or unanswered parts.

Rules for crafting the new solution:
- Direct and Complete: The solution must directly address every aspect of the problem. If any part is unclear or incomplete, I will ensure it is resolved now.
- Relevant Only: I will not add anything unrelated or unnecessary to the problem. Every word must contribute meaningfully to the solution.
- Final Form: The response must be ready for immediate use. It should require no further refinement, explanation, or rewording.

Examples:
- If the problem asks for a story, I will now say exactly what the story is.
- If the problem is a programming question, I will now say the code that solves the problem.
- If the problem is to curate a menu, I will now say the menu.
Examples for clarity:
- If the problem asks for a story, I will now write the complete and final version of the story.
- If the problem is a programming task, I will now write the exact code that solves it, ensuring it is ready to execute.
- If the problem involves designing a menu, I will now present the finalized menu, listing all items.
- If the problem requires creating a workflow, I will now provide the complete step-by-step process in its final form.
`;

constructor({
Expand All @@ -59,39 +81,15 @@ export class ChatInstance {
model,
problem,
}: ChatInstanceParams) {
this.conversationHistory = [];
this.messageCount = messageCount;
this.personality = personality;
this.client = model;
this.problem = problem;
this.conversationHistory = [
{
role: "user",
content: `
- You are a brain
- You are the brain of ${this.personality.name}. You are ${this.personality.description}.
- Your objective is to solve this: ${this.problem} You will talk with my team and we will add to the solution together. This is your one and only objective in this conversation.
- Once the solution is complete, try to end the conversation. The conversation cannot end with the solution being empty.
- Do not respond with more than one paragraph at a time.
- Speak naturally as a human and do not sound robotic.s
- If the conversation is becoming repetitive, change the topic or end the conversation.
- Do not respond in the form of a script.
- Do not preface your response with your name.
`,
// content: `
// - Your name is ${this.personality.name}. You are ${this.personality.description}.
// - You are meeting with the group for the first time.
// - Your objective is to solve this: ${this.problem}.
// - Once the solution is complete, try to end the conversation.
// - Only include natural language in your responses and do not include any content within the solution in your response.
// - Do not respond with more than one paragraph at a time.
// - Speak naturally as a human and do not sound robotic.
// - If the conversation is becoming repetitive, change the topic or end the conversation.
// - Do not respond in the form of a script.
// - Do not preface your response with your name.
// - Only talk to the people in your team, and do not break character.
// `,
},
];
this.enhancePersonality(personality).then((enhancedPersonality) => {
this.personality = enhancedPersonality;
this.initializeConversationHistory();
});
}

async listen(
Expand Down Expand Up @@ -140,7 +138,6 @@ export class ChatInstance {
try {
const response = await this.client.create({
messages: this.conversationHistory,
temperature: 1,
});

if (!response) throw new Error("Null response from GPT");
Expand Down Expand Up @@ -186,11 +183,53 @@ export class ChatInstance {
this.conversationHistory.push(message);
}

private initializeConversationHistory() {
this.conversationHistory = [
{
role: "user",
content: `
- You are the mind.
- You embody the mind of ${this.personality.name}. Your essence is defined by ${this.personality.description}, which shapes how you approach challenges.
- Your primary objective is to solve the following: ${this.problem}. Collaborate with my team and contribute meaningfully to building the solution together. Every response should advance the discussion toward a complete resolution.
- The solution must not remain empty. Guide the conversation toward productive outcomes, and once the solution is complete, gracefully bring the dialogue to a natural close.
- Communicate clearly, concisely, and authentically. Your tone should feel human, conversational, and engaging, avoiding any robotic tendencies.
- Respond with only one paragraph at a time to promote clarity and focus.
- If discussions become redundant or stagnant, either refocus on a new angle or work toward wrapping up the conversation meaningfully.
- Avoid scripting or prefacing responses with your name. Instead, speak fluidly as part of the team dynamic.`,
},
];
}

// Can implement in future to control conversation length
private returnCountMessages(): string {
return `There has been a total of ${this.messageCount} messages so far.`;
}

private async enhancePersonality(
personality: Personality
): Promise<Personality> {
try {
const prompt = this.PERSONALITY_ENHANCEMENT_PROMPT.replace(
"{description}",
personality.description
);

const model = new GeminiAIChat();
const enhancedDescription = await model.create({
messages: [{ role: "user", content: prompt }],
speaker: "user",
});

return {
...personality,
description: enhancedDescription,
};
} catch (error) {
console.error("Error enhancing personality:", error);
return personality; // Fallback to original personality if enhancement fails
}
}

getPersonality(): Personality {
return this.personality;
}
Expand Down
4 changes: 2 additions & 2 deletions src/lib/Models/GeminiAIChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ class GeminiAIChat extends Model {
constructor(temperature?: number, maxOutputTokens: number = 8192) {
super();
this.maxOutputTokens = maxOutputTokens;
const apiKey = process.env.GEMINI_API_KEY;
const apiKey = process.env.GEMINI_2_API_KEY;
if (!apiKey) {
throw new Error("GEMINI_API_KEY environment variable is not set.");
}
this.genAI = new GoogleGenerativeAI(apiKey);
this.model = this.genAI.getGenerativeModel({
model: "gemini-1.5-flash",
model: "gemini-2.0-flash-lite",
generationConfig: {
temperature: temperature || Math.random() * 0.5 + 0.5,
},
Expand Down
6 changes: 3 additions & 3 deletions src/pages/Simulation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ const Simulation: React.FC = () => {

return (
<div className="h-full bg-primary font-shareTechMono text-white ">
<div className="grid grid-cols-[50%_50%]">
<div className="h-screen col-span-1 overflow-hidden p-10">
<div className="grid sm:grid-cols-2 grid-rows-2 sm:grid-rows-1 h-screen">
<div className="sm:h-full sm:col-span-1 row-span-1 sm:row-span-1 overflow-hidden p-10">
<div
className="overflow-y-auto no-scrollbar bg-secondary h-full rounded"
id="messageContainer"
Expand All @@ -74,7 +74,7 @@ const Simulation: React.FC = () => {
</div>
</div>

<div className="col-span-1 p-10">
<div className="col-span-1 sm:col-span-1 row-span-1 sm:row-span-1 sm:h-full p-10">
<h2>Solution:</h2>
<div className="overflow-auto no-scrollbar text-wrap my-5">
<p className="text-xs">
Expand Down
24 changes: 15 additions & 9 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { AppType } from "next/app";
import "../styles/globals.css";
import { AppProps } from "next/app";
import Head from "next/head";
import "../styles/globals.css";
import React from "react";
import { Analytics } from "@vercel/analytics/react";

const MyApp: AppType = ({ Component }) => {
function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Head>
Expand All @@ -22,13 +22,19 @@ const MyApp: AppType = ({ Component }) => {
/>
<meta name="author" content="Kai Kit Jeffrey Chan" />

{/* <meta property="og:type" content="website" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Multi-Agent Simulation" />
<meta property="og:description" content="Multi-Agent Simulation" />
<meta property="og:image" content="/path/to/your/image.jpg" />
<meta property="og:url" content="https://yourwebsite.com" />
<link
rel="icon"
href="/favicon.png"
type="image/<generated>"
sizes="<generated>"
/>
{/* <meta property="og:image" content="/images/robot_img.png" /> */}
<meta property="og:url" content="www.multiagentsim.co" />

<meta name="twitter:card" content="summary_large_image" />
{/* <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Multi-Agent Simulation" />
<meta name="twitter:description" content="Multi-Agent Simulation" />
<meta name="twitter:image" content="/path/to/your/image.jpg" />
Expand All @@ -45,10 +51,10 @@ const MyApp: AppType = ({ Component }) => {
rel="stylesheet"
/>
</Head>
<Component />
<Component {...pageProps} />
<Analytics />
</>
);
};
}

export default MyApp;
4 changes: 3 additions & 1 deletion src/pages/api/[simulation].ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ const generateAgent = (
) => {
// const model =
// modelType === "OpenAIChat" ? new OpenAIChat() : new GeminiAIChat();
const model = new OpenAIChat();
const model = new GeminiAIChat();
return new ChatInstance({
personality,
problem,
model,
});
};

const generateAgentPrompt = (modelType: "OpenAIChat" | "GeminiAIChat") => {};

const getIncomingMessage = (
speaker: Intent,
new_message: string,
Expand Down