fix: stale urlId on first save, action-runner abort race, and stuck spinner on interrupted file actions - #2188
Open
Cadenadb wants to merge 3 commits into
Open
Conversation
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.
Summary
Three small, independent bug fixes found while debugging a real interrupted-generation scenario (an LLM response cut off mid-file). Each is reproducible on current
mainand verified against a live deployment.1.
app/lib/persistence/useChatHistory.ts— stale closure on first saveWhen a new chat's first
urlIdis generated (storeMessageHistory), it's assigned to a local_urlIdand to React state viasetUrlId(urlId), but thesetMessages(...)call that actually persists the chat still reads the oldurlIdclosure variable, which is stillundefinedat that point. The chat gets saved withurlId: undefinedand never becomes reachable from the sidebar again (history list filters onitem.urlId && item.description), even though the chat and its messages are otherwise saved correctly. One-word fix: use_urlId(the value just computed a few lines above) instead ofurlIdin that call.2.
app/lib/runtime/action-runner.ts— abort() undone by an already-queued executionCalling
action.abort()setsstatus: 'aborted', butrunAction()had already chained a call onto#currentExecutionPromisebefore the abort happened. That queued#executeAction()runs on a later microtask and unconditionally doesthis.#updateAction(actionId, { status: 'running' })at its start, silently overwriting the abort. Fixed two ways:abort()now also setsexecuted: true(sorunAction()'s existingif (action.executed) return;guard prevents any future re-queue), and#executeAction()now checksaction.abortSignal.abortedbefore doing anything, so an already-queued execution can no longer clobber an abort that happened in between.3.
app/components/chat/Artifact.tsx— spinner never resolves for an interrupted file actionIf a response gets cut off mid-file (token limit, dropped connection, client crash), the corresponding
<boltAction type="file">never gets its closing tag, so it never receives the event that would flip it to'complete'. The action list then shows a spinner for that file forever, even after reload, even with no generation active — nothing is actually running, but the UI can't tell. Rather than trying to catch every code path that can leave an action in this state, this fixes it at render time:ActionListnow reads the existingstreamingStatestore, and a'file'action stuck atpending/runningis shown as aborted once nothing is actually streaming.'start'/'shell'actions are intentionally excluded, since those can legitimately keep running well after the text stream ends (e.g. a real in-progressnpm install).Testing
All three verified on a real fork deployment against a chat where generation was genuinely interrupted mid-file (frozen tab). Confirmed: (a) the affected chat becomes reachable from history again on new chats, (b) the abort no longer gets silently reverted, (c) the file action correctly shows as aborted instead of spinning forever, with no change in behavior for actions that complete normally or for shell/start actions that are still genuinely running.
Scope
Deliberately minimal and independent from each other -- no unrelated refactors, no changes to files outside these three.