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

    gptel: No advice for tool spec argument preprocessing (#794)
    
    * gptel.el (gptel--preprocess-tool-args, gptel--make-tool,
    gptel-tool, gptel--make-tool-internal):
    To work around inconsistent advice evaluation for cl-struct
    constructors, separate tool construction into two functions:
    `gptel--make-tool-internal' is the cl-struct constructor, now
    unadvised.  `gptel--make-tool' runs the constructor after
    preprocessing the tool spec to change :types to strings (and
    possibly other accommodations in the future) the tool spec to
    change :types to strings (and possibly other accommodations in the
    future).  Leave `gptel-make-tool' unchanged.
    
    The problem of inconsistent advice application to cl-struct
    constructors (which have a compiler macro attached) can be seen
    in the following example.  Place the following in an elisp file
    and native-compile and load it:
    
      ;; -*- lexical-binding: t; -*-
      (cl-defstruct teststruct foo)
    
      (define-advice make-teststruct (:filter-args (rest) modify-args)
        (plist-put rest :foo "changed")
        rest)
    
    Now running (make-teststruct :foo "original") will cause the
    struct to have its :foo key set to either "original" or "changed",
    depending on whether the advice ran.  Whether the advice runs
    appears to depend on the environment and the method of evaluation.
    
    - The advice runs when evaluated in IELM, via pp-eval-last-sexp or
    pp-eval-expression.
    
    - The advice doesn't run when evaluated via eval-last-sexp,
    eval-defun or eval-buffer.
    
    This requires further investigation.
---
 gptel.el | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/gptel.el b/gptel.el
index 3fb4bad0df..c0ceeeb8eb 100644
--- a/gptel.el
+++ b/gptel.el
@@ -1526,7 +1526,7 @@ a tool, use `gptel-make-tool', which see."
   :type '(repeat gptel-tool))
 
 (cl-defstruct (gptel-tool (:constructor nil)
-                          (:constructor gptel--make-tool
+                          (:constructor gptel--make-tool-internal
                            (&key function name description args
                                  async category confirm include
                                  &allow-other-keys))
@@ -1547,11 +1547,6 @@ feed the LLM the results.  You can add tools via
   (confirm nil :type boolean :documentation "Seek confirmation before running 
tool?")
   (include nil :type boolean :documentation "Include tool results in buffer?"))
 
-(define-advice gptel--make-tool (:filter-args (rest) preprocess-args)
-  "Convert symbol :type values to strings in the args in REST."
-  (cl-callf gptel--preprocess-tool-args (plist-get rest :args))
-  rest)
-
 (defun gptel--preprocess-tool-args (spec)
   "Convert symbol :type values in tool SPEC to strings destructively."
   ;; NOTE: Do not use `sequencep' here, as that covers strings too and breaks
@@ -1577,6 +1572,10 @@ feed the LLM the results.  You can add tools via
                        (gptel--preprocess-tool-args element))))))
   spec)
 
+(defun gptel--make-tool (&rest spec)
+  "Construct a gptel-tool according to SPEC."
+  (apply #'gptel--make-tool-internal (gptel--preprocess-tool-args spec)))
+
 (defvar gptel--known-tools nil
   "Alist of gptel tools arranged by category.
 

Reply via email to