| Internet-Draft | PACE | November 2026 |
| Nandakumar & Jennings | Expires 5 May 2027 | [Page] |
This document defines the Protocol for Agent Communication Exchange (PACE), an agentic dialog management protocol with a binding to Media over QUIC Transport (MOQT). A dialog is the correlated sequence of interactions between two or more participants over the course of a task. PACE defines a transport-independent dialog context and control operations to establish, modify, and terminate dialogs and to revoke propagation relationships. It specifies how that context stays coherent across intermediaries, trust boundaries, modality changes, and interruptions, and how it is carried over MOQT. PACE does not interpret or define dialog content. Over MOQT, a dialog can combine text, audio, video, and request/response exchanges in point-to-point, point-to-multipoint, and multi-party topologies. Application-layer agent protocols such as A2A, MCP, and AutoGen keep their own message formats and carry the dialog context through their own extension points.¶
This note is to be removed before publishing as an RFC.¶
The latest revision of this draft can be found at https://suhasHere.github.io/draft-nandakumar-agentproto-pace/draft-nandakumar-agentproto-pace.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-nandakumar-agentproto-pace/.¶
Discussion of this document takes place on the Agent Communication Protocols Working Group mailing list (mailto:agentproto@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/agentproto/. Subscribe at https://www.ietf.org/mailman/listinfo/agentproto/.¶
Source for this draft and an issue tracker can be found at https://github.com/suhasHere/draft-nandakumar-agentproto-pace.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 5 May 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
AI agents are autonomous software systems that work with users, other agents, and tools to complete tasks. The exchanges between them form dialogs. A dialog is the correlated sequence of interactions between two or more participants over the course of a task. For dialogs to work across platforms and vendors, participants need a common way to correlate a dialog and maintain its lifecycle across multiple hops, intermediaries, trust boundaries, and changes of modality or network attachment, without sharing the content of the dialog itself.¶
This document defines the Protocol for Agent Communication Exchange (PACE). PACE has two parts:¶
A transport-independent agentic dialog management protocol (Section 3): the dialog context, the control operations that manage its lifecycle, and the rules participants and intermediaries follow when propagating it.¶
A binding of that protocol to Media over QUIC Transport (MOQT) [MoQ-TRANSPORT] (Section 4, Section 4.3), which carries the dialog context on MOQT tracks and uses MOQT relays for fan-out, prioritization, and multiplexing of dialog control alongside text, audio, video, and request/response exchanges.¶
In terms of the Agent Communication Protocol architecture [ARCH], the first part realizes the Agentic Dialog Management block (Section 6.1 of [ARCH]), and the second is the MOQT profile corresponding to Section 9.1 of [ARCH].¶
The dialog context consists of identifiers and lifecycle state only. Content exchanged with AI models, such as conversation memory, retrieved documents, or prompts, is not part of it. The content is opaque to PACE, the MOQT binding carries it on content tracks without interpreting it. PACE does not replace application-layer agent protocols. A2A, MCP, AutoGen, and similar protocols keep their native messages and carry the dialog context through their own extension points (Section 8).¶
Agent interactions are increasingly live dialogs rather than one-shot requests. A user speaks while an agent answers, cuts in, and expects the agent to stop. Voice and video run alongside chat, streaming model output, and tool calls. Several agents and people work on the same task, and the task can outlast a single connection or network. In natural spoken conversation, people take turns within a few hundred milliseconds [STIVERS], so an interruption has to take effect ahead of output that is already queued. PACE is designed for these dialogs.¶
PACE addresses the following goals.¶
Dialog correlation: A dialog identifier that stays stable across hops, intermediaries, trust boundaries, modality changes, and time. Defined by the dialog context: identifier, generation, state, controller, and participants (Section 3.1).¶
Multi-modal exchange: Real-time media, chat, streaming model output, and request/response operations in one dialog. Each modality keeps its own latency and reliability, and none of them delays the others, even when they share one transport session (Section 5).¶
Multi-party exchange: Point-to-point, point-to-multipoint, and multi-party dialogs among agents and people. Relays fan out each message, so a sender publishes once however many participants there are, and late joiners catch up from relay caches (Section 6).¶
Low-latency interaction: Dialog control, including interruption and cancellation, takes effect within the latency of natural conversation and ahead of queued content, so that agents can hold an interactive voice conversation (Section 5).¶
Dialog lifecycle: Opening, updating, and terminating dialogs, and revoking propagation relationships, with the controller as the single authoritative source of state (Section 3.2).¶
Resilience: Recovery from path and intermediary failures, resumption after interruption, and defined behavior when a participant or the controller is unreachable (Section 3.3, Section 4.3.5).¶
Transport independence: A dialog model that any transport can carry. This document specifies a MOQT binding: namespaces, tracks, operation mapping, and delivery (Section 4).¶
Application protocol reuse: MCP, the Personal Agent Protocol, AutoGen, and A2A keep their native messages and carry the dialog context (Section 8).¶
Identity and authorization reuse: Agent identity separate from user identity, delegated authorization, and selective disclosure, without mandating a token format (Section 7, Section 9).¶
Privacy: Mitigations for linkage through persistent dialog and participant identifiers (Section 9.3).¶
PACE does not define trust frameworks, authorization protocols, or audit data structures; deployments use existing mechanisms, and auditing systems can use dialog identifiers. Dialog content, model behavior, planning, and task semantics are also out of scope.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
The correlated sequence of interactions between two or more participants over the course of a task. A dialog can outlast any single message exchange, MOQT session, or transport connection. A two-party dialog is an agentic dialog [ARCH], which composes larger topologies by cascading two-party dialogs; PACE supports both cascaded and multi-party dialogs (Section 6).¶
The identifiers and lifecycle state needed to correlate and maintain a dialog (Section 3.1). The dialog context does not include content exchanged with AI models, such as conversation memory, retrieved documents, prompts, or media payloads. It corresponds to the meta-data of the [ARCH] dialog context. The [ARCH] log is the dialog's content, which a binding carries; in the MOQT binding, it is the sequence of objects on the dialog's content tracks (Section 4.2.2).¶
A UUID that names a dialog for its whole lifetime.¶
A user-facing client, agent, tool, or service that takes part in a dialog and processes its dialog context. Each participant has a participant identifier that is unique within the dialog. In the MOQT binding, the participant identifier is the agent-id field of the participant's tracks in the dialog namespace (Section 4.1). A participant plays the principal or agent role of [ARCH]; the controller is usually the principal's client.¶
The participant that opened the dialog. The controller is the authoritative source of the dialog context and the only participant that changes the participant set, expiration, generation, or terminal state.¶
An entity that forwards dialog context between participants without being the source of it. A MOQT relay that forwards PACE tracks is an intermediary, and so is a gateway that transforms one modality into another.¶
The authorization and forwarding relationship that allows a participant or intermediary to receive or forward a dialog's context. PACE signals the creation and revocation of such relationships; the deployment's authorization mechanism enforces them.¶
A transport-level session established with MOQT SETUP. A MOQT session is not a dialog: one dialog can span several MOQT sessions, and one MOQT session can carry several dialogs.¶
The PACE architecture layers as follows:¶
┌─────────────────────────────────────────────────────────┐ │ Application Protocols (A2A, MCP, AutoGen, Poppy, ...) │ ├─────────────────────────────────────────────────────────┤ │ PACE Dialog Management: dialog-id │ lifecycle │ │ │ propagation │ ├─────────────────────────────────────────────────────────┤ │ PACE MOQT Binding: namespaces │ control tracks │ │ │ media and operation tracks │ priority │ ├─────────────────────────────────────────────────────────┤ │ MOQT: Pub/Sub │ Namespace Routing │ Relay Caching │ ├─────────────────────────────────────────────────────────┤ │ QUIC / WebTransport: TLS 1.3 │ Mux │ Migration │ └─────────────────────────────────────────────────────────┘
Identity, authentication, authorization, and encryption are building blocks used across these layers. PACE integrates them (Section 7, Section 9) but does not define new ones.¶
Live dialogs (Section 1.1) place the following requirements on the transport that carries them. They refine the transport aspects of Section 8 of [ARCH] for live, multi-modal dialogs.¶
Low latency: Each flow reaches participants within the latency its modality needs: under 100 ms for real-time media, and under a second for chat and streaming model output (Section 5). A loss or a backlog on one flow does not add delay to another.¶
Push delivery: Content, new participants, new flows, and new dialogs reach participants as soon as they are published, without polling.¶
Interruption: Dialog control, such as an interruption or a cancellation, reaches its receiver ahead of content that is already queued. Real-time content that is too late to be useful is dropped instead of being delivered late.¶
Concurrent flows: Real-time media, chat, streaming model output, tool calls, and bulk transfers share one dialog and one connection, each with its own priority and reliability.¶
Fan-out: One message reaches every participant without the sender sending a copy to each. Participants that join late or reconnect can catch up.¶
Continuity: A dialog survives connection migration, network changes, reconnection, and intermediaries.¶
Scale and control: Dialogs scale through intermediaries across regions, and each intermediary enforces who may send and receive.¶
Request/response mechanisms might not meet these requirements. When a dialog's flows share one ordered connection, a cancellation waits behind output that has already been sent, and one lost packet stalls every flow. Delivery to several participants, and learning about new ones, are left to the application.¶
This document specifies a MOQT binding for exchanging dialogs. Media over QUIC Transport (MOQT) [MoQ-TRANSPORT] is a publish/subscribe protocol over QUIC [RFC9000]. It meets each requirement in Section 2.1 with a transport mechanism, so agent protocols do not need to rebuild them.¶
Low latency: Objects are sent as soon as they are produced, on QUIC streams or datagrams alike, and relays forward them as they arrive, without waiting for the rest of a group. Each track has its own streams, so a loss on one flow does not hold up the others. Datagrams are not retransmitted, so real-time media keeps flowing under congestion instead of waiting for lost data.¶
Push delivery: Agents publish and subscribe directly, with no polling and no long-lived HTTP connections. Content reaches subscribers as soon as it is published. SUBSCRIBE_TRACKS on a namespace prefix delivers all current and future tracks under that prefix, so new participants and flows appear without a separate signaling channel. Output that arrives minutes or hours after its input reaches the subscriber without a webhook or a client-side HTTP server.¶
Interruption: Publisher priority (per subgroup or datagram) and subscriber priority (per subscription) let dialog control overtake queued lower-priority data, so a cancellation reaches the agent ahead of output already in flight. Per-track delivery timeouts let the publisher mark time-sensitive objects: objects that miss the deadline, such as a voice frame whose playout window has passed, are dropped at the relay instead of wasting bandwidth and queue depth.¶
Concurrent flows: One MOQT session carries sub-100ms media, sub-second chat, and best-effort bulk transfers at the same time, in one congestion control context. Objects can be delivered over QUIC datagrams, which suit real-time audio and video where lower latency matters more than retransmission, or over QUIC streams, which suit agent chat, operations, and bulk transfers that need ordered, reliable delivery.¶
Fan-out: A single PUBLISH reaches every subscriber through the relay, so multi-agent collaboration does not need application-level broadcast code, and the publisher keeps no per-subscriber state. Relay caches let late-joining or reconnecting agents catch up without the publisher retransmitting.¶
Continuity: QUIC provides connection migration (for example, from Wi-Fi to cellular) and 0-RTT resumption. A dialog is not tied to a MOQT session: one dialog can span several sessions (Section 1.3). An agent namespace is not tied to a host either, so the principal and the agent can each move between hosts over a dialog's lifetime and a new client instance catches up from relay caches.¶
Scale and control: Relays handle NAT traversal, load balancing, and fan-out without direct peer-to-peer connections, and they can be stacked hierarchically to spread load across regions without an all-to-all mesh. Namespace-level access control maps onto agent authorization scopes: the relay decides who may publish or subscribe to each namespace. QUIC provides TLS 1.3 for every hop.¶
Where UDP is blocked, the same MOQT binding can run over QMux [QMUX], which provides QUIC stream and datagram operations over TLS over TCP. Agents keep one protocol stack instead of falling back to a separate one, at the cost of TCP head-of-line blocking and reliable, ordered datagrams.¶
This section defines the dialog context, its lifecycle, and the rules for propagating it. The mapping of this protocol onto MOQT is defined in Section 4.¶
A dialog context contains the following fields:¶
dialog_id: A UUID version 4 [RFC9562]. The controller generates it
when opening the dialog. It remains unchanged for the lifetime of the
dialog, including when the dialog crosses an intermediary, changes
modality, or resumes after a connection loss.¶
generation: An unsigned integer identifying the current controller
state. The initial generation is 0. The controller increments it by
one for each committed change to the dialog context, including a
change in a participant's state.¶
state: One of pending, active, or terminated.¶
controller_id: The participant identifier of the controller.¶
participants: The set of participant identifiers in the dialog, each
with a state: invited, active, left, rejected, or revoked.¶
expires_at: An optional absolute time in RFC 3339 date-time format.
When present, participants treat the dialog as terminated at that
time.¶
parent_dialog_ids: An optional list of dialog-ids, set by the
controller in OPEN when the dialog is opened to carry out work
delegated from another dialog. The first entry is the dialog that
triggered this one, followed by that dialog's own parents, so the list
traces the delegation chain back to the originating dialog (Section 6.2.1 of [ARCH]). It does not change after OPEN.¶
The context is encoded as a JSON object:¶
{
"dialog_id": "550e8400-e29b-41d4-a716-446655440000",
"generation": 0,
"controller_id": "agent-a",
"state": "pending",
"participants": [
{"participant_id": "agent-a", "state": "active"},
{"participant_id": "agent-b", "state": "invited"}
],
"expires_at": "2026-10-23T12:00:00Z"
}
¶
The expires_at member is omitted when the dialog has no configured
expiration, and parent_dialog_ids is omitted when the dialog was not
opened from another dialog. A context snapshot MUST contain every other
member,
including participants whose states are left, rejected, or
revoked. A controller MUST NOT remove a participant from a later
snapshot; it changes that participant's state instead. The controller
MUST appear in the participant set with state active.¶
The identity of the principal on whose behalf a delegated dialog runs
travels in the credentials member as a delegation chain
(Section 7.1.2), not in the dialog context.¶
These identifiers are correlation values. They MUST NOT be treated as credentials or bearer authorization. Knowing a parent dialog-id does not grant access to the parent dialog. A participant identifier MUST NOT encode personal or task information.¶
Dialog parameters are negotiated in the parameters member of OPEN,
ACCEPT, UPDATE, and JOIN_REQUEST (Section 3.4). They describe
how the dialog is conducted and are not part of the dialog context:¶
dialog_type: Short-lived (bounded duration) or long-lived
(indefinite)¶
idle_timeout: Maximum idle duration before the controller
terminates the dialog¶
max_participants: Maximum number of participants in the dialog¶
supported_modalities: Data modalities the participant can handle¶
supported_protocols: Application protocols offered (A2A, MCP, etc.)¶
content_encoding: Compression applied to content payloads (for
example, gzip); absent means none (Section 4.2.3)¶
Short-lived dialogs carry an expires_at in the dialog context and end
when it passes. Long-lived dialogs omit expires_at and continue
across idle periods and interruptions until the controller terminates
them. When idle_timeout is set and the dialog has been idle for that
long, with no content or control sent by any participant, the
controller SHOULD publish TERMINATE.¶
The dialog lifecycle has three states:¶
OPEN (controller, generation 0)
|
v
+-------------+
UPDATE +-->| PENDING |------------------+
| +-------------+ |
| | | |
+------+ | UPDATE committing | TERMINATE
| an invitee's ACCEPT | or expiry
v v
+-------------+ +------------+
UPDATE, REVOKE +-->| ACTIVE |----------->| TERMINATED |
| +-------------+ TERMINATE | (final) |
| | or expiry +------------+
+------+
The controller has opened the dialog, but no invitee has accepted.¶
At least one invitee has accepted, and the dialog has not been terminated or expired. The context can be modified with UPDATE and REVOKE.¶
The controller has terminated the dialog, or its expiration time has passed. This state is final.¶
Only the controller causes transitions. UPDATE, REVOKE and TERMINATE each advance the generation by one. ACCEPT, REJECT, JOIN_REQUEST and LEAVE are requests the controller commits with UPDATE. Interruptions and cancellations do not change the state.¶
An interruption, such as a lost connection or relay failure, does not change the dialog state. Participants recover the current context as described in Section 3.3. A participant's own state is tracked separately from the dialog state: joining or leaving does not by itself terminate the dialog. When the controller commits a LEAVE that leaves it as the only active participant, it SHOULD publish TERMINATE. This lets an agent that is not the controller end a two-party dialog.¶
The control operations below cover the lifecycle functions of Section 6.1.2 of [ARCH]. Initiation is OPEN, and termination is TERMINATE, expiry, or a LEAVE that ends a two-party dialog. Suspension needs no operation: a dialog persists through idle periods with no transport connection, and a binding can pause individual flows. Resumption is STATE_REQUEST together with the binding's recovery of missed content (Section 4.3.5 for MOQT), and cancellation is CANCEL (Section 3.2.3).¶
PACE defines the following control operations:¶
| Operation | Sender | Generation | Effect |
|---|---|---|---|
| OPEN | Controller | 0 | Creates a pending dialog and identifies invitees. |
| ACCEPT | Participant or invitee | Current | Accepts an invitation or a parameter proposal. |
| REJECT | Participant or invitee | Current | Rejects an invitation or a parameter proposal. |
| UPDATE | Controller | Next | Replaces the participant set or expiration. |
| JOIN_REQUEST | Prospective participant | Latest known, or 0 | Requests admission to an existing dialog. |
| LEAVE | Participant | Current | Leaves the dialog. The controller records the participant as left. |
| REVOKE | Controller | Next | Revokes a participant's propagation relationship. |
| TERMINATE | Controller | Next | Ends the dialog. |
| CANCEL | Any participant | Current | Asks receivers to stop work started by the sender's earlier input (Section 3.2.3). |
| CANCEL_ACK | Any participant | Current | Reports the outcome of a CANCEL. |
| STATE_REQUEST | Participant | Current | Requests the current context after a gap or reconnection. |
| STATE | Controller | Current | Supplies a complete context snapshot. |
| ERROR | Any participant | Current | Reports that an operation was not applied, and why. |
Only the controller changes the dialog context. Other participants send requests and responses, and the controller commits the result.¶
OPEN includes at least one invitee.¶
ACCEPT and REJECT answer a proposal from the controller, named by
in_reply_to: an invitation in OPEN or UPDATE, or a parameter
change carried in parameters on UPDATE. After the controller
commits an invitee's answer, its state is active or rejected. A
participant that rejects a parameter change remains in the dialog;
the controller then withdraws the change in a later UPDATE or
revokes the participant.¶
JOIN_REQUEST does not add a participant. The controller admits the
requester by sending UPDATE with the requester's state set to
invited, or refuses it with ERROR policy-rejected.¶
ACCEPT, REJECT, JOIN_REQUEST, and LEAVE do not modify the context by themselves. The controller commits each resulting change by publishing UPDATE with the complete context at the next generation.¶
The dialog becomes active when the controller publishes such an
UPDATE after at least one invitee has accepted.¶
REVOKE is controller-authoritative. It carries the complete context at
the next generation, sets the target participant's state to revoked,
and ends that participant's propagation relationship. A participant or
intermediary that receives REVOKE:¶
A principal that interrupts an agent, a policy decision, or a failed
subtask can require work to stop at once. PACE carries cancellation as
a dialog control operation rather than relying on connection teardown,
so a binding can deliver it ahead of queued content. The MOQT binding
sends it on the ctrl track at critical priority (Section 4.3.6).¶
CANCEL does not change the dialog context and does not end the dialog.
Its scope member selects the work to stop:¶
A single operation the sender started, named in target.¶
All work the receivers carry out in delegated dialogs whose
parent_dialog_ids include this dialog. A receiver that controls
such a dialog sends CANCEL with scope dialog in it, so cancellation
propagates down the delegation chain and dependent subtasks do not
continue after the parent work is withdrawn.¶
All work the sender started in this dialog, together with its subtree.¶
A receiver applies CANCEL through the application protocol's own
cancellation where one exists, such as MCP notifications/cancelled
or A2A CancelTask, so the application sees its native cancel. CANCEL
is idempotent: a receiver that has already acted on a CANCEL reports
the same outcome again and does not repeat side effects.¶
Each receiver doing affected work answers with CANCEL_ACK, giving one of these outcomes:¶
UPDATE, REVOKE, and TERMINATE carry the next generation and a complete context, so a receiver replaces its state as a whole instead of merging partial updates. Other operations carry the current generation (Table 1).¶
The controller MUST serialize its state-changing operations and MUST NOT reuse a generation for different state.¶
A receiver MUST reject a controller operation whose generation is
lower than the latest generation it accepted, with ERROR
stale-generation.¶
If a receiver sees a generation greater than the next expected one, it MUST send STATE_REQUEST and MUST NOT infer the missing changes.¶
A prospective participant does not yet track the dialog, so its JOIN_REQUEST carries the latest generation it knows, or 0. The controller does not reject a JOIN_REQUEST as stale.¶
Receivers use the message identifier and generation to detect duplicates and stale messages. Reprocessing a duplicate operation MUST NOT repeat its side effects.¶
TERMINATE is final.¶
After TERMINATE, a receiver MUST reject later operations for the dialog, except a duplicate TERMINATE or a STATE needed to complete synchronization.¶
Expiration has the same effect as TERMINATE. Each participant
evaluates it locally from expires_at, and it does not create a new
generation.¶
A controller SHOULD publish TERMINATE before the expiration time when it can.¶
Resuming a transport connection does not reopen a terminated or expired dialog.¶
Correlation across hops: An intermediary MUST preserve the dialog identifier, generation, and lifecycle operation when forwarding dialog context. It MUST NOT create a new dialog identifier or change the dialog state. This document defines no identifier-alias mechanism; a deployment that needs aliases requires a separate mechanism that securely correlates the alias with the original dialog.¶
Trust boundaries: A participant forwarding dialog context into another trust domain does so only within a propagation relationship that the deployment's authorization mechanism permits. Authorization to forward or subscribe at the transport layer does not by itself make an entity a participant.¶
Modality changes: Transforming a modality, such as converting audio to text, does not create a new dialog. Participants and intermediaries MUST keep the same dialog identifier and current lifecycle state across the transformation.¶
Continuity over time: After a connection loss, a participant MAY reconnect, over a new transport session if necessary, using the existing dialog identifier. It MUST obtain the current context from the controller with STATE_REQUEST before acting on state that may have changed while it was disconnected. Recovering the dialog context does not imply that any application operation was delivered or completed, or that it is safe to retry.¶
Unreachability: If the controller is unreachable, participants MUST suspend actions that depend on an unconfirmed context change. Each participant remains at the last generation it accepted until the controller is reachable again or the dialog expires. Participants MUST NOT create a replacement dialog solely because a path or intermediary failed. If an invitee or participant is unreachable, the controller MAY revoke it or let the dialog expire, according to deployment policy.¶
A PACE control message is a UTF-8 encoded JSON object [RFC8259]. Every control message contains these members:¶
version: The integer 1.¶
type: One of the operations in Section 3.2.¶
dialog_id: The canonical textual form of the dialog's UUID.¶
generation: A non-negative integer no greater than 2^53 - 1.¶
sender_id: The sender's participant identifier.¶
message_id: A UUID version 4 unique to this message.¶
Control messages also carry the following type-specific members:¶
context: The complete dialog context, encoded as the JSON object
defined in Section 3.1.¶
in_reply_to: The message_id of the OPEN or UPDATE being accepted
or rejected, of the CANCEL being acknowledged, or of the message an
ERROR rejects.¶
target_id: The participant identifier whose propagation relationship
is revoked.¶
scope: The cancellation scope: operation, subtree, or dialog
(Section 3.2.3).¶
target: The operation to cancel when scope is operation. Its
form is defined by the transport binding (Section 4.3.6).¶
outcome: One of stopped, completed, or irreversible.¶
last_accepted_generation: The highest generation the sender has
accepted from the controller, or -1 if it has accepted none.¶
reason: One of malformed, unsupported-version,
unsupported-operation, stale-generation, unauthorized,
authorization-unavailable, or policy-rejected. These
distinguish validation, authorization, and policy failures
from transport failures, which MOQT reports separately (Section 6.1.5 of [ARCH]).¶
Each type requires the members listed below:¶
| Type | Required type-specific members |
|---|---|
| OPEN |
context
|
| ACCEPT |
in_reply_to
|
| REJECT |
in_reply_to; reason optional |
| UPDATE |
context
|
| JOIN_REQUEST | none |
| LEAVE | none |
| REVOKE |
target_id, context
|
| TERMINATE |
context
|
| STATE_REQUEST |
last_accepted_generation
|
| STATE |
context
|
| CANCEL |
scope; target when scope is operation
|
| CANCEL_ACK |
in_reply_to, outcome
|
| ERROR |
in_reply_to, reason
|
For OPEN, context has generation 0 and state pending, and carries
parent_dialog_ids when the dialog is delegated. For UPDATE,
REVOKE, and TERMINATE, context has the next generation, and a
TERMINATE context has state terminated. An UPDATE that adds a
participant sets that participant's state to invited; the
participant becomes active only after it accepts and the controller
publishes a later UPDATE.¶
Three optional members carry information that is not part of the dialog context:¶
parameters: On OPEN, ACCEPT, UPDATE, and JOIN_REQUEST, the dialog
parameters being proposed or accepted, such as modalities and
application protocols (Section 3.1.1).¶
credentials: On any message, an identity assertion or
authorization proof in a format selected by the deployment
(Section 7.1.1). A participant
refreshes its credentials before they expire by including new ones
on a later message.¶
nonce: On OPEN, ACCEPT, UPDATE, and JOIN_REQUEST, a fresh random
value, with at least 128 bits of entropy and base64url-encoded, to
which the recipient binds the presentation in its next
credentials (Section 7.1.4).¶
JSON member order is insignificant. Receivers MUST ignore unrecognized
optional members, MUST reject an unrecognized type, and MUST reject
messages with missing required members, invalid member types, or an
unsupported version. Receivers MUST limit the size of a control message
to a locally configured maximum. A participant MUST NOT include
application content in a control message.¶
This section specifies how the dialog management protocol of Section 3 is carried over MOQT.¶
PACE uses MOQT's hierarchical namespace for routing, isolation, and multiplexing. In MOQT, content is addressed by a Track Namespace (an ordered set of up to 32 fields, compared as byte sequences [MoQ-TRANSPORT]) together with a Track Name. PACE organizes communication into two namespace scopes: an agent namespace for each agent's identity and invitations, and a dialog namespace for all of a dialog's traffic.¶
("pace", "agents", {agent-id}) -- {track}
¶
This is an agent's persistent identity on the relay network. Each agent publishes the following tracks:¶
"card" — Agent Card containing capabilities, identity claims,
authentication schemes, and MOQT connectivity information
(Section 7.2.3)¶
("pace", "agents", {agent-id}, "invites") -- {invitee-id} — One
track per agent it invites to dialogs (Section 4.1.3)¶
The common prefix ("pace", "agents") enables SUBSCRIBE_NAMESPACE-based
discovery of all agents on the network. An agent follows another by
subscribing to its card and to the invitation track named by the
follower's own agent-id. See Section 7.2 for the complete
discovery flow.¶
("pace", "dialogs", {dialog-id}, {agent-id}) -- {track}
¶
The dialog-id is the dialog identifier (Section 3.1). The
controller mints it when it opens the dialog. Each participant
publishes its tracks for the dialog under its own agent-id field
within the dialog's namespace; the agent-id is the participant
identifier used in the dialog context. Each participant issues
SUBSCRIBE_TRACKS on the dialog prefix ("pace", "dialogs",
{dialog-id}), so it receives every participant's tracks, including
those of participants added later, as PUBLISH messages forwarded by
the relay.¶
Each participant in a dialog publishes the following tracks:¶
"ctrl" — Dialog control messages (Section 3.4)¶
"chat" — Chat messages and streaming LLM output¶
"audio" — Real-time audio stream¶
"video" — Real-time video stream¶
"progress" — Progress output, such as token counts, elapsed time,
and liveness, kept apart from the response¶
"ops/{req-id}" — Request/response operations (one track per request)¶
Only the ctrl track carries the dialog context. The other tracks
carry dialog content and are outside the dialog context. In the terms
of Section 4.2.11 of [ARCH], chat, audio, and video carry
response output, operation and protocol binding tracks carry
information output, and progress carries progress output.¶
Protocol bindings extend the dialog namespace with additional namespace fields, so that multiple protocols can operate concurrently within a single dialog without track name collisions:¶
("pace", "dialogs", {dialog-id}, {agent-id}, {proto}, {category},
...) -- {id}
¶
{proto} is the protocol identifier of the binding: "mcp",
"poppy", "a2a", or "ext" followed by a further field naming
another protocol (Section 8).¶
{category} is the operation or primitive type (e.g., request,
response, task for A2A; tools, resources, prompts for MCP).¶
{id}, the track name, is the request, task, tool or resource
identifier. A binding MAY define further namespace fields between
{category} and the track name.¶
For example, in a dialog whose dialog-id is
550e8400-e29b-41d4-a716-446655440000 (written D below), the
following Full Track Names are used:¶
A2A: "agent-a" sends request "r1" (in a dialog with "agent-b")
("pace","dialogs",D,"agent-a","a2a","request") -- "r1"
A2A: "agent-b" publishes updates for task "t1"
("pace","dialogs",D,"agent-b","a2a","task") -- "t1"
MCP: client "agent-a" calls tool "read_file" on "fs-server"
("pace","dialogs",D,"agent-a","mcp","tools","read_file")
-- "request"
MCP: "fs-server" publishes the result of that call
("pace","dialogs",D,"fs-server","mcp","tools","read_file")
-- "response"
¶
The MCP tracks above are the request and response tracks of
(mcp, {server-id}, clients, {client-id}, tools, {tool-name}) in MCP
over MOQT [MCP-MOQT], with the leading
(mcp, {server-id}, clients, {client-id}) fields replaced by the
dialog namespace and the publisher's agent-id (Section 8.3).¶
See Appendix A for concrete examples of agent-to-agent, agent-to-tool, and multi-agent collaboration workflows.¶
("pace", "agents", {controller-id}, "invites") -- {invitee-id}
¶
An agent learns a dialog's dialog-id before it can subscribe to the dialog. A controller tells an invitee that follows it (Section 7.2) by publishing on a track under its own agent namespace, named by the invitee's agent-id. Each object, in its own group, is a JSON object with these members:¶
dialog_id — The dialog identifier¶
controller_id — The controller's agent-id¶
expires_at — Optional; the time after which the invitation is
void¶
An invitation only points to the dialog. The dialog context, including
the OPEN or UPDATE that invites the agent, stays on the controller's
ctrl track, which the invitee reads before deciding. Relay
authorization (Section 9.2.1) forwards each invitation track
only to the invitee it names, so other followers of the controller do
not see it. An invitee that comes online late catches up on pending
invitations with a join fetch and ignores those whose expires_at has
passed.¶
An agent that does not follow the controller learns the dialog-id out of band, for example through the application protocol's own channel (Section 8.4).¶
Editor's note: This document does not define how to invite an agent that neither follows the controller nor can be reached out of band, or how to advertise a dialog for others to join. These are left for future work.¶
Agents MUST establish either a native QUIC connection or a WebTransport [RFC9297] session as defined in [MoQ-TRANSPORT]. For native QUIC connections, agents MUST use the ALPN value "moqt". For WebTransport, the protocol is negotiated using the "WT-Available-Protocols" mechanism as specified in [MoQ-TRANSPORT].¶
Upon establishing the MOQT session via the SETUP message exchange defined in [MoQ-TRANSPORT], an agent performs the bootstrap sequence to make itself discoverable:¶
Announce: PUBLISH_NAMESPACE on ("pace", "agents", {agent-id})¶
Publish Agent Card: PUBLISH on track "card" under its namespace¶
Discover peers: SUBSCRIBE_NAMESPACE on ("pace", "agents") to
learn about other agents on the network¶
See Section 7.2 for the full discovery flow that follows bootstrap.¶
Each agent publishes only under its own agent-id: its card and
invitations under ("pace","agents",{agent-id}), and its dialog
tracks under ("pace","dialogs",{dialog-id},{agent-id}). A
participant issues SUBSCRIBE_TRACKS on the dialog prefix to receive
the tracks of all participants. The relay handles fan-out to all
subscribers via prefix matching. This publishing model ensures clear
ownership and enables relay caching.¶
Namespace structure and track names are defined in Section 4.1.¶
Each PACE object payload is one protocol message, with no PACE
header: a control message (Section 3.4) on ctrl tracks, an
invitation on invitation tracks, and the protocol's native message on
binding tracks. The
track namespace identifies the protocol, and MOQT carries the length.¶
Payloads are uncompressed unless the participants agree on a
content_encoding dialog parameter (Section 3.1.1). It
applies to binding tracks only, never to ctrl or invitation tracks.¶
This section specifies how the operations of Section 3 are
carried over MOQT. Each control message is one MOQT object on the
sender's ctrl track under
("pace","dialogs",{dialog-id},{agent-id}). MOQT control messages
(PUBLISH, SUBSCRIBE, their responses, PUBLISH_DONE) establish and end
the subscriptions that carry those objects. They are not dialog
operations: PUBLISH_OK accepts a MOQT subscription, not a dialog, and a
participant MUST NOT infer acceptance, rejection, or termination of a
dialog from a MOQT response or cancellation alone.¶
The ctrl track MUST use Subgroup Delivery Mode and MUST NOT use
Datagram Delivery Mode or a finite delivery timeout. A participant
publishes control objects in increasing Object ID order, and the
controller publishes state-changing operations in increasing
generation order. Because ctrl is a track of its own, a CANCEL,
ERROR, or TERMINATE is not lost or delayed when a content track fails
or falls behind.¶
Prerequisite: B learns the dialog-id from A's invitation, which requires that B follows A (Section 7.2), or out of band. A does not need B's prefix: all participants' tracks are under the dialog prefix.¶
Below, PUBLISH, SUBSCRIBE, and SUBSCRIBE_TRACKS are MOQT messages;
OPEN, ACCEPT, and UPDATE are PACE control messages sent as objects on
the sender's ctrl track. Agent A (controller) opens a dialog with
Agent B (invitee):¶
A generates a dialog-id (UUID version 4) and issues
SUBSCRIBE_TRACKS on ("pace","dialogs",{dialog-id}), which covers
all participants' tracks, including future ones.¶
A issues PUBLISH for
("pace","dialogs",{dialog-id},"agent-a") -- "ctrl" and sends OPEN
on it, listing B as invited, with parameters
(Section 3.1.1) and credentials.¶
A sends an invitation on
("pace","agents","agent-a","invites") -- "agent-b"
(Section 4.1.3), which B subscribed to when it started following
A.¶
B issues SUBSCRIBE with FILL_PARAMETERS on A's ctrl track, reads
OPEN, and decides. Until it accepts, B subscribes to nothing else,
so it receives no dialog content.¶
B issues PUBLISH for
("pace","dialogs",{dialog-id},"agent-b") -- "ctrl" and sends
ACCEPT (or REJECT) on it, with its parameters and credentials. On
accepting, B issues SUBSCRIBE_TRACKS on the dialog prefix, which
also covers A's ctrl track.¶
The relay forwards B's PUBLISH to A through A's SUBSCRIBE_TRACKS from step 1, and A reads ACCEPT.¶
A sends UPDATE (generation 1) on its ctrl track, marking B and
the dialog active. If B rejected, the UPDATE marks B rejected,
and B ends its ctrl track with PUBLISH_DONE.¶
Tracks either agent publishes later reach every participant through its SUBSCRIBE_TRACKS on the dialog prefix. Multi-party dialogs follow the same pattern, and existing participants receive a new participant's tracks without subscribing again.¶
An agent that knows a dialog's dialog-id but was not invited asks to
join by issuing PUBLISH for its own ctrl track,
("pace","dialogs",{dialog-id},{joiner-id}) -- "ctrl", and sending
JOIN_REQUEST as the first object on it. The relay forwards the
PUBLISH to every participant holding SUBSCRIBE_TRACKS on the dialog
prefix, not only the controller. Only the controller acts on
JOIN_REQUEST; other participants MUST ignore it, and MAY decline a
PUBLISH for a track whose agent-id is not in the dialog context. A
joiner therefore discloses in its credentials only claims it is
willing for every participant to see. The controller validates the
credentials and decides whether to admit the joiner. The joiner
subscribes to the controller's ctrl track with FILL_PARAMETERS, so
it receives the current dialog state as well as the answer. To
admit it, the controller invites the joiner with UPDATE, the joiner
answers with ACCEPT and subscribes to the dialog prefix, and the
controller's next UPDATE marks it active. A controller that declines
answers with ERROR policy-rejected, and the joiner then ends its
ctrl track with PUBLISH_DONE. Before admission, the joiner's
authorization covers only publishing its own ctrl track and reading
the controller's (Section 9.2.1).¶
MOQT Setup Options are exchanged hop by hop. PACE defines one Setup Option, which lets a PACE-aware relay or a directly connected peer learn that the endpoint implements PACE:¶
| Setup Option | ID | Description |
|---|---|---|
| pace-version | 0x50414301 | Highest PACE control-message version supported |
The version member of each control message remains authoritative.¶
In this binding, a dialog is idle (Section 3.1.2) while no participant publishes an object on any of its tracks.¶
The controller changes the participant set or the expiration by
publishing UPDATE on its ctrl track with the complete context at the
next generation. Participants request changes with JOIN_REQUEST or
LEAVE; only the controller commits them. Parameter changes, such as
adding a modality, are proposed in parameters on UPDATE, and each
participant answers with ACCEPT or REJECT (Section 3.2). An UPDATE
that adds a participant is followed by an invitation to it
(Section 4.1.3).¶
Participants MAY use MOQT's REQUEST_UPDATE message to change per-subscription parameters, such as pausing delivery with FORWARD=0, resuming with FORWARD=1, or changing priorities and filters, without tearing down the subscription. REQUEST_UPDATE is the right tool for track-level changes that do not need dialog-wide agreement; pausing a video track while chat and ctrl keep flowing is a typical case. Pausing a subscription does not stop the publisher from producing objects and is not a cancellation.¶
PACE recovers from network and intermediary failures in several ways:¶
QUIC Connection Migration: QUIC's connection ID lets a MOQT session survive network path changes (such as WiFi to cellular). The dialog state is unaffected.¶
Relay Caching: Relays may cache recent objects, so a reconnecting agent can pick up what it missed without the peer retransmitting. Relays are not required to cache, and they never become the authoritative source of the dialog context.¶
Dialog Resumption: After losing its MOQT session, which it detects
through the QUIC idle timeout or a subscription timeout, an agent
reconnects
(to the same relay or an alternate one), re-issues PUBLISH_NAMESPACE
on its agent namespace, its follow subscriptions
(Section 7.2), and SUBSCRIBE_TRACKS on the dialog prefix,
which includes the controller's ctrl track, and sends STATE_REQUEST with its last
accepted generation. It applies the controller's STATE only after
authenticating the controller and checking that the generation is not
older than its last accepted one (Section 3.2.4). A join fetch from
the last Location it received then shows which content was published
while it was away, so it can decide whether to resend its own input.¶
Join Fetch for Mid-Dialog Catch-Up: An agent joining a dialog in
progress, or recovering after a disconnect, uses the fill fetch
mechanism from [MoQ-TRANSPORT]. The subscriber issues SUBSCRIBE with
FILL_PARAMETERS on the chat or operation track; the publisher opens a
unidirectional fill fetch stream carrying the historical range
(typically the latest complete group) before live objects resume on
the subscription. "Catch up on prior content, then follow live"
happens atomically, without a separate FETCH roundtrip. For the dialog
context itself, STATE is authoritative; a fetched old ctrl object
cannot establish the current lifecycle state by itself.¶
Bounded Historical Fetch: To retrieve a specific range of past objects deterministically, for example replaying a task's output history, agents use FETCH with explicit Start and End Locations. The publisher confirms the actual End Location in FETCH_OK.¶
Unreachable Controller: If the controller's ctrl track cannot be
resubscribed, participants follow the unreachability rules in
Section 3.3: they suspend context-dependent actions and do not
create a replacement dialog. A slow subscriber whose subscription ends
with PUBLISH_DONE (TOO_FAR_BEHIND) resubscribes and resynchronizes
with STATE_REQUEST.¶
A participant sends CANCEL (Section 3.2.3) as an object on its
ctrl track at critical priority (0-15). Scopes dialog and
subtree need no target. For scope subtree, a receiver that
controls a delegated dialog whose parent_dialog_ids include this
dialog sends CANCEL with scope dialog on its own ctrl track in
that delegated dialog. For scope operation, target names a track
the sender publishes in the dialog and, optionally, a group on it:¶
{
"namespace": ["mcp", "tools", "search"],
"track": "request",
"group": 3
}
¶
namespace lists the namespace fields that follow
("pace","dialogs",{dialog-id},{agent-id}). Without group, all work
started by objects on the track is cancelled. Each receiver doing the
affected work publishes CANCEL_ACK on its own ctrl track and stops
publishing objects for that work, ending a track that carried only
that work with PUBLISH_DONE.¶
Pausing delivery with REQUEST_UPDATE (FORWARD=0), unsubscribing, or closing a MOQT session does not cancel work.¶
The controller ends the dialog by sending TERMINATE on its ctrl
track (Section 3.2.6). Upon termination, pending operations are
cancelled, and dialog resources are released after a configurable
grace period.¶
After TERMINATE, or when expires_at passes, each participant SHOULD
send PUBLISH_DONE on every dialog track it was publishing (ctrl,
chat, audio, video, and any operation tracks), and ends its
subscription to the dialog prefix. PUBLISH_DONE signals that no
further objects will be delivered on the track, allowing subscribers
and relays to release state without waiting for timeouts. Neither
PUBLISH_DONE nor STOP_SENDING substitutes for TERMINATE.¶
A participant leaves by sending LEAVE on its ctrl track. The
controller commits it with UPDATE, marking the participant left,
and SHOULD send TERMINATE if only the controller remains active
(Section 3.2). The leaver then ends its tracks with PUBLISH_DONE and
its subscription to the dialog prefix.¶
When the controller sends REVOKE, every participant stops forwarding dialog context to the revoked participant and cancels any subscriptions held only on its behalf (Section 3.2). The revoked participant ends its tracks with PUBLISH_DONE, and participants MAY decline its later PUBLISHes. The deployment also withdraws the revoked participant's authorization at the relay, for example by letting its [MoQ-C4M] token expire or by refusing revalidation, so that the relay stops delivering the participant's subscriptions to the dialog's tracks.¶
When an agent is leaving the network entirely (not just a single
dialog), it cancels its PUBLISH_NAMESPACE for
("pace","agents",{agent-id}). Relays then send NAMESPACE_DONE to
agents with matching SUBSCRIBE_NAMESPACE subscriptions.¶
Over the MOQT binding, a dialog can carry several data modalities concurrently, each with appropriate quality of service. This content is outside the dialog context; a change of modality does not change the dialog (Section 3.3).¶
PACE defines the following data modality classes:¶
| Modality | Latency | Examples | Delivery |
|---|---|---|---|
| Real-time | < 100ms | Voice, video, screen share | Continuous stream |
| Semi-real-time | < 1s | Chat messages, streaming LLM output | Ordered objects |
| Non-real-time | Best effort | Tool calls, file transfers, documents | Reliable delivery |
These classes correspond to the low-latency loss-tolerant, reliable ordered, and high-throughput reliable delivery semantics of Section 8.1 of [ARCH].¶
Each modality maps to dedicated MOQT tracks within the dialog namespace (Section 4.1.2). Different modalities are isolated by track name while sharing the dialog context and authorization.¶
Within a track, a MOQT group is a synchronization point. The objects in a group carry what belongs together at that point, such as one message, one request and its incremental results, or one phase of an operation, and relays carry them together. A publisher starts a new group at each point where a receiver can begin consuming the track without earlier objects, so a subscriber that joins or recovers starts at a group boundary (Section 4.3.5).¶
MOQT's 0-255 priority scale enables differentiated treatment of messages based on urgency and modality. PACE defines the following tiers of subscriber priority:¶
| Priority Range | Category | Use |
|---|---|---|
| 0-15 | Dialog Control | All control messages on the ctrl track, including CANCEL, ERROR, and REVOKE |
| 16-31 | Urgent Signals | Application signals that must preempt content, such as a request for a human |
| 32-63 | Real-time Media | Voice/video frames |
| 64-95 | Interactive | Chat messages, streaming LLM tokens |
| 96-127 | Standard Operations | Tool calls, request/response |
| 128-159 | Discovery | Agent Cards, invitations |
| 160-191 | Background | Telemetry, non-critical notifications |
| 192-255 | Bulk Transfer | File transfers, documents |
MOQT relays forward Publisher Priority unchanged, so PACE applies
policy through subscriber priority, which MOQT applies before publisher
priority. A subscriber sets the subscriber priority of each
subscription according to its policy for that peer and track, and can
change it with REQUEST_UPDATE, so a publisher cannot raise the urgency
of its traffic beyond what its subscribers allow. A subscriber MUST
subscribe to a ctrl track with a subscriber priority in the Dialog
Control tier.¶
Request/response interactions use coordinated publish operations.
Agent A publishes a request object on its own track
("pace","dialogs",{dialog-id},"agent-a") -- "ops/{req-id}". Agent B,
which has subscribed to the dialog prefix, receives the request,
processes it, and publishes the response on its own corresponding track
("pace","dialogs",{dialog-id},"agent-b") -- "ops/{req-id}". Agent A
receives the response through its own subscription to the dialog
prefix.¶
For a detailed example of request/response over MOQT tracks, see [MCP-MOQT] which defines this pattern for MCP tool invocations.¶
Long-running operations produce incremental results as MOQT objects. The publisher starts a new group at each synchronization point (Section 5.2), such as a phase transition (initialization, progress, completion), and the objects in a group carry the incremental data for that phase.¶
Late-joining subscribers catch up mid-operation with a join fetch, and retrieve a specific range with a bounded fetch (Section 4.3.5).¶
Upon operation completion, the publisher sends PUBLISH_DONE on the operation track to signal end-of-stream. Receivers treat PUBLISH_DONE as the authoritative completion marker; publishers MUST NOT emit further objects on that track after PUBLISH_DONE.¶
To cancel an in-progress streaming operation, the requester publishes
CANCEL on its ctrl track (Section 4.3.6), or the application
protocol's own cancel message on its request or operation track. The
publisher then stops the operation and sends PUBLISH_DONE to end the
stream. REQUEST_UPDATE with
FORWARD=0 only pauses delivery to that subscriber; it does not cancel
the operation.¶
Audio and video streams use dedicated tracks ("audio", "video")
with ascending group order and high priority (32-63),
ensuring media frames preempt lower-priority data under congestion.¶
PACE supports multiple communication topologies through MOQT's relay fan-out:¶
Point-to-Point: Two agents publish and subscribe to each other's dialog tracks. Used for tool invocation, task delegation, and bilateral collaboration.¶
Point-to-Multipoint (Fan-Out): One agent publishes; multiple agents subscribe. The relay handles fan-out without the publisher maintaining per-subscriber state. Used for broadcast notifications and shared context distribution.¶
Multi-Party: All participants publish on their own tracks and subscribe to the dialog prefix. The controller adds a participant with UPDATE; existing participants see the new participant in the context and receive its tracks through their existing subscription.¶
Hierarchical Teams: A coordinator creates child PACE dialogs to
delegate subtasks. Each level operates as a separate dialog with
narrowed authorization scope, and each child's parent_dialog_ids
links it to the dialogs above it (Section 3.1). Delegation
chains (Section 7.1.2) maintain an auditable path from the
original user authorization, and CANCEL with scope subtree stops the
work below a level (Section 3.2.3).¶
PACE treats the agent as an authenticated principal distinct from the user it represents. Separating the two makes it possible to revoke an agent without affecting the user, scope an agent to a subset of what the user is allowed to do, and audit what the agent did on its own versus what the user initiated.¶
PACE does not define a new identity token format or claim set. The
credential an agent presents in the credentials member of the
control message it uses to open, accept, or join a dialog
(Section 3.4) identifies:¶
the agent, by its participant identifier in the dialog or by an
identifier that the protocol binding relates to it, such as the
Poppy client_id (Section 8.4);¶
the user, workload, or organization the agent acts for; and¶
when the agent acts for another agent, the delegation chain (Section 7.1.2).¶
In JWT-based formats, these map to the registered claims sub, iss,
iat, and exp [RFC7519] and to the act (actor) claim
[RFC8693] for delegation. Other formats carry the equivalent
information in their own fields. The token format and the trust
framework are chosen by the deployment.¶
Agents present credentials using existing mechanisms. The mechanism in
use is advertised in the Agent Card (Section 7.2.3) and indicated in
the credentials member of control messages; it is not negotiated in
MOQT SETUP, which is hop by hop (Section 4.3.2.1).¶
| Mechanism | Identity | Authorization | Reference |
|---|---|---|---|
| JWT | Agent and principal claims | Scope claims | [RFC7519] |
| SD-JWT | Selectively disclosed claims | Selectively disclosed scope claims | [RFC9901] |
| SD-Card | Attested agent metadata, key-bound presentation | Disclosure per discovery context | [SD-CARD] |
| OAuth 2.0 access token (JWT or opaque) | Token claims | Delegated user authorization | [RFC6749] |
| GNAP | Fine-grained, continuous grants | [RFC9635] | |
| WIMSE workload credentials | Workload identity | With deployment policy | [WIMSE-CREDS] |
| mTLS client certificate | Infrastructure-anchored identity | With deployment policy | [RFC8446] |
| Common Access Token (CAT) | Relay-level namespace authorization | [MoQ-C4M] |
A deployment profile MUST pick at least one mechanism for identity and one for authorization; one mechanism can provide both. Receivers MUST verify a credential's signature, issuer, and expiration before acting on its claims, and validate authorization using the rules of the mechanism in use.¶
When an agent acts on behalf of another agent, its credential carries
the delegation chain, such as nested act claims [RFC8693], tracing
the authorization path (for
example, User → Coordinator → Researcher → Tool). Each entry names
the granter, the agent being granted, and the scope granted at that
hop. The receiver walks the chain and MUST reject it if any hop
broadens scope relative to its granter (see Section 9).¶
An agent that holds an SD-Card can obtain such a token with OAuth 2.0
Token Exchange, presenting its SD-Card as the actor token; the issued
token's act claim then carries the sub and iss of the SD-Card
(Section 7.1 of [SD-CARD]).¶
Different peers need different claims: a tool may need only the agent identifier and its authorization, not the delegation chain or the principal. Agents SHOULD disclose only what each peer requires, using the selective disclosure of the mechanism in use (Section 7.1.1). For agent metadata, SD-Card [SD-CARD] lets an agent disclose issuer-attested claims per peer, and an Agent Card (Section 7.2.3) can be an SD-Card.¶
Selective disclosure does not make agents anonymous: an SD-Card's
sub is always disclosed and stable, so its presentations can be
linked (Section 3.1 of [SD-CARD]). Identifier linkage is addressed
in Section 9.3.¶
A presentation proves possession only when it is bound to the
verifier and to a fresh value from it, such as an SD-Card Key Binding
JWT (Section 6 of [SD-CARD]). A verifier sends a nonce in its
control message (Section 3.4), and the peer's next control
message carries, in its credentials member, a presentation bound to
that nonce, with the verifier's agent-id as audience.¶
When a dialog opens (Section 4.3.1), OPEN carries the controller's nonce, ACCEPT carries the invitee's bound presentation and its own nonce, and the controller's UPDATE carries its presentation bound to that nonce. Joining uses JOIN_REQUEST, UPDATE, and ACCEPT the same way (Section 4.3.2). A participant that requires a key-bound presentation and does not receive a valid one MUST NOT treat the peer as authenticated.¶
Agent discovery uses MOQT's namespace operations to find agents and follow their activity. Discovery operates on the Agent Namespace scope defined in Section 4.1. Each agent is identified by a globally unique agent-id (UUID), verifiable via the Agent Card (see Section 7.2.3).¶
Each agent announces its presence by issuing PUBLISH_NAMESPACE on
("pace","agents",{agent-id}).¶
Agents discover peers by issuing SUBSCRIBE_NAMESPACE on the common
prefix ("pace","agents").¶
The relay sends NAMESPACE messages to subscribers for each matching PUBLISH_NAMESPACE, enabling agents to learn about each other without prior knowledge.¶
If an agent-id is known out-of-band (e.g., from a registry or URL), agents MAY skip Phase 1 and proceed directly to Phase 2.¶
Once Agent B knows Agent A's agent-id, B follows A with two subscriptions:¶
B issues SUBSCRIBE on ("pace","agents","agent-a") -- "card" and
reads A's Agent Card (Section 7.2.3).¶
B issues SUBSCRIBE on
("pace","agents","agent-a","invites") -- "agent-b". When A
invites B to a dialog, the invitation arrives on this track
(Section 4.1.3), and B then subscribes to the dialog.¶
Following is B's choice: B follows the agents from which it is willing to receive invitations. Following does not show B any of A's dialogs. A follows B the same way when it expects invitations from B.¶
Each agent publishes an Agent Card on track "card" under its namespace
("pace","agents",{agent-id}). When capabilities change, the agent
publishes a new object (incrementing the MOQT group).¶
All Agent Cards MUST include:¶
Agent identifier (UUID) and display name¶
Supported modalities and protocols¶
Authentication schemes¶
Identity claims (issuer, public key, expiration)¶
PACE does not define a card format. An Agent Card is the agent's
application protocol metadata in a signed form, such as an A2A Agent
Card (Section 8.5) or an SD-Card [SD-CARD], which lets the agent
disclose different claims to different peers. The card names the
agent's namespace ("pace","agents",{agent-id}), and receivers MUST
check that it equals the namespace on which the card was published.¶
The "card" track reaches every subscriber through relays, so a card
on it is not bound to any one verifier. It shows that its claims are
signed and unmodified, but not that the publisher is the agent.
Receivers MUST verify the card's signature and expiration before
acting on its claims, and a participant that relies on the agent's
identity MUST obtain a key-bound presentation in credentials
(Section 7.1.4).¶
Every subscriber sees the card, so an agent that uses pairwise or per-dialog agent-ids (Section 9.3) publishes a separate card, with a separate key, for each agent-id; otherwise the card links them.¶
PACE manages dialog identifiers, lifecycle, and context propagation. Application-layer agent protocols keep their native message formats and semantics, and carry the dialog context through their own extension points (Section 8.1). PACE does not change those protocols; any standardized mapping is coordinated with their maintainers.¶
Over the MOQT binding, an application protocol's messages also need a place on MOQT tracks. This section defines that placement for MCP, the Personal Agent Protocol (Poppy), A2A, and a generic JSON-RPC baseline for custom protocols. Each binding runs inside a PACE dialog, using the dialog namespace (Section 4.1.2) and the channel architecture (Section 5). Multiple bindings can coexist in a single dialog, each under its own protocol namespace field, so one agent can speak A2A to a peer and MCP to a tool in the same dialog.¶
An application message joins a dialog by carrying a dialog reference
in the protocol's own extension point, whether or not the protocol
runs over MOQT. The reference is this object, under the metadata key
org.ietf.agentproto/dialog-context:¶
{
"dialog_id": "550e8400-e29b-41d4-a716-446655440000",
"generation": 3
}
¶
generation is the latest generation the sender knows. The
controller's ctrl track stays authoritative; a receiver that needs
the full context sends STATE_REQUEST.¶
| Protocol | Carried in | Keep distinct from |
|---|---|---|
| MCP |
_meta
|
JSON-RPC request IDs and the [MCP-MOQT] client ID |
| Poppy | Track namespace (Section 8.4) | Conversation ID |
| AutoGen | Message metadata
|
Conversation ID |
| A2A | Message metadata
|
contextId, taskId
|
A dialog-id MUST NOT be used as a task, request, content, or session identifier, or as a credential.¶
A binding specifies:¶
Protocol identifier: the namespace field that follows the dialog-id.¶
Namespace pattern: how operations map to namespace fields and track names within the agent's dialog namespace.¶
Message serialization: how native messages are encoded in MOQT object payloads. Bindings SHOULD use the native wire format as the object payload (Section 4.2.3).¶
Dialog reference: where messages carry the dialog reference (Section 8.1).¶
Priority: which PACE priority tier its tracks use (Section 5).¶
Identity and authorization: how the protocol's own identity and authorization constructs (if any) relate to the credential mechanisms (Section 7.1.1) in this document.¶
A complete mapping of each protocol operation to MOQT primitives belongs in a protocol-specific document, such as [MCP-MOQT] for MCP.¶
Protocols use distinct protocol namespace fields within PACE dialogs.
In the tables of this section, a pattern such as
("a2a", "task") -- {task-id} gives the namespace fields that follow
("pace", "dialogs", {dialog-id}, {agent-id}), then the track name.¶
In the examples, D is the dialog-id.¶
| Binding | Protocol Fields | Example Full Track Name |
|---|---|---|
| MCP |
"mcp"
|
("pace","dialogs",D,"fs","mcp","tools","read") -- "response"
|
| Poppy |
"poppy"
|
("pace","dialogs",D,"acme","poppy","conversation") -- "events"
|
| A2A |
"a2a"
|
("pace","dialogs",D,"agent-a","a2a","task") -- "t1"
|
| Generic |
"ext", {proto}
|
("pace","dialogs",D,"agent-a","ext","proto","rpc") -- "call"
|
The Model Context Protocol [MCP] binding enables tool and resource
access for agents. Within a PACE dialog, MCP tracks add an "mcp"
namespace field after the dialog-id, under the namespace of the agent
that publishes the track:¶
Namespace: ("pace", "dialogs", {dialog-id}, {agent-id}, "mcp",
{category}, ...)
Tracks: {track-name}
¶
The complete MCP over MOQT specification, covering track structure,
operation mapping, message serialization, Agent Skills, and relay
support, is defined in [MCP-MOQT]. PACE adopts its track semantics.
The mapping is mechanical: the leading
(mcp, {server-id}, clients, {client-id}) or (mcp, {server-id})
fields of an MCP over MOQT namespace are replaced by ("pace",
"dialogs", {dialog-id}, {agent-id}, "mcp"), and the remaining
namespace fields and the track name are kept unchanged. For example,
with {cli} and {srv} the agent-ids of the MCP client and server:¶
| Track | MCP over MOQT | Within PACE |
|---|---|---|
| Tool request |
(mcp, {server-id}, clients, {client-id}, tools, {tool-name}) -- request
|
("pace","dialogs",{dialog-id},{cli},"mcp","tools",{tool-name}) -- "request"
|
| Tool response |
(mcp, {server-id}, clients, {client-id}, tools, {tool-name}) -- response
|
("pace","dialogs",{dialog-id},{srv},"mcp","tools",{tool-name}) -- "response"
|
| Resource |
(mcp, {server-id}, resources) -- {resource-uri}
|
("pace","dialogs",{dialog-id},{srv},"mcp","resources") -- {resource-uri}
|
MCP needs no handshake of its own, and MCP over MOQT client IDs are not used within PACE: PACE supplies the dialog-id, and peers learn each other's MCP tracks through SUBSCRIBE_TRACKS on the dialog prefix.¶
MCP messages keep their native JSON-RPC format as the object payload
(Section 4.2.3) and carry the dialog reference in _meta
(Section 8.1). Key operations map as follows:¶
| MCP Operation | MOQT |
|---|---|
tools/call
|
Request object in a new group on the client's ("mcp","tools",{tool-name}) -- "request" track; the result in the same group on the server's matching "response" track |
| Progress and partial results | Further objects in that group on the "response" track (Section 5.5) |
resources/read
|
FETCH or SUBSCRIBE on the server's ("mcp","resources") -- {resource-uri} track |
notifications/cancelled
|
Applied from PACE CANCEL (Section 3.2.3) |
MCP tracks use the PACE priority tiers (Section 5) as [MCP-MOQT] assigns them: control, tool, prompt, task and skill execution tracks use Standard Operations, catalog and skill content tracks Discovery, and resource tracks Bulk Transfer.¶
An MCP server that holds an MCP SD-Card returns a key-bound
presentation to the client that requests one
(Section 8.2.4 of [SD-CARD]). That presentation is specific to the
requesting client, and SD-Card requires the response carrying it to
have a private cacheScope. Within PACE, relay authorization keeps
the response track within the dialog (Section 9.2.1). The
nonce and audience prevent replay of the presentation, but other
participants of the dialog can read the claims it discloses, so the
server discloses only claims that every participant may see.¶
When a Key Binding JWT carries an interaction_id, an agent includes
it in the MCP requests it makes for that interaction
(Section 8.5 of [SD-CARD]). Agents MAY use the dialog-id as the
interaction_id, so that presentations and messages correlate on the
same identifier.¶
The Personal Agent Protocol (Poppy) [POPPY] lets a person's own
agent (the Personal Agent) sign in to a Company and talk to the
Company's agent (the Company Agent). Poppy defines discovery through a
poppy.json document, OAuth-based identity with pairwise user
identifiers, API access through OpenAPI and MCP, and a Conversations
protocol over HTTPS.¶
This binding carries Poppy Conversations over PACE. Poppy discovery,
OAuth sign-in, web browsing, feedback and excluded-task documents are
unchanged and continue to use HTTPS. Poppy APIs of type mcp can use
the MCP binding (Section 8.3) when the Company offers MCP over
MOQT.¶
The Personal Agent is the PACE dialog initiator and the Company Agent
is the responder. A Company that offers this binding lists it in the
agent.protocols array of its poppy.json. Poppy ignores protocol
types it does not recognize, so the entry can sit alongside the
default poppy HTTPS entry:¶
{
"agent": {
"protocols": [
{ "type": "poppy", "endpoint": "https://acme.example/agent" },
{
"type": "pace",
"binding": "poppy",
"endpoint": "https://acme.example/poppy/pace",
"relayEndpoint": "moqt://relay.acme.example:4443",
"namespace": ["pace", "agents", "acme"]
}
]
}
}
¶
The pace protocol type is not defined by Poppy Draft 0.3. Until Poppy
defines it, the entry is carried as a Poppy extension named under a
domain the publisher controls, as Poppy's extension rules require.
The Personal Agent MUST apply Poppy's poppy.json validation (domain
match and issuer checks) before using the entry. namespace is the
Company Agent's agent namespace, and endpoint is the HTTPS URL at
which the Personal Agent starts a conversation (see below).¶
A Company that holds a Company SD-Card (Section 8.3 of [SD-CARD])
carries the agent member of its poppy.json in the SD-Card's
selectively disclosable agent claim. It can therefore leave the
pace entry out of its public poppy.json and disclose it only to
the Personal Agents it chooses. A disclosed pace entry that also
appears in poppy.json MUST match it, as SD-Card's consistency rules
require.¶
Namespace: ("pace", "dialogs", {dialog-id}, {agent-id}, "poppy",
"conversation")
Tracks: "messages" | "requests" | "events" | "deltas"
¶
| Publisher | Track | Content |
|---|---|---|
| Personal Agent |
messages
|
Poppy messages sent by the Personal Agent |
| Personal Agent |
requests
|
Conversation requests: handoff to a human |
| Company Agent |
events
|
Poppy events: message, state, authorization, user_requested, direct_opened, direct_closed
|
| Company Agent |
deltas
|
Non-durable text-delta events |
The Company Agent's {agent-id} is the one in the namespace advertised
in poppy.json. The Personal Agent's {agent-id} MUST be pairwise: it
MUST differ for each Company, MUST NOT be derived from the person's
identity, and SHOULD NOT equal the Poppy User ID. A Personal Agent MAY
use a fresh {agent-id} for each dialog. This preserves Poppy's
property that a Company knows a person only by an opaque identifier
that differs at every Company. It also stops relays, which always see
namespaces, from linking a person's conversations across Companies.
Personal Agents do not publish an Agent Card or answer agent discovery
(Section 7.2), and the Company does not follow them.¶
The Company does not follow the Personal Agent, so the Personal Agent gives it the dialog-id over HTTPS (Section 4.1.3):¶
The Personal Agent generates a dialog-id and sends a POST request
to endpoint with the Poppy-Session header, as for every endpoint
a Poppy extension defines, and the body {"dialog_id": "<D>",
"agent_id": "<pairwise agent-id>"}.¶
The Company verifies the Session JWT, issues SUBSCRIBE_TRACKS on
("pace","dialogs",D), and responds with a token [MoQ-C4M]
that authorizes the Personal Agent for that dialog only
(Section 9.2.1).¶
The Personal Agent connects to relayEndpoint, subscribes to the
dialog prefix, and publishes OPEN on its ctrl track, with itself
as controller and the Company Agent invited (Section 4.3.1). The
dialog continues as in Section 4.3.1 from step 5.¶
Poppy messages and events keep their native JSON format as the object payload (Section 4.2.3). The dialog reference is not carried in them, because the dialog-id is in every track namespace.¶
| Poppy Conversations | PACE / MOQT |
|---|---|
| Start a conversation | The dialog-id handoff over HTTPS, then OPEN with the Personal Agent as controller (see above). The Poppy conversation ID is assigned as in Poppy and is distinct from the dialog-id |
| Send a message | One object per message, in a new group, on the messages track |
| Read events, resume from a cursor | SUBSCRIBE to the events track, with FILL_PARAMETERS or FETCH from the Location after the last event received |
| Request a human | A handoff object on the requests track |
| Direct Conversation | A new dialog whose parent_dialog_ids starts with the parent dialog-id |
| Close | TERMINATE |
Each event is one object in its own group, so an event's MOQT Location
serves as the Poppy cursor. The messages, requests, and events
tracks are durable and MUST NOT use a finite delivery timeout; the
deltas track SHOULD use OBJECT_DELIVERY_TIMEOUT. The Company Agent
MUST treat a repeated message id from the same User as a duplicate,
as Poppy requires. Handoff requests use the Urgent Signals priority
tier, and messages and events the Interactive tier (Section 5).¶
The Agent-to-Agent Protocol [A2A] binding places A2A messages on
tracks under each agent's dialog namespace, using the "a2a" protocol
namespace field:¶
| Track Pattern | Content |
|---|---|
("a2a", "request") -- {request-id}
|
A2A JSON-RPC requests |
("a2a", "response") -- {request-id}
|
A2A JSON-RPC responses |
("a2a", "task") -- {task-id}
|
Task status and artifact updates |
A2A messages keep their native JSON-RPC 2.0 format as the object
payload (Section 4.2.3) and carry the dialog reference in
the message metadata (Section 8.1). Key operations
map as follows:¶
| A2A Operation | MOQT |
|---|---|
SendMessage
|
Request object on the client's request track; the response on the server's response track with the same request-id |
SendStreamingMessage
|
Response objects on the response track, ended by PUBLISH_DONE (Section 5.5) |
GetTask
|
FETCH on the server's ("a2a","task") -- {task-id} track |
SubscribeToTask
|
SUBSCRIBE on that task track, with FILL_PARAMETERS to catch up |
CancelTask
|
Applied from PACE CANCEL (Section 3.2.3) |
A response that creates a task carries the A2A task-id, which names the server's task track. A2A tracks use the Interactive priority tier for requests and responses and the Standard Operations tier for task updates (Section 5). An A2A agent advertises PACE support through A2A's own Agent Card extension mechanism, pointing to its PACE Agent Card (Section 7.2.3).¶
An A2A agent that holds an A2A SD-Card (Section 8.4 of [SD-CARD])
publishes it as its PACE Agent Card. Its supportedInterfaces claim
is disclosed per element and its capabilities claim selectively,
so the agent can disclose its PACE interface and extension only in
the discovery contexts it chooses. The SD-Card A2A extension, which
carries a key-bound presentation in the metadata of the first Message
or Task in a context, works unchanged over these tracks because A2A
messages keep their native format. An A2A contextId is used within
one dialog, so the agent presents its SD-Card at most once per
contextId in that dialog.¶
A complete mapping of A2A operations to MOQT is left to a separate document coordinated with the A2A maintainers, as [MCP-MOQT] does for MCP.¶
A protocol without its own binding uses the "ext" protocol namespace
field followed by a field naming the protocol:¶
Namespace: ("pace", "dialogs", {dialog-id}, {agent-id}, "ext",
{protocol-name}, ...)
Tracks: {identifier}
¶
The protocol's native messages are the object payloads
(Section 4.2.3), and they carry the dialog reference in
the protocol's own extension point (Section 8.1). The
protocol defines its own namespace fields and track names below
{protocol-name}.¶
PACE inherits MOQT's relay architecture for geographic distribution and load management:¶
Multiple subscribers to the same track result in a single upstream subscription, which reduces origin load.¶
Edge relays cache content close to subscribers, which cuts round-trip latency.¶
Relay failures stay localized; other paths keep operating.¶
Agent network loss and relay failure are recovered as described in Section 4.3.5. An unreachable participant or controller is handled by the rules in Section 3.3, and a dialog that outlasts its expiration or idle timeout ends as described in Section 3.1.2.¶
The threats described in Section 10 of [ARCH] apply to PACE.¶
QUIC and TLS 1.3 0-RTT data can be replayed. Participants MUST NOT send control messages that change state or cancel work (OPEN, ACCEPT, UPDATE, JOIN_REQUEST, LEAVE, REVOKE, TERMINATE, CANCEL) in 0-RTT data.¶
TODO: further considerations.¶
TODO¶
The examples below share these conventions:¶
D1 to D7 stand for dialog-ids (UUIDs). A, B, and C are
agents with agent-ids agent-a, agent-b, and agent-c; other
agents are named in the example that introduces them.¶
Before each example, every agent follows the others (Section 7.2). Each invitee learns the dialog-id from an invitation (Section 4.1.3), and every participant holds SUBSCRIBE_TRACKS on the dialog prefix. The relay therefore forwards every new dialog track to the participants, and the steps do not repeat the invitations or relay hops.¶
Each example lists the tracks by publisher, then the steps. gen
is the dialog generation after a controller operation.¶
JSON-RPC messages are shown without the dialog reference
(Section 8.1) and, for MCP, without the per-request
_meta fields of [MCP]; real messages carry both.¶
A asks B to do a task. This example shows the complete dialog lifecycle; the later examples abbreviate it.¶
A publishes:
("pace","dialogs",D1,"agent-a") -- "ctrl" OPEN, UPDATE,
TERMINATE
("pace","dialogs",D1,"agent-a","a2a","request") -- "r1"
task request
B publishes:
("pace","dialogs",D1,"agent-b") -- "ctrl" ACCEPT
("pace","dialogs",D1,"agent-b","a2a","response") -- "r1"
task result
¶
A publishes OPEN on its ctrl track (gen 0, B invited) and an
invitation on ("pace","agents","agent-a","invites") -- "agent-b".¶
B reads OPEN on A's ctrl track and publishes ACCEPT on its own
ctrl track.¶
A publishes UPDATE (gen 1, B active). The dialog is active.¶
A publishes the A2A request on its request track r1:
{"jsonrpc":"2.0","method":"SendMessage","params":{...},"id":"r1"},
with the dialog reference in the message metadata
(Section 8.1).¶
B publishes the result on its response track r1.¶
A publishes TERMINATE (gen 2). B could instead have sent LEAVE.¶
A reads a file through an MCP server, fs-tool.¶
A publishes:
("pace","dialogs",D2,"agent-a") -- "ctrl"
("pace","dialogs",D2,"agent-a","mcp","tools","readFile")
-- "request" tools/call
fs-tool publishes:
("pace","dialogs",D2,"fs-tool") -- "ctrl"
("pace","dialogs",D2,"fs-tool","mcp","tools","readFile")
-- "response" result
¶
A opens the dialog with fs-tool (OPEN, ACCEPT, UPDATE).¶
A publishes the call as Object 0 of a new group, say Group 7, on
its readFile request track:
{"jsonrpc":"2.0","method":"tools/call","params":{"name":"readFile",
"arguments":{"path":"/data/report.csv"}},"id":"t1"}.¶
fs-tool publishes the result as the final object in Group 7 of its
readFile response track:
{"jsonrpc":"2.0","id":"t1","result":{"resultType":"complete",
"content":[...]}}. The JSON-RPC id pairs the response with the
request; the matching Group ID helps relays and recovery
([MCP-MOQT]).¶
A makes further calls as new groups, or terminates the dialog.¶
A asks code-tool to generate code. The call takes a while, so
code-tool reports progress while it works and sends the code in the
final result.¶
A publishes:
("pace","dialogs",D3,"agent-a") -- "ctrl"
("pace","dialogs",D3,"agent-a","mcp","tools","generateCode")
-- "request" tools/call,
cancellation
code-tool publishes:
("pace","dialogs",D3,"code-tool") -- "ctrl"
("pace","dialogs",D3,"code-tool","mcp","tools","generateCode")
-- "response" progress, result
¶
A opens the dialog with code-tool (OPEN, ACCEPT, UPDATE).¶
A publishes the call as Object 0 of Group 5 on its generateCode
request track, asking for progress with a progressToken:
{"jsonrpc":"2.0","id":"g1","method":"tools/call","params":
{"name":"generateCode","arguments":{"language":"python"},
"_meta":{"progressToken":"g1"}}}.¶
code-tool publishes Group 5 of its generateCode response track as
shown in the table below. It sends the progress notifications in
one subgroup and the result in another, so that each is on its own
QUIC stream and a large result does not delay the progress
updates ([MCP-MOQT]). A receives each object as soon as it
arrives, orders them by Object ID, and knows the call is complete
when the result arrives.¶
To cancel instead, A publishes notifications/cancelled as the next
object in Group 5 of its request track ([MCP-MOQT]). code-tool
stops and ends Group 5 of its response track with a JSON-RPC
error.¶
The table lists the objects in code-tool's reply, in Object ID order, and the subgroup that carries each.¶
| Object | Subgroup | Content |
|---|---|---|
| 0 | 0 |
notifications/progress: progress 0 of 3, "Planning modules" |
| 1 | 0 |
notifications/progress: progress 1 of 3, "Generated parser" |
| 2 | 0 |
notifications/progress: progress 2 of 3, "Generated tests" |
| 3 | 1 |
tools/call result with the generated code (142 lines) |
A user's client, U (agent-id user-u), talks to a voice agent, V
(agent-id agent-v). V answers by voice while a tool call it made to
search-tool is still running. The user cuts in, and V has to stop
speaking and cancel the tool call at once.¶
U publishes:
("pace","dialogs",D4,"user-u") -- "ctrl" ACCEPT
("pace","dialogs",D4,"user-u") -- "audio" microphone
V publishes:
("pace","dialogs",D4,"agent-v") -- "ctrl" OPEN, UPDATE,
CANCEL
("pace","dialogs",D4,"agent-v") -- "audio" speech
("pace","dialogs",D4,"agent-v") -- "chat" reply text
("pace","dialogs",D4,"agent-v","mcp","tools","search")
-- "request" tools/call
search-tool publishes:
("pace","dialogs",D4,"search-tool") -- "ctrl" ACCEPT,
CANCEL_ACK
("pace","dialogs",D4,"search-tool","mcp","tools","search")
-- "response" results
¶
V opens the dialog with U (OPEN, ACCEPT, UPDATE) and adds search-tool the same way.¶
V answers the user. It publishes speech on its audio track as
datagrams at media priority (32-63), with a short
OBJECT_DELIVERY_TIMEOUT, and the reply text on chat at interactive
priority (64-95). Its call to search-tool, Group 3 of the search
request track, is still running.¶
The user starts speaking. U publishes microphone audio on its
audio track, and the relay forwards each frame to V as it
arrives. The dialog does not change.¶
V detects the user's speech and stops producing speech and text. It
publishes CANCEL on its ctrl track at critical priority (0-15),
with scope operation and a target naming Group 3 of its
search request track (Section 4.3.6). The cancellation is
sent ahead of any chat objects V has already queued, and a loss on
the audio datagrams does not delay it.¶
Speech objects that the relay has not delivered within their delivery timeout are dropped at the relay, so the user does not hear the rest of the old answer after cutting in.¶
search-tool applies the CANCEL as MCP notifications/cancelled,
stops, publishes no further objects in Group 3, and publishes
CANCEL_ACK with outcome stopped on its ctrl track. V
listens to the rest of the user's audio and answers in new groups
on its audio and chat tracks.¶
The dialog, its generation, and the MOQT sessions stay the same throughout: an interruption changes the content of a dialog, not the dialog. If the dialog's flows shared one ordered connection, the cancellation in step 4 would wait behind the output V had already sent.¶
A coordinates research by B, a web researcher, and C, a data analyst.¶
A publishes:
("pace","dialogs",D5,"agent-a") -- "ctrl" OPEN, UPDATE,
TERMINATE
("pace","dialogs",D5,"agent-a") -- "chat" assignments
B publishes:
("pace","dialogs",D5,"agent-b") -- "ctrl" ACCEPT
("pace","dialogs",D5,"agent-b") -- "chat" status
("pace","dialogs",D5,"agent-b","a2a","task") -- "research-1"
findings
C publishes:
("pace","dialogs",D5,"agent-c") -- "ctrl" ACCEPT
("pace","dialogs",D5,"agent-c") -- "chat" status
("pace","dialogs",D5,"agent-c","a2a","task") -- "analysis-1"
results
¶
Because each participant subscribes to the dialog prefix, every agent
receives every other agent's tracks in D5; no per-track
subscriptions are needed.¶
A publishes OPEN (gen 0, B and C invited). B and C each publish
ACCEPT, and A commits both in one UPDATE (gen 1).¶
A posts assignments on chat. The relay delivers each object once
to B and once to C.¶
B publishes findings on research-1 as they arrive, one group per
research phase.¶
C reads B's findings as they arrive and publishes its analysis on
analysis-1.¶
A follows both tracks, posts a summary on chat, and publishes
TERMINATE (gen 2). Each agent then ends its dialog tracks with
PUBLISH_DONE.¶
An AutoGen [AutoGen] runtime, R, hosts a group chat with a human, H,
and a remote agent, B. AutoGen has no binding of its own, so R uses the
generic binding (Section 8.6) with "autogen" as the protocol
name, and each AutoGen message carries the dialog reference in its
metadata (Section 8.1).¶
R publishes:
("pace","dialogs",D6,"runtime-r") -- "ctrl" OPEN, UPDATE,
TERMINATE
("pace","dialogs",D6,"runtime-r","ext","autogen") -- "conv1"
R's agents' turns
H publishes:
("pace","dialogs",D6,"user-h") -- "ctrl" ACCEPT
("pace","dialogs",D6,"user-h") -- "chat" human input
B publishes:
("pace","dialogs",D6,"agent-b") -- "ctrl" ACCEPT
("pace","dialogs",D6,"agent-b","ext","autogen") -- "conv1"
B's turns
¶
R opens D6 (gen 0, H and B invited), and commits both ACCEPTs in
one UPDATE (gen 1).¶
R's group chat manager picks the next speaker, as AutoGen does. The
speaker's message goes out once on its publisher's conv1 track,
and the relay delivers it to every other participant.¶
When the manager asks the human, H answers on chat.¶
For a nested chat, R opens a child dialog D7 whose
parent_dialog_ids is [D6], and posts its result back in D6.¶
R publishes TERMINATE (gen 2) when the chat ends.¶