summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-08-13 12:01:33 -0500
committerCraig Jennings <c@cjennings.net>2025-08-13 12:01:33 -0500
commit36af271a71606b628a395950f3233a55afc91800 (patch)
tree0067a5734630944d2709d63999f7fda06955adc0 /modules
parentef9602052894e97f8bd8abba7306169caf5c5ee8 (diff)
downloaddotemacs-36af271a71606b628a395950f3233a55afc91800.tar.gz
dotemacs-36af271a71606b628a395950f3233a55afc91800.zip
added user and LLM model and version + timestamp for all responses
Diffstat (limited to 'modules')
-rw-r--r--modules/ai-config.el127
1 files changed, 107 insertions, 20 deletions
diff --git a/modules/ai-config.el b/modules/ai-config.el
index 643bac0b..196a2fad 100644
--- a/modules/ai-config.el
+++ b/modules/ai-config.el
@@ -20,9 +20,6 @@
;;; Code:
-;; ----------------------------------- GPTel -----------------------------------
-;; integration with ChatGPT and other large language models.
-
(defvar default-directive
"You are a large language model living in Emacs. You understand philosophy, critical theory, and comparative
literature at a university graduate student level. You are concise and always provide references to source material.")
@@ -38,38 +35,128 @@
"You are a large language model and a funny conversation partner who asks good questions.")
-(defun toggle-gptel ()
- "Toggle the visibility of the ChatGPT buffer."
+;; -------------------------------- Toggle GPTel -------------------------------
+;; Toggle GPTel's buffer in a side window
+
+(defun cj/toggle-gptel ()
+ "Toggle the visibility of the ChatGPT buffer without prompting for a name."
(interactive)
- (let ((buffer (get-buffer "*ChatGPT*")))
- (if (and buffer (get-buffer-window buffer))
- (delete-window (get-buffer-window buffer))
- (if buffer
- (display-buffer-in-side-window buffer '((side . right) (window-width . 0.4)))
- (gptel)))))
+ (let ((buffer (get-buffer "*AI-Assistant*")))
+ (if (and buffer (get-buffer-window buffer))
+ (delete-window (get-buffer-window buffer))
+ (if buffer
+ (display-buffer-in-side-window buffer '((side . right) (window-width . 0.4)))
+ ;; Call gptel with a fixed buffer name to skip prompt
+ (gptel "*AI-Assistant*" gptel-model)))))
+
+;; ;; defer prefixing the prompt until gptel is actually loaded
+;; (with-eval-after-load 'gptel
+;; ;; Define the var if the package hasn't yet
+;; (unless (boundp 'gptel-prompt-prefix-alist)
+;; (defvar gptel-prompt-prefix-alist nil
+;; "Alist mapping major modes to prompt prefixes for gptel.")
+;; (add-to-list 'gptel-prompt-prefix-alist
+;; (cons 'org-mode
+;; (concat "*** cj "
+;; (format-time-string "[%Y-%m-%d %H:%M:%S]")
+;; "\n")))))
+
+;; ----------------------------------- GPTel -----------------------------------
+;; Emacs integration with large language models
(use-package gptel
- :defer t
+ :defer .5
:commands (gptel gptel-send)
:bind
- (("C-h G" . gptel)
- ("<f9>" . toggle-gptel)
+ (("C-h G" . cj/toggle-gptel)
+ ("<f9>" . cj/toggle-gptel)
(:map gptel-mode-map
- ("C-<return>" . gptel-send)))
+ ("C-<return>" . gptel-send)))
:custom
- (gptel-model "gpt-4")
(gptel-default-mode 'org-mode)
+ (gptel-expert-commands t)
+ (gptel-track-media t)
+ (gptel-include-reasoning 'ignore)
+ (gptel-model 'gpt-4o)
+ (gptel-log-level 'info)
+ (gptel--debug nil)
:config
(setq gptel-directives
- `((default . ,default-directive)
- (code-only . ,code-only-directive)
- (writing . ,writing-directive)
- (chat . ,chat-directive)))
+ `((default . ,default-directive)
+ (code-only . ,code-only-directive)
+ (writing . ,writing-directive)
+ (chat . ,chat-directive)))
+
+ ;; fancy prompt
+ (add-to-list 'gptel-prompt-prefix-alist
+ (cons 'org-mode
+ (concat "*** cj "
+ (format-time-string "[%Y-%m-%d %H:%M:%S]")
+ "\n")))
;; Grab the secret from the auth file
(setq auth-sources `((:source ,authinfo-file)))
(setq gptel-api-key (auth-source-pick-first-password :host "api.openai.com")))
+;; -------------------------- GPTel Fancy Org Headers --------------------------
+;; each response will be generated under it's own org mode header with backend
+;; and model indicated. This is useful for leveraging several LLMs and comparing
+;; and saving responses between them.
+
+(defun cj/gptel-backend-and-model ()
+ "Return gptel backend and model with timestamp in the desired format."
+ (let ((backend (if (boundp 'gptel-backend) (aref gptel-backend 1)))
+ (model (if (boundp 'gptel-model) gptel-model))
+ (timestamp (format-time-string "[%Y-%m-%d %H:%M:%S]")))
+ (format "%s: %s %s" backend model timestamp)))
+
+(defun cj/gptel-insert-model-in-non-gptel-buffers ()
+ "Add the backend, model, and timestamp in non-dedicated GPTel buffers.
+To be used in `gptel-pre-response-hook`."
+ (unless (member 'gptel-mode local-minor-modes)
+ (goto-char (point-max))
+ (insert (format "\n%s: " (cj/gptel-backend-and-model)))
+ (goto-char (point-max))))
+
+(defun cj/gptel-insert-model-in-chat-buffers (response-begin-pos response-end-pos)
+ "Add the backend, model, and timestamp in dedicated chat buffers.
+Can be used with the `gptel-post-response-functions` hook."
+ (let* ((gptel-org-prefix (alist-get 'org-mode gptel-prompt-prefix-alist))
+ (inserted-string (format "%s %s\n"
+ (substring gptel-org-prefix 0 (string-match " " gptel-org-prefix))
+ (cj/gptel-backend-and-model)))
+ (len-inserted (length inserted-string)))
+ (goto-char response-begin-pos)
+ (insert inserted-string)
+ (goto-char (+ response-end-pos len-inserted))))
+
+;; (defun cj/gptel-backend-and-model ()
+;; "Return gptel backend and model (if any)."
+;; (let ((backend (if (boundp 'gptel-backend) (aref gptel-backend 1)))
+;; (model (if (boundp 'gptel-model) gptel-model)))
+;; (format "(%s %s)" backend model)))
+
+;; (defun cj/gptel-insert-model-in-non-gptel-buffers ()
+;; "This function will add the backend and model in the \"dynamic\" buffers, not in dedicated chat buffers.
+;; To be used in `gptel-pre-response-hook'."
+;; (unless (member 'gptel-mode local-minor-modes)
+;; (goto-char (point-max))
+;; (insert (format "\n%s: " (cj/gptel-backend-and-model)))
+;; (goto-char (point-max))))
+;; (add-hook 'gptel-pre-response-hook 'cj/gptel-insert-model-in-non-gptel-buffers)
+
+;; (defun cj/gptel-insert-model-in-chat-buffers (response-begin-pos response-end-pos)
+;; "This function adds the backend and model in dedicated chat buffers.
+;; Can be used with the `gptel-post-response-functions' hook."
+;; (let* ((gptel-org-prefix (alist-get 'org-mode gptel-prompt-prefix-alist))
+;; (inserted-string (format "%s %s\n"
+;; (substring gptel-org-prefix 0 (string-match " " gptel-org-prefix))
+;; (cj/gptel-backend-and-model)))
+;; (len-inserted (length inserted-string )))
+;; (goto-char response-begin-pos)
+;; (insert inserted-string)
+;; (goto-char (+ response-end-pos len-inserted))))
+;; (add-hook 'gptel-post-response-functions 'cj/gptel-insert-model-in-chat-buffers)
(provide 'ai-config)
;;; ai-config.el ends here