From 644e3412443ad9eb1e6e7d822537b5b74a66faed Mon Sep 17 00:00:00 2001 From: daedsidog <41439659+daedsidog@users.noreply.github.com> Date: Fri, 15 Dec 2023 19:30:16 +0200 Subject: [PATCH] Add multiline prefixes & AI response prefixes (#142) gptel: Add customizable prompt/response prefixes gptel.el (gptel-prompt-prefix-alist, gptel-response-prefix-alist, gptel-prompt-prefix-string, gptel-response-prefix-string, gptel--url-get-response): Add customizable response prefixes (per major-mode) in `gptel-response-prefix-alist`. Rename `gptel-prompt-string` -> `gptel-prompt-prefix-string` The function `gptel-response-prefix-string` returns the prefix string for the response in the current major-mode. gptel-openai.el, gptel-ollama.el (gptel--parse-buffer): Remove the prompt and response prefixes when creating prompt strings to send to the LLM API. gptel-curl.el (gptel-curl--stream-cleanup, gptel-curl--stream-insert-response): Insert the response prefix for the current major-mode before inserting the LLM API response. --- gptel-curl.el | 7 +++++-- gptel-ollama.el | 8 +++++--- gptel-openai.el | 3 ++- gptel.el | 26 +++++++++++++++++++++----- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/gptel-curl.el b/gptel-curl.el index 027dfb5..9035873 100644 --- a/gptel-curl.el +++ b/gptel-curl.el @@ -183,7 +183,7 @@ PROCESS and _STATUS are process parameters." (with-current-buffer (marker-buffer start-marker) (pulse-momentary-highlight-region (+ start-marker 2) tracking-marker) (when gptel-mode (save-excursion (goto-char tracking-marker) - (insert "\n\n" (gptel-prompt-string))))) + (insert "\n\n" (gptel-prompt-prefix-string))))) (with-current-buffer gptel-buffer (when gptel-mode (gptel--update-header-line " Ready" 'success)))) ;; Or Capture error message @@ -232,7 +232,10 @@ See `gptel--url-get-response' for details." (gptel--update-header-line " Typing..." 'success) (goto-char start-marker) (unless (or (bobp) (plist-get info :in-place)) - (insert "\n\n")) + (insert "\n\n") + (when gptel-mode + ;; Put prefix before AI response. + (insert (gptel-response-prefix-string)))) (setq tracking-marker (set-marker (make-marker) (point))) (set-marker-insertion-type tracking-marker t) (plist-put info :tracking-marker tracking-marker)) diff --git a/gptel-ollama.el b/gptel-ollama.el index d3afd46..2bfd306 100644 --- a/gptel-ollama.el +++ b/gptel-ollama.el @@ -89,9 +89,11 @@ Ollama models.") :system gptel--system-message :prompt (if (prop-match-p prop) - (string-trim (buffer-substring-no-properties (prop-match-beginning prop) - (prop-match-end prop)) - "[*# \t\n\r]+") + (string-trim + (buffer-substring-no-properties (prop-match-beginning prop) + (prop-match-end prop)) + (format "[\t\r\n ]*%s[\t\r\n ]*" (regexp-quote (gptel-prompt-prefix-string))) + (format "[\t\r\n ]*%s[\t\r\n ]*" (regexp-quote (gptel-response-prefix-string)))) "")))))) ;;;###autoload diff --git a/gptel-openai.el b/gptel-openai.el index 0339fa9..cfd2b98 100644 --- a/gptel-openai.el +++ b/gptel-openai.el @@ -100,7 +100,8 @@ (string-trim (buffer-substring-no-properties (prop-match-beginning prop) (prop-match-end prop)) - "[*# \t\n\r]+")) + (format "[\t\r\n ]*%s[\t\r\n ]*" (regexp-quote (gptel-prompt-prefix-string))) + (format "[\t\r\n ]*%s[\t\r\n ]*" (regexp-quote (gptel-response-prefix-string))))) prompts) (and max-entries (cl-decf max-entries))) (cons (list :role "system" diff --git a/gptel.el b/gptel.el index 17d5564..7f9ddb1 100644 --- a/gptel.el +++ b/gptel.el @@ -230,11 +230,22 @@ defaults to `text-mode'." (text-mode . "### ")) "String inserted after the response from ChatGPT. -This is an alist mapping major modes to the prefix strings. This +This is an alist mapping major modes to the prefix strings. This is only inserted in dedicated gptel buffers." :group 'gptel :type '(alist :key-type symbol :value-type string)) +(defcustom gptel-response-prefix-alist + '((markdown-mode . "") + (org-mode . "") + (text-mode . "")) + "String inserted after the response from ChatGPT. + +This is an alist mapping major modes to the reply prefix strings. This +is only inserted in dedicated gptel buffers before the AI's response." + :group 'gptel + :type '(alist :key-type symbol :value-type string)) + (defcustom gptel-crowdsourced-prompts-file (let ((cache-dir (or (getenv "XDG_CACHE_HOME") (getenv "XDG_DATA_HOME") @@ -412,9 +423,12 @@ and \"apikey\" as USER." (skip-syntax-forward "w.") ,@body)) -(defun gptel-prompt-string () +(defun gptel-prompt-prefix-string () (or (alist-get major-mode gptel-prompt-prefix-alist) "")) +(defun gptel-response-prefix-string () + (or (alist-get major-mode gptel-response-prefix-alist) "")) + (defun gptel--restore-state () "Restore gptel state when turning on `gptel-mode'. @@ -733,11 +747,13 @@ See `gptel--url-get-response' for details." (goto-char start-marker) (run-hooks 'gptel-pre-response-hook) (unless (or (bobp) (plist-get info :in-place)) - (insert "\n\n")) + (insert "\n\n") + (when gptel-mode + (insert (gptel-response-prefix-string)))) (let ((p (point))) (insert response) (pulse-momentary-highlight-region p (point))) - (when gptel-mode (insert "\n\n" (gptel-prompt-string)))) + (when gptel-mode (insert "\n\n" (gptel-prompt-prefix-string)))) (when gptel-mode (gptel--update-header-line " Ready" 'success)))) (gptel--update-header-line (format " Response Error: %s" status-str) 'error) @@ -969,9 +985,9 @@ buffer created or switched to." (visual-line-mode 1)) (t (funcall gptel-default-mode))) (unless gptel-mode (gptel-mode 1)) - (if (bobp) (insert (or initial (gptel-prompt-string)))) (goto-char (point-max)) (skip-chars-backward "\t\r\n") + (if (bobp) (insert (or initial (gptel-prompt-prefix-string)))) (when (called-interactively-p 'gptel) (pop-to-buffer (current-buffer)) (message "Send your query with %s!"