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
(defun gptel-org-tools--org-ql-select-dates (buf date)
(defun gptel-org-tools--org-ql-select-by-date (buf date)
(org-ql-select
(get-buffer buf)
`(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
(gptel-make-tool
:function #'gptel-org-tools--org-ql-select-dates
:name "org-ql-select-dates"
:description "Extract org subtree by date in YYYY or YYYY-MM format. Prefer using this first when request specifies for time periods."
:function #'gptel-org-tools--org-ql-select-by-date
:name "org-ql-select-by-date"
: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"
:type string
:description "Buffer name.")
'(:name "date"
: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"))
#+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.
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)))
(kill-buffer (current-buffer))
content)))
:name "org-agenda-fortnight"
:description "Get X days of user's org-agenda."
:name "org-agenda-seek"
:description "Get user's agenda/ tasking from now to X days in the past or future"
:args (list '(:name "days"
:type integer
:description "Days. Positive = future. Negative = past. Default: 14"))
@ -569,11 +569,7 @@ Retrieve the headings where the heading matches query..
(org-ql-select
(get-buffer buf)
`(heading ,query)
:action #'(lambda ()
(concat
(buffer-substring-no-properties
(line-beginning-position)
(line-end-position))))))
:action #''gptel-org-tools--heading))
(add-to-list 'gptel-org-tools
@ -670,7 +666,7 @@ And, the "grab everything that matches" tool.
(org-ql-select
buffer
`(rifle ,query)
:action #'gptel-org-tools--heading-subtree)
:action #'gptel-org-tools--heading-body)
(message "Buffer '%s' does not exist." buf))))
(add-to-list 'gptel-org-tools
@ -687,10 +683,10 @@ And, the "grab everything that matches" tool.
:category "org-ql"))
#+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.)
#+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-agenda-files)
`(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
(gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-tags-local
:name "org-ql-select-agenda-tags-local"
:function #'gptel-org-tools--org-ql-select-all-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."
:args (list '(:name "query"
:type string
@ -708,19 +704,19 @@ This pulls all the headings (and their contents) when they match tags (without i
:category "org-ql"))
#+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.)
#+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-agenda-files)
`(tags ,query)
:action #'gptel-org-tools--heading-subtree))
:action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools
(gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-tags
:name "org-ql-select-agenda-tags"
:function #'gptel-org-tools--org-ql-select-all-tags
:name "org-ql-select-all-tags"
:description "Run single word query against all files in (org-agenda-files). WITH tag inheritance."
:args (list '(:name "query"
:type string
@ -728,7 +724,7 @@ This pulls all the headings (and their contents) when they match tags (with inhe
:category "org-ql"))
#+end_src
***** org-ql-select-agenda-rifle
***** org-ql-select-all-rifle
And for the entire =(org-agenda-files)=.
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.
#+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-agenda-files)
`(rifle ,query)
:action #'gptel-org-tools--heading-subtree))
:action #'gptel-org-tools--heading-body))
(add-to-list 'gptel-org-tools
(gptel-make-tool
:function #'gptel-org-tools--org-ql-select-agenda-rifle
:name "org-ql-select-agenda-rifle"
:function #'gptel-org-tools--org-ql-select-all-rifle
:name "org-ql-select-all-rifle"
:description "Run single word query against ALL org-mode files (notes)."
:args (list '(:name "query"
:type string
@ -758,6 +754,26 @@ This means that /every org-mode file I have/ is part of this search.
#+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
#+begin_src elisp
(provide 'gptel-org-tools)

View file

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