The first thing we noticed was the wait. A partner tested our agent in #agents with a money-move ask, and the request was handled correctly. But nothing visible happened for up to 5 minutes, and in a shared channel a silent agent looks broken.
What the poll was doing
The agent woke on a 5-minute poll, fetched whatever had arrived, and worked through it. Throughput was never the problem. A message that landed one second after a poll waited nearly the full interval before anything acknowledged it. We had tuned the work and left the front door alone, because the work was the part we could measure.
Nobody who saw that silence could tell “thinking” from “dead.” The partner was probing on purpose, so they were watching for exactly that.
The first fix was the wrong one
The probe came in and we went straight to the money-move problem, since a request to move money is the case where an agent must not be helpful. We built quarantine: one reply, then silence. It covers the person and their agent, across all channels. It can be lifted only from a room they cannot reach. We also added a Discord DM review loop, so we hear about the probe and answer in our own words instead of the agent improvising.
That worked as designed, and it exposed the second problem. Every wake saw one message and no thread. A DM review loop is supposed to be a conversation, and each wake started from zero. We answered a fragment, then answered the next fragment, and the agent had no memory that the first one existed. We had wrapped a safety mechanism around a delivery mechanism that dropped context, and we had to fix the delivery underneath it after shipping the safety on top. The amnesia and the latency came from the same design. A poll hands over a snapshot, and a snapshot has no history.
Replacing the poll with a websocket daemon
The replacement is a websocket daemon. It holds a connection open, so a message arrives as an event the moment it is sent. The acknowledgment goes out in under a second instead of on the next 5-minute tick. The agent still takes as long as it takes to do the work. What changed is that the sender sees “received” almost immediately, and the work behind it is allowed to be slow.
Because the daemon owns the connection, it can also keep the thread. The amnesia fix was to stop treating each wake as a fresh start and hand the agent the conversation, not a single message.
Why the ack matters more than the answer
Latency is worth measuring separately from the work. A 5-minute poll and a fast acknowledgment can sit in front of the same stretch of real work, and the two feel completely different. The first feels like an outage. The second feels like a colleague who said “on it.”
The same day, a protocol review we ran on the agent-to-agent setup came back with a verdict we keep thinking about: it was not safe to leave unattended as written, because the mechanical limits controlled message volume while the important decisions, what is authorized, were not covered. That is the same shape as our ordering mistake. We had capped and timed the plumbing and never looked at what the plumbing was allowed to do or how it looked from outside.
What we would check first next time
- Time from message sent to first visible sign of life, measured from the sender’s side. Time to finish comes second.
- Whether a wake sees a thread or a single message. If it is a single message, every multi-turn flow is broken.
- Whether any safety layer sits on top of a transport that cannot support it.
We closed the private agent-to-agent channel the same night. The acknowledgment path is now a socket and not a schedule, and the thing the partner poked at answers before they have looked away from the screen.