Add regexp tool

This commit is contained in:
Phil Bajsicki 2025-04-17 02:34:58 +02:00
parent aaed27319b
commit 7fba16a02e
2 changed files with 113 additions and 85 deletions

View file

@ -517,7 +517,7 @@ 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-by-date (buf date)
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,date) `(heading ,date)
@ -526,18 +526,18 @@ But, any customizations to tweak this is left to the user, as everyone has their
(add-to-list 'gptel-org-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-by-date
:name "org-ql-select-dates" :name "org-ql-select-by-date"
:description "Extract org subtree by date in YYYY or YYYY-MM format. Prefer using this first when request specifies for time periods." :description "Returns all timestamped headings matching query. Query may be: YYYY, YYYY-MM, YYYY-MM-DD. Prefer using this first when request specifies any time periods. Example: get all headings matching March 2025: \"2025-03\""
:args (list '(:name "buffer" :args (list '(:name "buffer"
:type string :type string
:description "Buffer name.") :description "Buffer name.")
'(:name "date" '(:name "date"
:type string :type string
: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."))
:category "org")) :category "org"))
#+end_src #+end_src
***** org-agenda-fortnight ***** org-agenda-seek
This is still work in progress, the idea is to have the LLM check my calendar and see what my plans are. I have not had time to really dig into this yet. This is still work in progress, the idea is to have the LLM check my calendar and see what my plans are. I have not had time to really dig into this yet.
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.
@ -550,8 +550,8 @@ It works, in principle, but I haven't been able to find a use for it yet. The re
(let ((content (buffer-string))) (let ((content (buffer-string)))
(kill-buffer (current-buffer)) (kill-buffer (current-buffer))
content))) content)))
:name "org-agenda-fortnight" :name "org-agenda-seek"
:description "Get X days of user's org-agenda." :description "Get user's agenda/ tasking from now to X days in the past or future"
:args (list '(:name "days" :args (list '(:name "days"
:type integer :type integer
:description "Days. Positive = future. Negative = past. Default: 14")) :description "Days. Positive = future. Negative = past. Default: 14"))
@ -569,11 +569,7 @@ Retrieve the headings where the heading matches query..
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,query) `(heading ,query)
:action #'(lambda () :action #''gptel-org-tools--heading))
(concat
(buffer-substring-no-properties
(line-beginning-position)
(line-end-position))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -670,7 +666,7 @@ And, the "grab everything that matches" tool.
(org-ql-select (org-ql-select
buffer buffer
`(rifle ,query) `(rifle ,query)
:action #'gptel-org-tools--heading-subtree) :action #'gptel-org-tools--heading-body)
(message "Buffer '%s' does not exist." buf)))) (message "Buffer '%s' does not exist." buf))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -687,10 +683,10 @@ And, the "grab everything that matches" tool.
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
***** org-ql-select-agenda-tags-local ***** org-ql-select-all-tags-local
This pulls all the headings (and their contents) when they match tags (without inheritance.) This pulls all the headings (and their contents) when they match tags (without inheritance.)
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-ql-select-agenda-tags-local (query) (defun gptel-org-tools--org-ql-select-all-tags-local (query)
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags-local ,query) `(tags-local ,query)
@ -699,8 +695,8 @@ This pulls all the headings (and their contents) when they match tags (without i
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-tags-local :function #'gptel-org-tools--org-ql-select-all-tags-local
:name "org-ql-select-agenda-tags-local" :name "org-ql-select-all-tags-local"
:description "Run single word query against all files in (org-agenda-files). WITHOUT tag inheritance, only directly tagged headings." :description "Run single word query against all files in (org-agenda-files). WITHOUT tag inheritance, only directly tagged headings."
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
@ -708,19 +704,19 @@ This pulls all the headings (and their contents) when they match tags (without i
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
***** org-ql-select-agenda-tags ***** org-ql-select-all-tags
This pulls all the headings (and their contents) when they match tags (with inheritance; if a parent entry has the tag, descendant entries do, too.) This pulls all the headings (and their contents) when they match tags (with inheritance; if a parent entry has the tag, descendant entries do, too.)
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-ql-select-agenda-tags (query) (defun gptel-org-tools--org-ql-select-all-tags (query)
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags ,query) `(tags ,query)
:action #'gptel-org-tools--heading-subtree)) :action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-tags :function #'gptel-org-tools--org-ql-select-all-tags
:name "org-ql-select-agenda-tags" :name "org-ql-select-all-tags"
:description "Run single word query against all files in (org-agenda-files). WITH tag inheritance." :description "Run single word query against all files in (org-agenda-files). WITH tag inheritance."
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
@ -728,7 +724,7 @@ This pulls all the headings (and their contents) when they match tags (with inhe
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
***** org-ql-select-agenda-rifle ***** org-ql-select-all-rifle
And for the entire =(org-agenda-files)=. And for the entire =(org-agenda-files)=.
Note that I define my agenda in this way: Note that I define my agenda in this way:
@ -740,16 +736,16 @@ Note that I define my agenda in this way:
This means that /every org-mode file I have/ is part of this search. This means that /every org-mode file I have/ is part of this search.
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-ql-select-agenda-rifle (query) (defun gptel-org-tools--org-ql-select-all-rifle (query)
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(rifle ,query) `(rifle ,query)
:action #'gptel-org-tools--heading-subtree)) :action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-rifle :function #'gptel-org-tools--org-ql-select-all-rifle
:name "org-ql-select-agenda-rifle" :name "org-ql-select-all-rifle"
:description "Run single word query against ALL org-mode files (notes)." :description "Run single word query against ALL org-mode files (notes)."
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
@ -758,6 +754,26 @@ This means that /every org-mode file I have/ is part of this search.
#+end_src #+end_src
***** org-ql-select-all-regexp
#+begin_src elisp
(defun gptel-org-tools--org-ql-select-all-rifle (query)
(org-ql-select
(org-agenda-files)
`(regexp ,query)
:action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools
(gptel-make-tool
:function #'gptel-org-tools--org-ql-select-all-rifle
:name "org-ql-select-all-rifle"
:description "Run regexp on ALL files at once."
:args (list '(:name "query"
:type string
:description "Regexp, Emacs Lisp format."))
:category "org-ql"))
#+end_src
** End ** End
#+begin_src elisp #+begin_src elisp
(provide 'gptel-org-tools) (provide 'gptel-org-tools)

