branch: elpa/gptel
commit ead44a2891f4c384546c2032c8bb488ca0e8b890
Author: Trannie Carter <[email protected]>
Commit: Karthik Chikmagalur <[email protected]>

    gptel-ollama: Handle streaming tool calls
    
    * gptel-ollama.el (gptel-curl--parse-stream): Handle streaming
    tool calls.  The handling is identical to the non-streaming case,
    as it appears Ollama sends the entire tool call in one response
    chunk.
    
    * gptel-request.el (gptel-request): Don't block streaming when
    using Ollama + tools.
---
 gptel-ollama.el  | 18 +++++++++++++++---
 gptel-request.el |  3 ---
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/gptel-ollama.el b/gptel-ollama.el
index c17e8b4150d..abecfb6c551 100644
--- a/gptel-ollama.el
+++ b/gptel-ollama.el
@@ -55,9 +55,22 @@ Intended for internal use only.")
           (setq pt (point))
           (let ((done (map-elt content :done))
                 (reasoning (map-nested-elt content '(:message :thinking)))
-                (response (map-nested-elt content '(:message :content))))
+                (response (map-nested-elt content '(:message :content)))
+                (tool-calls (map-nested-elt content '(:message :tool_calls))))
             (when (and response (not (eq response :null)))
               (push response content-strs))
+            (when (and tool-calls (not (eq tool-calls :null)))
+              (gptel--inject-prompt
+               (plist-get info :backend) (plist-get info :data)
+               `(:role "assistant" :content :null :tool_calls ,(vconcat 
tool-calls)))
+              (cl-loop
+               for tool-call across tool-calls  ;replace ":arguments" with 
":args"
+               for call-spec = (copy-sequence (plist-get tool-call :function))
+               do (plist-put call-spec :args
+                             (plist-get call-spec :arguments))
+               (plist-put call-spec :arguments nil)
+               collect call-spec into tool-use
+               finally (plist-put info :tool-use tool-use)))
             (if (and reasoning (not (eq reasoning :null)))
                 (plist-put info :reasoning
                            (concat (plist-get info :reasoning) reasoning))
@@ -124,8 +137,7 @@ Store response metadata in state INFO."
     (when (and gptel-use-tools gptel-tools)
       ;; TODO(tool): Find out how to force tool use for Ollama
       (plist-put prompts-plist :tools
-                 (gptel--parse-tools backend gptel-tools))
-      (plist-put prompts-plist :stream :json-false))
+                 (gptel--parse-tools backend gptel-tools)))
     ;; if the temperature and max-tokens aren't set as
     ;; backend/model-specific, use the global settings
     (when (and gptel-temperature (not (plist-get options-plist :temperature)))
diff --git a/gptel-request.el b/gptel-request.el
index dc193be7894..955f1c09217 100644
--- a/gptel-request.el
+++ b/gptel-request.el
@@ -2050,9 +2050,6 @@ Initiate the request when done."
              ;; TODO(tool) Limit tool use to capable models after documenting 
:capabilities
              ;; (gptel-use-tools (and (gptel--model-capable-p 'tool-use) 
gptel-use-tools))
              (stream (and (plist-get info :stream) gptel-use-curl gptel-stream
-                          ;; HACK(tool): no stream if Ollama + tools.  Need to 
find a better way
-                          (not (and (eq (type-of gptel-backend) 'gptel-ollama)
-                                    gptel-tools gptel-use-tools))
                           ;; Check model-specific request-params for streaming 
preference
                           (let* ((model-params (gptel--model-request-params 
gptel-model))
                                  (stream-spec (plist-get model-params 
:stream)))

Reply via email to