-
Notifications
You must be signed in to change notification settings - Fork 2.9k
fix: 🐛 Fix the cancel button #5662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: 🐛 Fix the cancel button #5662
Conversation
✅ Deploy Preview for continuedev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
state.mainEditorContentTrigger = | ||
state.history[state.history.length - 2].editorState; | ||
state.history = state.history.slice(0, -2); | ||
// TODO is this logic correct for tool use conversations? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO was on the mark. I've followed up with an implementation that follows this line of thinking and peformed extensive testing to validate it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chezsmithy this will be a great problem to solve, has been on my mind recently.
The main issue and reason I hadn't approached this yet is that (correct me if I'm wrong) if the user cancels streaming in Agent mode with this implementation after several turns of the conversation, there will be no recent user messages and it will essentially truncate to the beginning of the convo since the pattern is
user -> assistant + calls -> tool -> assistant + calls -> tool -> assistant + calls etc.
In this case we also can't just truncate back to the last tool message because (if I remember right) e.g. Anthropic won't accept the handshake user -> assistant + calls -> tool (= user in anthropic/gemini) -> user because of sequential user messages
Would love ideas/brainstorming on how to solve this!
@RomneyDa I ran a number of scenarios last night, and I agree with your assessment. There really isn't a good way to roll back to a point in time and keep all the call data balanced to avoid failures with the next API call. I've seen other tools handle this differently with checkpoints that allow you to restore artifact state but do not modify the history and do not allow a cancel option. Typically the loss of context from the last user message seems to be pretty short. The biggest loss can be tool outcome state. Perhaps there is a way to summarize those lost outcomes and inject that into the next user message, or maybe provide that as an option for the user? (E.g You are restarting a cancelled flow, would you like for me to include a summary of your cancelled tool calls into the next request?). |
Another thought. Maybe we have adaptive cancel. If you cancel a thinking call or LLM request after a user message, it rolls to the last user message. If you cancel during a tools call it only cancels the call but doesn't roll back. Perhaps if a tools call has occurred since the last user message we never allow roll back, only cancelling the next tool call. |
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chezsmithy really appreciate the thorough testing here.
I think despite the solid PR description, I may have lost the core idea being implemented here, not easily grasping the exact scope/consequence of these changes.
Could you write up a quick re-outline of the exact approach/changes again?
@@ -362,6 +369,7 @@ export interface AssistantChatMessage { | |||
role: "assistant"; | |||
content: MessageContent; | |||
toolCalls?: ToolCallDelta[]; | |||
toolCallId?: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toolCallId shouldn't be on user chat message since one user message can have multiple tool calls, should already be within each toolcalldelta
@@ -96,7 +96,7 @@ export function LumpToolbar() { | |||
<StopButton | |||
className="text-gray-400" | |||
onClick={() => { | |||
dispatch(cancelStream()); | |||
dispatch(cancelButton()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
semantic nitpick, thinking cancelStream makes more sense as the action performed, and since dispatched on keyboard events not just button click. also reduces file changes
role: "tool", | ||
content: "Tool use was cancelled.", | ||
toolCallId: toolCallId | ||
} as ToolResultChatMessageWithId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we avoid a new one-off message type and use the existing ChatHistoryItemWithMessageId
type?
await dispatch(setInactive()); | ||
await dispatch(abortStream()); | ||
await dispatch(clearLastEmptyResponse()); | ||
await dispatch(streamAssistantMessage({ content: "The request has been cancelled." })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In chat mode this should just terminate, shouldn't stream an assistant response
}); | ||
|
||
// Add handlers for clearLastEmptyResponseThunk | ||
builder.addCase(clearLastEmptyResponse.fulfilled, (state, action) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If no action can remove
}, | ||
|
||
// Add handlers for cancelToolCallAndAddResult | ||
builder.addCase(cancelToolCallAndAddResult.fulfilled, (state, action) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be moved to the thunk so that it's all in one place? I'm not super familiar with the builder paradigm, could you explain the advantage of it vs dispatching a new message/tool call status from the thunk? Stylistic opinion but feels a bit disjointed. Testability related?
@RomneyDa I want to solve for the following: Today using AWS bedrock as a back end hitting the cancel button result in a non presumable session about 70% of the time. The user has to start a new session to recover loosing all context.
Where I am at:
Hope this helps? - S. |
Description
Updated clearLastEmptyResponse to handle cleanup of dangling thinking, and assistant messages. Also look for dangling tools use and tool result messages that might cause an error with certain APIs like AWS bedrock.
Clearly note that the request has been cancelled to the LLM and stop processing.
Cancel running terminal commands by killing them.
This should resolve any issues where dangling thinking or tools use messages are left behind when the cancel button is used breaking the ability to continue the session.
TODO: I discovered one edge case that I could use help fixing. When a file is edited there is a small window between when the edit is started and the editor displays the edits, Accept and Reject Buttons where the request can be cancelled. In this case the cancel button can leave things in an odd state with code still highlighted and the Accept / Reject buttons left behind. I wasn't sure how to check if we are in that state, and fully cancel the Edit Session. Effectively, I would like to perform he same operations as clicking the Reject Button. (Remove decorations, and cancel the edit session). I believe @RomneyDa's change to make the apply cancellable should solve for this.
Checklist
Screenshots
[ For visual changes, include screenshots. Screen recordings are particularly helpful, and appreciated! ]
Testing instructions
Enable Thinking
In Agent Mode:
In Agent Mode:
In Agent Mode:
Summary by mrge
Cancelling a user request now removes all history after the last user message, cleaning up any leftover thinking or tool messages.