Function: gptel--display-tool-calls
gptel--display-tool-calls is a natively compiled function defined in
gptel.el.
Signature
(gptel--display-tool-calls TOOL-CALLS INFO &optional USE-MINIBUFFER)
Documentation
Handle tool call confirmation.
TOOL-CALLS should be a list of tool call specifications or results, structured as:
((tool args callback) ...)
for tool call specifications to be confirmed. INFO contains the state of the request. To prompt for tool call confirmation, use either an overlay in the request buffer or the minibuffer (if USE-MINIBUFFER is non-nil).
Source Code
;; Defined in /nix/store/q3r7g81pvghw7a523kjk2k2zih3pfk8z-emacs-packages-deps/share/emacs/site-lisp/elpa/gptel-20261002.545/gptel.el
(defun gptel--display-tool-calls (tool-calls info &optional use-minibuffer)
"Handle tool call confirmation.
TOOL-CALLS should be a list of tool call specifications or results,
structured as:
((tool args callback) ...)
for tool call specifications to be confirmed. INFO contains the
state of the request. To prompt for tool call confirmation, use
either an overlay in the request buffer or the minibuffer (if
USE-MINIBUFFER is non-nil)."
(let* ((start-marker (plist-get info :position))
(tracking-marker (plist-get info :tracking-marker)))
;; pending tool calls look like ((tool callback args) ...)
(with-current-buffer (marker-buffer start-marker)
(if (or use-minibuffer ;prompt for confirmation from the minibuffer
buffer-read-only ;TEMP(tool-preview) Handle read-only buffers better
(get-char-property
(max (point-min) (1- (or tracking-marker start-marker)))
'read-only))
(let* ((minibuffer-allow-text-properties t)
(backend-name (gptel-backend-name (plist-get info :backend)))
(tool-call-names
(mapconcat (lambda (c) (propertize (gptel-tool-name (car c))
'face 'font-lock-keyword-face))
tool-calls ", "))
(len (length tool-calls))
(prompt (format "%s wants to run %s tool %s (%s). "
backend-name len (if (> len 1) "calls" "call")
tool-call-names))
(choices '((?y "Run tools") (?n "Cancel (resumable)")
(?r "Steer") (?i "Inspect or edit")))
(choice (read-multiple-choice prompt choices)))
(pcase (car choice)
(?y (gptel--accept-tool-calls tool-calls))
(?n (gptel--reject-tool-calls))
(?r (gptel--steer-tool-calls tool-calls nil info))
(?i (gptel--inspect-tool-calls tool-calls info))))
;; Prompt for confirmation from the response 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: " 'face 'font-lock-string-face)
(propertize "C-c C-k" 'face 'help-key-binding)
(propertize ", Steer: " 'face 'font-lock-string-face)
(propertize "C-c C-r" 'face 'help-key-binding)
(propertize ", Inspect: " 'face 'font-lock-string-face)
(propertize "C-c C-i" 'face 'help-key-binding)))
(confirm-strings)
;; 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)))
(preview-handlers)
(ov (or (cdr-safe (get-char-property-and-overlay
start-marker 'gptel-tool))
(make-overlay ov-start (or tracking-marker start-marker)
nil nil nil)))
(arg-values)
(prompt-ov))
(if tracking-marker
;; "Unlock" the tracking marker before inserting tool call previews
(set-marker-insertion-type tracking-marker t)
;; If the cursor is at the overlay-end, it ends up outside, so move it back
(when (= (point) start-marker) (ignore-errors (backward-char))))
(save-excursion
(goto-char (overlay-end ov))
(pcase-dolist (`(,tool-spec ,arg-plist _) tool-calls)
;; Call tool-specific confirmation prompt
(setq arg-values (gptel--map-tool-args tool-spec arg-plist))
(if-let* ((funcs (cdr (assoc (gptel-tool-name tool-spec)
gptel--tool-preview-alist)))
((functionp (car-safe funcs))))
;;preview-teardown func preview-handle overlay/buffer
(push (list (cadr funcs) (funcall (car funcs) arg-values info))
preview-handlers)
(push (gptel--format-tool-call (gptel-tool-name tool-spec) arg-values)
confirm-strings)))
(and confirm-strings (apply #'insert (nreverse confirm-strings)))
(add-text-properties (overlay-end ov) (1- (point))
'(read-only t font-lock-fontified t))
;; "Lock" the tracking marker again
(when tracking-marker (set-marker-insertion-type tracking-marker nil))
(setq prompt-ov (make-overlay (overlay-end ov) (point) nil t))
(overlay-put
prompt-ov 'before-string
(concat
"\n"
(propertize " " 'display `(space :align-to (- right ,(length actions-string) 2))
'face '(:inherit font-lock-string-face :underline t :extend t))
actions-string
(format (propertize "\n%s wants to run:\n\n"
'face 'font-lock-string-face)
backend-name)))
(overlay-put
prompt-ov 'after-string
(concat (propertize "\n" 'face
'(:inherit font-lock-string-face :underline t :extend t))))
(overlay-put prompt-ov 'evaporate t)
(overlay-put ov 'prompt (cons prompt-ov (overlay-get ov 'prompt)))
(move-overlay ov ov-start (point)))
;; Add confirmation prompt to the overlay
(when preview-handlers
(overlay-put ov 'previews
(nconc (overlay-get ov 'previews) preview-handlers)))
;; Including INFO is required for tool call inspection (state
;; management and updates)
(overlay-put ov 'info info)
(overlay-put ov 'mouse-face 'highlight)
(overlay-put ov 'gptel-tool
(nconc (overlay-get ov 'gptel-tool) tool-calls))
(overlay-put ov 'help-echo
(concat "Tool call(s) requested: " actions-string))
(overlay-put ov 'keymap gptel-tool-call-actions-map)
prompt-ov)))))