Elevator pitch
What are you proposing to change?ACP v2 should support both whole-message updates and streamed message chunks for user messages, agent messages, and agent thoughts. Whole-message updates are upserts keyed by
messageId, while chunks append content to the message with the matching messageId.
Status quo
How do things work today and what problems does this cause? Why would we change things?ACP v1 primarily reports user, agent, and thought messages as chunks:
messageId.
What we propose to do about it
What are you proposing to improve the situation?ACP v2 should define whole-message session updates:
user_messageagent_messageagent_thought
messageId:
messageIdis required.contentand_metaare patch fields.- An omitted patch field leaves the previous value unchanged.
nullexplicitly clears or unsets the field.- Any concrete value replaces the previous value.
contentis replaced as a whole array, not appended.[]andnullboth clearcontent.- For a new
messageId, omitted fields use Client defaults.
user_message_chunkagent_message_chunkagent_thought_chunk
content item to the current content of the message with the matching messageId.
The Prompt Lifecycle RFD explores acknowledging user-message insertion by returning its agent-generated messageId in the prompt response. Live updates and chunks for that user message would use the same ID, as would replay if the agent retains the message. Retaining the message is optional; live-only messages, including locally handled commands, need not appear in later history. The response confirms insertion and establishes the submitting client’s association with the message; the corresponding updates report its content and placement. They describe the same insertion, but clients must tolerate updates arriving before or after the response. No additional correlation field or metadata-only update is required for live streaming.
When replay reconstructs a message from its beginning using chunks, the Agent must first send the corresponding user_message, agent_message, or agent_thought update with the same ID and content: [] to clear retained content before appending the replayed chunks. This rule applies to all message types. A metadata-only update would leave retained content unchanged and duplicate it during replay. A full-content message update can instead replace the retained content directly.
Interaction between updates and chunks
Clients apply message updates and chunks in the order they are received for eachmessageId.
If a message update includes content, that content array replaces all content currently stored for the message, including content accumulated from earlier chunks:
[C].
If chunks arrive after a message update, they append to the update’s current content:
[A, B].
If a message update omits content, it does not change the current content. This lets Agents update _meta or future optional fields without resending the whole content array:
Shiny future
How will things play out once this feature exists?Agents can choose the reporting style that matches the data they have:
- use whole-message updates for replay, accepted user messages, and already-complete model output;
- use chunks for streaming output;
- combine both when an Agent needs to seed content and then stream more, or correct/replace content after streaming.
Implementation details and plan
Tell me more about your implementation. What is your detailed implementation plan?
- Add the
user_message,agent_message, andagent_thoughtsession update variants to v2. - Require
messageIdon whole-message updates and chunks. - Represent
contentand_metaas three-state patch fields so omitted,null, and concrete values can be distinguished. - Document ordering semantics between whole-message updates and chunks in the protocol docs.
- A stateful adapter may convert a content-bearing whole-message update to v1 by fanning out one v1 chunk per content block only when it knows the v1 side has not already received content for that
messageId; v1 has no way to replace earlier chunks. Patch-only updates,content: null,content: [], and_meta: nullcannot be represented by v1 chunks and must not be silently dropped.
Frequently asked questions
What questions have arisen over the course of authoring this document or during subsequent discussions?
Why are message updates upserts instead of required full snapshots?
Upserts let Agents update_meta or future optional message fields without resending the whole content array.
Why does content replace instead of append?
Appending is already represented by chunks. A whole-message update needs to be able to replay, correct, or replace the current content for a message. Making content a replacement array gives each update type a distinct behavior: message updates replace fields, chunks append content.
What happens when a message update arrives before any chunks?
The Client creates or updates the message for thatmessageId. Later chunks with the same messageId append to the current content.
What happens when chunks arrive before a message update?
The Client appends those chunks to the message for thatmessageId. A later message update with content replaces the accumulated content.
Revision history
- 2026-06-09: Initial draft.