Skip to content

Operator replies overwrite previous agent agentName in UI (order not advanced for human assistant messages) #282

Description

@ra333leven

Description

When using the Agent component with a “human operator takeover” flow, a human operator’s reply can overwrite the previous agent’s agentName in the UI. The root cause appears to be how order is advanced and how UIMessages are combined.

From the docs:

  • Messages are ordered by order and stepOrder per thread.[[Message ordering](https://docs.convex.dev/agents/messages#message-ordering)]
  • When saveMessage or generateText is called, the message is added at the thread’s next order with stepOrder = 0, and response messages share that order with increasing stepOrder.[[Message ordering](https://docs.convex.dev/agents/messages#message-ordering)]
  • listUIMessages / useUIMessages return UIMessages that combine multiple MessageDocs into a single UI bubble when there are multiple tool calls followed by an assistant message.[[Messages](https://docs.convex.dev/agents/messages); [Showing messages in React](https://docs.convex.dev/agents/messages#showing-messages-in-react)]

Observed behavior

  1. An AI agent sends an assistant reply (e.g. agentName: "support-bot").
  2. A human operator sends a reply using saveMessage with role: "assistant" and agentName: "human:<name>". This is similar to the “Saving a message from a human as an agent” pattern in the docs.[[Human agents](https://docs.convex.dev/agents/human-agents)]
  3. The operator’s assistant message ends up sharing the same order as the prior agent reply.
  4. On the client, useUIMessages returns a single UIMessage where the previous agent’s content is merged with the operator’s agentName, so the agent’s reply renders as if it came from the operator.

The optimistic UI path (which inserts at maxOrder + 1) does not show this problem; only the server-side save does.

Workaround I’m using

Because there’s no documented way to manually advance order, I’m currently working around this by:

  • Inserting a hidden role: "user" message with a special internal marker (e.g. "[internal:operator]") right before saving the operator’s assistant message.
  • Filtering that marker out in the UI render (similar to how internal markers like [internal:compose] are typically hidden).

This forces the operator turn onto a new order, so it no longer merges with the previous agent reply.

What I’m asking

  • Is this merging behavior (human assistant messages reusing the previous assistant’s order) expected?
  • If not, could the Agent component:
    • Either advance order for standalone assistant saveMessage calls that are not part of an LLM response, or
    • Expose a supported way to force a new order / prevent merging for specific messages?

Right now the only reliable lever I’ve found is the hidden user-message anchor, which feels like a hack and adds extra internal messages to the thread.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions