Fix org-ql-select-rifle

This commit is contained in:
Phil Bajsicki 2025-04-15 21:17:23 +02:00
parent f7b3de3789
commit 44d56bdefd
2 changed files with 451 additions and 432 deletions

View file

@ -120,6 +120,12 @@ Stuff, headers, etc.
;;; Code:) ;;; Code:)
#+end_src #+end_src
** gptel-org-tools
Collects into =gptel-org-tools= list, distinct from =gptel-tools=
#+begin_src elisp
(defvar gptel-org-tools '())
#+end_src
** The tools ** The tools
*** Emacs *** Emacs
These tools are primarily concerned with Emacs, Emacs Lisp, and files-or-buffers. These tools are primarily concerned with Emacs, Emacs Lisp, and files-or-buffers.
@ -133,7 +139,7 @@ E.g. can't find the right ~org-ql-select~ query? Let's use an eldritch abominati
Highly not recommended, but sometimes an LLM can pull a rabbit out of pure entropy. Highly not recommended, but sometimes an LLM can pull a rabbit out of pure entropy.
#+begin_src elisp :tangle no #+begin_src elisp :tangle no
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (elisp) :function (lambda (elisp)
(unless (stringp elisp) (error "elisp code must be a string")) (unless (stringp elisp) (error "elisp code must be a string"))
@ -145,7 +151,8 @@ Highly not recommended, but sometimes an LLM can pull a rabbit out of pure entro
:args (list '(:name "eval" :args (list '(:name "eval"
:type string :type string
:description "The Emacs Lisp code to evaluate.")) :description "The Emacs Lisp code to evaluate."))
:category "emacs")) :category "emacs"
:confirm t))
#+end_src #+end_src
**** list-buffers **** list-buffers
@ -155,7 +162,7 @@ The rationale behind using ~ibuffer~ is the same as with dired. They both displa
Seems to be one of the most reliable tools in the basket... mostly because Seems to be one of the most reliable tools in the basket... mostly because
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (arg) :function (lambda (arg)
(with-temp-buffer (with-temp-buffer
@ -181,7 +188,7 @@ Be sure to customize the function to point to your org directory, if you wish. I
#+end_comment #+end_comment
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (dir) :function (lambda (dir)
(with-temp-buffer (with-temp-buffer
@ -200,7 +207,7 @@ Be sure to customize the function to point to your org directory, if you wish. I
**** find-buffer-visiting **** find-buffer-visiting
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (filename) :function (lambda (filename)
(bufferp (find-buffer-visiting (expand-file-name filename)))) (bufferp (find-buffer-visiting (expand-file-name filename))))
@ -211,24 +218,27 @@ Be sure to customize the function to point to your org directory, if you wish. I
:description "The filename to compare to open buffers.")) :description "The filename to compare to open buffers."))
:category "org-mode")) :category "org-mode"))
#+end_src #+end_src
**** find-file-noselect **** open-file-inactive
Continuation from above. Open a file into a buffer for processing. Onec it's found by dired-list. Continuation from above. Open a file into a buffer for processing, once it's found by dired-list.
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (file) :function (lambda (file)
(find-file-noselect file)) (with-current-buffer (get-buffer-create file)
:name "find-file-noselect" (insert-file-contents file)
:description "Open the file in a buffer. This doesn't interfere with the user." (current-buffer)))
:name "open-file-inactive"
:description "Open the file in a background buffer. This doesn't interfere with the user."
:args (list '(:name "file" :args (list '(:name "file"
:type string :type string
:description "Path to file..")) :description "Path to file.."))
:category "filesystem")) :category "filesystem"))
#+end_src #+end_src
**** read-file-contents **** read-file-contents
This reads file contents, This reads file contents,
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (filename) :function (lambda (filename)
(with-temp-buffer (with-temp-buffer
@ -243,7 +253,7 @@ This reads file contents,
#+end_src #+end_src
**** describe-variable **** describe-variable
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (var) :function (lambda (var)
(let ((symbol (intern var))) (let ((symbol (intern var)))
@ -260,7 +270,7 @@ This reads file contents,
**** describe-function **** describe-function
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (fun) :function (lambda (fun)
(let ((symbol (intern fun))) (let ((symbol (intern fun)))
@ -307,7 +317,6 @@ Pretty simple, does what it says on the tin. It gets all the tags from the =buff
This is not, by any means, sufficient, but I do tag people and specific events frequently enough that it helps save on the context window. This is not, by any means, sufficient, but I do tag people and specific events frequently enough that it helps save on the context window.
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-extract-tags (buffer) (defun gptel-org-tools--org-extract-tags (buffer)
(interactive "bBuffer: ")
(with-current-buffer buffer (with-current-buffer buffer
(let ((tags '())) (let ((tags '()))
(org-map-entries (org-map-entries
@ -319,7 +328,7 @@ This is not, by any means, sufficient, but I do tag people and specific events f
(push tag tags)))))) (push tag tags))))))
(sort (-uniq tags) #'string<)))) (sort (-uniq tags) #'string<))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-extract-tags :function #'gptel-org-tools--org-extract-tags
:name "org-extract-tags" :name "org-extract-tags"
@ -337,7 +346,6 @@ Then we need to pull /some/ information from the buffer, without dragging the en
Therefore, headings. A reasonable amount of information, and still keeping the signal-to-noise ratio pretty decent. Therefore, headings. A reasonable amount of information, and still keeping the signal-to-noise ratio pretty decent.
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-extract-headings (buffer) (defun gptel-org-tools--org-extract-headings (buffer)
(interactive "bBuffer: ")
(with-current-buffer buffer (with-current-buffer buffer
(org-map-entries (org-map-entries
#'(buffer-substring-no-properties #'(buffer-substring-no-properties
@ -346,7 +354,7 @@ Therefore, headings. A reasonable amount of information, and still keeping the s
t t
'file))) 'file)))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-extract-headings :function #'gptel-org-tools--org-extract-headings
:name "org-extract-headings" :name "org-extract-headings"
@ -366,6 +374,11 @@ My current goal is to replace this monstrosity with individual functions for eac
But in the interim, this works. Kind of. But in the interim, this works. Kind of.
#+begin_comment
Currently *not* tangled, as I'm testing breaking out each type of query into its own individual tool.
#+end_comment
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-ql-select (buf query) (defun gptel-org-tools--org-ql-select (buf query)
(org-ql-select (org-ql-select
@ -381,7 +394,7 @@ But in the interim, this works. Kind of.
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position)))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select :function #'gptel-org-tools--org-ql-select
:name "org-ql-select" :name "org-ql-select"
@ -417,7 +430,6 @@ But, any customizations to tweak this is left to the user, as everyone has their
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-ql-select-dates (buf date) (defun gptel-org-tools--org-ql-select-dates (buf date)
(interactive "fBuffer: \nsDate (YYYY or YYYY-MM): ")
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,date) `(heading ,date)
@ -427,7 +439,7 @@ But, any customizations to tweak this is left to the user, as everyone has their
(org-end-of-subtree))))) (org-end-of-subtree)))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-dates :function #'gptel-org-tools--org-ql-select-dates
:name "org-ql-select-dates" :name "org-ql-select-dates"
@ -445,7 +457,7 @@ This is still work in progress, the idea is to have the LLM check my calendar an
It works, in principle, but I haven't been able to find a use for it yet. The real challenge is in building a context where the tools integrate with each-other in a way that makes sense. For now, this exists. It works, in principle, but I haven't been able to find a use for it yet. The real challenge is in building a context where the tools integrate with each-other in a way that makes sense. For now, this exists.
#+begin_src elisp #+begin_src elisp
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (days) :function (lambda (days)
(with-temp-buffer (with-temp-buffer
@ -479,7 +491,7 @@ Retrieve the headings where the heading matches query..
(line-end-position)))))) (line-end-position))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-headings :function #'gptel-org-tools--org-ql-select-headings
:name "org-ql-select-headings" :name "org-ql-select-headings"
@ -500,14 +512,14 @@ Retrieve all the headings where either heading or content matches query.
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(rifle ,query) `(rifle ,query)
:action :action #'(lambda () :action #'(lambda ()
(concat (concat
(buffer-substring-no-properties (buffer-substring-no-properties
(line-beginning-position) (line-beginning-position)
(line-end-position)))))) (line-end-position))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-headings-rifle :function #'gptel-org-tools--org-ql-select-headings-rifle
:name "org-ql-select-headings-rifle" :name "org-ql-select-headings-rifle"
@ -537,7 +549,7 @@ This pulls all the headings (and their contents) when they match tags (without i
(line-beginning-position))))))) (line-beginning-position)))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-tags-local :function #'gptel-org-tools--org-ql-select-tags-local
:name "org-ql-select-tags-local" :name "org-ql-select-tags-local"
@ -567,7 +579,7 @@ This pulls all the headings (and their contents) when they match tags (with inhe
(line-beginning-position))))))) (line-beginning-position)))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-tags :function #'gptel-org-tools--org-ql-select-tags
:name "org-ql-select-tags" :name "org-ql-select-tags"
@ -585,8 +597,10 @@ This pulls all the headings (and their contents) when they match tags (with inhe
And, the "grab everything that matches" tool. And, the "grab everything that matches" tool.
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-ql-select-rifle (buf query) (defun gptel-org-tools--org-ql-select-rifle (buf query)
(let ((buffer (get-buffer buf)))
(if buffer
(org-ql-select (org-ql-select
(get-buffer buf) buffer
`(rifle ,query) `(rifle ,query)
:action #'(lambda () :action #'(lambda ()
(concat (concat
@ -594,9 +608,10 @@ And, the "grab everything that matches" tool.
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))
(message "Buffer '%s' does not exist." buf))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-rifle :function #'gptel-org-tools--org-ql-select-rifle
:name "org-ql-select-rifle" :name "org-ql-select-rifle"

View file

@ -34,7 +34,9 @@
;;; Code:) ;;; Code:)
(add-to-list 'gptel-tools (defvar gptel-org-tools '())
(add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (arg) :function (lambda (arg)
(with-temp-buffer (with-temp-buffer
@ -50,7 +52,7 @@
:optional t)) :optional t))
:category "emacs")) :category "emacs"))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (dir) :function (lambda (dir)
(with-temp-buffer (with-temp-buffer
@ -66,7 +68,7 @@
:optional t)) :optional t))
:category "filesystem")) :category "filesystem"))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (filename) :function (lambda (filename)
(bufferp (find-buffer-visiting (expand-file-name filename)))) (bufferp (find-buffer-visiting (expand-file-name filename))))
@ -77,18 +79,20 @@
:description "The filename to compare to open buffers.")) :description "The filename to compare to open buffers."))
:category "org-mode")) :category "org-mode"))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (file) :function (lambda (file)
(find-file-noselect file)) (with-current-buffer (get-buffer-create file)
:name "find-file-noselect" (insert-file-contents file)
:description "Open the file in a buffer. This doesn't interfere with the user." (current-buffer)))
:name "open-file-inactive"
:description "Open the file in a background buffer. This doesn't interfere with the user."
:args (list '(:name "file" :args (list '(:name "file"
:type string :type string
:description "Path to file..")) :description "Path to file.."))
:category "filesystem")) :category "filesystem"))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (filename) :function (lambda (filename)
(with-temp-buffer (with-temp-buffer
@ -101,7 +105,7 @@
:description "The filename to read.")) :description "The filename to read."))
:category "org-mode")) :category "org-mode"))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (var) :function (lambda (var)
(let ((symbol (intern var))) (let ((symbol (intern var)))
@ -115,7 +119,7 @@
:description "Variable name")) :description "Variable name"))
:category "emacs")) :category "emacs"))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (fun) :function (lambda (fun)
(let ((symbol (intern fun))) (let ((symbol (intern fun)))
@ -131,7 +135,6 @@
:category "emacs")) :category "emacs"))
(defun gptel-org-tools--org-extract-tags (buffer) (defun gptel-org-tools--org-extract-tags (buffer)
(interactive "bBuffer: ")
(with-current-buffer buffer (with-current-buffer buffer
(let ((tags '())) (let ((tags '()))
(org-map-entries (org-map-entries
@ -143,7 +146,7 @@
(push tag tags)))))) (push tag tags))))))
(sort (-uniq tags) #'string<)))) (sort (-uniq tags) #'string<))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-extract-tags :function #'gptel-org-tools--org-extract-tags
:name "org-extract-tags" :name "org-extract-tags"
@ -154,7 +157,6 @@
:category "org-mode")) :category "org-mode"))
(defun gptel-org-tools--org-extract-headings (buffer) (defun gptel-org-tools--org-extract-headings (buffer)
(interactive "bBuffer: ")
(with-current-buffer buffer (with-current-buffer buffer
(org-map-entries (org-map-entries
#'(buffer-substring-no-properties #'(buffer-substring-no-properties
@ -163,7 +165,7 @@
t t
'file))) 'file)))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-extract-headings :function #'gptel-org-tools--org-extract-headings
:name "org-extract-headings" :name "org-extract-headings"
@ -187,7 +189,7 @@
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position)))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select :function #'gptel-org-tools--org-ql-select
:name "org-ql-select" :name "org-ql-select"
@ -201,7 +203,6 @@
:category "org")) :category "org"))
(defun gptel-org-tools--org-ql-select-dates (buf date) (defun gptel-org-tools--org-ql-select-dates (buf date)
(interactive "fBuffer: \nsDate (YYYY or YYYY-MM): ")
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,date) `(heading ,date)
@ -211,7 +212,7 @@
(org-end-of-subtree))))) (org-end-of-subtree)))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-dates :function #'gptel-org-tools--org-ql-select-dates
:name "org-ql-select-dates" :name "org-ql-select-dates"
@ -224,7 +225,7 @@
:description "Date in YYYY or YYYY-MM format. Can add multiple like so: \"YYYY-MM\" \"YYYY-MM\"")) :description "Date in YYYY or YYYY-MM format. Can add multiple like so: \"YYYY-MM\" \"YYYY-MM\""))
:category "org")) :category "org"))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (days) :function (lambda (days)
(with-temp-buffer (with-temp-buffer
@ -250,7 +251,7 @@
(line-end-position)))))) (line-end-position))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-headings :function #'gptel-org-tools--org-ql-select-headings
:name "org-ql-select-headings" :name "org-ql-select-headings"
@ -267,14 +268,14 @@
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(rifle ,query) `(rifle ,query)
:action :action #'(lambda () :action #'(lambda ()
(concat (concat
(buffer-substring-no-properties (buffer-substring-no-properties
(line-beginning-position) (line-beginning-position)
(line-end-position)))))) (line-end-position))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-headings-rifle :function #'gptel-org-tools--org-ql-select-headings-rifle
:name "org-ql-select-headings-rifle" :name "org-ql-select-headings-rifle"
@ -300,7 +301,7 @@
(line-beginning-position))))))) (line-beginning-position)))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-tags-local :function #'gptel-org-tools--org-ql-select-tags-local
:name "org-ql-select-tags-local" :name "org-ql-select-tags-local"
@ -326,7 +327,7 @@
(line-beginning-position))))))) (line-beginning-position)))))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-tags :function #'gptel-org-tools--org-ql-select-tags
:name "org-ql-select-tags" :name "org-ql-select-tags"
@ -340,8 +341,10 @@
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-rifle (buf query) (defun gptel-org-tools--org-ql-select-rifle (buf query)
(let ((buffer (get-buffer buf)))
(if buffer
(org-ql-select (org-ql-select
(get-buffer buf) buffer
`(rifle ,query) `(rifle ,query)
:action #'(lambda () :action #'(lambda ()
(concat (concat
@ -349,9 +352,10 @@
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))
(message "Buffer '%s' does not exist." buf))))
(add-to-list 'gptel-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-rifle :function #'gptel-org-tools--org-ql-select-rifle
:name "org-ql-select-rifle" :name "org-ql-select-rifle"