Skip to content

fix(client): clear pending prompts the transcript shows were delivered - #61679

Merged
jlongster merged 2 commits into
devfrom
fix/pending-prompt-recovery
Nov 4, 2026
Merged

jlongster merged 2 commits into
devfrom
fix/pending-prompt-recovery

Conversation

@jlongster

@jlongster jlongster commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

A submitted prompt is shown as Pending right away and stays in the client's outbox until its session.inbox.enqueued event arrives. The event stream has no replay, so if that event is lost in a reconnect, the row never leaves the outbox. In an idle session the prompt is delivered within milliseconds, so the inbox read after the reconnect doesn't find it, and the outbox guard keeps it. The prompt shows as Pending forever, even though it already ran. This was seen in the desktop app connected to a remote server; the TUI shares the same data layer.

Transcript reads only return delivered input. Now, when message.sync returns a message whose ID is a pending row, the client takes it out of the outbox and removes the row. The reload after a reconnect (and the first load when a session is opened) clears stuck prompts that way.

How did you verify your code works?

Two new tests in packages/client/test/solid-inbox-race.test.ts: one drops only the delivery event, the other drops every event after the POST succeeds and checks that a later inbox read doesn't bring the row back. Both fail without the change. bun test (259 tests) and tsc --noEmit pass in packages/client.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Added by the opencode bot (AI-generated).

Fixes #56748

Related: #59615

@opencodejr opencodejr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change looks sound. I ran the new tests against the base data.ts: both fail there and pass with this change. The full packages/client suite (259 tests) and tsc --noEmit pass. I also traced the reconnect path. Disconnecting invalidates the cached reads, and the TUI then reloads the inbox and the transcript at the same time. The fix holds whichever finishes first, since removePending records the removal for a concurrent inbox read. I couldn't drive this end to end in the TUI because it needs the event stream dropped mid-delivery.

Public API is unchanged: this only changes internal client state handling.

No blocking concerns.

Fixes #56748
Related: #59615

@opencodejr opencodejr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new commit is correct. The "free usage limit" fixture listed msg_queued_user as both waiting in the inbox and already delivered in the transcript, which real data can't do. Now that a transcript read clears delivered rows, that test failed until the message came out of the transcript fixture. I confirmed it fails with the old fixture and passes with the new one. tsc in packages/tui gives the same errors as on the base.

Public API is unchanged. No new concerns.

@jlongster
jlongster merged commit 0d226da into dev Nov 4, 2026
20 checks passed
@jlongster
jlongster deleted the fix/pending-prompt-recovery branch November 4, 2026 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tui: queued card for a delivered image message lingers above the prompt input

1 participant