Closed agzam closed 1 month ago
Ah yeah, I'm aware of this issue. It's unrelated to Org mode. See prior discussions in #406, #321, #351, #343.
There is no easy fix for this yet. Rather, there are several easy ways to fix it but all of them create new problems. Here are three independent things you can do to avoid the error (i.e., any one of them will work, don't do them all):
gptel-post-request-functions
or manually. (Obviously this is not an acceptable compromise.)feature-overlays
branch of gptel.(setf (alist-get 'gptel 'text-property-default-nonsticky nil 'remove) nil)
Each of these causes other problems, but it's possible you may not encounter any of them.
Eventually I need to find a solution that works with minimal compromises.
It's unrelated to Org mode
For some reason I don't see it (at least not as often) when using Markdown mode.
when i looked at the code after a recent "invalid_request_error" I realized, that my buffer had adjacent GPTEL_BOUNDS
shoudnt it just merge:
:GPTEL_BOUNDS: ((359 . 835) (836 . 2720) (2721 . 3388))
to
:GPTEL_BOUNDS: ((359 . 2720) (2721 . 3388))
and then there would be no empty user message? Would this be a solution?
I got the feeling, that gptel sometimes produces these invalid_request_error-hickups even if you dont edit the response. For debugging purposes i wrote some functions, which visually show the gptel-bounds:
;; gptel chat coloring
(defvar gptel-bounds-overlay nil
"Variable to store the overlay for GPTEL_BOUNDS.")
(defun show-and-highlight-gptel-bounds ()
"Display the first occurrence of GPTEL_BOUNDS property in the file and highlight the bounds."
(interactive)
(save-excursion
(goto-char (point-min))
(let ((bounds-str (org-entry-get (point) "GPTEL_BOUNDS")))
(if bounds-str
(let ((bounds (read bounds-str)))
(message "GPTEL_BOUNDS: %s" bounds-str)
(highlight-bounds bounds))
(message "No GPTEL_BOUNDS property found in the file.")))))
(defun highlight-bounds (bounds-list)
"Highlight the regions specified by BOUNDS-LIST."
(dolist (range bounds-list)
(let ((start (car range))
(end (cdr range)))
(when (and (numberp start) (numberp end) (<= start end))
(let ((overlay (make-overlay start end)))
(overlay-put overlay 'face '(:background "light sky blue"))
(overlay-put (make-overlay start (1+ start)) 'face '(:background "steel blue"))
(overlay-put (make-overlay (1- end) end) 'face '(:background "steel blue"))
(push overlay gptel-bounds-overlay))))))
(defun toggle-highlight-gptel-bounds ()
"Toggle the highlighting of GPTEL_BOUNDS."
(interactive)
(if gptel-bounds-overlay
(progn
(mapc 'delete-overlay gptel-bounds-overlay)
(setq gptel-bounds-overlay nil)
(message "GPTEL_BOUNDS highlighting removed."))
(save-excursion
(goto-char (point-min))
(let ((bounds-str (org-entry-get (point) "GPTEL_BOUNDS")))
(if bounds-str
(let ((bounds (read bounds-str)))
(highlight-bounds bounds)
(message "GPTEL_BOUNDS highlighting enabled."))
(message "No GPTEL_BOUNDS property found in the file."))))))
(global-set-key (kbd "C-c h") 'toggle-highlight-gptel-bounds)
if you execute this code you can toggle highlighting of system messages, and get a clearer image what is going on.
assistant messages
are highlighted with a blue background, with the start and end character in a darker blue.
For example i had the following conversation:
you see that a system message is ending at character 971 and the next one starting right at 972. If i want to continue the chat with a second question, thats were empty user messages are created, an then claude complains.
thats the relevant snippet from gptel-log
(re-search-forward \":GPTEL_BOUNDS: (\" nil t)"
},
{
"role": "user",
"content": ""
},
{
"role": "assistant",
"content": "\n (let ((bounds
@agzam, @wlauppe could you try it now? I added a clause to the logic for Anthropic where I don't include "empty" user prompts in the message.
(Even if this works, this is a stopgap solution -- as I haven't been able to find a response tracking method that is both robust and simple.)
Apologies for the delay, just wanted to make sure it's good. This is what I have in my config
(setq gptel-default-mode 'org-mode)
(setf (alist-get 'org-mode gptel-prompt-prefix-alist) "* ")
Sorry, with org-indent-mode my converstations were weirdly shifting onto the right, so I removed a few asterisks.
Been using it for a couple of days, so far no issues with the requests. Looks good. Thank you very much.
Closing this now.
@wlauppe and @agzam, feel free to reopen if you can still reproduce the error.
karthik, if you write an updated :GPTEL_BOUNDS:
line, do you account for the changes in length?
For example if it had length 10 and the new :GPTEL_BOUNDS:
line has length 20. the number in the
cons cell should be 10 higher, becouse GPTEL_BOUNDS is inserted at the beginning of the buffer. (359 . 835) (836 . 2720)
becomes (369 . 845) (846 . 2730) do you do that?
karthik, if you write an updated
:GPTEL_BOUNDS:
line, do you account for the changes in length? For example if it had length 10 and the new:GPTEL_BOUNDS:
line has length 20. the number in the cons cell should be 10 higher, becouse GPTEL_BOUNDS is inserted at the beginning of the buffer.(359 . 835) (836 . 2720)
becomes (369 . 845) (846 . 2730) do you do that?
Fixed-point iteration: https://github.com/karthink/gptel/blob/master/gptel-org.el#L410
I think it is nice to have a workaround hack, to be able to work with Claude in conversation mode even if something is broken at the moment, but at the same time I think we are very close at finding the real problem, and this workaround obscures the fact that something is broken. Do you understand why the gptel--get-buffer-bounds() function. from gptel.el
(defun gptel--get-buffer-bounds ()
"Return the gptel response boundaries in the buffer as an alist."
(save-excursion
(save-restriction
(widen)
(goto-char (point-max))
(let ((prop) (bounds))
(while (setq prop (text-property-search-backward
'gptel 'response t))
(push (cons (prop-match-beginning prop)
(prop-match-end prop))
bounds))
bounds))))
returns, two adjacent cells of a text which has consecutively the text property ' gptel 'response? eg.
:GPTEL_BOUNDS: ((359 . 2720) (2721 . 3388))
At the same time i got some spurious errors, and dont know if there are connected to the workaround hack. Thats why havent answered with 👍
I may play around with the old version for a bit, maybe I find something out.
and this workaround obscures the fact that something is broken.
If you are referring to the workaround chosen as the solution in this thread, it's a workaround, but nothing is broken. The text-properties are applied and read as intended.
:GPTEL_BOUNDS: ((359 . 2720) (2721 . 3388))
These bounds are correct, you can have one character without the gptel
text-property between 2720 and 2721. Text property bounds are the "edges" between chars. Typically this character ends up being some kind of whitespace.
The real question is if we should also apply this text property to the range 2720-2721. Unfortunately making the gptel
property sticky causes a bunch of other problems. There has been extensive discussion about this, see the issues linked in this comment above, and see (info "(elisp) Sticky Properties")
for details on sticky text properties.
Text property bounds are the "edges" between chars.
i thought the above means. character 359 up to and included character 2720 is an assistant message? and character 2721 up to and included character 3388 too? This wrong?
thanks for pointing me to the sticky text properties documentation.
i thought the above means. character 359 up to and included character 2720 is an assistant message? and character 2721 up to and included character 3388 too? This wrong?
There is no character at 359, a character occupies the range from 359 to 360. Similarly, there is no character at 2720. So the above means that all characters between points 359 and 2720 are part of an assistant message, as are characters between points 2721 and 3388.
The single character between the points 2720 and 2721 is part of the user prompt. It's recognized as user input because it was inserted by the user, possibly by running a command like fill-region
or typing in the newline character there.
Anecdotally, I never had this error.
I set
gptel-default-mode
toorg-mode
and at first, it seemed that it's worked, but it sometimes can fail.What I did: