Repository navigation
Replies: 1 comment
|
Adding the other half of this, from a session that ended in a run of truncated turns: on those turns the fork control is never rendered, so the discarded rejection you describe is never even reached. From 1. Text-less final message → no action row at all. const closing = finalized.findLast(hasText) ?? null
if (closing === null) return tail === null ? null : <div …>{tail}</div>which skips the whole 2. Error turns disable it. branchUnavailable: closing === null || latestTranscriptSeq !== closing.finalNode.seqand Net effect for the user: the turns where you most want to branch away (truncated, errored) are exactly the ones with no usable control, and there is no message explaining why. Reported separately as #7215 — deliberately not duplicating your swallow finding here. Evidence: https://gist.github.com/gorban/4725c87390cb391047a2f14b56b98d28 |
Uh oh!
There was an error while loading. Please reload this page.
Both session-fork gestures discard their failure:
packages/client/ui-workspace/src/client/index.ts(forkSession):packages/client/ui-conversation/src/client/apply.ts(forkAt), identical shape for the fork-from-event gesture in the chat view.Each comment names what it keeps, and that part is accurate. The problem is what it does not do: the user clicked fork, nothing opened, and nothing was said. The control reads as dead.
Nothing else observes it
service.forkrejects with aSessionForkError, or with a plainErrorfrom the child rename. The host's fork handler returns that failure as a wire error result, with no host-side log. So the reason exists only inside the discarded rejection -- "no completed turn to fork from", a workspace-attach failure, a post-creation rename failure -- and is then dropped. There is no unhandled-rejection trace either, since the handler is attached.This is not the repo's usual pattern. The convention elsewhere is that an empty
catchnames what it swallows and why nothing else can reach it; here nothing else can.Suggested fix
No contract change is needed, which is the appealing part.
forkSessioncan stay(sessionId: SessionId) => void-- the notice does not travel back through the injected face, so no renderer changes:conversation.input.for(actx).notify(...)is the composer notice channel that detached command results already use -- the same idiom asui-commands'noticeFor. Two properties make it the right surface here:For
ui-workspacethis needs no new dependency:@deepseek-ai/dsh-client-ui-conversationis already declared there, and its service registration is already in scope throughcontract/slots.ts.Carried in a fork with a regression test on each site; both fail against the empty catch. ui-workspace and ui-conversation suites pass (611 tests).
Happy to open a PR.
All reactions