Clarify LLM-facing descriptions

This commit is contained in:
Phil Bajsicki 2025-04-16 14:54:54 +02:00
parent c781b00be4
commit de14a8d066
2 changed files with 110 additions and 61 deletions

View file

@ -76,9 +76,6 @@ I change models a lot, and this /just works/ for most models, even if some aren'
(require 'gptel) (require 'gptel)
#+end_src #+end_src
#+RESULTS:
: gptel
With that out of the way, let's get to the tools. With that out of the way, let's get to the tools.
* Usage options: * Usage options:
I only use Doom Emacs, so here's how I do it. I only use Doom Emacs, so here's how I do it.
@ -168,7 +165,40 @@ Collects into =gptel-org-tools= list, distinct from =gptel-tools=
#+begin_src elisp #+begin_src elisp
(defvar gptel-org-tools '()) (defvar gptel-org-tools '())
#+end_src #+end_src
** Helper Functions
These abstract away some of the tool definitions.
Both of these clear the org-ql-cache to work around issues where a file may be updated between tool calls.
*** Retrieve heading and body (without subheadings)
#+begin_src elisp
(defun gptel-org-tools--heading-body ()
(concat
(buffer-substring-no-properties
(line-beginning-position)
(progn
(outline-next-heading)
(line-beginning-position)))
"---\n"))
#+end_src
*** Retrieve heading and subheadings (until next same-level heading)
#+begin_src elisp
(defun gptel-org-tools--heading-subtree ()
(concat
(buffer-substring-no-properties
(line-beginning-position)
(org-end-of-subtree))
"---\n"))
#+end_src
** Note on org-ql
Given that there isn't (yet?) a built-in way of disabling caching, every (org-ql-select) call is wrapped like so.
See [[https://github.com/alphapapa/org-ql/issues/437][this issue]] for details.
#+begin_src elisp :tangle no
(let ((org-ql-cache (make-hash-table)))
(org-ql-select ...))
#+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.
@ -430,13 +460,7 @@ Currently *not* tangled, as I'm testing breaking out each type of query into its
(if (stringp query) (if (stringp query)
(read query) (read query)
query) query)
:action #'(lambda () :action #'gptel-org-tools--heading-body
(concat
(buffer-substring-no-properties
(line-beginning-position)
(progn
(outline-next-heading)
(line-beginning-position)))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
@ -477,10 +501,7 @@ But, any customizations to tweak this is left to the user, as everyone has their
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,date) `(heading ,date)
:action #'(lambda () :action #'gptel-org-tools--heading-subtree))
(buffer-substring-no-properties
(line-beginning-position)
(org-end-of-subtree)))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -525,14 +546,15 @@ The following tools are still very much WIP, and I think they're self-explanator
Retrieve the headings where the heading matches query.. Retrieve the headings where the heading matches query..
#+begin_src elisp #+begin_src elisp
(defun gptel-org-tools--org-ql-select-headings (buf query) (defun gptel-org-tools--org-ql-select-headings (buf query)
(org-ql-select (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,query) `(heading ,query)
: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-org-tools (add-to-list 'gptel-org-tools
@ -545,7 +567,7 @@ Retrieve the headings where the heading matches query..
:description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.") :description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.")
'(:name "query" '(:name "query"
:type string :type string
:description "The string to pass into org-ql-select-headings. This is a bare string. Example: \"searchterm\"")) :description "The string to match entry headings against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
@ -553,14 +575,15 @@ Retrieve the headings where the heading matches query..
Retrieve all the headings where either heading or content matches query. Retrieve all the headings where either heading or content matches query.
#+begin_src elisp #+begin_src elisp
(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 (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(rifle ,query) `(rifle ,query)
: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-org-tools (add-to-list 'gptel-org-tools
@ -573,7 +596,7 @@ Retrieve all the headings where either heading or content matches query.
:description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.") :description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.")
'(:name "query" '(:name "query"
:type string :type string
:description "The string to pass into org-ql-select-headings-rifle. This is a bare string. Example: \"searchterm\"")) :description "The string to match entry headings against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
@ -581,7 +604,8 @@ Retrieve all the headings where either heading or content matches query.
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-tags-local (buf query) (defun gptel-org-tools--org-ql-select-tags-local (buf query)
(org-ql-select (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(tags-local ,query) `(tags-local ,query)
:action #'(lambda () :action #'(lambda ()
@ -590,7 +614,7 @@ This pulls all the headings (and their contents) when they match tags (without i
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -603,7 +627,7 @@ This pulls all the headings (and their contents) when they match tags (without i
:description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.") :description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.")
'(:name "query" '(:name "query"
:type string :type string
:description "The tags to match entry headings against. Example: \"tag1\" \"tag2\"")) :description "The string match entry tags against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
@ -611,7 +635,8 @@ This pulls all the headings (and their contents) when they match tags (without i
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-tags (buf query) (defun gptel-org-tools--org-ql-select-tags (buf query)
(org-ql-select (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(tags ,query) `(tags ,query)
:action #'(lambda () :action #'(lambda ()
@ -620,7 +645,7 @@ This pulls all the headings (and their contents) when they match tags (with inhe
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -633,15 +658,16 @@ This pulls all the headings (and their contents) when they match tags (with inhe
:description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.") :description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.")
'(:name "query" '(:name "query"
:type string :type string
:description "The tags to match entry headings against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry headings against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
***** org-ql-select-rifle ***** org-ql-select-rifle
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 hash-gptl-org-tools--org-ql-select-rifle ()
(let ((buffer (get-buffer buf))) (let ((org-ql-cache (make-hash-table))
(buffer (get-buffer buf)))
(if buffer (if buffer
(org-ql-select (org-ql-select
buffer buffer
@ -665,15 +691,15 @@ And, the "grab everything that matches" tool.
:description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.") :description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.")
'(:name "query" '(:name "query"
:type string :type string
:description "The strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry headings and content against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
***** org-ql-select-agenda-tags-local ***** org-ql-select-agenda-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 (query) (defun gptel-org-tools--org-ql-select-agenda-tags (query)
(let ((org-ql-cache (make-hash-table)))
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags-local ,query) `(tags-local ,query)
@ -683,7 +709,7 @@ This pulls all the headings (and their contents) when they match tags (without i
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -693,7 +719,7 @@ This pulls all the headings (and their contents) when they match tags (without i
:description "Run simple word query against all files in (org-agenda-files). WITHOUT tag inheritance, only directly tagged headings." :description "Run simple 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 "Plain list of strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry tags against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
@ -701,6 +727,7 @@ This pulls all the headings (and their contents) when they match tags (without i
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-agenda-tags (query)
(let ((org-ql-cache (make-hash-table)))
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags ,query) `(tags ,query)
@ -710,7 +737,7 @@ This pulls all the headings (and their contents) when they match tags (with inhe
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -720,7 +747,7 @@ This pulls all the headings (and their contents) when they match tags (with inhe
:description "Run simple word query against all files in (org-agenda-files). WITH tag inheritance." :description "Run simple 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 "Plain list of strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry tags against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src
@ -737,6 +764,7 @@ 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-agenda-rifle (query)
(let ((org-ql-cache (make-hash-table)))
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(rifle ,query) `(rifle ,query)
@ -746,7 +774,7 @@ This means that /every org-mode file I have/ is part of this search.
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
@ -755,7 +783,7 @@ This means that /every org-mode file I have/ is part of this search.
:description "Run simple word query against all files in (org-agenda-files)" :description "Run simple word query against all files in (org-agenda-files)"
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
:description "Plain list of strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry headings and content against."))
:category "org-ql")) :category "org-ql"))
#+end_src #+end_src

View file

@ -38,6 +38,22 @@
(defvar gptel-org-tools '()) (defvar gptel-org-tools '())
(defun gptel-org-tools--heading-body ()
(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"))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
:function (lambda (arg) :function (lambda (arg)
@ -167,10 +183,7 @@
(org-ql-select (org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,date) `(heading ,date)
:action #'(lambda () :action #'gptel-org-tools--heading-subtree))
(buffer-substring-no-properties
(line-beginning-position)
(org-end-of-subtree)))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -202,14 +215,15 @@
: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 (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(heading ,query) `(heading ,query)
: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-org-tools (add-to-list 'gptel-org-tools
@ -222,18 +236,19 @@
:description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.") :description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.")
'(:name "query" '(:name "query"
:type string :type string
:description "The string to pass into org-ql-select-headings. This is a bare string. Example: \"searchterm\"")) :description "The string to match entry headings against."))
: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 (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(rifle ,query) `(rifle ,query)
: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-org-tools (add-to-list 'gptel-org-tools
@ -246,11 +261,12 @@
:description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.") :description "The name of the buffer. See the NAME column in ~emacs-list-buffers~.")
'(:name "query" '(:name "query"
:type string :type string
:description "The string to pass into org-ql-select-headings-rifle. This is a bare string. Example: \"searchterm\"")) :description "The string to match entry headings against."))
: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 (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(tags-local ,query) `(tags-local ,query)
:action #'(lambda () :action #'(lambda ()
@ -259,7 +275,7 @@
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -272,11 +288,12 @@
:description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.") :description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.")
'(:name "query" '(:name "query"
:type string :type string
:description "The tags to match entry headings against. Example: \"tag1\" \"tag2\"")) :description "The string match entry tags against."))
: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 (let ((org-ql-cache (make-hash-table)))
(org-ql-select
(get-buffer buf) (get-buffer buf)
`(tags ,query) `(tags ,query)
:action #'(lambda () :action #'(lambda ()
@ -285,7 +302,7 @@
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -298,11 +315,12 @@
:description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.") :description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.")
'(:name "query" '(:name "query"
:type string :type string
:description "The tags to match entry headings against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry headings against."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-rifle (buf query) (defun hash-gptl-org-tools--org-ql-select-rifle ()
(let ((buffer (get-buffer buf))) (let ((org-ql-cache (make-hash-table))
(buffer (get-buffer buf)))
(if buffer (if buffer
(org-ql-select (org-ql-select
buffer buffer
@ -326,10 +344,11 @@
:description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.") :description "The name of the buffer. See the NAME column in `emacs-list-buffers`. Using filename fails.")
'(:name "query" '(:name "query"
:type string :type string
:description "The strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry headings and content against."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-agenda-tags (query) (defun gptel-org-tools--org-ql-select-agenda-tags (query)
(let ((org-ql-cache (make-hash-table)))
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags-local ,query) `(tags-local ,query)
@ -339,7 +358,7 @@
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -349,10 +368,11 @@
:description "Run simple word query against all files in (org-agenda-files). WITHOUT tag inheritance, only directly tagged headings." :description "Run simple 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 "Plain list of strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry tags against."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-agenda-tags (query) (defun gptel-org-tools--org-ql-select-agenda-tags (query)
(let ((org-ql-cache (make-hash-table)))
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(tags ,query) `(tags ,query)
@ -362,7 +382,7 @@
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
@ -372,10 +392,11 @@
:description "Run simple word query against all files in (org-agenda-files). WITH tag inheritance." :description "Run simple 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 "Plain list of strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry tags against."))
:category "org-ql")) :category "org-ql"))
(defun gptel-org-tools--org-ql-select-agenda-rifle (query) (defun gptel-org-tools--org-ql-select-agenda-rifle (query)
(let ((org-ql-cache (make-hash-table)))
(org-ql-select (org-ql-select
(org-agenda-files) (org-agenda-files)
`(rifle ,query) `(rifle ,query)
@ -385,7 +406,7 @@
(line-beginning-position) (line-beginning-position)
(progn (progn
(outline-next-heading) (outline-next-heading)
(line-beginning-position))))))) (line-beginning-position))))))))
(add-to-list 'gptel-org-tools (add-to-list 'gptel-org-tools
(gptel-make-tool (gptel-make-tool
@ -394,7 +415,7 @@
:description "Run simple word query against all files in (org-agenda-files)" :description "Run simple word query against all files in (org-agenda-files)"
:args (list '(:name "query" :args (list '(:name "query"
:type string :type string
:description "Plain list of strings to match entry headings and content against. Example: \"tag1\" \"tag2\"")) :description "The string to match entry headings and content against."))
:category "org-ql")) :category "org-ql"))
(provide 'gptel-org-tools) (provide 'gptel-org-tools)