branch: elpa/gptel
commit a6ee2e07b5f23ea3211141fad7cccb5ccf3fbb57
Author: Karthik Chikmagalur <karthikchikmaga...@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>

    gptel-openai: Handle reasoning_content in gptel-openai (#1028)
    
    Look for "reasoning_content" fields in the OpenAI-API response
    parsers.  Previously we only looked for "reasoning" fields,
    delegating "reasoning_content" handling to the separate
    gptel-deepseek backend.
    
    It turns out that OpenAI-compatible APIs are now split on this:
    
    - "reasoning": Used by Openrouter and some others
    - "reasoning_content": Used by vLLM, Llama.cpp, sglang, Deepseek
    and others
    
    A separate Deepseek backend is still required as it has extra
    requirements for the messages array format, see the implementation
    of `gptel--parse-buffer' for Deepseek.
    
    * gptel-openai.el (gptel-curl--parse-stream,
    gptel--parse-response): Handle "reasoning_content" field.
    
    * gptel-openai-extras.el (gptel-curl--parse-stream,
    gptel--parse-response): Remove methods specialized to Deepseek for
    handling "reasoning_content", as the underlying OpenAI
    implementation will handle this now.
---
 gptel-openai-extras.el | 31 -------------------------------
 gptel-openai.el        |  6 ++++--
 2 files changed, 4 insertions(+), 33 deletions(-)

diff --git a/gptel-openai-extras.el b/gptel-openai-extras.el
index 22064e02578..c45b4a4ab9c 100644
--- a/gptel-openai-extras.el
+++ b/gptel-openai-extras.el
@@ -278,37 +278,6 @@ parameters."
                               (:copier nil)
                               (:constructor gptel--make-deepseek)))
 
-(cl-defmethod gptel-curl--parse-stream :before ((_backend gptel-deepseek) info)
-  "Capture reasoning block stream into INFO."
-  (unless (eq (plist-get info :reasoning-block) 'done)
-    (save-excursion
-      (ignore-errors
-        (catch 'done
-          (while (re-search-forward "^data:" nil t)
-            (unless (looking-at-p " *\\[DONE\\]")
-              (when-let* ((response (gptel--json-read))
-                          (delta (map-nested-elt response '(:choices 0 
:delta))))
-                (if-let* ((reasoning (plist-get delta :reasoning_content))
-                          ((not (eq reasoning :null))))
-                    ;; :reasoning will be consumed by the gptel-request 
callback
-                    ;; and reset by the stream filter.
-                    (plist-put info :reasoning
-                               (concat (plist-get info :reasoning) reasoning))
-                  ;; Done with reasoning if we get non-empty content
-                  (when-let* (((plist-member info :reasoning)) ;Is this a 
reasoning model?
-                              (content (plist-get delta :content)) ;Started 
receiving text content?
-                              ((not (or (eq content :null) (string-empty-p 
content)))))
-                    (plist-put info :reasoning-block t) ;Signal end of 
reasoning block
-                    (throw 'done t)))))))))))
-
-(cl-defmethod gptel--parse-response :before ((_backend gptel-deepseek) 
response info)
-  "Capture reasoning block in RESPONSE into INFO."
-  (let* ((choice0 (map-nested-elt response '(:choices 0)))
-         (message (plist-get choice0 :message))
-         (reasoning (plist-get message :reasoning_content)))
-    (when (and (stringp reasoning) (length> reasoning 0))
-      (plist-put info :reasoning reasoning))))
-
 (cl-defmethod gptel--parse-buffer :around ((_backend gptel-deepseek) 
_max-entries)
   "Merge successive prompts in the prompts list that have the same role.
 
diff --git a/gptel-openai.el b/gptel-openai.el
index f87642cff36..79bed587dd5 100644
--- a/gptel-openai.el
+++ b/gptel-openai.el
@@ -240,7 +240,8 @@ information if the stream contains it."
                       (push (plist-get func :arguments) (plist-get info 
:partial_json)))))
                 ;; Check for reasoning blocks, currently only used by 
Openrouter
                 (unless (eq (plist-get info :reasoning-block) 'done)
-                  (if-let* ((reasoning-chunk (plist-get delta :reasoning)) 
;for Openrouter and co
+                  (if-let* ((reasoning-chunk (or (plist-get delta :reasoning) 
;for Openrouter and co
+                                                 (plist-get delta 
:reasoning_content))) ;for Deepseek, Llama.cpp
                             ((not (or (eq reasoning-chunk :null) 
(string-empty-p reasoning-chunk)))))
                       (plist-put info :reasoning
                                  (concat (plist-get info :reasoning) 
reasoning-chunk))
@@ -281,7 +282,8 @@ Mutate state INFO with response metadata."
        collect call-spec into tool-use
        finally (plist-put info :tool-use tool-use)))
     (when (and content (not (or (eq content :null) (string-empty-p content))))
-      (when-let* ((reasoning (plist-get message :reasoning)) ;look for 
reasoning blocks
+      (when-let* ((reasoning (or (plist-get message :reasoning) ;for 
Openrouter and co
+                                 (plist-get message :reasoning_content))) ;for 
Deepseek, Llama.cpp
                   ((and (stringp reasoning) (not (string-empty-p reasoning)))))
         (plist-put info :reasoning reasoning))
       content)))

Reply via email to