branch: elpa/gptel
commit 08014b56671b58f8ed0d6b7a0eedb830406750c2
Author: Psionik K <73710933+psioni...@users.noreply.github.com>
Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>

    gptel: Separate tool confirmation and result insertion
    
    * gptel.el (gptel--insert-response, gptel--display-tool-calls,
    gptel--display-tool-results): Separate `gptel--display-tool-calls'
    into two functions, one for handling tool confirmations and one
    for results.  This is in preparation for the breaking API change
    to `gptel-request'.
    
    NOTE: Tool result insertion into buffers is broken as of this
    commit.
    
    Adjust the predicates for handling tools in
    `gptel--insert-response'.
    
    * gptel-curl.el (gptel-curl--stream-insert-response): Ditto.
---
 gptel-curl.el      |   4 +-
 gptel-transient.el |   2 +
 gptel.el           | 222 +++++++++++++++++++++++++++--------------------------
 3 files changed, 120 insertions(+), 108 deletions(-)

diff --git a/gptel-curl.el b/gptel-curl.el
index eae18229a6..7972e6e68e 100644
--- a/gptel-curl.el
+++ b/gptel-curl.el
@@ -258,7 +258,9 @@ See `gptel--url-get-response' for details."
            (insert response)
            (run-hooks 'gptel-post-stream-hook)))))
     ((pred consp)
-     (gptel--display-tool-calls response info))))
+     (gptel--display-tool-calls response info))
+    (_                                  ; placeholder for later condition
+     (gptel--display-tool-results response info))))
 
 (defun gptel-curl--stream-filter (process output)
   (let* ((fsm (alist-get process gptel--request-alist))
diff --git a/gptel-transient.el b/gptel-transient.el
index 8c455d807e..db89c86abe 100644
--- a/gptel-transient.el
+++ b/gptel-transient.el
@@ -1230,6 +1230,7 @@ This sets the variable `gptel-include-tool-results', 
which see."
             (lambda (resp info)
               (cond
                ((stringp resp) (message "%s response: %s" backend-name resp))
+               ;; XXX Check types
                ((consp resp) (gptel--display-tool-calls resp info 'minibuffer))
                ((and (null resp) (plist-get info :error))
                 (message "%s response error: %s"
@@ -1242,6 +1243,7 @@ This sets the variable `gptel-include-tool-results', 
which see."
                ((stringp resp) (kill-new resp)
                 (message "%s response: \"%s\" copied to kill-ring." 
backend-name
                          (truncate-string-to-width resp 30)))
+               ;; XXX Check types
                ((consp resp) (gptel--display-tool-calls resp info 'minibuffer))
                ((and (null resp) (plist-get info :error))
                 (message "%s response error: %s" backend-name
diff --git a/gptel.el b/gptel.el
index ed2828e2e7..f76a8cd810 100644
--- a/gptel.el
+++ b/gptel.el
@@ -2359,8 +2359,10 @@ See `gptel--url-get-response' for details."
              (plist-put info :tracking-marker (setq tracking-marker 
(point-marker)))
              ;; for uniformity with streaming responses
              (set-marker-insertion-type tracking-marker t)))))
-      ((pred consp)                  ;tool call or tool result?
-       (gptel--display-tool-calls response info)))))
+      ((pred consp)
+       (gptel--display-tool-calls response info))
+      (_
+       (gptel--display-tool-results response info)))))
 
 (defun gptel--create-prompt (&optional prompt-end)
   "Return a full conversation prompt from the contents of this buffer.
@@ -2722,111 +2724,117 @@ RESPONSE is
 for tool call results.  INFO contains the state of the request."
   (let* ((start-marker (plist-get info :position))
          (tracking-marker (plist-get info :tracking-marker)))
-    (if (cl-typep (caar response) 'gptel-tool) ;tool calls
-        ;; pending tool calls look like ((tool callback args) ...)
-        (with-current-buffer (plist-get info :buffer)
-          (if use-minibuffer        ;prompt for confirmation from the 
minibuffer
-              (let* ((minibuffer-allow-text-properties t)
-                     (backend-name (gptel-backend-name (plist-get info 
:backend)))
-                     (prompt (format "%s wants to run " backend-name)))
-                (map-y-or-n-p
-                 (lambda (tool-call-spec)
-                   (concat prompt (propertize (gptel-tool-name (car 
tool-call-spec))
-                                              'face 'font-lock-keyword-face)
-                           ": "))
-                 (lambda (tcs) (gptel--accept-tool-calls (list tcs) nil))
-                 response '("tool call" "tool calls" "run")
-                 `((?i ,(lambda (_) (save-window-excursion
-                                 (with-selected-window
-                                     (gptel--inspect-fsm gptel--fsm-last)
-                                   (goto-char (point-min))
-                                   (when (search-forward-regexp "^:tool-use" 
nil t)
-                                    (forward-line 0) (hl-line-highlight))
-                                   (use-local-map
-                                    (make-composed-keymap
-                                     (define-keymap "q" (lambda () 
(interactive)
-                                                          (quit-window)
-                                                          
(exit-recursive-edit)))
-                                     (current-local-map)))
-                                   (recursive-edit) nil)))
-                    "inspect call(s)"))))
-            ;; Prompt for confirmation from the chat buffer
-            (let* ((backend-name (gptel-backend-name (plist-get info 
:backend)))
-                   (actions-string
-                    (concat (propertize "Run tools: " 'face 
'font-lock-string-face)
-                            (propertize "C-c C-c" 'face 'help-key-binding)
-                            (propertize ", Cancel request: " 'face 
'font-lock-string-face)
-                            (propertize "C-c C-k" 'face 'help-key-binding)
-                            (propertize ", Inspect: " 'face 
'font-lock-string-face)
-                            (propertize "C-c C-i" 'face 'help-key-binding)))
-                   (confirm-strings
-                    (list (concat "\n" actions-string
-                                  (propertize "\n" 'face '(:inherit 
font-lock-string-face
-                                                           :underline t 
:extend t))
-                                  (format (propertize "\n%s wants to run:\n"
-                                                      'face 
'font-lock-string-face)
-                                          backend-name))))
-                   ;; FIXME(tool) use a wrapper instead of a manual 
text-property search,
-                   ;; this is fragile
-                   (ov-start (save-excursion
-                               (goto-char start-marker)
-                               (text-property-search-backward 'gptel 'response)
-                               (point)))
-                   (ov (or (cdr-safe (get-char-property-and-overlay
-                                      start-marker 'gptel-tool))
-                           (make-overlay ov-start (or tracking-marker 
start-marker)))))
-              ;; If the cursor is at the overlay-end, it ends up outside, so 
move it back
-              (unless tracking-marker
-                (when (= (point) start-marker) (ignore-errors 
(backward-char))))
-              (pcase-dolist (`(,tool-spec ,arg-values _) response)
-                (push (gptel--format-tool-call (gptel-tool-name tool-spec) 
arg-values)
-                      confirm-strings))
-              (push (concat (propertize "\n" 'face '(:inherit 
font-lock-string-face
-                                                     :underline t :extend t)))
-                    confirm-strings)
-              ;; Add confirmation prompt to the overlay
-              (overlay-put ov 'after-string
-                           (apply #'concat (nreverse confirm-strings)))
-              (overlay-put ov 'mouse-face 'highlight)
-              (overlay-put ov 'gptel-tool response)
-              (overlay-put ov 'help-echo
-                           (concat "Tool call(s) requested: " actions-string))
-              (overlay-put ov 'keymap
-                           (define-keymap
-                             "<mouse-1>" #'gptel--dispatch-tool-calls
-                             "C-c C-c" #'gptel--accept-tool-calls
-                             "C-c C-k" #'gptel--reject-tool-calls
-                             "C-c C-i"
-                             (lambda () (interactive)
-                               (with-selected-window
-                                   (gptel--inspect-fsm gptel--fsm-last)
-                                 (goto-char (point-min))
-                                 (when (search-forward-regexp "^:tool-use" nil 
t)
-                                   (forward-line 0)
-                                   (hl-line-highlight)))))))))
-      ;; finished tool call results look like ((name args result) ...)
-      ;; Insert tool results
-      (when gptel-include-tool-results
-        (with-current-buffer (marker-buffer start-marker)
-          (cl-loop
-           for (name args result) in response
-           with include-names =
-           (mapcar #'gptel-tool-name
-                   (cl-remove-if-not #'gptel-tool-include (plist-get info 
:tools)))
-           if (or (eq gptel-include-tool-results t) (member name 
include-names))
-           do (funcall
-               (plist-get info :callback)
-               (if (derived-mode-p 'org-mode)
-                   (concat "\n:TOOL_CALL:\n" (gptel--format-tool-call name 
args)
-                           "\n" (gptel--to-string result) "\n:END:\n")
-                 (concat "\n```\n" name "\n" (gptel--to-string result) 
"\n```"))
-               info)
-           (when (derived-mode-p 'org-mode) ;fold drawer
-             (ignore-errors
-               (save-excursion
-                 (goto-char (plist-get info :tracking-marker))
-                 (forward-line -1) ;org-fold-hide-drawer-toggle requires Emacs 
29.1
-                 (when (looking-at "^:END:") (org-cycle)))))))))))
+    (with-current-buffer (plist-get info :buffer)
+      (if use-minibuffer            ;prompt for confirmation from the 
minibuffer
+          (let* ((minibuffer-allow-text-properties t)
+                 (backend-name (gptel-backend-name (plist-get info :backend)))
+                 (prompt (format "%s wants to run " backend-name)))
+            (map-y-or-n-p
+             (lambda (tool-call-spec)
+               (concat prompt (propertize (gptel-tool-name (car 
tool-call-spec))
+                                          'face 'font-lock-keyword-face)
+                       ": "))
+             (lambda (tcs) (gptel--accept-tool-calls (list tcs) nil))
+             response '("tool call" "tool calls" "run")
+             `((?i ,(lambda (_) (save-window-excursion
+                             (with-selected-window
+                                 (gptel--inspect-fsm gptel--fsm-last)
+                               (goto-char (point-min))
+                               (when (search-forward-regexp "^:tool-use" nil t)
+                                 (forward-line 0) (hl-line-highlight))
+                               (use-local-map
+                                (make-composed-keymap
+                                 (define-keymap "q" (lambda () (interactive)
+                                                      (quit-window)
+                                                      (exit-recursive-edit)))
+                                 (current-local-map)))
+                               (recursive-edit) nil)))
+                   "inspect call(s)"))))
+        ;; Prompt for confirmation from the chat buffer
+        (let* ((backend-name (gptel-backend-name (plist-get info :backend)))
+               (actions-string
+                (concat (propertize "Run tools: " 'face 'font-lock-string-face)
+                        (propertize "C-c C-c" 'face 'help-key-binding)
+                        (propertize ", Cancel request: " 'face 
'font-lock-string-face)
+                        (propertize "C-c C-k" 'face 'help-key-binding)
+                        (propertize ", Inspect: " 'face 'font-lock-string-face)
+                        (propertize "C-c C-i" 'face 'help-key-binding)))
+               (confirm-strings
+                (list (concat "\n" actions-string
+                              (propertize "\n" 'face '(:inherit 
font-lock-string-face
+                                                                :underline t 
:extend t))
+                              (format (propertize "\n%s wants to run:\n"
+                                                  'face 'font-lock-string-face)
+                                      backend-name))))
+               ;; FIXME(tool) use a wrapper instead of a manual text-property 
search,
+               ;; this is fragile
+               (ov-start (save-excursion
+                           (goto-char start-marker)
+                           (text-property-search-backward 'gptel 'response)
+                           (point)))
+               (ov (or (cdr-safe (get-char-property-and-overlay
+                                  start-marker 'gptel-tool))
+                       (make-overlay ov-start (or tracking-marker 
start-marker)))))
+          ;; If the cursor is at the overlay-end, it ends up outside, so move 
it back
+          (unless tracking-marker
+            (when (= (point) start-marker) (ignore-errors (backward-char))))
+          (pcase-dolist (`(,tool-spec ,arg-values _) response)
+            (push (gptel--format-tool-call (gptel-tool-name tool-spec) 
arg-values)
+                  confirm-strings))
+          (push (concat (propertize "\n" 'face '(:inherit font-lock-string-face
+                                                          :underline t :extend 
t)))
+                confirm-strings)
+          ;; Add confirmation prompt to the overlay
+          (overlay-put ov 'after-string
+                       (apply #'concat (nreverse confirm-strings)))
+          (overlay-put ov 'mouse-face 'highlight)
+          (overlay-put ov 'gptel-tool response)
+          (overlay-put ov 'help-echo
+                       (concat "Tool call(s) requested: " actions-string))
+          (overlay-put ov 'keymap
+                       (define-keymap
+                         "<mouse-1>" #'gptel--dispatch-tool-calls
+                         "C-c C-c" #'gptel--accept-tool-calls
+                         "C-c C-k" #'gptel--reject-tool-calls
+                         "C-c C-i"
+                         (lambda () (interactive)
+                           (with-selected-window
+                               (gptel--inspect-fsm gptel--fsm-last)
+                             (goto-char (point-min))
+                             (when (search-forward-regexp "^:tool-use" nil t)
+                               (forward-line 0)
+                               (hl-line-highlight)))))))))))
+
+(defun gptel--display-tool-results (response info)
+  "Display tool results.
+RESPONSE is
+
+ ((name args result) ...)
+
+for tool call results.  INFO contains the state of the request."
+  (let* ((start-marker (plist-get info :position))
+         (tracking-marker (plist-get info :tracking-marker)))
+    (when gptel-include-tool-results
+      (with-current-buffer (marker-buffer start-marker)
+        (cl-loop
+         for (name args result) in response
+         with include-names =
+         (mapcar #'gptel-tool-name
+                 (cl-remove-if-not #'gptel-tool-include (plist-get info 
:tools)))
+         if (or (eq gptel-include-tool-results t) (member name include-names))
+         do (funcall
+             (plist-get info :callback)
+             (if (derived-mode-p 'org-mode)
+                 (concat "\n:TOOL_CALL:\n" (gptel--format-tool-call name args)
+                         "\n" (gptel--to-string result) "\n:END:\n")
+               (concat "\n```\n" name "\n" (gptel--to-string result) "\n```"))
+             info)
+         (when (derived-mode-p 'org-mode) ;fold drawer
+           (ignore-errors
+             (save-excursion
+               (goto-char (plist-get info :tracking-marker))
+               (forward-line -1) ;org-fold-hide-drawer-toggle requires Emacs 
29.1
+               (when (looking-at "^:END:") (org-cycle))))))))))
 
 (defun gptel--format-tool-call (name arg-values)
   "Format a tool call for display in the buffer.

Reply via email to