Problem
On authoritative origin/master@fb7b295, the sidebar allows deleting a conversation while its agent is streaming. deleteConversation removes the row from UI/DB but does not abort the conversation controller, resolve an outstanding ask_user, or remove the ID from streaming state.
A direct store probe deleting an active configured run shows:
{
"immediate": {
"signalAborted": false,
"conversations": [],
"activeConversationId": null,
"isStreaming": true,
"streamingConversationIds": ["conv-delete"]
},
"continuedAfterDelete": true
}
A second probe deleting while ask_user is awaiting input shows:
{
"signalAborted": false,
"sendSettled": false,
"pendingQuestion": {
"callId": "call-1",
"question": "Choose?",
"convId": "conv-question"
},
"isStreaming": true,
"streamingConversationIds": ["conv-question"]
}
Consequences:
- A deleted conversation can keep running tools and commit side effects after the user believes it is gone.
- Deleting during
ask_user leaves an unreachable promise and orphan question that never settles.
- The app can remain globally
isStreaming: true with no conversation visible and no usable Stop target.
Expected
- Deleting a streaming conversation aborts its per-conversation controller immediately.
- If it is awaiting
ask_user, deletion resolves the stored resolver with the existing __ABORT__ sentinel so the agent can unwind.
- The deleted ID is removed from
streamingConversationIds; isStreaming is recomputed for the newly active conversation.
pendingQuestion and agentTurnInfo are cleared when they belong to the deleted conversation.
- Deleting a background stream must not stop another active conversation or incorrectly mark that active conversation idle.
- The existing agent finalizer remains the owner of controller cleanup and settled tool handling; deletion must not resurrect or persist the deleted conversation.
Proposed plan
- Treat
deleteConversation(id) as cancellation plus removal: resolve any per-conversation question, abort the controller, then update store state atomically.
- Remove only the deleted ID from streaming state and derive
isStreaming from the remaining IDs and next active conversation.
- Leave the controller entry until
runAgentWithModel finalizes so wasAborted remains true and memory consolidation stays skipped.
- Add product-level store regressions for an active stream, an
ask_user wait, and preservation of another active stream.
- Run focused tests, full CJS suite, both TypeScript compilers, Vite build, Electron isolation/runtime smoke tests, and dependency audits.
Non-goals
- Waiting synchronously for already-running non-cooperative tools before removing the conversation UI.
- Adding a confirmation dialog or changing sidebar design.
- Refactoring all chat lifecycle state into a new store.
- Changing Stop semantics for conversations that are not deleted.
Mainline note
The repository has no origin/main; origin/HEAD points to origin/master. This cycle starts from authoritative origin/master@fb7b295.
Problem
On authoritative
origin/master@fb7b295, the sidebar allows deleting a conversation while its agent is streaming.deleteConversationremoves the row from UI/DB but does not abort the conversation controller, resolve an outstandingask_user, or remove the ID from streaming state.A direct store probe deleting an active configured run shows:
{ "immediate": { "signalAborted": false, "conversations": [], "activeConversationId": null, "isStreaming": true, "streamingConversationIds": ["conv-delete"] }, "continuedAfterDelete": true }A second probe deleting while
ask_useris awaiting input shows:{ "signalAborted": false, "sendSettled": false, "pendingQuestion": { "callId": "call-1", "question": "Choose?", "convId": "conv-question" }, "isStreaming": true, "streamingConversationIds": ["conv-question"] }Consequences:
ask_userleaves an unreachable promise and orphan question that never settles.isStreaming: truewith no conversation visible and no usable Stop target.Expected
ask_user, deletion resolves the stored resolver with the existing__ABORT__sentinel so the agent can unwind.streamingConversationIds;isStreamingis recomputed for the newly active conversation.pendingQuestionandagentTurnInfoare cleared when they belong to the deleted conversation.Proposed plan
deleteConversation(id)as cancellation plus removal: resolve any per-conversation question, abort the controller, then update store state atomically.isStreamingfrom the remaining IDs and next active conversation.runAgentWithModelfinalizes sowasAbortedremains true and memory consolidation stays skipped.ask_userwait, and preservation of another active stream.Non-goals
Mainline note
The repository has no
origin/main;origin/HEADpoints toorigin/master. This cycle starts from authoritativeorigin/master@fb7b295.