xenodium / chatgpt-shell

ChatGPT and DALL-E Emacs shells + Org babel 🦄 + a shell maker for other providers
https://xenodium.com
GNU General Public License v3.0
785 stars 66 forks source link

Add a way to remove context from the transcript #210

Open steveyegge opened 3 weeks ago

steveyegge commented 3 weeks ago

Sometimes the model will spit out a long answer that's pretty terrible, usually because it misunderstood your prompt. But you have a lot of valuable context built up in the shell buffer. So what you'd like to is delete the last question & response.

One possible solution is to add a command to delete the last response and edit the last prompt. But even being able to just arbitrarily edit the buffer, taking out irrelevant content, and then switch it back to its normal read-only mode, would also be fine.

The motivation here is that you want to keep your context window from getting clipped, so you're doing manual garbage collection.

xenodium commented 3 weeks ago

Ah yeah, I've certainly run into this. I typically do either of two things (neither are nice tbh):

  1. Save session, open as a text buffer, edit, and reload session.
  2. Use undo until the last response is all gone.

Had a look, and maybe got a solution that strikes a good balance:

(defun shell-maker-delete-interaction-at-point ()
  "Delete interaction (request and response) at point."
  (interactive)
  (unless (eq major-mode (shell-maker-major-mode shell-maker--config))
    (user-error "Not in a shell"))
  (save-excursion
    (save-restriction
      (let ((inhibit-read-only t)
            (prompt-pos (save-excursion
                          (goto-char (process-mark
                                      (get-buffer-process (current-buffer))))
                          (point))))
        ;; Go to previous response if at last/empty prompt.
        (when (>= (point) prompt-pos)
          (goto-char prompt-pos)
          (forward-line -1)
          (end-of-line))
        ;; Removing `insert-in-front-hooks' from text, prior
        ;; to deleting region, ensures comint runs neither
        ;; `comint--mark-as-output' nor `comint--mark-yanked-as-output'
        ;; if user undoes the deletion, which breaks `comint' navigation.
        (remove-text-properties (point-min)
                                (point-max)
                                '(insert-in-front-hooks nil))
        (shell-maker-narrow-to-prompt)
        (delete-region (point-min) (point-max)))))
  (end-of-line))

You can remove any interaction from history by moving point and invoking shell-maker-delete-interaction-at-point.

Not had a chance to test thorouhly, though I think I did manage to at least prevent deletion undo from breaking navigation.

Fancy giving it a try? Be sure to save your transcript in case bad things happen ;)

edit: snuck in a (end-of-line), so point is left at a more convenient location.

xenodium commented 3 weeks ago

ps. If you M-x shell-maker-delete-interaction-at-point the last response, you can get the last query via M-n in case you'd like to edit it.

xenodium commented 3 weeks ago

Pushed in 6ac6324d6cf373c48d206552a12258bdeafc905e. Try M-x chatgpt-shell-delete-interaction-at-point. You'll need to reload both shell-maker.el and chatgpt-shell.el.

Happy to take function naming alternatives/suggestions.