fix(agent-sidebar): restore width+open on reload, add deleteConversation#305
Merged
Conversation
Three independent cross-host agent sidebar defects, all against v0.5.6: 1. Width not restored on reload. SidebarProvider's mount fetch only set lastOpenWidth, never the rendered sidebarWidth, so a persisted width was stranded until the next open gesture (close-then-reopen restored it; reload did not). Reconcile the fetched width into rendered state via a guarded functional updater (cur <= 0) so a user gesture landing before the async fetch is never clobbered. 2. Open flag dropped on reload. AppShell derived visibility purely from width, with no controlled-open prop, so the shell always painted closed regardless of the persisted open flag both host session hooks already expose. Add open?/onOpenChange? to AppShellProps, derive isOpen = open ?? (width > 0), seed/collapse width via an effect when controlled open flips, and fire onOpenChange from the open (FAB) and close handlers. Uncontrolled (open undefined) behavior is unchanged. 3. Remove conversation had no transport. The trash-icon delete button already shipped but nothing backed it. Add deleteConversation to the AgentChatClient contract and useAgentChat (optimistic history removal + thread clear when the open conversation is deleted, rollback on failure), re-exported through useAgentSession. No version bump — rides a later rollup release. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review follow-ups on the agent-sidebar reload/delete fix:
- SidebarProvider.test.tsx: the legacy localStorage `persistKey` unit test
("does not read localStorage at module load") still asserted width=0 after
mount, the pre-fix behavior. Defect #1's reconcile (setSidebarWidth((cur) =>
cur <= 0 ? stored : cur)) now restores a persisted 500 into the rendered
width over a defaultWidth of 0, so the assertion + comment are updated to
expect 500. The equivalent server-persistence test was already updated; this
legacy path was missed and was landing main red.
- useAgentChat.deleteConversation: switch the rollback from a full-list
overwrite to a MERGE updater (mirrors renameConversation), re-inserting the
removed row at its original index — preserves any conversation created
between the optimistic drop and the failed network call instead of
clobbering it. Behavior-identical in the common case.
- AppShell.tsx: clarify two comments (controlled-open effect dep rationale;
the load-bearing `sidebarWidth > 0` panel guard) — no behavior change.
No version bump — rides a later rollup release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
Storybook Preview: https://mirrorstack-ai.github.io/web-ui-kit/pr/305/ |
Merged
I-am-nothing
added a commit
that referenced
this pull request
Jun 14, 2026
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.
What
Fixes three independent cross-host agent-sidebar defects (all against v0.5.6), plus the review follow-ups.
Defect 1 — width not restored on reload
SidebarProvider's mount fetch only setlastOpenWidth, never the renderedsidebarWidth, so a persisted width was stranded until the next open gesture (close-then-reopen restored it; a reload did not). Now the fetched width is reconciled into rendered state via a guarded functional updater (setSidebarWidth((cur) => (cur <= 0 ? stored : cur))) so a user gesture that lands before the async fetch is never clobbered — first writer of a real width wins.Defect 2 — open flag dropped on reload
AppShellderived visibility purely from width, with no controlled-open prop, so the shell always painted closed regardless of the persisted open flag both host session hooks already expose. Addedopen?/onOpenChange?toAppShellProps, deriveisOpen = open ?? (sidebarWidth > 0), seed/collapse width via an effect when controlledopenflips, and fireonOpenChangefrom the FAB (open) and close handlers. Uncontrolled (open === undefined) behavior is unchanged.Defect 3 — remove conversation had no transport
The trash-icon delete button already shipped but nothing backed it. Added
deleteConversationto theAgentChatClientcontract anduseAgentChat(optimistic history removal + open-thread clear, rollback on failure), re-exported throughuseAgentSession.Root cause
Width and open were two separate pieces of state, but only width was being rehydrated and only width drove rendering. The persisted open flag had no path into the rendered shell, and the persisted width landed in reopen-memory (
lastOpenWidth) rather than the renderedsidebarWidth. Reload reads both from the server but the shell discarded both signals. The fix routes the persisted width into rendered state and adds a controlled-open contract so the host's persisted open flag actually paints.Review follow-ups (second commit)
persistKeylocalStorage unit test (SidebarProvider.test.tsx> "does not read localStorage at module load") still assertedwidth === 0after mount — the pre-fix behavior. Defect 1's reconcile now restores the persisted500into the rendered width over adefaultWidthof0, so the assertion + comment were updated to expect500. The equivalent server-persistence test was already updated; this legacy path was missed and was landing main red (1/768 failing). Suite is now green (768/768).deleteConversationrollback switched from a full-list overwrite to a MERGE updater (mirrorsrenameConversation), re-inserting the removed row at its original index — preserves any conversation created between the optimistic drop and a failed network call. Behavior-identical in the common case.AppShell.tsxcomments tightened (controlled-open effect dep rationale; the load-bearingsidebarWidth > 0panel guard). No behavior change.Verification
pnpm test— 768/768 passing (was 767/768 with 1 red)pnpm typecheck— cleanpnpm build— cleanVersioning
No
package.jsonversion bump and no CHANGELOG touch. These kit changes ride a later 0.5.7 rollup release, not this PR.DRAFT — cross-repo merge order
This sidebar fix is part of a coordinated cross-repo change. Land in this order:
api-platformapi-client-sharedweb-ui-kit← this PRweb-applicationsweb-accountWhy draft: web-ui-kit depends on the upstream repos' unpublished releases landing first (api-platform, then api-client-shared). Keep this as a draft until those two are merged and the dependent release/contract is available. Un-draft once api-platform and api-client-shared have landed and this can ride the 0.5.7 rollup release into web-applications / web-account.
🤖 Generated with Claude Code