gptel: Make model parameters global

* gptel.el (gptel-backend, gptel-model, gptel-temperature,
gptel-max-tokens, gptel--num-messages-to-send,
gptel--system-message): Make all model/request paramters global
variables, i.e. not buffer-local by default.  This is following
the discussion in #249.

* gptel-transient.el (gptel-menu, gptel-system-prompt--setup,
gptel-system-prompt, gptel--suffix-system-message,
gptel--infix-provider, gptel--infix-temperature, gptel--switches,
gptel--set-buffer-locally, gptel--set-with-scope): and associated
transient methods: add a toggle `gptel--set-buffer-locally` to
allow model parameters to be set buffer-locally.  The function
`gptel--set-with-scope` can be used to reset a variable or set it
buffer-locally.

Reorder gptel-transient so all the custom classes, methods and
utility functions are at the top.

* README.org (all backend sections): Replace `setq-default` with
setq in the recommended configuration.
This commit is contained in:
Karthik Chikmagalur 2024-03-16 18:30:49 -07:00
parent e3b3591d73
commit 5dcbf40066
3 changed files with 220 additions and 156 deletions

View file

@ -160,10 +160,10 @@ You can pick this backend from the menu when using gptel. (see [[#usage][Usage]]
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "gpt-3.5-turbo" gptel-model "gpt-3.5-turbo"
gptel-backend (gptel-make-azure "Azure-1" gptel-backend (gptel-make-azure "Azure-1"
:protocol "https" :protocol "https"
@ -192,10 +192,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. Additionally you may want to increase the response token size since GPT4All uses very short (often truncated) responses by default. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above. Additionally you may want to increase the response token size since GPT4All uses very short (often truncated) responses by default.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-max-tokens 500 gptel-max-tokens 500
gptel-model "mistral-7b-openorca.Q4_0.gguf" gptel-model "mistral-7b-openorca.Q4_0.gguf"
gptel-backend (gptel-make-gpt4all "GPT4All" gptel-backend (gptel-make-gpt4all "GPT4All"
@ -223,10 +223,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "mistral:latest" gptel-model "mistral:latest"
gptel-backend (gptel-make-ollama "Ollama" gptel-backend (gptel-make-ollama "Ollama"
:host "localhost:11434" :host "localhost:11434"
@ -251,10 +251,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "gemini-pro" gptel-model "gemini-pro"
gptel-backend (gptel-make-gemini "Gemini" gptel-backend (gptel-make-gemini "Gemini"
:key "YOUR_GEMINI_API_KEY" :key "YOUR_GEMINI_API_KEY"
@ -285,10 +285,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "test" gptel-model "test"
gptel-backend (gptel-make-openai "llama-cpp" gptel-backend (gptel-make-openai "llama-cpp"
:stream t :stream t
@ -319,10 +319,10 @@ You can pick this backend and the model (fastgpt/summarizer) from the transient
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "fastgpt" gptel-model "fastgpt"
gptel-backend (gptel-make-kagi "Kagi" gptel-backend (gptel-make-kagi "Kagi"
:key "YOUR_KAGI_API_KEY")) :key "YOUR_KAGI_API_KEY"))
@ -352,10 +352,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "mistralai/Mixtral-8x7B-Instruct-v0.1" gptel-model "mistralai/Mixtral-8x7B-Instruct-v0.1"
gptel-backend gptel-backend
(gptel-make-openai "TogetherAI" (gptel-make-openai "TogetherAI"
@ -387,10 +387,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "mistralai/Mixtral-8x7B-Instruct-v0.1" gptel-model "mistralai/Mixtral-8x7B-Instruct-v0.1"
gptel-backend gptel-backend
(gptel-make-openai "Anyscale" (gptel-make-openai "Anyscale"
@ -424,10 +424,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "pplx-7b-chat" gptel-model "pplx-7b-chat"
gptel-backend gptel-backend
(gptel-make-openai "Perplexity" (gptel-make-openai "Perplexity"
@ -458,10 +458,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq
gptel-model "claude-3-sonnet-20240229" ; "claude-3-opus-20240229" also available gptel-model "claude-3-sonnet-20240229" ; "claude-3-opus-20240229" also available
gptel-backend (gptel-make-anthropic "Claude" gptel-backend (gptel-make-anthropic "Claude"
:stream t :key "your-api-key")) :stream t :key "your-api-key"))
@ -489,11 +489,10 @@ You can pick this backend from the menu when using gptel (see [[#usage][Usage]])
***** (Optional) Set as the default gptel backend ***** (Optional) Set as the default gptel backend
The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the default value of =gptel-backend=. Use this instead of the above. The above code makes the backend available to select. If you want it to be the default backend for gptel, you can set this as the value of =gptel-backend=. Use this instead of the above.
#+begin_src emacs-lisp #+begin_src emacs-lisp
;; OPTIONAL configuration ;; OPTIONAL configuration
(setq-default (setq gptel-model "mixtral-8x7b-32768"
gptel-model "mixtral-8x7b-32768"
gptel-backend gptel-backend
(gptel-make-openai "Groq" (gptel-make-openai "Groq"
:host "api.groq.com" :host "api.groq.com"

View file

@ -33,7 +33,61 @@
(declare-function ediff-make-cloned-buffer "ediff-utils") (declare-function ediff-make-cloned-buffer "ediff-utils")
;; * Helper functions ;; * Helper functions and vars
(defvar gptel--set-buffer-locally nil
"Set model parameters from `gptel-menu' buffer-locally.
Affects the system message too.")
(defun gptel--set-with-scope (sym value &optional scope)
"Set SYMBOL's symbol-value to VALUE with SCOPE.
If SCOPE is non-nil, set it buffer-locally, else clear any
buffer-local value and set its default global value."
(if scope
(set (make-local-variable sym) value)
(kill-local-variable sym)
(set sym value)))
(defun gptel--get-directive (args)
"Find the additional directive in the transient ARGS.
Meant to be called when `gptel-menu' is active."
(cl-some (lambda (s) (and (stringp s) (string-prefix-p ":" s)
(concat "\n\n" (substring s 1))))
args))
(defun gptel--instructions-make-overlay (text &optional ov)
"TODO"
(save-excursion
(cond
((use-region-p) (goto-char (region-beginning)))
((gptel--in-response-p) (gptel-beginning-of-response))
(t (text-property-search-backward 'gptel 'response)))
(skip-chars-forward "\n \t")
(if (and ov (overlayp ov))
(move-overlay ov (point) (point) (current-buffer))
(setq ov (make-overlay (point) (point) nil t)))
(overlay-put ov 'before-string nil)
;; (unless (or (bobp) (eq (char-before) "\n"))
;; (overlay-put ov 'before-string (propertize "\n" 'font-lock-face 'shadow)))
(overlay-put ov 'category 'gptel)
(overlay-put
ov 'after-string
(concat
(propertize (concat "GPTEL: " text)
'font-lock-face '(:inherit shadow :box t))
"\n"))
ov))
(defun gptel--transient-read-variable (prompt initial-input history)
"Read value from minibuffer and interpret the result as a Lisp object.
PROMPT, INITIAL-INPUT and HISTORY are as in the Transient reader
documention."
(ignore-errors
(read-from-minibuffer prompt initial-input read-expression-map t history)))
(defun gptel--refactor-or-rewrite () (defun gptel--refactor-or-rewrite ()
"Rewrite should be refactored into refactor. "Rewrite should be refactored into refactor.
@ -105,6 +159,100 @@ which see."
(forward-line 1))))) (forward-line 1)))))
gptel--crowdsourced-prompts)) gptel--crowdsourced-prompts))
;; * Transient classes and methods for gptel
(defclass gptel--switches (transient-lisp-variable)
((display-if-true :initarg :display-if-true :initform "for this buffer")
(display-if-false :initarg :display-if-false :initform "globally"))
"Boolean lisp variable class for gptel-transient.")
(cl-defmethod transient-infix-read ((obj gptel--switches))
"Cycle through the mutually exclusive switches."
(not (oref obj value)))
(cl-defmethod transient-format-value ((obj gptel--switches))
(with-slots (value display-if-true display-if-false) obj
(format
(propertize "(%s)" 'face 'transient-delimiter)
(concat
(propertize display-if-false
'face (if value 'transient-inactive-value 'transient-value))
(propertize "|" 'face 'transient-delimiter)
(propertize display-if-true
'face (if value 'transient-value 'transient-inactive-value))))))
(defclass gptel-lisp-variable (transient-lisp-variable)
((display-nil :initarg :display-nil))
"Lisp variables that show :display-nil instead of nil.")
(cl-defmethod transient-format-value
((obj gptel-lisp-variable))
(propertize (prin1-to-string (or (oref obj value)
(oref obj display-nil)))
'face 'transient-value))
(cl-defmethod transient-infix-set ((obj gptel-lisp-variable) value)
(funcall (oref obj set-value)
(oref obj variable)
(oset obj value value)
gptel--set-buffer-locally))
(defclass gptel-provider-variable (transient-lisp-variable)
((model :initarg :model)
(model-value :initarg :model-value)
(always-read :initform t)
(set-value :initarg :set-value :initform #'set))
"Class used for gptel-backends.")
(cl-defmethod transient-format-value ((obj gptel-provider-variable))
(propertize (concat (gptel-backend-name (oref obj value)) ":"
(buffer-local-value (oref obj model) transient--original-buffer))
'face 'transient-value))
(cl-defmethod transient-infix-set ((obj gptel-provider-variable) value)
(pcase-let ((`(,backend-value ,model-value) value))
(funcall (oref obj set-value)
(oref obj variable)
(oset obj value backend-value)
gptel--set-buffer-locally)
(funcall (oref obj set-value)
(oref obj model)
(oset obj model-value model-value)
gptel--set-buffer-locally)))
(defclass gptel-option-overlaid (transient-option)
((display-nil :initarg :display-nil)
(overlay :initarg :overlay))
"Transient options for overlays displayed in the working buffer.")
(cl-defmethod transient-format-value ((obj gptel-option-overlaid))
"set up the in-buffer overlay for additional directive, a string.
Also format its value in the Transient menu."
(let ((value (oref obj value))
(ov (oref obj overlay))
(argument (oref obj argument)))
;; Making an overlay
(if (or (not value) (string-empty-p value))
(when ov (delete-overlay ov))
(with-current-buffer transient--original-buffer
(oset obj overlay (gptel--instructions-make-overlay value ov)))
(letrec ((ov-clear-hook
(lambda () (when-let* ((ov (oref obj overlay))
((overlayp ov)))
(remove-hook 'transient-exit-hook
ov-clear-hook)
(delete-overlay ov)))))
(add-hook 'transient-exit-hook ov-clear-hook)))
;; Updating transient menu display
(if value
(propertize (concat argument (truncate-string-to-width value 25 nil nil "..."))
'face 'transient-value)
(propertize
(concat "(" (symbol-name (oref obj display-nil)) ")")
'face 'transient-inactive-value))))
;; * Transient Prefixes ;; * Transient Prefixes
@ -120,12 +268,14 @@ which see."
(string-replace (string-replace
"\n" "" "\n" ""
(truncate-string-to-width (truncate-string-to-width
gptel--system-message (max (- (window-width) 6) 14) nil nil t))) gptel--system-message (max (- (window-width) 12) 14) nil nil t)))
["" [""
"Instructions" "Instructions"
("s" "Set system message" gptel-system-prompt :transient t) ("s" "Set system message" gptel-system-prompt :transient t)
(gptel--infix-add-directive)]] (gptel--infix-add-directive)]]
[["Model Parameters" [[:pad-keys t
"Model Parameters"
(gptel--infix-variable-scope)
(gptel--infix-provider) (gptel--infix-provider)
(gptel--infix-max-tokens) (gptel--infix-max-tokens)
(gptel--infix-num-messages-to-send) (gptel--infix-num-messages-to-send)
@ -238,12 +388,12 @@ which see."
(message "Directive: %s" (message "Directive: %s"
,(string-replace "\n" "" ,(string-replace "\n" ""
(truncate-string-to-width prompt 100 nil nil t))) (truncate-string-to-width prompt 100 nil nil t)))
(setq gptel--system-message ,prompt)) (gptel--set-with-scope 'gptel--system-message ,prompt
gptel--set-buffer-locally))
:transient 'transient--do-return) :transient 'transient--do-return)
into prompt-suffixes into prompt-suffixes
finally return finally return
(nconc (nconc
(list (list 'gptel--suffix-system-message))
prompt-suffixes prompt-suffixes
(list (list "SPC" "Pick crowdsourced prompt" (list (list "SPC" "Pick crowdsourced prompt"
'gptel--read-crowdsourced-prompt 'gptel--read-crowdsourced-prompt
@ -267,12 +417,13 @@ More extensive system messages can be useful for specific tasks.
Customize `gptel-directives' for task-specific prompts." Customize `gptel-directives' for task-specific prompts."
[:description [:description
(lambda () (format "System Message: %s" (lambda () (string-replace
(string-replace
"\n" "" "\n" ""
(truncate-string-to-width (truncate-string-to-width
gptel--system-message 100 nil nil t)))) gptel--system-message (max (- (window-width) 12) 14) nil nil t)))
:class transient-column [(gptel--suffix-system-message)]
[(gptel--infix-variable-scope)]]
[:class transient-column
:setup-children gptel-system-prompt--setup :setup-children gptel-system-prompt--setup
:pad-keys t]) :pad-keys t])
@ -305,23 +456,14 @@ Customize `gptel-directives' for task-specific prompts."
;; ** Infixes for model parameters ;; ** Infixes for model parameters
(defun gptel--transient-read-variable (prompt initial-input history) (transient-define-infix gptel--infix-variable-scope ()
"Read value from minibuffer and interpret the result as a Lisp object. "Set gptel's model parameters and system message in this buffer or globally."
:argument "scope"
PROMPT, INITIAL-INPUT and HISTORY are as in the Transient reader :variable 'gptel--set-buffer-locally
documention." :class 'gptel--switches
(ignore-errors :format " %k %d %v"
(read-from-minibuffer prompt initial-input read-expression-map t history))) :key "="
:description (propertize "Set" 'face 'transient-inactive-argument))
(defclass gptel-lisp-variable (transient-lisp-variable)
((display-nil :initarg :display-nil))
"Lisp variables that show :display-nil instead of nil.")
(cl-defmethod transient-format-value
((obj gptel-lisp-variable))
(propertize (prin1-to-string (or (oref obj value)
(oref obj display-nil)))
'face 'transient-value))
(transient-define-infix gptel--infix-num-messages-to-send () (transient-define-infix gptel--infix-num-messages-to-send ()
"Number of recent messages to send with each exchange. "Number of recent messages to send with each exchange.
@ -333,6 +475,7 @@ include."
:description "previous responses" :description "previous responses"
:class 'gptel-lisp-variable :class 'gptel-lisp-variable
:variable 'gptel--num-messages-to-send :variable 'gptel--num-messages-to-send
:set-value #'gptel--set-with-scope
:display-nil 'all :display-nil 'all
:format " %k %v %d" :format " %k %v %d"
:key "-n" :key "-n"
@ -348,38 +491,19 @@ responses."
:description "Response length (tokens)" :description "Response length (tokens)"
:class 'gptel-lisp-variable :class 'gptel-lisp-variable
:variable 'gptel-max-tokens :variable 'gptel-max-tokens
:set-value #'gptel--set-with-scope
:display-nil 'auto :display-nil 'auto
:key "-c" :key "-c"
:prompt "Response length in tokens (leave empty: default, 80-200: short, 200-500: long): " :prompt "Response length in tokens (leave empty: default, 80-200: short, 200-500: long): "
:reader 'gptel--transient-read-variable) :reader 'gptel--transient-read-variable)
(defclass gptel-provider-variable (transient-lisp-variable)
((model :initarg :model)
(model-value :initarg :model-value)
(always-read :initform t)
(set-value :initarg :set-value :initform #'set))
"Class used for gptel-backends.")
(cl-defmethod transient-format-value ((obj gptel-provider-variable))
(propertize (concat (gptel-backend-name (oref obj value)) ":"
(buffer-local-value (oref obj model) transient--original-buffer))
'face 'transient-value))
(cl-defmethod transient-infix-set ((obj gptel-provider-variable) value)
(pcase-let ((`(,backend-value ,model-value) value))
(funcall (oref obj set-value)
(oref obj variable)
(oset obj value backend-value))
(funcall (oref obj set-value)
(oref obj model)
(oset obj model-value model-value))))
(transient-define-infix gptel--infix-provider () (transient-define-infix gptel--infix-provider ()
"AI Provider for Chat." "AI Provider for Chat."
:description "GPT Model" :description "GPT Model"
:class 'gptel-provider-variable :class 'gptel-provider-variable
:prompt "Model provider: " :prompt "Model: "
:variable 'gptel-backend :variable 'gptel-backend
:set-value #'gptel--set-with-scope
:model 'gptel-model :model 'gptel-model
:key "-m" :key "-m"
:reader (lambda (prompt &rest _) :reader (lambda (prompt &rest _)
@ -388,7 +512,7 @@ responses."
nconc (cl-loop for model in (gptel-backend-models backend) nconc (cl-loop for model in (gptel-backend-models backend)
collect (list (concat name ":" model) backend model)) collect (list (concat name ":" model) backend model))
into models-alist finally return into models-alist finally return
(cdr (assoc (completing-read "Model: " models-alist nil t) (cdr (assoc (completing-read prompt models-alist nil t)
models-alist))))) models-alist)))))
(transient-define-infix gptel--infix-temperature () (transient-define-infix gptel--infix-temperature ()
@ -396,67 +520,13 @@ responses."
:description "Temperature (0 - 2.0)" :description "Temperature (0 - 2.0)"
:class 'transient-lisp-variable :class 'transient-lisp-variable
:variable 'gptel-temperature :variable 'gptel-temperature
:set-value #'gptel--set-with-scope
:key "-t" :key "-t"
:prompt "Temperature controls the response randomness (0.0-2.0, leave empty for default): " :prompt "Temperature controls the response randomness (0.0-2.0, leave empty for default): "
:reader 'gptel--transient-read-variable) :reader 'gptel--transient-read-variable)
;; ** Infix for the refactor/rewrite system message ;; ** Infix for the refactor/rewrite system message
(defun gptel--instructions-make-overlay (text &optional ov)
"TODO"
(save-excursion
(cond
((use-region-p) (goto-char (region-beginning)))
((gptel--in-response-p) (gptel-beginning-of-response))
(t (text-property-search-backward 'gptel 'response)))
(skip-chars-forward "\n \t")
(if (and ov (overlayp ov))
(move-overlay ov (point) (point) (current-buffer))
(setq ov (make-overlay (point) (point) nil t)))
(overlay-put ov 'before-string nil)
;; (unless (or (bobp) (eq (char-before) "\n"))
;; (overlay-put ov 'before-string (propertize "\n" 'font-lock-face 'shadow)))
(overlay-put ov 'category 'gptel)
(overlay-put
ov 'after-string
(concat
(propertize (concat "GPTEL: " text)
'font-lock-face '(:inherit shadow :box t))
"\n"))
ov))
(defclass gptel-option-overlaid (transient-option)
((display-nil :initarg :display-nil)
(overlay :initarg :overlay))
"Transient options for overlays displayed in the working buffer.")
(cl-defmethod transient-format-value ((obj gptel-option-overlaid))
"set up the in-buffer overlay for additional directive, a string.
Also format its value in the Transient menu."
(let ((value (oref obj value))
(ov (oref obj overlay))
(argument (oref obj argument)))
;; Making an overlay
(if (or (not value) (string-empty-p value))
(when ov (delete-overlay ov))
(with-current-buffer transient--original-buffer
(oset obj overlay (gptel--instructions-make-overlay value ov)))
(letrec ((ov-clear-hook
(lambda () (when-let* ((ov (oref obj overlay))
((overlayp ov)))
(remove-hook 'transient-exit-hook
ov-clear-hook)
(delete-overlay ov)))))
(add-hook 'transient-exit-hook ov-clear-hook)))
;; Updating transient menu display
(if value
(propertize (concat argument (truncate-string-to-width value 25 nil nil "..."))
'face 'transient-value)
(propertize
(concat "(" (symbol-name (oref obj display-nil)) ")")
'face 'transient-inactive-value))))
(transient-define-infix gptel--infix-add-directive () (transient-define-infix gptel--infix-add-directive ()
"Additional directive intended for the next query only. "Additional directive intended for the next query only.
@ -487,12 +557,6 @@ Or in an extended conversation:
:description "Add directive" :description "Add directive"
:transient t) :transient t)
(defun gptel--get-directive (args)
"Find the additional directive in the transient ARGS of this command."
(cl-some (lambda (s) (and (string-prefix-p ":" s)
(concat "\n\n" (substring s 1))))
args))
(transient-define-infix gptel--infix-rewrite-prompt () (transient-define-infix gptel--infix-rewrite-prompt ()
"Chat directive (system message) to use for rewriting or refactoring." "Chat directive (system message) to use for rewriting or refactoring."
:description (lambda () (if (derived-mode-p 'prog-mode) :description (lambda () (if (derived-mode-p 'prog-mode)
@ -564,7 +628,7 @@ Or in an extended conversation:
backend-name backend-name
(truncate-string-to-width resp 30)))))) (truncate-string-to-width resp 30))))))
((setq gptel-buffer-name ((setq gptel-buffer-name
(cl-some (lambda (s) (and (string-prefix-p "g" s) (cl-some (lambda (s) (and (stringp s) (string-prefix-p "g" s)
(substring s 1))) (substring s 1)))
args)) args))
(setq output-to-other-buffer-p t) (setq output-to-other-buffer-p t)
@ -616,7 +680,7 @@ Or in an extended conversation:
(gptel--update-status " Waiting..." 'warning) (gptel--update-status " Waiting..." 'warning)
(setq position (point))))))) (setq position (point)))))))
((setq gptel-buffer-name ((setq gptel-buffer-name
(cl-some (lambda (s) (and (string-prefix-p "b" s) (cl-some (lambda (s) (and (stringp s) (string-prefix-p "b" s)
(substring s 1))) (substring s 1)))
args)) args))
(setq output-to-other-buffer-p t) (setq output-to-other-buffer-p t)
@ -717,9 +781,12 @@ This uses the prompts in the variable
(message "No prompts available."))) (message "No prompts available.")))
(transient-define-suffix gptel--suffix-system-message () (transient-define-suffix gptel--suffix-system-message ()
"Edit LLM directives." "Edit LLM system message.
When LOCAL is non-nil, set the system message only in the current buffer."
:transient 'transient--do-exit :transient 'transient--do-exit
:description "Set or edit system message" :description "Set or edit system message"
:format " %k %d"
:key "s" :key "s"
(interactive) (interactive)
(let ((orig-buf (current-buffer)) (let ((orig-buf (current-buffer))
@ -771,7 +838,8 @@ This uses the prompts in the variable
(let ((system-message (let ((system-message
(buffer-substring msg-start (point-max)))) (buffer-substring msg-start (point-max))))
(with-current-buffer orig-buf (with-current-buffer orig-buf
(setq gptel--system-message system-message))) (gptel--set-with-scope 'gptel--system-message system-message
gptel--set-buffer-locally)))
(funcall quit-to-menu))) (funcall quit-to-menu)))
(local-set-key (kbd "C-c C-k") quit-to-menu))))) (local-set-key (kbd "C-c C-k") quit-to-menu)))))

View file

@ -369,7 +369,8 @@ interactively call `gptel-send' with a prefix argument."
:safe #'always :safe #'always
:type '(alist :key-type symbol :value-type string)) :type '(alist :key-type symbol :value-type string))
(defvar-local gptel--system-message (alist-get 'default gptel-directives)) (defvar gptel--system-message (alist-get 'default gptel-directives)
"The system message used by gptel.")
(put 'gptel--system-message 'safe-local-variable #'always) (put 'gptel--system-message 'safe-local-variable #'always)
(defcustom gptel-max-tokens nil (defcustom gptel-max-tokens nil
@ -381,7 +382,6 @@ responses.
To set the target token count for a chat session interactively To set the target token count for a chat session interactively
call `gptel-send' with a prefix argument." call `gptel-send' with a prefix argument."
:local t
:safe #'always :safe #'always
:group 'gptel :group 'gptel
:type '(choice (integer :tag "Specify Token count") :type '(choice (integer :tag "Specify Token count")
@ -401,7 +401,6 @@ The current options for ChatGPT are
To set the model for a chat session interactively call To set the model for a chat session interactively call
`gptel-send' with a prefix argument." `gptel-send' with a prefix argument."
:local t
:safe #'always :safe #'always
:group 'gptel :group 'gptel
:type '(choice :type '(choice
@ -421,7 +420,6 @@ of the response, with 2.0 being the most random.
To set the temperature for a chat session interactively call To set the temperature for a chat session interactively call
`gptel-send' with a prefix argument." `gptel-send' with a prefix argument."
:local t
:safe #'always :safe #'always
:group 'gptel :group 'gptel
:type 'number) :type 'number)
@ -461,7 +459,6 @@ one of the available backend creation functions:
- `gptel-make-gemini' - `gptel-make-gemini'
See their documentation for more information and the package See their documentation for more information and the package
README for examples." README for examples."
:local t
:safe #'always :safe #'always
:group 'gptel :group 'gptel
:type `(choice :type `(choice
@ -477,7 +474,7 @@ This opens up advanced options in `gptel-menu'.")
(defvar-local gptel--bounds nil) (defvar-local gptel--bounds nil)
(put 'gptel--bounds 'safe-local-variable #'always) (put 'gptel--bounds 'safe-local-variable #'always)
(defvar-local gptel--num-messages-to-send nil) (defvar gptel--num-messages-to-send nil)
(put 'gptel--num-messages-to-send 'safe-local-variable #'always) (put 'gptel--num-messages-to-send 'safe-local-variable #'always)
(defcustom gptel-log-level nil (defcustom gptel-log-level nil