Welcome back! In Chapter 1: Tool Definition & Interface, we built the "application form" for our message tool. We defined what a message looks like (Recipient, Summary, Content).
But once the AI fills out that form, how does the message actually travel from one agent to another?
In this chapter, we explore Swarm Communication.
Imagine two AI agents running on your computer. One is the Team Lead (managing the plan) and one is a Researcher (looking up docs).
Usually, these are two separate processes. They don't share memory. The Team Lead cannot just "think" something and have the Researcher know it. They are like two people working in different rooms with the doors closed.
To solve this, we use the File System. Since both agents are on the same computer, they can both access the hard drive.
We implement a protocol called Swarm. It works exactly like a physical office mail system:
Let's look at the code that handles a standard message (one-to-one). This is the function handleMessage.
It takes the content, packages it with a timestamp and the sender's name, and drops it in the recipient's "tray."
// Inside SendMessageTool.ts
async function handleMessage(recipientName, content, summary, context) {
const senderName = getAgentName() || 'Team Lead'
const teamName = getTeamName(context.getAppState())
// The core action: Write to the file system
await writeToMailbox(recipientName, {
from: senderName,
text: content,
summary: summary,
timestamp: new Date().toISOString(),
}, teamName)
return { data: { success: true, message: `Sent to ${recipientName}` } }
}
What's happening here?
senderName).teamName).Sometimes, the Team Lead needs to tell everyone something (e.g., "The project goals have changed"). This is a Broadcast.
In our tool interface, the AI selects this by setting to: "*".
Under the hood, we can't just write to a magic "*" file. We have to manually copy the letter to every single team member.
async function handleBroadcast(content, summary, context) {
// 1. Get the Roster (the Team File)
const teamName = getTeamName(context.getAppState())
const teamFile = await readTeamFileAsync(teamName)
// 2. Loop through every member
for (const member of teamFile.members) {
// Don't send mail to yourself!
if (member.name === getAgentName()) continue
// 3. Drop a copy in their tray
await writeToMailbox(member.name, {
text: content,
summary: summary,
/* ... timestamp/sender ... */
}, teamName)
}
return { data: { success: true, message: 'Broadcast complete' } }
}
Key Concept: The "Team File" acts like an employee roster. We read it to find out who exists, then we loop through that list to deliver the message one by one.
Now we connect these functions to the main call() method we teased in Chapter 1. This acts as the switchboard operator.
// Inside the tool's call() method
async call(input, context) {
// Scenario A: Broadcasting to everyone
if (input.to === '*') {
return handleBroadcast(input.message, input.summary, context)
}
// Scenario B: Direct message to a specific teammate
return handleMessage(input.to, input.message, input.summary, context)
}
Simple, right?
If the destination is *, run the loop. Otherwise, just write to that specific person.
(Note: The actual code has more checks for "Structured Messages" and "Bridges", which we will cover in later chapters).
Let's look at a diagram of what happens when Team Lead sends a message to Researcher.
Using files for "Swarm" communication is great for beginners and robust for local development because:
We now have a working "Post Office."
handleMessage).handleBroadcast).However, so far we are just sending plain text strings like "Hello." What if we need to send a formal request, like "Please approve this plan" or "Shut down now"? Plain text is too messy for strictly controlled commands.
In the next chapter, we will introduce Structured Coordination Protocols to handle these complex interactions.
Next Chapter: Structured Coordination Protocols
Generated by Code IQ