This uses the tool support from gptel to let any LLM with tool support

  • search my bbdb for contact info
  • perform a bbdb search for all contacts with an anniversary field
  • use gnus to compose an email

plus a few helper functions to make it useful (like giving it the ability to query the current date).

The tool definition it used in the above screenshot are:

(defun gptel-tool--get-date ()
  "Return the current date"
  (format-time-string "%Y-%m-%d"))

(defun gptel-tool--compose-email (to-address subject text)
  "Open an email compose buffer '*new message*' to to-address with subject subject."
  (gnus-setup-message 'message (message-mail to-address subject))
  (insert (concat "\n" text)))

(defun gptel-tool--bbdb-search (name)
  "Search bbdb for NAME"
  (bbdb-search (bbdb-records) :name name))

(defun gptel-tool--bbdb-search-anniversary (anniversary-type)
  "Search bbdb for anniversary with ANNIVERSARY-TYPE"
  (let ((bbdb-default-xfield 'anniversary))
    (bbdb-search (bbdb-records) :xfield anniversary-type)))

And they get registered with the following code:

      (gptel-make-tool
       :function #'gptel-tool--get-date
       :name  "gptel-tool--get-date"
       :description "Use to get the current date in %Y-%m-%d format. After calling this tool, stop. Then continue fulfilling user's request."
       :category "emacs")

      (gptel-make-tool
       :function #'gptel-tool--compose-email
       :name  "gptel-tool--compose-email"
       :description "Open an email compose buffer and set subject, to-address and body. After calling this tool, stop. Then continue fulfilling user's request."
       :args (list '(:name "to-address"
                           :type string
                           :description "The address to send to")
                   '(:name "subject"
                           :type string
                           :description "The mail subject")
                   '(:name "body"
                           :type string
                           :description "The body text of the email"))
       :category "emacs")

      (gptel-make-tool
       :function #'gptel-tool--bbdb-search
       :name  "gptel-tool--bbdb-search"
       :description "Return a bbdb entry for name, or nil if not found. After calling this tool, stop. Then continue fulfilling user's request."
       :args (list '(:name "name"
                           :type string
                           :description "The name to search for"))
       :category "emacs")

      (gptel-make-tool
       :function #'gptel-tool--bbdb-search-anniversary
       :name  "gptel-tool--bbdb-search-anniversary"
       :description "Return or a specific anniversary type. After calling this tool, stop. Then continue fulfilling user's request."
       :args (list '(:name "anniversary-type"
                           :type string
                           :description "The anniversary to search for, for example 'birthday' for birthdays"))
       :category "emacs")