Skip to main content

0035: Agent conversations are per topic, and people can stop and pause them

ADR 0034 kept one agent conversation per local role and peer role. Every person's request through that pair then shared one history and one agent session on both sides, and the run that received an answer could not tell who had asked: a reply to a person's question reached the peer role's agent conversation and stopped there. An agent conversation is now one exchange about one topic, identified on the wire by an opaque thread ID, so the answer comes back to the run that knows who is waiting, and one person's text never sits in the context of another's.

The topic, its root, follows from what the sending run works on, so agents never choose or name one:

  • A run in a person's conversation with the role: that conversation (there is at most one per person and role).
  • A run on a task: that task. A subtask is a topic of its own.
  • A run in an agent conversation: that conversation's root. An agent conversation the peer started is its own root.

A send goes to the agent conversation with key (connection, root, sending role, recipient role), created on first use with a new random thread ID. So a reply from an agent conversation goes back in it, and a role that relays a peer's request to a third role does so in an agent conversation rooted in the peer's, which brings the answer back down the same chain without revealing it. Only roles in a run send; a role token without a run has no topic and is refused.

The receiver keys agent conversations by connection and thread ID. An unknown ID starts an agent conversation rooted in itself; a known one continues it; one whose roles do not match is rejected. Nothing about the root crosses the wire. Ordering is per agent conversation: one waiting for an acknowledgement holds up only its own later text.

Visibility follows the root. A person reads an agent conversation when they can read its root: the person of a conversation, members for a task and for one the peer started. One whose root is gone is readable by owners. A role reads its own, as before.

Lifetime. A finished task leaves its agent conversations working: a late answer can still be reported on it. When a root is deleted (a conversation, or a task), its agent conversations close: their runs end, their history stays, and later text in them is rejected with the reason thread. The sender then closes its side too, so its next send from that root starts a new agent conversation, which the receiver sees as one the peer started.

Stop. A person who can read an agent conversation can stop its agent: its turn is cancelled and its process ends, keeping the session, as for a person's conversation. The text it was given in that turn counts as handled, so a request it worked on too long is dropped rather than retried. Text that arrives afterwards continues it, and the agent hears that it was stopped; nothing else restarts it.

Pause. An owner can pause a connection, and unpause it, on their side. While it is paused, every agent of its conversations is stopped, roles cannot send on it, text waiting to be sent fails, and text from the peer is rejected with the reason paused, which the peer records as a failure with a notice to its role. Nothing starts again when it is unpaused. Pausing is local and reversible; revoking stays permanent.

Considered Options​

Keeping one agent conversation per role pair, recording locally where an outgoing message came from and telling the receiving run about it, was smaller: no migration of the key and no new wire field. It still mixed every person's requests in one session on both sides, and relied on the agent to keep them apart.

Waking the person's conversation with the peer's reply cannot tell which person an answer belongs to when several people's requests share a pair, and would bring peer-authored text into a run acting for a person, which ADR 0034 keeps apart.

Threads per person rather than per topic would mix a person's own unrelated tasks and conversation. Threads chosen by the agent would give it one more thing to get wrong; deriving the root from the run gives none.

A resume action after stop would also hold off a peer that keeps writing. A stop is for an agent that works too long on one request; a peer that will not stop is what pausing the connection is for.

Consequences​

Migration 038 deletes the agent conversations, text and runs from before this decision (test text only, approved for deletion by Morten) and recreates the tables keyed by thread. There is no compatibility with installations from before it: a text frame needs its thread ID, so both sides upgrade together.

A run in an agent conversation is told its root: which person's conversation, or which task, it answers for, and how to report there. Posting to a person's conversation stays an explicit, authorized local send.

A role busy in many topics with one peer role has as many agent conversations, each with its own run. The connection's queue limit still bounds what waits in all of them.

agent history for a role still lists everything between it and a peer role; people read one agent conversation at a time, as its root allows.