View file

@ -46,27 +46,27 @@
'"\n---\n")) '"\n---\n"))
(defun gptel-org-tools--heading-body () (defun gptel-org-tools--heading-body ()
(concat (concat
(buffer-substring-no-properties (buffer-substring-no-properties
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))) (line-beginning-position)))
"---\n")) "---\n"))
(defun gptel-org-tools--heading-subtree () (defun gptel-org-tools--heading-subtree ()
(concat (concat
(buffer-substring-no-properties (buffer-substring-no-properties
(line-beginning-position) (line-beginning-position)
(org-end-of-subtree)) (org-end-of-subtree))
"---\n")) "---\n"))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (arg) :function (lambda (arg)
(list-buffers-noselect) (list-buffers-noselect)
(with-current-buffer "*Buffer List*" (with-current-buffer "*Buffer List*"
(buffer-string))) (buffer-string)))
:name "list-buffers" :name "list-buffers"
:description "Access the list of buffers open in Emacs, including file names and full paths." :description "Access the list of buffers open in Emacs, including file names and full paths."
:args (list '(:name "arg" :args (list '(:name "arg"
@ -107,11 +107,11 @@
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (file) :function (lambda (file)
(with-current-buffer (get-buffer-create file) (with-current-buffer (get-buffer-create file)
(insert-file-contents file) (insert-file-contents file)
(concat (concat
(current-buffer) (current-buffer)
"\n---\nTool execution complete. Proceed with next step."))) "\n---\nTool execution complete. Proceed with next step.")))
:name "open-file-inactive" :name "open-file-inactive"
:description "Open the file in a background buffer. This doesn't interfere with the user." :description "Open the file in a background buffer. This doesn't interfere with the user."
:args (list '(:name "file" :args (list '(:name "file"
@ -173,11 +173,11 @@
(defun gptel-org-tools--org-extract-headings (buffer) (defun gptel-org-tools--org-extract-headings (buffer)
(if (member buffer gptel-org-tools-skip-heading-extraction) (if (member buffer gptel-org-tools-skip-heading-extraction)
(user-error "Buffer %s has too many headings, use org-extract-tags or org-ql-select-rifle." buffer) (user-error "Buffer %s has too many headings, use org-extract-tags or org-ql-select-rifle." buffer)
(with-current-buffer buffer (with-current-buffer buffer
(org-map-entries (org-map-entries
#'gptel-org-tools--heading #'gptel-org-tools--heading
t t
'file)))) 'file))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
@ -189,7 +189,7 @@
:description "The Org buffer to extract headings from.")) :description "The Org buffer to extract headings from."))
:category "org-mode")) :category "org-mode"))
(defun gptel-org-tools--org-ql-select-dates (buf date) (defun gptel-org-tools--org-ql-select-by-date (buf date)
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,date) `(heading ,date)
@ -198,15 +198,15 @@
(add-to-list 'gptel-org-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-by-date
:name "org-ql-select-dates" :name "org-ql-select-by-date"
:description "Extract org subtree by date in YYYY or YYYY-MM format. Prefer using this first when request specifies for time periods." :description "Returns all timestamped headings matching query. Query may be: YYYY, YYYY-MM, YYYY-MM-DD. Prefer using this first when request specifies any time periods. Example: get all headings matching March 2025: \"2025-03\""
:args (list '(:name "buffer" :args (list '(:name "buffer"
:type string :type string
:description "Buffer name.") :description "Buffer name.")
'(:name "date" '(:name "date"
:type string :type string
: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."))
:category "org")) :category "org"))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -217,22 +217,18 @@
(let ((content (buffer-string))) (let ((content (buffer-string)))
(kill-buffer (current-buffer)) (kill-buffer (current-buffer))
content))) content)))
:name "org-agenda-fortnight" :name "org-agenda-seek"
:description "Get X days of user's org-agenda." :description "Get user's agenda/ tasking from now to X days in the past or future"
:args (list '(:name "days" :args (list '(:name "days"
:type integer :type integer
:description "Days. Positive = future. Negative = past. Default: 14")) :description "Days. Positive = future. Negative = past. Default: 14"))
:category "org")) :category "org"))
(defun gptel-org-tools--org-ql-select-headings (buf query) (defun gptel-org-tools--org-ql-select-headings (buf query)
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,query) `(heading ,query)
:action #'(lambda () :action #''gptel-org-tools--heading))
(concat
(buffer-substring-no-properties
(line-beginning-position)
(line-end-position))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -249,10 +245,10 @@
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-headings-rifle (buf query) (defun gptel-org-tools--org-ql-select-headings-rifle (buf query)
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(rifle ,query) `(rifle ,query)
:action #'gptel-org-tools--heading)) :action #'gptel-org-tools--heading))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -269,7 +265,7 @@
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-tags-local (buf query) (defun gptel-org-tools--org-ql-select-tags-local (buf query)
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(tags-local ,query) `(tags-local ,query)
:action #'gptel-org-tools-heading-body)) :action #'gptel-org-tools-heading-body))
@ -289,7 +285,7 @@
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-tags (buf query) (defun gptel-org-tools--org-ql-select-tags (buf query)
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(tags ,query) `(tags ,query)
:action #'gptel-org-tools--heading-body)) :action #'gptel-org-tools--heading-body))
@ -308,12 +304,12 @@
: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))) (let ((buffer (get-buffer buf)))
(if buffer (if buffer
(org-ql-select (org-ql-select
buffer buffer
`(rifle ,query) `(rifle ,query)
:action #'gptel-org-tools--heading-subtree) :action #'gptel-org-tools--heading-body)
(message "Buffer '%s' does not exist." buf)))) (message "Buffer '%s' does not exist." buf))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -329,7 +325,7 @@
:description "A single keyword to search for.")) :description "A single keyword to search for."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-agenda-tags-local (query) (defun gptel-org-tools--org-ql-select-all-tags-local (query)
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags-local ,query) `(tags-local ,query)
@ -338,45 +334,61 @@
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-tags-local :function #'gptel-org-tools--org-ql-select-all-tags-local
:name "org-ql-select-agenda-tags-local" :name "org-ql-select-all-tags-local"
:description "Run single word query against all files in (org-agenda-files). WITHOUT tag inheritance, only directly tagged headings." :description "Run single word query against all files in (org-agenda-files). WITHOUT tag inheritance, only directly tagged headings."
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
:description "A single word to scan for.")) :description "A single word to scan for."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-agenda-tags (query) (defun gptel-org-tools--org-ql-select-all-tags (query)
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags ,query) `(tags ,query)
:action #'gptel-org-tools--heading-subtree)) :action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-tags :function #'gptel-org-tools--org-ql-select-all-tags
:name "org-ql-select-agenda-tags" :name "org-ql-select-all-tags"
:description "Run single word query against all files in (org-agenda-files). WITH tag inheritance." :description "Run single word query against all files in (org-agenda-files). WITH tag inheritance."
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
:description "A single word to scan for.")) :description "A single word to scan for."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-agenda-rifle (query) (defun gptel-org-tools--org-ql-select-all-rifle (query)
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(rifle ,query) `(rifle ,query)
:action #'gptel-org-tools--heading-subtree)) :action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-rifle :function #'gptel-org-tools--org-ql-select-all-rifle
:name "org-ql-select-agenda-rifle" :name "org-ql-select-all-rifle"
:description "Run single word query against ALL org-mode files (notes)." :description "Run single word query against ALL org-mode files (notes)."
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
:description "The keyword to match entry headings and content against.")) :description "The keyword to match entry headings and content against."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-all-rifle (query)
(org-ql-select
(org-agenda-files)
`(regexp ,query)
:action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools
(gptel-make-tool
:function #'gptel-org-tools--org-ql-select-all-rifle
:name "org-ql-select-all-rifle"
:description "Run regexp on ALL files at once."
:args (list '(:name "query"
:type string
:description "Regexp, Emacs Lisp format."))
:category "org-ql"))
(provide 'gptel-org-tools) (provide 'gptel-org-tools)
;;; gptel-org-tools.el ends here ;;; gptel-org-tools.el ends here