ACP clients group streamed agent_message_chunk / agent_thought_chunk
updates into one assistant reply by messageId, and use a new id to
start the next reply (root-reply replacement semantics). Hermes' ACP
adapter sent every chunk without a messageId, so clients that replace
'the current assistant message' per chunk collapsed separate
autonomous turns into one bubble.
- AssistantMessageIdAllocator (per ACP session, monotonic across
turns): a contiguous run of reasoning + text deltas shares one
hermes-assistant-N id; the None flush sentinel Hermes core emits
before tool execution / at end of stream closes it.
- make_message_cb / make_thinking_cb stamp update.message_id when an
allocator is provided; legacy no-allocator shape unchanged.
- Unstreamed final responses open their own id; plugin-transformed
responses reuse the streamed message's id (replacement).
- Tests: grouping until flush, thought+text sharing, monotonic ids,
empty-string vs None sentinel, legacy shape.