CopilotChat's send-after-replay guard (#7657) doesn't cover generic AG-UI HttpAgent agents · Issue #7688 · CopilotKit/CopilotKit · GitHub
Skip to content

CopilotChat's send-after-replay guard (#7657) doesn't cover generic AG-UI HttpAgent agents #7688

Open

Description

@rgoldberg-personal

What happened

#7657 ("fix(react-core): wait for thread replay before sending prompts") added a guard in CopilotChat.tsx's waitForActiveRunToSettle that awaits pendingConnectionsRef.current.get(agent) — a promise wrapping agent.connect() — before allowing a new submission, specifically to prevent sending while a saved conversation is still replaying.

This doesn't help for agents built on @ag-ui/client's generic AbstractAgent/HttpAgent (e.g. @ag-ui/crewai's CrewAIAgent) that never override connect(). AbstractAgent.connect() is:

connect(e){throw new l.AGUIConnectNotImplementedError}

— always throws — and connectAgent()'s own catchError specifically swallows exactly that exception type, resolving the connection promise to an already-complete empty observable almost instantly. So the new guard has nothing real to await for this agent type: it resolves before any actual history replay has happened.

Repro

  1. A CopilotKit app registers an @ag-ui/crewai CrewAIAgent (or any other HttpAgent subclass that doesn't override connect()) as its agent, talking to a backend with a saved multi-turn conversation.
  2. Reload the page / revisit an existing thread with history.
  3. Immediately (before the replayed history visibly finishes rendering) type and send a new message.
  4. The new message renders ahead of / interleaved incorrectly with the replayed history that logically precedes it, and — per the AG-UI client's merge-by-id behavior (deliberately never reorders once a message is placed — Snapshot tool results are appended after streamed follow-up text ag-ui-protocol/ag-ui#2767) — stays that way permanently for the session.

Why #7657 doesn't fix this

The PR's own description scopes it to "Intelligence proxies" (ProxiedCopilotRuntimeAgent) hydrating through a delegate whose completion isn't otherwise visible — validated against "a real FastAPI/LangGraph SQLite backend." That's a narrower agent architecture than the generic AG-UI HttpAgent path. For HttpAgent-based agents, connectAgent() is a confirmed no-op (see above), so the new pendingConnectionsRef-based guard introduced in that PR never actually waits on this path's real replay work — whatever mechanism this agent type actually uses to load history isn't observed by the new guard at all.

Suggested direction

waitForActiveRunToSettle would need to also account for a replay that happens via an actual run (RUN_STARTED → ... → RUN_FINISHED), not only via connect()/connectAgent() — e.g. also awaiting agent.isRunning/activeRunCompletionPromise settling for whatever triggers the initial history load for a resolved threadId, regardless of whether that agent type implements connect().

Environment

  • @copilotkit/react-core / react-ui / runtime: 1.77.1
  • @ag-ui/client: 1.0.2
  • @ag-ui/crewai: 0.0.4

Activity

  1. copilotkit-outpost-bot commented on Oct 7, 2026

    @copilotkit-outpost-bot

    ⚠️ This is an AI-generated response. We've escalated this to our engineering team — someone will follow up in this thread shortly.

    Engineering will need to verify this — the analysis is detailed and the scoping question about whether waitForActiveRunToSettle's pendingConnectionsRef guard covers the HttpAgent/AbstractAgent replay path is exactly the kind of thing that requires running the code.

    What I can confirm from the source in context: waitForActiveRunToSettle in packages/react-core/src/v2/components/chat/CopilotChat.tsx does have a second guard — after the pendingConnectionsRef await — that checks agent.isRunning && activeRunCompletionPromise and awaits it (source, lines 862–873). If the initial history replay for HttpAgent-based agents fires as a real RUN_STARTED → RUN_FINISHED sequence and sets agent.isRunning = true before waitForActiveRunToSettle is called, that second guard would catch it. Whether agent.isRunning is reliably true at the moment a user submits during early replay — i.e., whether there's a window between the run starting and isRunning being observable — is the open question your report raises, and that's what the team will need to verify against the actual HttpAgent lifecycle.


    🤖 Generated by CopilotKit AI Support · Documentation


    Was this helpful? React with 👍 or 👎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions