branch: elpa/gptel
commit 51d39e9136c25a45dae58513e599377b87bc2902
Author: Tom Cahill <t...@tomwcahill.com>
Commit: GitHub <nore...@github.com>

    gptel-anthropic: Fix invalid duplication of tool_call message (#734)
    
    When a `message_delta` event is received, we append any tool calls from the
    response to the global vector of messages and then modify the `tool-use` 
lists
    in the FSM info to put them in the right shape for actually invoking tools. 
This
    can cause issues if an error occurs after those modifications have already 
been
    made - if the `gptel--json-read` call for the `message_delta`'s data fails
    because we don't yet have the full object, the error handler silently 
discards
    the error and resets the point to the start of the same event again. Next 
time
    we re-enter `gptel-curl--parse-stream`, we'll again try to process the
    `message_delta` event but because we modified the tool use blocks in the 
last
    invocation, we'll push duplicate messages with the incorrect format 
(`input` is
    empty and `args` has the contents that `input` is supposed to).
    
    For example, here's what the messages vector looks like when we encounter 
this
    issue in the repro script described by @kmontag in
    https://github.com/karthink/gptel/issues/725:
    
    ```
            [(:role "user" :content
                    "Open the file '~/example.el' and make 5 changes of your 
choosing. Make each change individually. Don't ask for clarification.")
             (:role "assistant" :content
                    [(:type "text" :text
                            #("I'll open the file and make 5 individual changes 
of my choosing. Let me first check the contents of the file."
                              0 9 (gptel response front-sticky (gptel)) 9 40
                              (gptel response front-sticky (gptel)) 40 87
                              (gptel response front-sticky (gptel)) 87 109
                              (gptel response front-sticky (gptel))))
                     (:type "tool_use" :id "toolu_01WHEjX2hivzCrcufv9RaCnY" 
:name
                            "readFile" :input (:filename "~/example.el"))])
             (:role "assistant" :content
                    [(:type "tool_use" :id "01WHEjX2hivzCrcufv9RaCnY" :name
                            "readFile" :input nil :args (:filename 
"~/example.el"))])]
    ```
---
 gptel-anthropic.el | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gptel-anthropic.el b/gptel-anthropic.el
index 9dd2214fed..dde7ab6cc5 100644
--- a/gptel-anthropic.el
+++ b/gptel-anthropic.el
@@ -117,7 +117,8 @@ information if the stream contains it.  Not my best work, I 
know."
            ((looking-at "message_delta")
             ;; collect stop_reason, usage_tokens and prepare tools
             (forward-line 1) (forward-char 5)
-            (when-let* ((tool-use (plist-get info :tool-use)))
+            (when-let* ((tool-use (plist-get info :tool-use))
+                        (response (gptel--json-read)))
               (let* ((data (plist-get info :data))
                      (prompts (plist-get data :messages)))
                 (plist-put ; Append a COPY of response text + tool-use to the 
prompts list
@@ -139,8 +140,7 @@ information if the stream contains it.  Not my best work, I 
know."
                         (plist-put tool-call :input nil)
                         (plist-put tool-call :id 
(gptel--anthropic-unformat-tool-id
                                                   (plist-get tool-call :id))))
-                      tool-use)))
-            (when-let* ((response (gptel--json-read)))
+                      tool-use))
               (plist-put info :output-tokens
                          (map-nested-elt response '(:usage :output_tokens)))
               (plist-put info :stop-reason

Reply via email to