-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Improve AI diff UX #14910
base: master
Are you sure you want to change the base?
Improve AI diff UX #14910
Conversation
Question: The PR description says the change log was updated (due to breaking changes), but i do not see the update in the PR? |
- Updates editors when new suggestions proposed - Separates accept and saving actions to avoid unnecessary prompts - Avoids use of untitled editors to avoid prompts for them
b07a34a
to
5a11c4b
Compare
Fair point. I'd say that some of the breakage is optional, and I'd prefer to update the changelog once I know which bits have survived review (or been added because of it). But I can write an entry now and then try to keep it up to date if anything changes, if you prefer. |
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.
Awesome, this improves the current state already immensely!
Asking to Save
- Open a diff editor and close it in a dirty state -> you should be prompted to save. I thought about getting rid of this if the user hasn't actually interacted with the editor, since then the state is saved as part of the LLM interaction. Let me know your thoughts.
- Open a diff editor and then delete the corresponding node. The editor should close. It should prompt you whether you want to save. Same question as re: (3).
I personally would prefer, if we don't ask the user whether they would like to save, if the right side of the suggestion-diff-editor hasn't been changed by the user. Feels unexpected. But its tricky and I can happily live with both.
Accept vs Apply, etc.
I like the new naming much better than what we had before! Thanks!
Shouldn't we also propagate that to the UI too? The labels of the button and hovers still use the term accept. I think it'll be better to keep the naming in the code and UI consistent, and change "Accept" to "Apply" and "Undo" to "Revert" and "Delete" to "Discard"?
Dirty State When Applied
If the state of a suggestion is "Applied" and we open the diff editor, shouldn't we avoid the dirty state in the diff editor? It is already applied and the dirty state suggests that it is not, in my view.
The Left Side of the Suggestion Diff Editor
Currently the left side is the state of the file at the time where the change set element has been created and remains in this state.
Shouldn't we keep the left side of the diff editor always up to date with what's currently in the file system or Monaco workspace? If I made changes in between, and hit save in the diff editor, I wouldn't even see that I'm overwriting my changes. If we would show the actual current state left, I'd at least see that as a diff.
On the other hand, it currently reflects what the LLM was using as its basis; also, if the user applied the suggestions, the diff editor now still shows the actual original suggestions. Makes sense too.
However, overall, it feels more logical to me, if the left side is always the current workspace state. This would also mean that if I applied the suggestions, there are no further AI suggestions to review -- so the diff editor becomes clean (no changes).
In conclusion, I lean towards syncing the left side with the current Monaco workspace state (or file system state if not open). To me the benefits outweigh the single advantage of the current approach --- ie that I still can see what the LLM originally suggested. But to the user this is not really relevant information, once they already reviewed and accepted the changes. And they can always revert in the change set UI.
this.state = 'applied'; | ||
if (this.type === 'delete') { | ||
async apply(contents?: string): Promise<void> { | ||
if (await this.changeSetFileService.trySave(this.changedUri)) { /** Continue */ } else if (this.type === 'delete') { |
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.
Optional nitpick: Just a matter of taste, but I personally find /** Continue */ less clear. You might consider negating the condition and either duplicating the closeDiffsFor()
call or nesting the if-statement inside the negated condition.
Oh, one more observation: We should probably change the |
What it does
Fixes parts of #14768. In particular:
autosavable
field from theResource
interface to theSaveable
interface and then not perform autosaves if theSaveable
says it doesn't want to be autosaved. @msujew, you've recently worked on the autosaving infrastructure, so I'd be grateful to get your thoughts. Another alternative I considered was to pipe theSaveReason
through to theResource
's save options so that some resources could just reject automatic saves, but that feels less clean than having theSaveable
declare itself exempt from that system.@Reviewers
, please see what you think of the way the diff behaves when you save the right side. It will still show the diff relative to original state, without showing that the underlying left-side file has actually been updated. I can fix that by using mutable in-memory resources, but then the lifecycle gets a little trickier.apply
cycle of the ChangeSetFileElement. This allows us to avoid hanging dirty state or prompts to save when the user believes they have saved / applied the changes.ChangeSetElements
fromaccept
anddiscard
toapply
andrevert
and removes the'discarded'
state option. The practical reason for doing so was that we were inconsistent in our handling of 'reverted' changes: we let them be reapplied on the element level, but we didn't reactivate the globalActivate
button on the ChangeSet level. Now if the user reverts a change, it returns to'pending'
state: I don't think we should stand in the way of the user having third thoughts. Semantically,discard
also sounded more likedelete
than it behaved. I'm open to discussion about this point.delete
, I added optionaldispose
to theChangeSetElement
interface to be called when the element is deleted. This lets me do cleanup like closing diff editors when a change element is deleted. I have some misgivings about the lifecycle still: we currently replace elements in the change set, but we don't want everything associated with a given proposal (e.g. diff editors) to die when it gets replaced.How to test
Follow-ups
Breaking changes
Attribution
Review checklist
Reminder for reviewers