fix(tui): rehydrate pending permissions & questions on reconnect#36603
Open
Mykhol wants to merge 3 commits into
Open
fix(tui): rehydrate pending permissions & questions on reconnect#36603Mykhol wants to merge 3 commits into
Mykhol wants to merge 3 commits into
Conversation
Pending permission/question prompts live only in server memory (a Deferred the tool blocks on) and are announced via a single fire-and-forget permission.asked/question.asked event. The SSE stream never replays them to a client that connects after the ask, and the TUI's bootstrap() hydrated everything except these. So detaching the TUI while a prompt was pending (or one raised while detached) left the agent blocked with no prompt shown and no way to answer short of forking the session. bootstrap() now calls hydratePending(), which fetches GET /permission and GET /question and seeds the stores via idempotent upserts that mirror the live *.asked event handlers (binary-search by id, skip if already present, honour auto-approve mode). Subagent prompts surface through the existing root-session aggregation in routes/session/index.tsx.
Contributor
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
Reproduces the detach/reattach bug: with a pending permission and question on the server and no live *.asked event, the reattached TUI must fetch them on connect. This test fails on the pre-fix sync.tsx (store stays undefined) and passes with hydratePending(). Adds /permission and /question defaults to the sync fetch fixture.
Contributor
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
Trim the two added comments to the file's sentence-case, why-focused convention: drop the server-internal Deferred detail and keep the client-side framing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes #36604
Type of change
What does this PR do?
Pending permission/question prompts only live in server memory (a
Deferredthe tool blocks on) and are announced with a singlepermission.asked/question.askedevent at ask time. The SSE stream only forwards events emitted after a client subscribes and never replays what's already pending, and the TUI'sbootstrap()hydrated everything except these two stores. So if you detach the TUI while a prompt is pending — or one is raised while you're detached — re-attaching shows no prompt even though the agent is still blocked, and the only way out is to fork the session.This adds
hydratePending()tobootstrap(), which fetchesGET /permissionandGET /questionon connect and seeds the stores. Inserts go through smallupserthelpers that mirror the existing*.askedevent handlers (binary-search by id, skip if already present), so hydration and any live events that arrive during bootstrap interleave without duplicating or clobbering. Auto-approve mode is honoured the same way the live handler does it. Subagent prompts surface via the existing root-session aggregation, so no extra work there.How did you verify your code works?
Added a test in
sync-live-hydration.test.tsxthat seeds a pending permission and question on the mock server, emits no live event, and asserts the store is hydrated on connect. It fails against the currentsync.tsx(sync.data.permission[sessionID]isundefined) and passes withhydratePending(), so it pins the exact regression. Fullpackages/tuisuite passes (192 pass / 0 fail),bun run typecheck(tsgo) is clean, andoxlintreports 0 errors on the changed files. Both list calls are wrapped in.catch()so an older server without these endpoints falls back to current behaviour.Screenshots / recordings
N/A — no visual change; this only re-populates prompts that already render today.
Checklist