branch: externals/ellama
commit bb0bdc2f8ffb82e18d22f4a4bcab954af3a5e91f
Merge: f00f7188cc 50f0f02a39
Author: Sergey Kostyaev <[email protected]>
Commit: GitHub <[email protected]>
Merge pull request #308 from s-kostyaev/enhance-session-management
Add `create-session` parameter to chat commands
---
NEWS.org | 16 +++++
README.org | 18 +++--
ellama-community-prompts.el | 1 +
ellama-context.el | 169 ++++++++++++++++++++++++++++++--------------
ellama-transient.el | 122 +++++++++++++++++++++++++++++---
ellama.el | 118 ++++++++++++++++++++-----------
ellama.info | 67 ++++++++++--------
7 files changed, 368 insertions(+), 143 deletions(-)
diff --git a/NEWS.org b/NEWS.org
index f21abf4945..668491c5b8 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -1,3 +1,19 @@
+* Version 1.8.0
+- Added ~create-session~ optional parameter to ~ellama-ask-about~,
+ ~ellama-ask-selection~, ~ellama-ask-line~, and ~ellama-code-review~ commands,
+ and added ~--new-session~ option to transient commands. These changes allow
+ creating a new session even if one is already active.
+- Added the ability to create an ephemeral session by adding a new ~:ephemeral~
+ argument to various functions and added the ~--ephemeral~ option to several
+ transient commands in ~ellama-transient.el~.
+- Implemented ephemeral context elements that are cleared after a single LLM
+ request. Added corresponding functions and transient suffixes to manage
+ ephemeral context elements, updating existing functions to handle both global
+ and ephemeral contexts.
+- Set up the transient menu to ensure the Ollama model is filled if it's empty.
+- Added ~use-hard-newlines~ variable and updated text insertion to use hard
+ newlines. Ensured that text is inserted only if there is a delta, and
improved
+ the conditional logic for filling paragraphs.
* Version 1.7.2
- Added detailed context management documentation.
* Version 1.7.1
diff --git a/README.org b/README.org
index c1d7ab2918..eed1ffa995 100644
--- a/README.org
+++ b/README.org
@@ -365,7 +365,9 @@ which may not always be appropriate.
A “global context” is maintained, which is a collection of text blocks
accessible to the LLM when responding to prompts. This global context is
-prepened to your prompt before transmission to the LLM.
+prepended to your prompt before transmission to the LLM. Additionally, Ellama
+supports an "ephemeral context," which is temporary and only available for a
+single request.
** Transient Menus for Context Management
@@ -378,12 +380,14 @@ The Context Commands transient menu is structured as
follows:
Context Commands:
-- Add: Provides options for adding content to the global context.
- - “b” "Add Buffer" ~ellama-context-add-buffer~
- - “d” "Add Directory" ~ellama-context-add-directory~
- - “f” "Add File" ~ellama-context-add-file~
- - “s” "Add Selection" ~ellama-context-add-selection~
- - “i” "Add Info Node" ~ellama-context-add-info-node~
+- Options: Provides options for managing ephemeral context.
+ - “-e” "Use Ephemeral Context" ~--ephemeral~
+- Add: Provides options for adding content to the global or ephemeral context.
+ - “b” "Add Buffer" ~ellama-transient-add-buffer~
+ - “d” "Add Directory" ~ellama-transient-add-directory~
+ - “f” "Add File" ~ellama-transient-add-file~
+ - “s” "Add Selection" ~ellama-transient-add-selection~
+ - “i” "Add Info Node" ~ellama-transient-add-info-node~
- Manage: Provides options for managing the global context.
- “m” "Manage context" ~ellama-context-manage~ - Opens the context
management buffer.
diff --git a/ellama-community-prompts.el b/ellama-community-prompts.el
index 9da7af4c38..9c6bd7be2e 100644
--- a/ellama-community-prompts.el
+++ b/ellama-community-prompts.el
@@ -113,6 +113,7 @@ PARSED-LINE is expected to be a list with three elements:
:act,
(defvar ellama-community-prompts-collection nil
"Community prompts collection.")
+;;;###autoload
(defun ellama-community-prompts-ensure ()
"Ensure that the community prompt collection are loaded and available.
This function ensures that the file specified by
`ellama-community-prompts-file'
diff --git a/ellama-context.el b/ellama-context.el
index 76dc55f318..ff0e82ff24 100644
--- a/ellama-context.el
+++ b/ellama-context.el
@@ -62,6 +62,9 @@
(defvar ellama-context-global nil
"Global context.")
+(defvar ellama-context-ephemeral nil
+ "Ephemeral context elements for a single LLM request.")
+
(defvar ellama--context-buffer " *ellama-context*")
(defvar ellama-context-buffer "*ellama-context*")
@@ -71,6 +74,7 @@
"Clear global context."
(interactive)
(setq ellama-context-global nil)
+ (setq ellama-context-ephemeral nil)
(with-current-buffer ellama--context-buffer
(erase-buffer))
(ellama-context-update-show))
@@ -80,7 +84,11 @@
(setq ellama-context-global
(cl-remove-if (lambda (el)
(string= name (ellama-context-element-display el)))
- ellama-context-global)))
+ ellama-context-global))
+ (setq ellama-context-ephemeral
+ (cl-remove-if (lambda (el)
+ (string= name (ellama-context-element-display el)))
+ ellama-context-ephemeral)))
;;;###autoload
(defun ellama-context-element-remove-by-name ()
@@ -93,7 +101,8 @@ the context."
(ellama-context--element-remove-by-name
(completing-read
"Remove context element: "
- (seq-uniq (mapcar #'ellama-context-element-display
ellama-context-global))))
+ (seq-uniq (mapcar #'ellama-context-element-display (append
ellama-context-global
+
ellama-context-ephemeral)))))
(ellama-context-update-show))
(defun ellama-context-update-show ()
@@ -102,19 +111,22 @@ the context."
(declare-function posframe-hide "ext:posframe")
(with-current-buffer (get-buffer-create ellama--context-buffer)
(erase-buffer)
- (if ellama-context-global
+ (if (or ellama-context-global
+ ellama-context-ephemeral)
(insert (format
" ellama ctx: %s"
(string-join
(mapcar
(lambda (el)
(ellama-context-element-display el))
- ellama-context-global)
+ (append ellama-context-global
+ ellama-context-ephemeral))
" ")))
(insert " ellama ctx")))
(when ellama-context-posframe-enabled
(require 'posframe)
- (if ellama-context-global
+ (if (or ellama-context-global
+ ellama-context-ephemeral)
(posframe-show
ellama--context-buffer
:poshandler ellama-context-poshandler
@@ -159,7 +171,8 @@ the context."
(when (listp header-line-format)
(if (and ellama-context-header-line-mode
(or ellama-context-line-always-visible
- ellama-context-global))
+ ellama-context-global
+ ellama-context-ephemeral))
(add-to-list 'header-line-format '(:eval (ellama-context-line)) t)
(setq header-line-format (delete '(:eval (ellama-context-line))
header-line-format)))))
@@ -183,7 +196,8 @@ the context."
"Update and display context information in the mode line."
(if (and ellama-context-mode-line-mode
(or ellama-context-line-always-visible
- ellama-context-global))
+ ellama-context-global
+ ellama-context-ephemeral))
(add-to-list 'mode-line-format '(:eval (ellama-context-line)) t)
(setq mode-line-format (delete '(:eval (ellama-context-line))
mode-line-format))))
@@ -219,7 +233,8 @@ the context."
(read-only-mode +1)
(ellama-context-mode)
(erase-buffer)
- (dolist (el ellama-context-global)
+ (dolist (el (append ellama-context-global
+ ellama-context-ephemeral))
(insert (ellama-context-element-display el))
(put-text-property (pos-bol) (pos-eol) 'context-element el)
(insert "\n"))
@@ -277,7 +292,9 @@ the context."
(defun ellama-context-remove-element (element)
"Remove context ELEMENT from global context."
(setf ellama-context-global
- (cl-remove element ellama-context-global :test
#'equal-including-properties)))
+ (cl-remove element ellama-context-global :test
#'equal-including-properties))
+ (setf ellama-context-ephemeral
+ (cl-remove element ellama-context-ephemeral :test
#'equal-including-properties)))
;;;###autoload
(defun ellama-context-preview-element-at-point ()
@@ -303,6 +320,9 @@ the context."
(cl-defgeneric ellama-context-element-add (element)
"Add the ELEMENT to the Ellama context.")
+(cl-defgeneric ellama-context-ephemeral-element-add (element)
+ "Add the ephemeral ELEMENT to the Ellama context.")
+
(cl-defgeneric ellama-context-element-extract (element)
"Extract the content of the context ELEMENT.")
@@ -321,6 +341,15 @@ the context."
(get-buffer-create ellama--context-buffer t)
(ellama-context-update-show))
+(cl-defmethod ellama-context-ephemeral-element-add ((element
ellama-context-element))
+ "Add the ephemeral ELEMENT to the Ellama context."
+ (setf ellama-context-ephemeral (nreverse ellama-context-ephemeral))
+ (cl-pushnew element ellama-context-ephemeral
+ :test #'equal-including-properties)
+ (setf ellama-context-ephemeral (nreverse ellama-context-ephemeral))
+ (get-buffer-create ellama--context-buffer t)
+ (ellama-context-update-show))
+
;; Buffer context element
(defclass ellama-context-element-buffer (ellama-context-element)
@@ -683,22 +712,29 @@ the context."
;;;###autoload
-(defun ellama-context-add-file ()
- "Add file to context."
+(defun ellama-context-add-file (&optional ephemeral)
+ "Add file to context.
+For one request only if EPHEMERAL."
(interactive)
(let* ((file-name (read-file-name "Select file: " nil nil t))
(element (ellama-context-element-file :name file-name)))
- (ellama-context-element-add element)))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))
-(defun ellama-context-add-file-quote-noninteractive (path content)
- "Add file with PATH quote CONTENT to context."
+(defun ellama-context-add-file-quote-noninteractive (path content &optional
ephemeral)
+ "Add file with PATH quote CONTENT to context.
+For one request only if EPHEMERAL."
(let ((element (ellama-context-element-file-quote
:path path :content content)))
- (ellama-context-element-add element)))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))
;;;###autoload
-(defun ellama-context-add-file-quote ()
- "Add file quote to context interactively."
+(defun ellama-context-add-file-quote (&optional ephemeral)
+ "Add file quote to context interactively.
+For one request only if EPHEMERAL."
(interactive)
(let ((path (buffer-file-name (current-buffer)))
(content (if (region-active-p)
@@ -710,30 +746,37 @@ the context."
(point-max)))))
(if (not path)
(warn "should be called from buffer associated with file")
- (ellama-context-add-file-quote-noninteractive path content))))
+ (ellama-context-add-file-quote-noninteractive path content ephemeral))))
;;;###autoload
-(defun ellama-context-add-buffer (buf)
- "Add BUF to context."
+(defun ellama-context-add-buffer (buf &optional ephemeral)
+ "Add BUF to context.
+For one request only if EPHEMERAL."
(interactive "bSelect buffer: ")
(let* ((buffer-name (if (stringp buf)
buf
(buffer-name buf)))
(element (ellama-context-element-buffer :name buffer-name)))
- (ellama-context-element-add element)))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))
;;;###autoload
-(defun ellama-context-add-directory (dir)
- "Add all files in DIR to the context."
+(defun ellama-context-add-directory (dir &optional ephemeral)
+ "Add all files in DIR to the context.
+For one request only if EPHEMERAL."
(interactive "DSelect directory: ")
(dolist (file-name (directory-files dir t "^[^\.].*"))
(unless (file-directory-p file-name)
(let ((element (ellama-context-element-file :name file-name)))
- (ellama-context-element-add element)))))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))))
;;;###autoload
-(defun ellama-context-add-selection ()
- "Add active region to context."
+(defun ellama-context-add-selection (&optional ephemeral)
+ "Add active region to context.
+For one request only if EPHEMERAL."
(interactive)
(if (region-active-p)
(let* ((data (buffer-substring-no-properties (region-beginning)
(region-end)))
@@ -746,32 +789,44 @@ the context."
(ellama-context-element-file-quote :path file-name
:content content)
(ellama-context-element-buffer-quote :name buffer-name
:content content))))
- (ellama-context-element-add element))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element)))
(warn "No active region")))
-(defun ellama-context-add-text (text)
- "Add TEXT to context."
+(defun ellama-context-add-text (text &optional ephemeral)
+ "Add TEXT to context.
+For one request only if EPHEMERAL."
(let ((element (ellama-context-element-text :content text)))
- (ellama-context-element-add element)))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))
(declare-function Info-copy-current-node-name "info")
;;;###autoload
-(defun ellama-context-add-info-node (node)
- "Add info NODE to context."
+(defun ellama-context-add-info-node (node &optional ephemeral)
+ "Add info NODE to context.
+For one request only if EPHEMERAL."
(interactive (list (Info-copy-current-node-name)))
(let ((element (ellama-context-element-info-node :name node)))
- (ellama-context-element-add element)))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))
-(defun ellama-context-add-info-node-quote-noninteractive (name content)
- "Add info node with NAME quote CONTENT to context."
+(defun ellama-context-add-info-node-quote-noninteractive (name content
&optional ephemeral)
+ "Add info node with NAME quote CONTENT to context.
+For one request only if EPHEMERAL."
(let ((element (ellama-context-element-info-node-quote
:name name :content content)))
- (ellama-context-element-add element)))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))
;;;###autoload
-(defun ellama-context-add-info-node-quote ()
- "Add info node quote to context interactively."
+(defun ellama-context-add-info-node-quote (&optional ephemeral)
+ "Add info node quote to context interactively.
+For one request only if EPHEMERAL."
(interactive)
(let ((name (Info-copy-current-node-name))
(content (if (region-active-p)
@@ -783,17 +838,21 @@ the context."
(point-max)))))
(if (not name)
(warn "should be called from `info' buffer")
- (ellama-context-add-info-node-quote-noninteractive name content))))
+ (ellama-context-add-info-node-quote-noninteractive name content
ephemeral))))
-(defun ellama-context-add-webpage-quote-noninteractive (name url content)
- "Add webpage with NAME and URL quote CONTENT to context."
+(defun ellama-context-add-webpage-quote-noninteractive (name url content
&optional ephemeral)
+ "Add webpage with NAME and URL quote CONTENT to context.
+For one request only if EPHEMERAL."
(let ((element (ellama-context-element-webpage-quote
:name name :url url :content content)))
- (ellama-context-element-add element)))
+ (if ephemeral
+ (ellama-context-ephemeral-element-add element)
+ (ellama-context-element-add element))))
;;;###autoload
-(defun ellama-context-add-webpage-quote-eww ()
- "Add webpage quote to context interactively from `eww'."
+(defun ellama-context-add-webpage-quote-eww (&optional ephemeral)
+ "Add webpage quote to context interactively from `eww'.
+For one request only if EPHEMERAL."
(interactive)
(defvar eww-data)
(declare-function eww-current-url "eww")
@@ -807,14 +866,15 @@ the context."
(buffer-substring-no-properties
(point-min)
(point-max)))))
- (ellama-context-add-webpage-quote-noninteractive name url content))
+ (ellama-context-add-webpage-quote-noninteractive name url content
ephemeral))
(warn "Should be called from `eww'.")))
;;;###autoload
(defun ellama-context-format (_)
"Format context for chat buffer."
(let ((mode (if (derived-mode-p 'org-mode) 'org-mode 'markdown-mode)))
- (if-let* ((context ellama-context-global))
+ (if-let* ((context (append ellama-context-global
+ ellama-context-ephemeral)))
(concat (string-join
(cons "Context:"
(mapcar (lambda (elt)
@@ -827,14 +887,17 @@ the context."
;;;###autoload
(defun ellama-context-prompt-with-context (prompt)
"Add context to PROMPT for sending to llm."
- (let* ((context ellama-context-global))
+ (let* ((context (append ellama-context-global
+ ellama-context-ephemeral)))
(if context
- (concat (string-join
- (cons "Context:"
- (mapcar #'ellama-context-element-extract context))
- "\n")
- "\n\n"
- prompt)
+ (prog1
+ (concat (string-join
+ (cons "Context:"
+ (mapcar #'ellama-context-element-extract context))
+ "\n")
+ "\n\n"
+ prompt)
+ (setq ellama-context-ephemeral nil))
prompt)))
(provide 'ellama-context)
diff --git a/ellama-transient.el b/ellama-transient.el
index 5f28cc51a9..458110be48 100644
--- a/ellama-transient.el
+++ b/ellama-transient.el
@@ -31,6 +31,7 @@
;;; Code:
(require 'ellama)
(require 'transient)
+(require 'ellama-context)
(defcustom ellama-transient-system-show-limit 45
"Maximum length of system message to show."
@@ -194,15 +195,28 @@ Otherwise, prompt the user to enter a system message."
:default-chat-non-standard-params
`[("num_ctx" . ,ellama-transient-context-length)]))
+(transient-define-suffix ellama-transient-code-review (&optional args)
+ "Review the code. ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (ellama-code-review
+ (transient-arg-value "--new-session" args)
+ :ephemeral (transient-arg-value "--ephemeral" args)))
+
;;;###autoload (autoload 'ellama-transient-code-menu "ellama-transient" nil t)
(transient-define-prefix ellama-transient-code-menu ()
"Code Commands."
+ ["Session Options"
+ :description (lambda () (ellama-session-line))
+ ("-n" "Create New Session" "--new-session")]
+ ["Ephemeral sessions"
+ :if (lambda () ellama-session-auto-save)
+ ("-e" "Create Ephemeral Session" "--ephemeral")]
[["Code Commands"
("c" "Complete" ellama-code-complete)
("a" "Add" ellama-code-add)
("e" "Edit" ellama-code-edit)
("i" "Improve" ellama-code-improve)
- ("r" "Review" ellama-code-review)
+ ("r" "Review" ellama-transient-code-review)
("m" "Generate Commit Message" ellama-generate-commit-message)]
["Quit" ("q" "Quit" transient-quit-one)]])
@@ -244,13 +258,40 @@ Otherwise, prompt the user to enter a system message."
("f" "Make Format" ellama-make-format)]
["Quit" ("q" "Quit" transient-quit-one)]])
+(transient-define-suffix ellama-transient-ask-line (&optional args)
+ "Ask line. ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (ellama-ask-line
+ (transient-arg-value "--new-session" args)
+ :ephemeral (transient-arg-value "--ephemeral" args)))
+
+(transient-define-suffix ellama-transient-ask-selection (&optional args)
+ "Ask selection. ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (ellama-ask-selection
+ (transient-arg-value "--new-session" args)
+ :ephemeral (transient-arg-value "--ephemeral" args)))
+
+(transient-define-suffix ellama-transient-ask-about (&optional args)
+ "Ask about current buffer or region. ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (ellama-ask-about
+ (transient-arg-value "--new-session" args)
+ :ephemeral (transient-arg-value "--ephemeral" args)))
+
;;;###autoload (autoload 'ellama-transient-ask-menu "ellama-transient" nil t)
(transient-define-prefix ellama-transient-ask-menu ()
"Ask Commands."
+ ["Session Options"
+ :description (lambda () (ellama-session-line))
+ ("-n" "Create New Session" "--new-session")]
+ ["Ephemeral sessions"
+ :if (lambda () ellama-session-auto-save)
+ ("-e" "Create Ephemeral Session" "--ephemeral")]
[["Ask Commands"
- ("l" "Ask Line" ellama-ask-line)
- ("s" "Ask Selection" ellama-ask-selection)
- ("a" "Ask About" ellama-ask-about)]
+ ("l" "Ask Line" ellama-transient-ask-line)
+ ("s" "Ask Selection" ellama-transient-ask-selection)
+ ("a" "Ask About" ellama-transient-ask-about)]
["Quit" ("q" "Quit" transient-quit-one)]])
;;;###autoload (autoload 'ellama-transient-translate-menu "ellama-transient"
nil t)
@@ -266,9 +307,50 @@ Otherwise, prompt the user to enter a system message."
(declare-function ellama-context-update-buffer "ellama-context")
(defvar ellama-context-buffer)
+(transient-define-suffix ellama-transient-add-buffer (&optional args)
+ "Add current buffer to context.
+ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (ellama-context-add-buffer
+ (read-buffer "Buffer: ")
+ (transient-arg-value "--ephemeral" args)))
+
+(transient-define-suffix ellama-transient-add-directory (&optional args)
+ "Add directory to context.
+ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (let ((directory (read-directory-name "Directory: ")))
+ (ellama-context-add-directory
+ directory
+ (transient-arg-value "--ephemeral" args))))
+
+(transient-define-suffix ellama-transient-add-file (&optional args)
+ "Add file to context.
+ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (ellama-context-add-file (transient-arg-value "--ephemeral" args)))
+
+(transient-define-suffix ellama-transient-add-selection (&optional args)
+ "Add current selection to context.
+ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (when (region-active-p)
+ (ellama-context-add-selection (transient-arg-value "--ephemeral" args))))
+
+(transient-define-suffix ellama-transient-add-info-node (&optional args)
+ "Add Info Node to context.
+ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (let ((info-node (Info-copy-current-node-name)))
+ (ellama-context-add-info-node
+ info-node
+ (transient-arg-value "--ephemeral" args))))
+
;;;###autoload (autoload 'ellama-transient-context-menu "ellama-transient" nil
t)
(transient-define-prefix ellama-transient-context-menu ()
"Context Commands."
+ ["Options"
+ ("-e" "Use Ephemeral Context" "--ephemeral")]
["Context Commands"
:description (lambda ()
(ellama-context-update-buffer)
@@ -276,11 +358,11 @@ Otherwise, prompt the user to enter a system message."
%s" (with-current-buffer ellama-context-buffer
(buffer-substring (point-min) (point-max)))))
["Add"
- ("b" "Add Buffer" ellama-context-add-buffer)
- ("d" "Add Directory" ellama-context-add-directory)
- ("f" "Add File" ellama-context-add-file)
- ("s" "Add Selection" ellama-context-add-selection)
- ("i" "Add Info Node" ellama-context-add-info-node)]
+ ("b" "Add Buffer" ellama-transient-add-buffer)
+ ("d" "Add Directory" ellama-transient-add-directory)
+ ("f" "Add File" ellama-transient-add-file)
+ ("s" "Add Selection" ellama-transient-add-selection)
+ ("i" "Add Info Node" ellama-transient-add-info-node)]
["Manage"
("m" "Manage context" ellama-context-manage)
("D" "Delete element" ellama-context-element-remove-by-name)
@@ -316,11 +398,25 @@ Otherwise, prompt the user to enter a system message."
("k" "Kill" ellama-kill-current-buffer)
("q" "Quit" transient-quit-one)]])
+(transient-define-suffix ellama-transient-chat (&optional args)
+ "Chat with Ellama. ARGS used for transient arguments."
+ (interactive (list (transient-args transient-current-command)))
+ (ellama-chat
+ (read-string "Ask Ellama: ")
+ (transient-arg-value "--new-session" args)
+ :ephemeral (transient-arg-value "--ephemeral" args)))
+
;;;###autoload (autoload 'ellama-transient-main-menu "ellama-transient" nil t)
(transient-define-prefix ellama-transient-main-menu ()
"Main Menu."
+ ["Session Options"
+ :description (lambda () (ellama-session-line))
+ ("-n" "Create New Session" "--new-session")]
+ ["Ephemeral sessions"
+ :if (lambda () ellama-session-auto-save)
+ ("-e" "Create Ephemeral Session" "--ephemeral")]
["Main"
- [("c" "Chat" ellama-chat)
+ [("c" "Chat" ellama-transient-chat)
("b" "Chat with blueprint" ellama-blueprint-select)
("B" "Blueprint Commands" ellama-transient-blueprint-menu)]
[("a" "Ask Commands" ellama-transient-ask-menu)
@@ -347,7 +443,11 @@ Otherwise, prompt the user to enter a system message."
[["Problem solving"
("R" "Solve reasoning problem" ellama-solve-reasoning-problem)
("D" "Solve domain specific problem"
ellama-solve-domain-specific-problem)]]
- [["Quit" ("q" "Quit" transient-quit-one)]])
+ [["Quit" ("q" "Quit" transient-quit-one)]]
+ (interactive)
+ (transient-setup 'ellama-transient-main-menu)
+ (when (string-empty-p ellama-transient-ollama-model-name)
+ (ellama-fill-transient-ollama-model ellama-provider)))
;;;###autoload (autoload 'ellama "ellama-transient" nil t)
(defalias 'ellama 'ellama-transient-main-menu)
diff --git a/ellama.el b/ellama.el
index a085afacad..2c732d26cf 100644
--- a/ellama.el
+++ b/ellama.el
@@ -6,7 +6,7 @@
;; URL: http://github.com/s-kostyaev/ellama
;; Keywords: help local tools
;; Package-Requires: ((emacs "28.1") (llm "0.24.0") (plz "0.8") (transient
"0.7") (compat "29.1"))
-;; Version: 1.7.2
+;; Version: 1.8.0
;; SPDX-License-Identifier: GPL-3.0-or-later
;; Created: 8th Oct 2023
@@ -1235,6 +1235,7 @@ FILTER is a function for text transformation."
(goto-char end-marker)
(let* ((filtered-text
(funcall filter text))
+ (use-hard-newlines t)
(common-prefix (concat
safe-common-prefix
(ellama-max-common-prefix
@@ -1248,26 +1249,26 @@ FILTER is a function for text transformation."
(length common-prefix)))
(delta (string-remove-prefix common-prefix filtered-text)))
(delete-char (- wrong-chars-cnt))
- (insert delta)
- (when (and
- ellama-fill-paragraphs
- (pcase ellama-fill-paragraphs
- ((cl-type function) (funcall ellama-fill-paragraphs))
- ((cl-type boolean) ellama-fill-paragraphs)
- ((cl-type list) (and (apply #'derived-mode-p
- ellama-fill-paragraphs)))))
- (if (not (eq major-mode 'org-mode))
- (fill-paragraph)
- (when (not (save-excursion
- (re-search-backward
- "#\\+BEGIN_SRC"
- beg-marker t)))
- (org-fill-paragraph))))
- (set-marker end-marker (point))
- (when (and ellama-auto-scroll (not ellama--stop-scroll))
- (ellama--scroll buffer end-marker))
- (setq safe-common-prefix (ellama--string-without-last-line
common-prefix))
- (setq previous-filtered-text filtered-text))))))))
+ (when delta (insert (propertize delta 'hard t))
+ (when (and
+ ellama-fill-paragraphs
+ (pcase ellama-fill-paragraphs
+ ((cl-type function) (funcall
ellama-fill-paragraphs))
+ ((cl-type boolean) ellama-fill-paragraphs)
+ ((cl-type list) (and (apply #'derived-mode-p
+
ellama-fill-paragraphs)))))
+ (if (not (eq major-mode 'org-mode))
+ (fill-paragraph)
+ (when (not (save-excursion
+ (re-search-backward
+ "#\\+BEGIN_SRC"
+ beg-marker t)))
+ (org-fill-paragraph))))
+ (set-marker end-marker (point))
+ (when (and ellama-auto-scroll (not ellama--stop-scroll))
+ (ellama--scroll buffer end-marker))
+ (setq safe-common-prefix (ellama--string-without-last-line
common-prefix))
+ (setq previous-filtered-text filtered-text)))))))))
(defun ellama--handle-partial (insert-text insert-reasoning reasoning-buffer)
"Handle partial llm callback.
@@ -1586,7 +1587,8 @@ Will call `ellama-chat-done-callback' and ON-DONE on
TEXT."
(save-excursion
(goto-char (point-max))
(insert "\n\n" (ellama-get-nick-prefix-for-mode) " " ellama-user-nick
":\n")
- (when ellama-session-auto-save
+ (when (and ellama-session-auto-save
+ buffer-file-name)
(save-buffer)))
(ellama--scroll)
(when ellama-chat-done-callback
@@ -1674,6 +1676,8 @@ ARGS contains keys for fine control.
:system STR -- send STR to model as system message.
+:ephemeral BOOL -- create an ephemeral session if set.
+
:on-done ON-DONE -- ON-DONE a function that's called with
the full response text when the request completes (with BUFFER current)."
(interactive "sAsk ellama: ")
@@ -1694,6 +1698,7 @@ the full response text when the request completes (with
BUFFER current)."
(or (plist-get args :provider)
ellama-provider
(ellama-get-first-ollama-chat-model))))
+ (ephemeral (plist-get args :ephemeral))
(session (or (plist-get args :session)
(if (or create-session
current-prefix-arg
@@ -1708,7 +1713,7 @@ the full response text when the request completes (with
BUFFER current)."
(ellama-session-provider
ellama--current-session)))))
(and (not ellama--current-session)
(not ellama--current-session-id)))
- (ellama-new-session provider prompt)
+ (ellama-new-session provider prompt ephemeral)
(or ellama--current-session
(with-current-buffer (ellama-get-session-buffer
(or (plist-get args
:session-id)
@@ -1782,25 +1787,39 @@ the full response text when the request completes (with
BUFFER current)."
#'ellama--translate-markdown-to-org-filter))))
;;;###autoload
-(defun ellama-ask-about ()
- "Ask ellama about selected region or current buffer."
+(defun ellama-ask-about (&optional create-session &rest args)
+ "Ask ellama about selected region or current buffer.
+
+If CREATE-SESSION set, creates new session even if there is an active session.
+
+ARGS contains keys for fine control.
+
+:ephemeral BOOL -- create an ephemeral session if set."
(interactive)
(declare-function ellama-context-add-selection "ellama-context")
(declare-function ellama-context-add-buffer "ellama-context")
- (let ((input (read-string "Ask ellama about this text: ")))
+ (let ((input (read-string "Ask ellama about this text: "))
+ (ephemeral (plist-get args :ephemeral)))
(if (region-active-p)
(ellama-context-add-selection)
(ellama-context-add-buffer (buffer-name (current-buffer))))
- (ellama-chat input)))
+ (ellama-chat input create-session :ephemeral ephemeral)))
;;;###autoload
-(defun ellama-ask-selection ()
- "Send selected region or current buffer to ellama chat."
+(defun ellama-ask-selection (&optional create-session &rest args)
+ "Send selected region or current buffer to ellama chat.
+
+If CREATE-SESSION set, creates new session even if there is an active session.
+
+ARGS contains keys for fine control.
+
+:ephemeral BOOL -- create an ephemeral session if set."
(interactive)
(let ((text (if (region-active-p)
(buffer-substring-no-properties (region-beginning)
(region-end))
- (buffer-substring-no-properties (point-min) (point-max)))))
- (ellama-chat text)))
+ (buffer-substring-no-properties (point-min) (point-max))))
+ (ephemeral (plist-get args :ephemeral)))
+ (ellama-chat text create-session :ephemeral ephemeral)))
(defcustom ellama-complete-prompt-template "You're providing text completion.
Complete the text. Do not aknowledge, reply with completion only."
"System prompt template for `ellama-complete'."
@@ -1898,11 +1917,18 @@ the full response text when the request completes (with
BUFFER current)."
:provider ellama-coding-provider))))
;;;###autoload
-(defun ellama-ask-line ()
- "Send current line to ellama chat."
+(defun ellama-ask-line (&optional create-session &rest args)
+ "Send current line to ellama chat.
+
+If CREATE-SESSION set, creates new session even if there is an active session.
+
+ARGS contains keys for fine control.
+
+:ephemeral BOOL -- create an ephemeral session if set."
(interactive)
- (let ((text (thing-at-point 'line)))
- (ellama-chat text)))
+ (let* ((text (thing-at-point 'line))
+ (ephemeral (plist-get args :ephemeral)))
+ (ellama-chat text create-session :ephemeral ephemeral)))
(defun ellama-instant (prompt &rest args)
"Prompt ellama for PROMPT to reply instantly.
@@ -2006,13 +2032,23 @@ ARGS contains keys for fine control.
(ellama-get-first-ollama-chat-model))))))
;;;###autoload
-(defun ellama-code-review ()
- "Review code in selected region or current buffer."
+(defun ellama-code-review (&optional create-session &rest args)
+ "Review code in selected region or current buffer.
+
+If CREATE-SESSION set, creates new session even if there is an active session.
+ARGS contains keys for fine control.
+
+:ephemeral BOOL -- create an ephemeral session if set."
(interactive)
- (if (region-active-p)
- (ellama-context-add-selection)
- (ellama-context-add-buffer (current-buffer)))
- (ellama-chat ellama-code-review-prompt-template nil :provider
ellama-coding-provider))
+ (let ((ephemeral (plist-get args :ephemeral)))
+ (if (region-active-p)
+ (ellama-context-add-selection)
+ (ellama-context-add-buffer (current-buffer)))
+ (ellama-chat
+ ellama-code-review-prompt-template
+ create-session
+ :provider ellama-coding-provider
+ :ephemeral ephemeral)))
;;;###autoload
(defun ellama-write (instruction)
diff --git a/ellama.info b/ellama.info
index 229a9e8913..9a305ef574 100644
--- a/ellama.info
+++ b/ellama.info
@@ -489,7 +489,9 @@ its pre-existing knowledge, which may not always be
appropriate.
A “global context” is maintained, which is a collection of text blocks
accessible to the LLM when responding to prompts. This global context
-is prepened to your prompt before transmission to the LLM.
+is prepended to your prompt before transmission to the LLM.
+Additionally, Ellama supports an "ephemeral context," which is temporary
+and only available for a single request.
* Menu:
@@ -512,12 +514,15 @@ The Context Commands transient menu is structured as
follows:
Context Commands:
- • Add: Provides options for adding content to the global context.
- • “b” "Add Buffer" ‘ellama-context-add-buffer’
- • “d” "Add Directory" ‘ellama-context-add-directory’
- • “f” "Add File" ‘ellama-context-add-file’
- • “s” "Add Selection" ‘ellama-context-add-selection’
- • “i” "Add Info Node" ‘ellama-context-add-info-node’
+ • Options: Provides options for managing ephemeral context.
+ • “-e” "Use Ephemeral Context" ‘--ephemeral’
+ • Add: Provides options for adding content to the global or ephemeral
+ context.
+ • “b” "Add Buffer" ‘ellama-transient-add-buffer’
+ • “d” "Add Directory" ‘ellama-transient-add-directory’
+ • “f” "Add File" ‘ellama-transient-add-file’
+ • “s” "Add Selection" ‘ellama-transient-add-selection’
+ • “i” "Add Info Node" ‘ellama-transient-add-info-node’
• Manage: Provides options for managing the global context.
• “m” "Manage context" ‘ellama-context-manage’ - Opens the
context management buffer.
@@ -1412,30 +1417,30 @@ Node: Commands8621
Node: Keymap14965
Node: Configuration17798
Node: Context Management23139
-Node: Transient Menus for Context Management23932
-Node: Managing the Context25390
-Node: Considerations26165
-Node: Minor modes26758
-Node: ellama-context-header-line-mode28746
-Node: ellama-context-header-line-global-mode29571
-Node: ellama-context-mode-line-mode30291
-Node: ellama-context-mode-line-global-mode31139
-Node: Ellama Session Header Line Mode31843
-Node: Enabling and Disabling32412
-Node: Customization32859
-Node: Ellama Session Mode Line Mode33147
-Node: Enabling and Disabling (1)33732
-Node: Customization (1)34179
-Node: Using Blueprints34473
-Node: Key Components of Ellama Blueprints35092
-Node: Creating and Managing Blueprints35699
-Node: Variable Management36680
-Node: Keymap and Mode37149
-Node: Transient Menus38085
-Node: Running Blueprints programmatically38631
-Node: Acknowledgments39218
-Node: Contributions39931
-Node: GNU Free Documentation License40315
+Node: Transient Menus for Context Management24047
+Node: Managing the Context25661
+Node: Considerations26436
+Node: Minor modes27029
+Node: ellama-context-header-line-mode29017
+Node: ellama-context-header-line-global-mode29842
+Node: ellama-context-mode-line-mode30562
+Node: ellama-context-mode-line-global-mode31410
+Node: Ellama Session Header Line Mode32114
+Node: Enabling and Disabling32683
+Node: Customization33130
+Node: Ellama Session Mode Line Mode33418
+Node: Enabling and Disabling (1)34003
+Node: Customization (1)34450
+Node: Using Blueprints34744
+Node: Key Components of Ellama Blueprints35363
+Node: Creating and Managing Blueprints35970
+Node: Variable Management36951
+Node: Keymap and Mode37420
+Node: Transient Menus38356
+Node: Running Blueprints programmatically38902
+Node: Acknowledgments39489
+Node: Contributions40202
+Node: GNU Free Documentation License40586
End Tag Table