Skip to content

fix: keep failed turns in saved history from breaking the chat - #54

Open
asasemahmed wants to merge 2 commits into
CopilotKit:mainfrom
asasemahmed:fix/replayed-history-errors
Open

asasemahmed wants to merge 2 commits into
CopilotKit:mainfrom
asasemahmed:fix/replayed-history-errors

Conversation

@asasemahmed

@asasemahmed asasemahmed commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

What changed

When one chat turn fails (for example, a provider rejects the API key), the main conversation stays broken afterwards:

  • Reopening the app shows "Could not load conversation. Your saved messages have not been changed. <old error>", and the composer stays disabled on every visit.
  • Past that, the stale error also appears as a banner with Retry response.

Connecting to a Rich Threads conversation replays its saved events, including the RUN_ERROR from the earlier failed turn. CopilotKit core reports replayed run errors through onError with code agent_run_error_event. hydrate() treated any error during connectAgent as a failed load, and the chat-wide onError subscriber showed it as a new error.

Now:

  • runConversationTurn accepts error codes to ignore.
  • While history replays, hydrate() and the chat error subscriber ignore only agent_run_error_event.
  • Connection failures (agent_connect_failed) still block loading. Errors from new turns still stop the run and pause the follow-up queue, as before.
  • Loads still replaying are counted, so when the thread changes mid-load, the old load finishing cannot end the new load's replay and bring back a stale banner.

Behavior change: if a live run fails while a reload is reconnecting to it, that error is now swallowed like a replayed one. No banner is shown; the failed turn stays in the transcript.

Verification

  • Two new tests in tests/conversation-sdk.test.ts use the real CopilotKitCore:
    • A connect that replays a saved RUN_ERROR rejects without the ignore list, which reproduces the bug, and resolves with it.
    • A connect that fails still rejects.
  • pnpm typecheck passes. biome ci passes on the changed files.
  • Rebased onto main. pnpm test: 200 passed, 0 failed, 1 skipped (POSIX-only).
  • Web app, before the fix: a thread whose previous turn had failed showed the "Could not load conversation" error on every load. After the fix, it loads with no stale banner, and new turns reply normally.

Integration limits

  • If the page reloads while a run is in progress and that run then fails during reconnect, its error is not shown as a banner. The failed turn stays in the transcript.
  • Tested on web only. The change is platform-independent state handling in chat.tsx.

@davidmckayv

Copy link
Copy Markdown
Contributor

Needs a fix before merge. The replaying flag is one shared ref across effect runs. If the thread changes while history is loading, the old load's finally clears it while the new load is still replaying, and a stale error banner comes back. Tie the flag to the effect's active token or a counter instead. Also state in the description that a live run failing after a reload is now swallowed. #59 conflicts with this PR and should rebase after it.

Connecting to a Rich Threads conversation replays its saved events,
including RUN_ERROR from any earlier failed turn. CopilotKit reports
those through onError as agent_run_error_event, so one failed reply
made the conversation fail to load ("Could not load conversation")
on every visit and showed a stale error banner.

While history replays, ignore agent_run_error_event only. Connection
failures (agent_connect_failed) still block loading, and errors from
new turns still stop the run and the follow-up queue.
@asasemahmed
asasemahmed force-pushed the fix/replayed-history-errors branch from 155706a to aa53c02 Compare September 25, 2026 20:19
@asasemahmed

Copy link
Copy Markdown
Contributor Author

The browser-container failure is an unrelated flaky network test (it passed on #55 and #60); could you re-run it?

@asasemahmed
asasemahmed force-pushed the fix/replayed-history-errors branch from aa53c02 to 45f00bc Compare September 26, 2026 22:01
@asasemahmed

Copy link
Copy Markdown
Contributor Author

Addressed the review: the replay flag is now a per-load counter, and the description states that a live-run failure after a reload is swallowed. CI is green now.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants