Lesson 10 · Collaboration

Handshakes between agents

Agents also need to "sign contracts". The request_id is the contract number.

⏱ ~10 min · 📝 3 interactive widgets · 🧑‍💻 Based on shareAI-lab · s10_team_protocols.py

Why do we need protocols?

In s09, send_message can carry any content. But when two agents need to reach agreement on something (e.g. "I want to shut down, is that OK?"), plain strings aren't enough. You need:

  • Requests with a clear identity (request_id), so responses can be matched back.
  • A state machine: pending -> approved | rejected, with clear consequences at each state.
  • Consistent fields: both sides know what approve: true means.

That's why shutdown_request / shutdown_response / plan_approval / plan_approval_response exist.

Shutdown protocol: the full flow

Lead wants alice to wrap up:

lead:
  # send shutdown_request, server records request_id
  req_id = uuid4()[:8]
  shutdown_requests[req_id] = {"target": "alice", "status": "pending"}
  send("alice", "shutdown_request", extra={"request_id": req_id})

alice:
  # next loop reads inbox, sees shutdown_request
  # decides: finish current task first, then approve
  tool_use("shutdown_response", request_id=req_id, approve=True)

lead:
  # receives shutdown_response, updates tracker to approved
  shutdown_requests[req_id]["status"] = "approved"
  # alice detects the approval and exits her loop

Shutdown FSM visualized

Walk through the state machine step by step. Alice can also reject - "I'm in the middle of something critical, can't stop now."

Plan Approval · same pattern, different domain

A teammate submits a plan for lead's approval before taking a big action:

alice:
  tool_use("plan_approval", plan="I'm planning to rewrite the entire auth module using JWT")
  # alice goes idle waiting for lead

lead:
  # sees alice's plan_approval_response request
  tool_use("plan_approval", request_id="...", approve=False,
           feedback="Hold off on auth for now, we're doing a full refactor next month")

Reading the s10 source reveals: both protocols use exactly the same request_id tracking pattern - just with different dictionary names (shutdown_requests vs plan_requests). This is "one pattern, two domains."

Why not abstract a shared Protocol base class? s10 intentionally avoids this. Two protocols today don't justify the abstraction. Each one can be understood independently. Extract it when you have four or five (rule of three).
Interactive

Widget 1 · Shutdown FSM · walk the state machine

Click Next to advance one step and see how request_id establishes a correspondence between the two agents.

Lead
Alice
shutdown_requests state table
{}
Interactive

Widget 2 · request_id correlation · don't mix up the contracts

Multiple requests are pending simultaneously. Click a response and watch the matching request update. This is what enables concurrent protocols.

Pending requests
Simulated responses (click to trigger)
Interactive

Widget 3 · Protocol Design · design your own third protocol

Apply the request_id pattern to new scenarios. Select the correct answer to proceed.

Correct: 0 / 5