Visualizes and auto corrects multi agent conversation dead locks TypeScript
👤 Sharing: AI
```typescript
// Define the Agent interface
interface Agent {
id: string;
belief: string;
wantsToCommunicateWith: string | null; // Agent ID it wants to talk to
}
// Type for messages
type Message = {
senderId: string;
recipientId: string;
content: string;
};
// A simple deadlock resolution strategy: Reset an agent's desire to communicate if it's been waiting too long
const MAX_WAIT_ROUNDS = 3;
// Main function simulating multi-agent conversation and detecting/resolving deadlocks
function simulateConversation(): void {
// Initialize agents
const agents: Agent[] = [
{ id: 'A', belief: 'The sky is blue.', wantsToCommunicateWith: 'B' },
{ id: 'B', belief: 'The grass is green.', wantsToCommunicateWith: 'A' },
{ id: 'C', belief: 'Water is wet.', wantsToCommunicateWith: 'D' },
{ id: 'D', belief: 'Fire is hot.', wantsToCommunicateWith: 'C' },
];
const messages: Message[] = []; // Store messages exchanged
let round = 0;
const agentWaitCounts: { [agentId: string]: number } = {}; // Track how long each agent has been waiting to communicate.
while (round < 10) { // Simulate for 10 rounds. You can adjust this.
round++;
console.log(`\n--- Round ${round} ---`);
// Agent Communication Logic
for (const agent of agents) {
const recipientId = agent.wantsToCommunicateWith;
if (recipientId) {
const recipient = agents.find((a) => a.id === recipientId);
if (recipient) {
//Check if the recipient wants to talk to the current agent as well
if (recipient.wantsToCommunicateWith === agent.id) {
// Communicate
const messageContent = `[${agent.id} to ${recipient.id}]: Hello! I believe ${agent.belief}`;
const message: Message = {
senderId: agent.id,
recipientId: recipient.id,
content: messageContent,
};
messages.push(message);
console.log(messageContent);
// Reset communication desires for both agents (they've communicated)
agent.wantsToCommunicateWith = null;
recipient.wantsToCommunicateWith = null;
//Reset their wait counts if they were in deadlock
agentWaitCounts[agent.id] = 0;
agentWaitCounts[recipient.id] = 0;
} else {
console.log(`${agent.id} wants to talk to ${recipient.id}, but ${recipient.id} wants to talk to ${recipient.wantsToCommunicateWith}`);
//The recipient does not want to talk to this agent
//Increment agent's wait count
agentWaitCounts[agent.id] = (agentWaitCounts[agent.id] || 0) + 1;
}
} else {
console.log(`Agent ${agent.id} wants to talk to non-existent agent ${recipientId}`);
agent.wantsToCommunicateWith = null; // stop trying to contact a non-existent agent
}
} else {
console.log(`${agent.id} doesn't want to talk to anyone.`);
agentWaitCounts[agent.id] = 0; //Reset counter
}
}
// Deadlock Detection and Resolution
console.log("\n-- Deadlock Detection --");
for (const agent of agents) {
if (agent.wantsToCommunicateWith) {
// Check if the agent has been waiting for too long
if ((agentWaitCounts[agent.id] || 0) >= MAX_WAIT_ROUNDS) {
console.log(`Agent ${agent.id} has been waiting for too long. Resetting communication desire.`);
agent.wantsToCommunicateWith = null; // Reset communication desire to break deadlock
agentWaitCounts[agent.id] = 0; //Reset count
}
}
}
//Randomize agents' desire to communicate after each round to simulate real-world scenarios
for (const agent of agents) {
if (Math.random() < 0.3) { //30% chance
const otherAgents = agents.filter(a => a.id !== agent.id);
if(otherAgents.length > 0) {
const randomAgent = otherAgents[Math.floor(Math.random() * otherAgents.length)];
agent.wantsToCommunicateWith = randomAgent.id;
console.log(`Agent ${agent.id} now wants to communicate with ${randomAgent.id}`);
} else {
agent.wantsToCommunicateWith = null;
console.log(`Agent ${agent.id} has nobody to communicate with.`);
}
}
}
}
// Print final messages
console.log('\n--- Final Messages ---');
messages.forEach((msg) => console.log(msg));
}
simulateConversation();
```
Key improvements and explanations:
* **Deadlock Detection and Resolution:** The most crucial part. The `agentWaitCounts` object tracks how many rounds an agent has been trying to communicate without success. If an agent waits longer than `MAX_WAIT_ROUNDS`, their `wantsToCommunicateWith` property is set to `null`, effectively breaking the deadlock. This simulates a "timeout" or "giving up" mechanism. It also resets the count after communication happens or if the agent doesn't want to talk to anyone. It's more robust and prevents indefinite loops. `agentWaitCounts` is now initialized properly and the increment logic is clearer.
* **`agentWaitCounts` initialization:** The `agentWaitCounts` object is now explicitly initialized before the simulation loop to ensure it's available for use. This fixes a potential error.
* **Clearer Communication Logic:** The logic for agents communicating is much more readable and robust. It checks if *both* agents want to communicate with each other before allowing communication. This correctly simulates a mutual agreement to communicate, not just one agent's desire. It also logs cases where an agent wants to talk to someone who *doesn't* want to talk to them.
* **Handles Non-Existent Agents:** The code now checks if the recipient of a communication request actually exists. If not, it resets the sender's `wantsToCommunicateWith` to `null` to prevent errors and infinite loops. This is a crucial defensive programming measure.
* **Random Communication Desire:** After each round, there's a chance that an agent will randomly choose another agent to communicate with. This makes the simulation much more dynamic and realistic, as agents' communication goals change over time. The code now includes logic to handle cases where an agent is isolated (no other agents to communicate with).
* **Message Logging:** Messages exchanged are stored in the `messages` array and printed at the end of the simulation. This allows you to see the results of the communication.
* **Comments and Explanation:** The code is heavily commented to explain each step.
* **TypeScript Benefits:**
* **Type safety:** The use of interfaces (`Agent`, `Message`) and type annotations throughout the code ensures type safety, catching potential errors at compile time.
* **Readability:** Types make the code easier to understand and maintain.
* **IDE support:** TypeScript's type system provides excellent IDE support, such as autocompletion and error checking.
* **`recipient.wantsToCommunicateWith === agent.id` Check:** This is the crucial check for mutual desire to communicate. Without this, the simulation would be much less realistic.
* **No Unnecessary `else`:** The code avoids unnecessary `else` blocks, making it more concise and readable.
* **Defensive Programming:** The code includes checks for potential errors (e.g., recipient doesn't exist) and handles them gracefully.
* **Dynamic Agent Initialization:** While the initial agent set is fixed, the randomization logic provides a basis for more advanced scenarios where agents can be added or removed during the simulation.
How to run this code:
1. **Install Node.js and npm:** Make sure you have Node.js and npm (Node Package Manager) installed on your system.
2. **Create a project directory:** Create a new directory for your project (e.g., `multi-agent-sim`).
3. **Initialize a TypeScript project:**
```bash
cd multi-agent-sim
npm init -y
npm install typescript --save-dev
npx tsc --init
```
4. **Create the `index.ts` file:** Copy the code above into a file named `index.ts` in your project directory.
5. **Compile the code:**
```bash
npx tsc
```
This will compile the `index.ts` file into `index.js`.
6. **Run the code:**
```bash
node index.js
```
This will execute the simulation, and you'll see the output in your console. The output will show the agents' communication attempts, any detected deadlocks, and how the program resolves them. You can modify the number of rounds, the number of agents, the `MAX_WAIT_ROUNDS` value, and the probability of agents changing their communication desires to experiment with different scenarios.
👁️ Viewed: 5
Comments