538 lines
22 KiB
EmacsLisp
538 lines
22 KiB
EmacsLisp
;;; gptel-org-tools.el --- LLM Tools for org-mode interaction. -*- lexical-binding: t; -*-
|
|
|
|
;; Copyright (C) 2025 Phil Bajsicki
|
|
|
|
;; Author: Phil Bajsicki <phil@bajsicki.com>
|
|
;; Keywords: extensions, comm, tools, matching, convenience,
|
|
;;
|
|
;; Author: Phil Bajsicki <phil@bajsicki.com>
|
|
;; Version: 0.0.2
|
|
;; Package-Requires: ((emacs "30.1") (gptel 0.9.8) (org-ql 0.9))
|
|
;; URL: https://github.com/phil/gptel-org-tools
|
|
;; SPDX-License-Identifier: GPL-3.0
|
|
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, version 3 of the License.
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
;; This file is NOT part of GNU Emacs.
|
|
|
|
;; This file is not part of GNU Emacs.
|
|
|
|
;;; Commentary:
|
|
|
|
;; All documentation regarding these functions is in the README.org file.
|
|
;; Repository: https://git.bajsicki.com/phil/gptel-org-tools
|
|
|
|
;;; Code:)
|
|
|
|
(defvar gptel-org-tools '())
|
|
|
|
(defvar gptel-org-tools-skip-heading-extraction '())
|
|
|
|
(defvar gptel-org-tools-result-limit 40000)
|
|
|
|
(defun gptel-org-tools--result-limit (result)
|
|
(if (>= (length (format "%s" result)) gptel-org-tools-result-limit)
|
|
(format "Results over %s character. Stop. Analyze. Find a different solution, or use a more specific query." gptel-org-tools-result-limit)
|
|
result))
|
|
|
|
(defun gptel-org-tools--heading ()
|
|
"Return the org-mode heading."
|
|
(concat
|
|
(buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(line-end-position))))
|
|
|
|
(defun gptel-org-tools--heading-body ()
|
|
"Return the org-mode heading and body text."
|
|
(concat
|
|
(buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(progn
|
|
(outline-next-heading)
|
|
(line-beginning-position)))))
|
|
|
|
(defun gptel-org-tools--heading-subtree ()
|
|
"Return the org-mode heading and all subheadings, with their body text."
|
|
(concat
|
|
(buffer-substring-no-properties
|
|
(line-beginning-position)
|
|
(org-end-of-subtree))))
|
|
|
|
(defun gptel-org-tool--list-buffers (&optional arg)
|
|
"Return list of buffers."
|
|
(list-buffers-noselect)
|
|
(with-current-buffer "*Buffer List*"
|
|
(let ((content (buffer-string)))
|
|
content)))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tool--list-buffers
|
|
:name "gptel-org-tool--list-buffers"
|
|
:args (list '(:name "arg"
|
|
:type string
|
|
:description "Does nothing."
|
|
:optional t))
|
|
:category "emacs"
|
|
:description "List buffers open in Emacs, including file names and full paths. After using this, stop. Then evaluate which files are most likely to be relevant to the user's request."))
|
|
|
|
(defun gptel-org-tools--dir (dir)
|
|
"Return directory listing."
|
|
(with-temp-buffer
|
|
(dired (or dir "~"))
|
|
(let ((content (buffer-string)))
|
|
(kill-buffer (current-buffer))
|
|
content)))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--dir
|
|
:name "gptel-org-tools--dir"
|
|
:description "List directory contents. After using this, stop. Evaluate for relevance. Then use your findings to fulfill user's request."
|
|
:args (list '(:name "dir"
|
|
:type string
|
|
:description "Directory path"
|
|
:optional t))
|
|
:category "filesystem"))
|
|
|
|
(defun gptel-org-tools--open-file-inactive (file)
|
|
"Open FILE in a buffer."
|
|
(with-current-buffer (get-buffer-create file)
|
|
(insert-file-contents file)
|
|
(concat
|
|
(current-buffer))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--open-file-inactive
|
|
:name "gptel-org-tools--open-file-inactive"
|
|
:description "Open the file in a background buffer. This doesn't interfere with the user. After calling this tool, stop. Then continue fulfilling user's request."
|
|
:args (list '(:name "file"
|
|
:type string
|
|
:description "Path to file.."))
|
|
:category "filesystem"))
|
|
|
|
(defun gptel-org-tools--describe-variable (var)
|
|
"Return documentation for VAR."
|
|
(let ((symbol (intern var)))
|
|
(if (boundp symbol)
|
|
(prin1-to-string (symbol-value symbol))
|
|
(format "Variable %s is not bound. This means the variable doesn't exist. Stop. Reassess what you're trying to do, examine the situation, and continue. " var))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--describe-variable
|
|
:name "gptel-org-tools--describe-variable"
|
|
:description "Returns variable contents. After calling this tool, stop. Evaluate if the result helps. Then continue fulfilling user's request."
|
|
:args (list '(:name "var"
|
|
:type string
|
|
:description "Variable name"))
|
|
:category "emacs"))
|
|
|
|
(defun gptel-org-tools--describe-function (fun)
|
|
"Return documentation for FUN."
|
|
(let ((symbol (intern fun)))
|
|
(if (fboundp symbol)
|
|
(prin1-to-string (documentation symbol 'function))
|
|
(format "Function %s is not defined." fun))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--describe-function
|
|
:name "gptel-org-tools--describe-function"
|
|
:description "Returns function description. After calling this tool, stop. Evaluate if the result helps. Then continue fulfilling user's request."
|
|
:args (list '(:name "fun"
|
|
:type string
|
|
:description "Function name"
|
|
:optional t))
|
|
:category "emacs"))
|
|
|
|
(defun gptel-org-tools--org-extract-tags (buffer)
|
|
"Return all tags from BUFFER."
|
|
(with-current-buffer buffer
|
|
(let ((tags '()))
|
|
(org-map-entries
|
|
(lambda ()
|
|
(let* ((components (org-heading-components))
|
|
(tag-string (car (last components))))
|
|
(when tag-string
|
|
(dolist (tag (split-string tag-string ":" t))
|
|
(push tag tags))))))
|
|
(sort (-uniq tags) #'string<))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-extract-tags
|
|
:name "gptel-org-tools--org-extract-tags"
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The Org buffer to extract tags from."))
|
|
:category "org-mode"
|
|
:description "Returns all tags from an org-mode buffer. When using this, evaluate the relevance of each tag to the user's request. After calling this tool, stop. Then continue fulfilling user's request."))
|
|
|
|
(defun gptel-org-tools--org-extract-headings (buffer)
|
|
"Return all headings from BUFFER."
|
|
(if (member buffer gptel-org-tools-skip-heading-extraction)
|
|
(user-error "Buffer %s has been blocked from this function by the user with reason: headings contain timestamps, no useful information. Use a different tool." buffer)
|
|
(with-current-buffer buffer
|
|
(org-map-entries
|
|
#'gptel-org-tools--heading
|
|
t
|
|
'file))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-extract-headings
|
|
:name "gptel-org-tools--org-extract-headings"
|
|
:description "Returns all headings from an org-mode buffer. After using this, stop. Then evaluate the relevance of the headings to the user's request. Then continue."
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The Org buffer to extract headings from."))
|
|
:category "org-mode"))
|
|
|
|
(defun gptel-org-tools--org-ql-select-date (buf date)
|
|
"Returns all timestamped headings matching the specified date or date range.
|
|
The date can be in the format YYYY, YYYY-MM, or YYYY-MM-DD.
|
|
|
|
BUFFER is the name of the buffer to search.
|
|
DATE is the date or date range to match."
|
|
(let* ((buffer (get-buffer buf))
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
(if (bufferp buffer)
|
|
(if (eq mode 'org-mode)
|
|
(let ((result
|
|
(org-ql-select buffer
|
|
`(heading ,date)
|
|
:action #'gptel-org-tools--heading-subtree)))
|
|
(concat (gptel-org-tools--result-limit result) "Results end here. Proceed with the next action."))
|
|
(message "Buffer '%s' isn't an org-mode buffer." buf))
|
|
(message "Buffer '%s' does not exist." buf))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-date
|
|
:name "gptel-org-tools--org-ql-select-date"
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "Buffer name.")
|
|
'(:name "date"
|
|
:type string
|
|
:description "Date string in YYYY or YYYY-MM format. No <, >, [, ]. Just the numbers and dashes."))
|
|
:category "org"
|
|
:description "Returns all timestamped headings and all of their subheadings matching query. Query may be: YYYY, YYYY-MM, YYYY-MM-DD.
|
|
Examples:
|
|
- \"YYYY\": gets all entries from year YYYY
|
|
- \"YYYY-MM\": gets all entries from month MM of year YYYY
|
|
|
|
After using this, stop. Then evaluate the relevance of the entries to the user's request. Then continue."))
|
|
|
|
(defun gptel-org-tools--org-agenda-seek (days)
|
|
"Return the results of org-agenda-list spanning now to DAYS."
|
|
(with-temp-buffer
|
|
(org-agenda-list (or days 14))
|
|
(let ((content (buffer-string)))
|
|
(kill-buffer (current-buffer))
|
|
(gptel-org-tools--result-limit content))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-agenda-seek
|
|
:name "gptel-org-tools--org-agenda-seek"
|
|
:args (list '(:name "days"
|
|
:type integer
|
|
:description "Days. Positive = future. Negative = past. Default: 14"))
|
|
:category "org"
|
|
:description "Return user's agenda (tasking) spanning X days from the current moment. Example:
|
|
- Get all tasks due in the next 7 days: \"7\"
|
|
- Get all tasks in the last 14 days: \"-14\"
|
|
After using this, stop. Evaluate the relevance of the results. Then continue."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-headings (buf query)
|
|
"Return headings matching QUERY from BUFFER."
|
|
(let* ((buffer (get-buffer buf))
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
(if buffer
|
|
(if (eq mode 'org-mode)
|
|
(let ((result
|
|
(org-ql-select
|
|
(get-buffer buf)
|
|
`(heading ,query)
|
|
:action #''gptel-org-tools--heading)))
|
|
(concat (gptel-org-tools--result-limit result) "Results end here. Proceed with the next action."))
|
|
(message "Buffer '%s' isn't an org-mode buffer." buf))
|
|
(message "Buffer '%s' does not exist." buf))))
|
|
|
|
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-headings
|
|
:name "gptel-org-tools--org-ql-select-headings"
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The name of the buffer. See the NAME column in ~list-buffers~.")
|
|
'(:name "query"
|
|
:type string
|
|
:description "The string to match entry headings against."))
|
|
:category "org-ql"
|
|
:description "Returns entries matching QUERY from BUFFER. Matches only a single string. After using this, evaluate which entries are relevant, and continue with user's request."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-headings-rifle (buf query)
|
|
"Return headings of entries (body included) that match keyword QUERY from BUFFER."
|
|
(let ((result
|
|
(org-ql-select
|
|
(get-buffer buf)
|
|
`(rifle ,query)
|
|
:action #'gptel-org-tools--heading)))
|
|
(gptel-org-tools--result-limit result)))
|
|
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-headings-rifle
|
|
:name "gptel-org-tools--org-ql-select-headings-rifle"
|
|
:description "Returns headings matching QUERY from BUFFER. Matches against both heading and content, but only returns headings. After using this, stop. Evaluate results. Then continue completing user's request."
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The name of the buffer. See the NAME column in ~list-buffers~.")
|
|
'(:name "query"
|
|
:type string
|
|
:description "The string to match entry headings against."))
|
|
:category "org-ql"))
|
|
|
|
(defun gptelg-tools--org-ql-select-tags-local (buf query)
|
|
"Return entries whose tags match QUERY in BUFFER, without inheritance."
|
|
(let* ((buffer (get-buffer buf))
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
(if buffer
|
|
(if (eq mode 'org-mode)
|
|
(let ((result
|
|
(org-ql-select
|
|
(get-buffer buf)
|
|
`(tags-local ,query)
|
|
:action #'gptel-org-tools--heading-body)))
|
|
(gptel-org-tools--result-limit result))
|
|
(message "Buffer '%s' isn't an org-mode buffer." buf))
|
|
(message "Buffer '%s' does not exist." buf))))
|
|
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-tags-local
|
|
:name "gptel-org-tools--org-ql-select-tags-local"
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The name of the buffer. See the NAME column in `list-buffers`. Using filename fails.")
|
|
'(:name "query"
|
|
:type string
|
|
:description "The string match entry tags against."))
|
|
:category "org-ql"
|
|
:description "Returns entries whose tags match QUERY from BUFFER, without tag inheritance. After using this, stop. Evaluate results for relevance, then proceed with completing user's request."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-tags-local-count (buf query)
|
|
"Return count of entries tagged QUERY in BUFFER."
|
|
(let* ((buffer (get-buffer buf))
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
(if buffer
|
|
(if (eq mode 'org-mode)
|
|
(length (org-ql-select
|
|
(get-buffer buf)
|
|
`(tags-local ,query)
|
|
:action #'gptel-org-tools--heading-body))
|
|
(message "Buffer '%s' isn't an org-mode buffer." buf))
|
|
(message "Buffer '%s' does not exist." buf))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-tags-local-count
|
|
:name "gptel-org-tools--org-ql-select-tags-local"
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The name of the buffer. See the NAME column in `list-buffers`. Using filename fails.")
|
|
'(:name "query"
|
|
:type string
|
|
:description "The string match entry tags against."))
|
|
:category "org-ql"
|
|
:description "Returns count of entries tagged with tag QUERY from BUFFER, without tag inheritance. After using this, stop. Evaluate results. Then proceed."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-tags (buf query)
|
|
"Return every entry tagged QUERY from BUFFER."
|
|
(let* ((buffer (get-buffer buf))
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
(if buffer
|
|
(if (eq mode 'org-mode)
|
|
(let ((result
|
|
(org-ql-select
|
|
(get-buffer buf)
|
|
`(tags ,query)
|
|
:action #'gptel-org-tools--heading-body))
|
|
(gptel-org-tools--result-limit result)))
|
|
(message "Buffer '%s' isn't an org-mode buffer." buf))
|
|
(message "Buffer '%s' does not exist." buf))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-tags
|
|
:name "gptel-org-tools--org-ql-select-tags"
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The name of the buffer. See the NAME column in `list-buffers`. Using filename fails.")
|
|
'(:name "query"
|
|
:type string
|
|
:description "The string to match entry headings against."))
|
|
:category "org-ql"
|
|
:description "Returns entries tagged QUERY from BUFFER, with tag inheritance. After using this, stop. Evaluate results. Only then proceed."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-rifle (buf query)
|
|
"Return every entry matching keyword QUERY from BUFFER."
|
|
(let* ((buffer (get-buffer buf))
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
(if buffer
|
|
(if (eq mode 'org-mode)
|
|
(let ((result
|
|
(org-ql-select
|
|
buffer
|
|
`(rifle ,query)
|
|
:action #'gptel-org-tools--heading-body)))
|
|
(gptel-org-tools--result-limit result))
|
|
(message "Buffer '%s' isn't an org-mode buffer." buf))
|
|
(message "Buffer '%s' does not exist." buf))))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-rifle
|
|
:name "gptel-org-tools--org-ql-select-rifle"
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The name of the buffer. See the NAME column in `list-buffers`. Using filename fails.")
|
|
'(:name "query"
|
|
:type string
|
|
:description "A single string to search for."))
|
|
:category "org-ql"
|
|
:description "Returns entries (heading and body) matching QUERY from BUFFER. This may pull too many results, only use if other tools fail. After using this, stop. Evaluate results. If necessary, re-plan. Only then proceed."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-regexp (buf query)
|
|
(let* ((buffer (get-buffer buf))
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
(if buffer
|
|
(if (eq mode 'org-mode)
|
|
(let ((result
|
|
(org-ql-select
|
|
buffer
|
|
`(regexp ,query)
|
|
:action #'gptel-org-tools--heading-body)))
|
|
(gptel-org-tools--result-limit result))
|
|
(message "Buffer '%s' isn't an org-mode buffer." buf))
|
|
(message "Buffer '%s' does not exist." buf))))
|
|
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-regexp
|
|
:name "gptel-org-tools--org-ql-select-regexp"
|
|
:description "Run regexp on ALL files at once."
|
|
:args (list '(:name "buffer"
|
|
:type string
|
|
:description "The name of the buffer. See the NAME column in `list-buffers`. Using filename fails.")
|
|
'(:name "query"
|
|
:type string
|
|
:description "Regexp, Emacs Lisp format. Automatically wrapped in a word boundary by the tool."))
|
|
:category "org-ql"
|
|
:description "Returns entries matching regexp QUERY from BUFFER. After using this, stop. Evaluate results for relevance, and proceed with completing user's request. The regexp *must* be in Emacs rx format!" ))
|
|
|
|
(defun gptel-org-tools--org-ql-select-all-tags-local (query)
|
|
"Return entries whose tags match QUERY in org-agenda-files.
|
|
QUERY is the tag to search for."
|
|
(let ((result
|
|
(org-ql-select
|
|
(org-agenda-files)
|
|
`(tags-local ,query)
|
|
:action #'gptel-org-tools--heading-body)))
|
|
(gptel-org-tools--result-limit result)))
|
|
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-all-tags-local
|
|
:name "gptel-org-tools--org-ql-select-all-tags-local"
|
|
:args (list '(:name "query"
|
|
:type string
|
|
:description "A single word to scan for."))
|
|
:category "org-ql"
|
|
:description "Returns entries whose tags match QUERY from all files, without tag inheritance. After using this, stop. Evaluate results. Then proceed with completing user's request."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-all-tags (query)
|
|
"Return entries whose tags match QUERY,
|
|
with inheritance, in org-agenda-files.
|
|
QUERY is the tag to search for."
|
|
(let ((result
|
|
(org-ql-select
|
|
(org-agenda-files)
|
|
`(tags ,query)
|
|
:action #'gptel-org-tools--heading-body)))
|
|
(gptel-org-tools--result-limit result)))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-all-tags
|
|
:name "gptel-org-tools--org-ql-select-all-tags"
|
|
:args (list '(:name "query"
|
|
:type string
|
|
:description "A simple (single) string to scan for."))
|
|
:category "org-ql"
|
|
:description "Returns entries whose tags match QUERY from BUFFER, with tag inheritance. After using this, stop. Evaluate results for relevance, and proceed with completing user's request."))
|
|
|
|
(defun gptel-org-tools--org-ql-select-all-rifle (query)
|
|
"Return entries containing QUERY from org-agenda-files.
|
|
QUERY is the keyword to search for."
|
|
(let ((result
|
|
(org-ql-select
|
|
(org-agenda-files)
|
|
`(rifle ,query)
|
|
:action #'gptel-org-tools--heading-body)))
|
|
(gptel-org-tools--result-limit result)))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-all-rifle
|
|
:name "gptel-org-tools--org-ql-select-all-rifle"
|
|
:description "Run simple (single) string against ALL org-mode files (notes)."
|
|
:args (list '(:name "query"
|
|
:type string
|
|
:description "The string to match entry headings and content against."))
|
|
:category "org-ql"
|
|
:description "Returns entries matching QUERY from all files. After using this, stop. Evaluate results for relevance, and proceed with completing user's request." ))
|
|
|
|
(defun gptel-org-tools--org-ql-select-all-regexp (query)
|
|
"Return all entries matching regexp QUERY in org-agenda-files.
|
|
QUERY is a regular expression."
|
|
(let ((result
|
|
(org-ql-select
|
|
(org-agenda-files)
|
|
`(regexp ,query)
|
|
:action #'gptel-org-tools--heading-body)))
|
|
(gptel-org-tools--result-limit result)))
|
|
|
|
(add-to-list 'gptel-org-tools
|
|
(gptel-make-tool
|
|
:function #'gptel-org-tools--org-ql-select-all-regexp
|
|
:name "gptel-org-tools--org-ql-select-all-regexp"
|
|
:description "Run regexp on ALL files at once."
|
|
:args (list '(:name "query"
|
|
:type string
|
|
:description "Regexp, Emacs Lisp format. Automatically wrapped in a word boundary by the tool."))
|
|
:category "org-ql"
|
|
:description "Returns entries matching regexp QUERY from all files. After using this, stop. Evaluate results for relevance, and proceed with completing user's request. The regexp *must* be in Emacs rx format!" ))
|
|
|
|
(provide 'gptel-org-tools)
|
|
;;; gptel-org-tools.el ends here
|