branch: externals/ellama
commit 10fa6ce6711c343e0e75c93d0956d2b14d0aae38
Author: Sergey Kostyaev <[email protected]>
Commit: Sergey Kostyaev <[email protected]>
Add view option to ellama‑tools confirmation
Extended ellama-tools-confirm to support a new ‘v’ choice that shows a
buffer
with full argument details before the user makes a decision. Updated the
prompt,
added buffer creation and display logic, and adjusted the confirmation flow
to
handle the new option. The docstring now reflects the additional
functionality.
This improves usability by allowing users to review arguments in full before
approving or denying a tool call.
---
ellama-tools.el | 125 +++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 83 insertions(+), 42 deletions(-)
diff --git a/ellama-tools.el b/ellama-tools.el
index 39121d486f..e3d6d9f0b8 100644
--- a/ellama-tools.el
+++ b/ellama-tools.el
@@ -123,56 +123,97 @@ Key is a function name symbol. Value is a boolean t.")
(defun ellama-tools-confirm (function &rest args)
"Ask user for confirmation before calling FUNCTION with ARGS.
Generates prompt automatically. User can approve once (y), approve
-for all future calls (a), or forbid (n). Returns the result of
-FUNCTION if approved, \"Forbidden by the user\" otherwise."
+for all future calls (a), forbid (n), or view the details in a
+buffer (v) before deciding. Returns the result of FUNCTION if
+approved, \"Forbidden by the user\" otherwise."
(let ((function-name (if (symbolp function)
- (symbol-name function)
- "anonymous-function"))
- (confirmation (gethash function ellama-tools-confirm-allowed nil)))
+ (symbol-name function)
+ "anonymous-function"))
+ (confirmation (gethash function ellama-tools-confirm-allowed nil)))
(cond
;; If user has approved all calls, just execute the function
((or confirmation
- ellama-tools-allow-all
- (cl-find function ellama-tools-allowed))
+ ellama-tools-allow-all
+ (cl-find function ellama-tools-allowed))
(let ((result (apply function args)))
- (if (stringp result)
- result
- (json-encode result))))
+ (if (stringp result)
+ result
+ (json-encode result))))
;; Otherwise, ask for confirmation
(t
;; Generate prompt with truncated string arguments
- (let* ((args-display
- (mapcar (lambda (arg)
- (cond
- ((stringp arg)
- (string-truncate-left
- arg
- ellama-tools-argument-max-length))
- (t
- (format "%S" arg))))
- args))
- (prompt (format "Allow calling %s with arguments: %s?"
- function-name
- (mapconcat #'identity args-display ", ")))
- (answer (read-char-choice
- (format "%s (y)es, (a)lways, (n)o, (r)eply: " prompt)
- '(?y ?a ?n ?r)))
- (result (cond
- ;; Yes - execute function once
- ((eq answer ?y)
- (apply function args))
- ;; Always - remember approval and execute function
- ((eq answer ?a)
- (puthash function t ellama-tools-confirm-allowed)
- (apply function args))
- ;; No - return nil
- ((eq answer ?n)
- "Forbidden by the user")
- ((eq answer ?r)
- (read-string "Answer to the agent: ")))))
- (when result (if (stringp result)
- result
- (json-encode result))))))))
+ (save-window-excursion
+ (let* ((args-display
+ (mapcar (lambda (arg)
+ (cond
+ ((stringp arg)
+ (string-truncate-left
+ arg
+ ellama-tools-argument-max-length))
+ (t
+ (format "%S" arg))))
+ args))
+ (prompt (format "Allow calling %s with arguments: %s?"
+ function-name
+ (mapconcat #'identity args-display ", ")))
+ answer result)
+ (catch 'done
+ (while t
+ (setq answer (read-char-choice
+ (format "%s (y)es, (a)lways, (n)o, (r)eply, (v)iew:
" prompt)
+ '(?y ?a ?n ?r ?v)))
+ (cond
+ ;; View - show buffer with full details
+ ((eq answer ?v)
+ (let* ((buf (get-buffer-create "*Ellama Confirmation*"))
+ (args-full
+ (mapcar (lambda (arg)
+ (cond
+ ((stringp arg)
+ arg)
+ (t
+ (format "%S" arg))))
+ args)))
+ (with-current-buffer buf
+ (erase-buffer)
+ (insert (propertize "Ellama Function Call Confirmation\n"
+ 'face '(:weight bold :height 1.2)))
+ (insert "\n")
+ (insert (format "Function: %s\n\n" function-name))
+ (insert "Arguments:\n")
+ (dolist (arg args-full)
+ (insert (format " - %s\n" arg)))
+ (insert "\n")
+ (insert (propertize "Please review the arguments above.\n"
+ 'face '(:slant italic)))
+ (insert "Return to the minibuffer to make your choice.\n\n")
+ (insert "Available choices:\n")
+ (insert " (y)es - Execute once\n")
+ (insert " (a)lways - Always execute for this function\n")
+ (insert " (n)o - Do not execute\n")
+ (insert " (r)eply - Provide a custom reply\n"))
+ (display-buffer buf)
+ (message "Viewing details in buffer. Return to minibuffer to
choose.")))
+ ;; Yes - execute function once
+ ((eq answer ?y)
+ (setq result (apply function args))
+ (throw 'done t))
+ ;; Always - remember approval and execute function
+ ((eq answer ?a)
+ (puthash function t ellama-tools-confirm-allowed)
+ (setq result (apply function args))
+ (throw 'done t))
+ ;; No - return nil
+ ((eq answer ?n)
+ (setq result "Forbidden by the user")
+ (throw 'done t))
+ ;; Reply - custom response
+ ((eq answer ?r)
+ (setq result (read-string "Answer to the agent: "))
+ (throw 'done t)))))
+ (when result (if (stringp result)
+ result
+ (json-encode result)))))))))
(defun ellama-tools-wrap-with-confirm (tool-plist)
"Wrap a tool's function with automatic confirmation.