#+title: gptel: A simple LLM client for Emacs

[[https://elpa.nongnu.org/nongnu/gptel.svg][file:https://elpa.nongnu.org/nongnu/gptel.svg]] [[https://stable.melpa.org/packages/gptel-badge.svg][file:https://stable.melpa.org/packages/gptel-badge.svg]] [[https://melpa.org/#/gptel][file:https://melpa.org/packages/gptel-badge.svg]]

gptel is a simple Large Language Model chat client for Emacs, with support for multiple models and backends.  It works in the spirit of Emacs, available at any time and uniformly in any buffer.

#+html: <div align="center">
| LLM Backend        | Supports | Requires                   |
|--------------------+----------+----------------------------|
| ChatGPT            | ✓        | [[https://platform.openai.com/account/api-keys][API key]]                    |
| Anthropic (Claude) | ✓        | [[https://www.anthropic.com/api][API key]]                    |
| Gemini             | ✓        | [[https://makersuite.google.com/app/apikey][API key]]                    |
| Ollama             | ✓        | [[https://ollama.ai/][Ollama running locally]]     |
| Llama.cpp          | ✓        | [[https://github.com/ggerganov/llama.cpp/tree/master/examples/server#quick-start][Llama.cpp running locally]]  |
| Llamafile          | ✓        | [[https://github.com/Mozilla-Ocho/llamafile#quickstart][Local Llamafile server]]     |
| GPT4All            | ✓        | [[https://gpt4all.io/index.html][GPT4All running locally]]    |
| Kagi FastGPT       | ✓        | [[https://kagi.com/settings?p=api][API key]]                    |
| Kagi Summarizer    | ✓        | [[https://kagi.com/settings?p=api][API key]]                    |
| Azure              | ✓        | Deployment and API key     |
| Groq               | ✓        | [[https://console.groq.com/keys][API key]]                    |
| Perplexity         | ✓        | [[https://docs.perplexity.ai/docs/getting-started][API key]]                    |
| OpenRouter         | ✓        | [[https://openrouter.ai/keys][API key]]                    |
| together.ai        | ✓        | [[https://api.together.xyz/settings/api-keys][API key]]                    |
| Anyscale           | ✓        | [[https://docs.endpoints.anyscale.com/][API key]]                    |
| PrivateGPT         | ✓        | [[https://github.com/zylon-ai/private-gpt#-documentation][PrivateGPT running locally]] |
| DeepSeek           | ✓        | [[https://platform.deepseek.com/api_keys][API key]]                    |
| Cerebras           | ✓        | [[https://cloud.cerebras.ai/][API key]]                    |
| Github Models      | ✓        | [[https://github.com/settings/tokens][Token]]                      |
| Novita AI          | ✓        | [[https://novita.ai/model-api/product/llm-api?utm_source=github_gptel&utm_medium=github_readme&utm_campaign=link][Token]]                      |
| xAI                | ✓        | [[https://console.x.ai?utm_source=github_gptel&utm_medium=github_readme&utm_campaign=link][API key]]                    |
#+html: </div>

*General usage*: ([[https://www.youtube.com/watch?v=bsRnh_brggM][YouTube Demo]])

https://user-images.githubusercontent.com/8607532/230516812-86510a09-a2fb-4cbd-b53f-cc2522d05a13.mp4

https://user-images.githubusercontent.com/8607532/230516816-ae4a613a-4d01-4073-ad3f-b66fa73c6e45.mp4

*In-place usage*

#+html: <p align="center">
https://github.com/user-attachments/assets/cec11aec-52f6-412e-9e7a-9358e8b9b1bf
#+html: </p>

*Media support*

#+html: <p align="center">
https://github.com/user-attachments/assets/1fd947e1-226b-4be2-bc68-7b22b2e3215f
#+html: </p>

*Multi-LLM support demo*:

https://github-production-user-asset-6210df.s3.amazonaws.com/8607532/278854024-ae1336c4-5b87-41f2-83e9-e415349d6a43.mp4

- It's async and fast, streams responses.
- Interact with LLMs from anywhere in Emacs (any buffer, shell, minibuffer, wherever)
- LLM responses are in Markdown or Org markup.
- Supports multiple independent conversations and one-off ad hoc interactions.
- Supports multi-modal models (include images, documents)
- Save chats as regular Markdown/Org/Text files and resume them later.
- You can go back and edit your previous prompts or LLM responses when continuing a conversation. These will be fed back to the model.
- Don't like gptel's workflow? Use it to create your own for any supported model/backend with a [[https://github.com/karthink/gptel/wiki/Defining-custom-gptel-commands][simple API]].

gptel uses Curl if available, but falls back to url-retrieve to work without external dependencies.

** Contents :toc:
  - [[#breaking-changes][Breaking changes!]]
  - [[#installation][Installation]]
      - [[#straight][Straight]]
      - [[#manual][Manual]]
      - [[#doom-emacs][Doom Emacs]]
      - [[#spacemacs][Spacemacs]]
  - [[#setup][Setup]]
    - [[#chatgpt][ChatGPT]]
    - [[#other-llm-backends][Other LLM backends]]
      - [[#azure][Azure]]
      - [[#gpt4all][GPT4All]]
      - [[#ollama][Ollama]]
      - [[#gemini][Gemini]]
      - [[#llamacpp-or-llamafile][Llama.cpp or Llamafile]]
      - [[#kagi-fastgpt--summarizer][Kagi (FastGPT & Summarizer)]]
      - [[#togetherai][together.ai]]
      - [[#anyscale][Anyscale]]
      - [[#perplexity][Perplexity]]
      - [[#anthropic-claude][Anthropic (Claude)]]
      - [[#groq][Groq]]
      - [[#openrouter][OpenRouter]]
      - [[#privategpt][PrivateGPT]]
      - [[#deepseek][DeepSeek]]
      - [[#cerebras][Cerebras]]
      - [[#github-models][Github Models]]
      - [[#novita-ai][Novita AI]]
      - [[#xai][xAI]]
  - [[#usage][Usage]]
    - [[#in-any-buffer][In any buffer:]]
    - [[#in-a-dedicated-chat-buffer][In a dedicated chat buffer:]]
      - [[#including-media-images-documents-with-requests][Including media (images, documents) with requests]]
      - [[#save-and-restore-your-chat-sessions][Save and restore your chat sessions]]
    - [[#setting-options-backend-model-request-parameters-system-prompts-and-more][Setting options (backend, model, request parameters, system prompts and more)]]
    - [[#include-more-context-with-requests][Include more context with requests]]
    - [[#rewrite-refactor-or-fill-in-a-region][Rewrite, refactor or fill in a region]]
    - [[#extra-org-mode-conveniences][Extra Org mode conveniences]]
  - [[#faq][FAQ]]
      - [[#i-want-to-use-gptel-in-a-way-thats-not-supported-by-gptel-send-or-the-options-menu][I want to use gptel in a way that's not supported by =gptel-send= or the options menu]]
      - [[#i-want-the-window-to-scroll-automatically-as-the-response-is-inserted][I want the window to scroll automatically as the response is inserted]]
      - [[#i-want-the-cursor-to-move-to-the-next-prompt-after-the-response-is-inserted][I want the cursor to move to the next prompt after the response is inserted]]
      - [[#i-want-to-change-the-formatting-of-the-prompt-and-llm-response][I want to change the formatting of the prompt and LLM response]]
      - [[#i-want-the-transient-menu-options-to-be-saved-so-i-only-need-to-set-them-once][I want the transient menu options to be saved so I only need to set them once]]
      - [[#can-i-change-the-transient-menu-key-bindings][Can I change the transient menu key bindings?]]
      - [[#how-does-gptel-distinguish-between-user-prompts-and-llm-responses][How does gptel distinguish between user prompts and LLM responses?]]
      - [[#doom-emacs-sending-a-query-from-the-gptel-menu-fails-because-of-a-key-conflict-with-org-mode][(Doom Emacs) Sending a query from the gptel menu fails because of a key conflict with Org mode]]
      - [[#chatgpt-i-get-the-error-http2-429-you-exceeded-your-current-quota][(ChatGPT) I get the error "(HTTP/2 429) You exceeded your current quota"]]
      - [[#why-another-llm-client][Why another LLM client?]]
  - [[#additional-configuration][Additional Configuration]]
  - [[#alternatives][Alternatives]]
    - [[#packages-using-gptel][Packages using gptel]]
  - [[#acknowledgments][Acknowledgments]]

** Breaking changes!

- =gptel-model= is now expected to be a symbol, not a string.  Please update your configuration.

** Installation

gptel can be installed in Emacs out of the box with =M-x package-install= ⏎ =gptel=.  This installs the latest commit.

If you want the stable version instead, add NonGNU-devel ELPA or MELPA-stable to your list of package sources (=package-archives=), then install gptel with =M-x package-install⏎= =gptel= from these sources.

(Optional: Install =markdown-mode=.)

#+html: <details><summary>
**** Straight
#+html: </summary>
#+begin_src emacs-lisp
  (straight-use-package 'gptel)
#+end_src

Installing the =markdown-mode= package is optional.
#+html: </details>
#+html: <details><summary>
**** Manual
#+html: </summary>
Clone or download this repository and run =M-x package-install-file⏎= on the repository directory.

Installing the =markdown-mode= package is optional.
#+html: </details>
#+html: <details><summary>
**** Doom Emacs
#+html: </summary>
In =packages.el=
#+begin_src emacs-lisp
(package! gptel)
#+end_src

In =config.el=
#+begin_src emacs-lisp
(use-package! gptel
 :config
 (setq! gptel-api-key "your key"))
#+end_src
"your key" can be the API key itself, or (safer) a function that returns the key.  Setting =gptel-api-key= is optional, you will be asked for a key if it's not found.

#+html: </details>
#+html: <details><summary>
**** Spacemacs
#+html: </summary>
In your =.spacemacs= file, add =llm-client= to =dotspacemacs-configuration-layers=.
#+begin_src emacs-lisp
(llm-client :variables
            llm-client-enable-gptel t)
#+end_src
#+html: </details>
** Setup
*** ChatGPT
Procure an [[https://platform.openai.com/account/api-keys][OpenAI API key]].

Optional: Set =gptel-api-key= to the key. Alternatively, you may choose a more secure method such as:

- Storing in =~/.authinfo=. By default, "api.openai.com" is used as HOST and "apikey" as USER.
  #+begin_src authinfo
machine api.openai.com login apikey password TOKEN
  #+end_src
- Setting it to a function that returns the key.

*** Other LLM backends
#+html: <details><summary>
**** Azure
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
(gptel-make-azure "Azure-1"             ;Name, whatever you'd like
  :protocol "https"                     ;Optional -- https is the default
  :host "YOUR_RESOURCE_NAME.openai.azure.com"
  :endpoint "/openai/deployments/YOUR_DEPLOYMENT_NAME/chat/completions?api-version=2023-05-15" ;or equivalent
  :stream t                             ;Enable streaming responses
  :key #'gptel-api-key
  :models '(gpt-3.5-turbo gpt-4))
#+end_src
Refer to the documentation of =gptel-make-azure= to set more parameters.

You can pick this backend from the menu when using gptel. (see [[#usage][Usage]]).

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model 'gpt-3.5-turbo
 gptel-backend (gptel-make-azure "Azure-1"
                 :protocol "https"
                 :host "YOUR_RESOURCE_NAME.openai.azure.com"
                 :endpoint "/openai/deployments/YOUR_DEPLOYMENT_NAME/chat/completions?api-version=2023-05-15"
                 :stream t
                 :key #'gptel-api-key
                 :models '(gpt-3.5-turbo gpt-4)))
#+end_src
#+html: </details>

#+html: <details><summary>
**** GPT4All
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
(gptel-make-gpt4all "GPT4All"           ;Name of your choosing
 :protocol "http"
 :host "localhost:4891"                 ;Where it's running
 :models '(mistral-7b-openorca.Q4_0.gguf)) ;Available models
#+end_src
These are the required parameters, refer to the documentation of =gptel-make-gpt4all= for more.

You can pick this backend from the menu when using gptel (see [[#usage][Usage]]).

***** (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 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
;; OPTIONAL configuration
(setq
 gptel-max-tokens 500
 gptel-model 'mistral-7b-openorca.Q4_0.gguf
 gptel-backend (gptel-make-gpt4all "GPT4All"
                 :protocol "http"
                 :host "localhost:4891"
                 :models '(mistral-7b-openorca.Q4_0.gguf)))
#+end_src

#+html: </details>

#+html: <details><summary>
**** Ollama
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
(gptel-make-ollama "Ollama"             ;Any name of your choosing
  :host "localhost:11434"               ;Where it's running
  :stream t                             ;Stream responses
  :models '(mistral:latest))          ;List of models
#+end_src
These are the required parameters, refer to the documentation of =gptel-make-ollama= for more.

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model 'mistral:latest
 gptel-backend (gptel-make-ollama "Ollama"
                 :host "localhost:11434"
                 :stream t
                 :models '(mistral:latest)))
#+end_src

#+html: </details>

#+html: <details><summary>
**** Gemini
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; :key can be a function that returns the API key.
(gptel-make-gemini "Gemini" :key "YOUR_GEMINI_API_KEY" :stream t)
#+end_src
These are the required parameters, refer to the documentation of =gptel-make-gemini= for more.

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model 'gemini-pro
 gptel-backend (gptel-make-gemini "Gemini"
                 :key "YOUR_GEMINI_API_KEY"
                 :stream t))
#+end_src

#+html: </details>

#+html: <details>
#+html: <summary>
**** Llama.cpp or Llamafile
#+html: </summary>

(If using a llamafile, run a [[https://github.com/Mozilla-Ocho/llamafile#other-example-llamafiles][server llamafile]] instead of a "command-line llamafile", and a model that supports text generation.)

Register a backend with
#+begin_src emacs-lisp
;; Llama.cpp offers an OpenAI compatible API
(gptel-make-openai "llama-cpp"          ;Any name
  :stream t                             ;Stream responses
  :protocol "http"
  :host "localhost:8000"                ;Llama.cpp server location
  :models '(test))                    ;Any names, doesn't matter for Llama
#+end_src
These are the required parameters, refer to the documentation of =gptel-make-openai= for more.

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model   'test
 gptel-backend (gptel-make-openai "llama-cpp"
                 :stream t
                 :protocol "http"
                 :host "localhost:8000"
                 :models '(test)))
#+end_src

#+html: </details>
#+html: <details><summary>
**** Kagi (FastGPT & Summarizer)
#+html: </summary>

Kagi's FastGPT model and the Universal Summarizer are both supported.  A couple of notes:

1. Universal Summarizer: If there is a URL at point, the summarizer will summarize the contents of the URL.  Otherwise the context sent to the model is the same as always: the buffer text upto point, or the contents of the region if the region is active.

2. Kagi models do not support multi-turn conversations, interactions are "one-shot".  They also do not support streaming responses.

Register a backend with
#+begin_src emacs-lisp
(gptel-make-kagi "Kagi"                    ;any name
  :key "YOUR_KAGI_API_KEY")                ;can be a function that returns the key
#+end_src
These are the required parameters, refer to the documentation of =gptel-make-kagi= for more.

You can pick this backend and the model (fastgpt/summarizer) from the transient menu when using gptel.

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model 'fastgpt
 gptel-backend (gptel-make-kagi "Kagi"
                 :key "YOUR_KAGI_API_KEY"))
#+end_src

The alternatives to =fastgpt= include =summarize:cecil=, =summarize:agnes=, =summarize:daphne= and =summarize:muriel=.  The difference between the summarizer engines is [[https://help.kagi.com/kagi/api/summarizer.html#summarization-engines][documented here]].

#+html: </details>
#+html: <details><summary>
**** together.ai
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; Together.ai offers an OpenAI compatible API
(gptel-make-openai "TogetherAI"         ;Any name you want
  :host "api.together.xyz"
  :key "your-api-key"                   ;can be a function that returns the key
  :stream t
  :models '(;; has many more, check together.ai
            mistralai/Mixtral-8x7B-Instruct-v0.1
            codellama/CodeLlama-13b-Instruct-hf
            codellama/CodeLlama-34b-Instruct-hf))
#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model   'mistralai/Mixtral-8x7B-Instruct-v0.1
 gptel-backend
 (gptel-make-openai "TogetherAI"         
   :host "api.together.xyz"
   :key "your-api-key"                   
   :stream t
   :models '(;; has many more, check together.ai
             mistralai/Mixtral-8x7B-Instruct-v0.1
             codellama/CodeLlama-13b-Instruct-hf
             codellama/CodeLlama-34b-Instruct-hf)))
#+end_src

#+html: </details>
#+html: <details><summary>
**** Anyscale
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; Anyscale offers an OpenAI compatible API
(gptel-make-openai "Anyscale"           ;Any name you want
  :host "api.endpoints.anyscale.com"
  :key "your-api-key"                   ;can be a function that returns the key
  :models '(;; has many more, check anyscale
            mistralai/Mixtral-8x7B-Instruct-v0.1))
#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model   'mistralai/Mixtral-8x7B-Instruct-v0.1
 gptel-backend
 (gptel-make-openai "Anyscale"
                 :host "api.endpoints.anyscale.com"
                 :key "your-api-key"
                 :models '(;; has many more, check anyscale
                           mistralai/Mixtral-8x7B-Instruct-v0.1)))
#+end_src

#+html: </details>
#+html: <details><summary>
**** Perplexity
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; Perplexity offers an OpenAI compatible API
(gptel-make-openai "Perplexity"         ;Any name you want
  :host "api.perplexity.ai"
  :key "your-api-key"                   ;can be a function that returns the key
  :endpoint "/chat/completions"
  :stream t
  :models '(;; has many more, check perplexity.ai
            pplx-7b-chat
            pplx-70b-chat
            pplx-7b-online
            pplx-70b-online))
#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model   'pplx-7b-chat
 gptel-backend
 (gptel-make-openai "Perplexity"
   :host "api.perplexity.ai"
   :key "your-api-key"
   :endpoint "/chat/completions"
   :stream t
   :models '(;; has many more, check perplexity.ai
             pplx-7b-chat
             pplx-70b-chat
             pplx-7b-online
             pplx-70b-online)))
#+end_src

#+html: </details>
#+html: <details><summary>
**** Anthropic (Claude)
#+html: </summary>
Register a backend with
#+begin_src emacs-lisp
(gptel-make-anthropic "Claude"          ;Any name you want
  :stream t                             ;Streaming responses
  :key "your-api-key")
#+end_src
The =:key= can be a function that returns the key (more secure).

You can pick this backend from the menu when using gptel (see [[#usage][Usage]]).

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model 'claude-3-sonnet-20240229 ;  "claude-3-opus-20240229" also available
 gptel-backend (gptel-make-anthropic "Claude"
                 :stream t :key "your-api-key"))
#+end_src

#+html: </details>
#+html: <details><summary>
**** Groq
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; Groq offers an OpenAI compatible API
(gptel-make-openai "Groq"               ;Any name you want
  :host "api.groq.com"
  :endpoint "/openai/v1/chat/completions"
  :stream t
  :key "your-api-key"                   ;can be a function that returns the key
  :models '(llama-3.1-70b-versatile
            llama-3.1-8b-instant
            llama3-70b-8192
            llama3-8b-8192
            mixtral-8x7b-32768
            gemma-7b-it))
#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]]).  Note that Groq is fast enough that you could easily set =:stream nil= and still get near-instant responses.

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq gptel-model   'mixtral-8x7b-32768
      gptel-backend
      (gptel-make-openai "Groq"
        :host "api.groq.com"
        :endpoint "/openai/v1/chat/completions"
        :stream t
        :key "your-api-key"
        :models '(llama-3.1-70b-versatile
                  llama-3.1-8b-instant
                  llama3-70b-8192
                  llama3-8b-8192
                  mixtral-8x7b-32768
                  gemma-7b-it)))
#+end_src

#+html: </details>

#+html: <details><summary>
**** OpenRouter
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; OpenRouter offers an OpenAI compatible API
(gptel-make-openai "OpenRouter"               ;Any name you want
  :host "openrouter.ai"
  :endpoint "/api/v1/chat/completions"
  :stream t
  :key "your-api-key"                   ;can be a function that returns the key
  :models '(openai/gpt-3.5-turbo
            mistralai/mixtral-8x7b-instruct
            meta-llama/codellama-34b-instruct
            codellama/codellama-70b-instruct
            google/palm-2-codechat-bison-32k
            google/gemini-pro))

#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]]).

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq gptel-model   'mixtral-8x7b-32768
      gptel-backend
      (gptel-make-openai "OpenRouter"               ;Any name you want
        :host "openrouter.ai"
        :endpoint "/api/v1/chat/completions"
        :stream t
        :key "your-api-key"                   ;can be a function that returns the key
        :models '(openai/gpt-3.5-turbo
                  mistralai/mixtral-8x7b-instruct
                  meta-llama/codellama-34b-instruct
                  codellama/codellama-70b-instruct
                  google/palm-2-codechat-bison-32k
                  google/gemini-pro)))

#+end_src

#+html: </details>
#+html: <details><summary>
**** PrivateGPT
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
(gptel-make-privategpt "privateGPT"               ;Any name you want
  :protocol "http"
  :host "localhost:8001"
  :stream t
  :context t                            ;Use context provided by embeddings
  :sources t                            ;Return information about source documents
  :models '(private-gpt))

#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]]).

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq gptel-model   'private-gpt
      gptel-backend
      (gptel-make-privategpt "privateGPT"               ;Any name you want
        :protocol "http"
        :host "localhost:8001"
        :stream t
        :context t                            ;Use context provided by embeddings
        :sources t                            ;Return information about source documents
        :models '(private-gpt)))

#+end_src

#+html: </details>
#+html: <details><summary>
**** DeepSeek
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; DeepSeek offers an OpenAI compatible API
(gptel-make-openai "DeepSeek"       ;Any name you want
  :host "api.deepseek.com"
  :endpoint "/chat/completions"
  :stream t
  :key "your-api-key"               ;can be a function that returns the key
  :models '(deepseek-chat deepseek-coder))

#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]]).

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq gptel-model   'deepseek-chat
      gptel-backend
      (gptel-make-openai "DeepSeek"     ;Any name you want
        :host "api.deepseek.com"
        :endpoint "/chat/completions"
        :stream t
        :key "your-api-key"             ;can be a function that returns the key
        :models '(deepseek-chat deepseek-coder)))

#+end_src

#+html: </details>
#+html: <details><summary>
**** Cerebras
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; Cerebras offers an instant OpenAI compatible API
(gptel-make-openai "Cerebras"
  :host "api.cerebras.ai"
  :endpoint "/v1/chat/completions"
  :stream t                             ;optionally nil as Cerebras is instant AI
  :key "your-api-key"                   ;can be a function that returns the key
  :models '(llama3.1-70b
            llama3.1-8b))
#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]]).

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq gptel-model   'llama3.1-8b
      gptel-backend
      (gptel-make-openai "Cerebras"
        :host "api.cerebras.ai"
        :endpoint "/v1/chat/completions"
        :stream nil
        :key "your-api-key"
        :models '(llama3.1-70b
                  llama3.1-8b)))
#+end_src

#+html: </details>
#+html: <details><summary>
**** Github Models
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
  ;; Github Models offers an OpenAI compatible API
  (gptel-make-openai "Github Models" ;Any name you want
    :host "models.inference.ai.azure.com"
    :endpoint "/chat/completions"
    :stream t
    :key "your-github-token"
    :models '(gpt-4o))
#+end_src

For all the available models, check the [[https://github.com/marketplace/models][marketplace]].

You can pick this backend from the menu when using (see [[#usage][Usage]]).

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
  ;; OPTIONAL configuration
  (setq gptel-model  'gpt-4o
        gptel-backend
        (gptel-make-openai "Github Models" ;Any name you want
          :host "models.inference.ai.azure.com"
          :endpoint "/chat/completions"
          :stream t
          :key "your-github-token"
          :models '(gpt-4o))
#+end_src

#+html: </details>
#+html: <details><summary>
**** Novita AI
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; Novita AI offers an OpenAI compatible API
(gptel-make-openai "NovitaAI"         ;Any name you want
  :host "api.novita.ai"
  :endpoint "/v3/openai"
  :key "your-api-key"                   ;can be a function that returns the key
  :stream t
  :models '(;; has many more, check https://novita.ai/llm-api
            gryphe/mythomax-l2-13b
            meta-llama/llama-3-70b-instruct
            meta-llama/llama-3.1-70b-instruct))
#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model   'gryphe/mythomax-l2-13b
 gptel-backend
 (gptel-make-openai "NovitaAI"         
   :host "api.novita.ai"
   :endpoint "/v3/openai"
   :key "your-api-key"                   
   :stream t
   :models '(;; has many more, check https://novita.ai/llm-api
             mistralai/Mixtral-8x7B-Instruct-v0.1
             meta-llama/llama-3-70b-instruct
             meta-llama/llama-3.1-70b-instruct)))
#+end_src

#+html: </details>

#+html: <details><summary>
**** xAI
#+html: </summary>

Register a backend with
#+begin_src emacs-lisp
;; xAI offers an OpenAI compatible API
(gptel-make-openai "xAI"           ;Any name you want
  :host "api.x.ai"
  :key "your-api-key"              ;can be a function that returns the key
  :endpoint "/v1/chat/completions"
  :stream t
  :models '(;; xAI now only offers `grok-beta` as of the time of this writing
            grok-beta))
#+end_src

You can pick this backend from the menu when using gptel (see [[#usage][Usage]])

***** (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 value of =gptel-backend=.  Use this instead of the above.
#+begin_src emacs-lisp
;; OPTIONAL configuration
(setq
 gptel-model   'grok-beta
 gptel-backend
 (gptel-make-openai "xAI"           ;Any name you want
   :host "api.x.ai"
   :key "your-api-key"              ;can be a function that returns the key
   :endpoint "/v1/chat/completions"
   :stream t
   :models '(;; xAI now only offers `grok-beta` as of the time of this writing
             grok-beta)))
#+end_src

#+html: </details>

** Usage

gptel provides a few powerful, general purpose and flexible commands.  You can dynamically tweak their behavior to the needs of your task with /directives/, redirection options and more.  There is a [[https://www.youtube.com/watch?v=bsRnh_brggM][video demo]] showing various uses of gptel -- but =gptel-send= might be all you need.

|-------------------+---------------------------------------------------------------------------------------------------|
| *To send queries* | Description                                                                                       |
|-------------------+---------------------------------------------------------------------------------------------------|
| =gptel-send=      | Send all text up to =(point)=, or the selection if region is active.  Works anywhere in Emacs.    |
| =gptel=           | Create a new dedicated chat buffer.  Not required to use gptel.                                   |
| =gptel-rewrite=   | Rewrite, refactor or change the selected region.  Can diff/ediff changes before merging/applying. |
|-------------------+---------------------------------------------------------------------------------------------------|

|---------------------+---------------------------------------------------------------|
| *To tweak behavior* |                                                               |
|---------------------+---------------------------------------------------------------|
| =C-u= =gptel-send=  | Transient menu for preferences, input/output redirection etc. |
| =gptel-menu=        | /(Same)/                                                      |
|---------------------+---------------------------------------------------------------|

|------------------+--------------------------------------------------------------------------------------------------------|
| *To add context* |                                                                                                        |
|------------------+--------------------------------------------------------------------------------------------------------|
| =gptel-add=      | Add/remove a region or buffer to gptel's context.  In Dired, add/remove marked files.                  |
| =gptel-add-file= | Add a file (text or supported media type) to gptel's context.  Also available from the transient menu. |
|------------------+--------------------------------------------------------------------------------------------------------|

|----------------------------+-----------------------------------------------------------------------------------------|
| *Org mode bonuses*         |                                                                                         |
|----------------------------+-----------------------------------------------------------------------------------------|
| =gptel-org-set-topic=      | Limit conversation context to an Org heading.  (For branching conversations see below.) |
| =gptel-org-set-properties= | Write gptel configuration as Org properties, for per-heading chat configuration.        |
|----------------------------+-----------------------------------------------------------------------------------------|

*** In any buffer:

1. Call =M-x gptel-send= to send the text up to the cursor. The response will be inserted below.  Continue the conversation by typing below the response.

2. If a region is selected, the conversation will be limited to its contents.

3. Call =M-x gptel-send= with a prefix argument (~C-u~)
   - to set chat parameters (GPT model, backend, system message etc) for this buffer,
   - include quick instructions for the next request only,
   - to add additional context -- regions, buffers or files -- to gptel,
   - to read the prompt from or redirect the response elsewhere,
   - or to replace the prompt with the response.

#+html: <img src="https://github.com/karthink/gptel/assets/8607532/3562a6e2-7a5c-4f7e-8e57-bf3c11589c73" align="center" alt="Image showing gptel's menu with some of the available query options.">

*** In a dedicated chat buffer:

*Note*: gptel works anywhere in Emacs.  The dedicated chat buffer only adds some conveniences.

1. Run =M-x gptel= to start or switch to the chat buffer. It will ask you for the key if you skipped the previous step. Run it with a prefix-arg (=C-u M-x gptel=) to start a new session.

2. In the gptel buffer, send your prompt with =M-x gptel-send=, bound to =C-c RET=.

3. Set chat parameters (LLM provider, model, directives etc) for the session by calling =gptel-send= with a prefix argument (=C-u C-c RET=):
   
#+html: <img src="https://github.com/karthink/gptel/assets/8607532/eb4867e5-30ac-455f-999f-e17123afb810" align="center" alt="Image showing gptel's menu with some of the available query options.">

That's it. You can go back and edit previous prompts and responses if you want.

The default mode is =markdown-mode= if available, else =text-mode=.  You can set =gptel-default-mode= to =org-mode= if desired.

#+html: <details><summary>
**** Including media (images, documents) with requests
#+html: </summary>

gptel supports sending media in Markdown and Org chat buffers, but this feature is disabled by default.

- You can enable it globally, for all models that support it, by setting =gptel-track-media=.  
- Or you can set it locally, just for the chat buffer, via the header line:

#+html: <img src="https://github.com/user-attachments/assets/91f6aaab-2ea4-4806-9cc9-39b4b46a8e6c" align="center" alt="Image showing a gptel chat buffer's header line with the button to toggle media support">

-----

There are two ways to include media with requests:

1. Adding media files to the context with =gptel-add-file=, described further below.
2. Including links to media in chat buffers, described here:

To send media -- images or other supported file types -- with requests in chat buffers, you can include links to them in the chat buffer.  Such a link must be "standalone", i.e. on a line by itself surrounded by whitespace.

In Org mode, for example, the following are all *valid* ways of including an image with the request:

- "Standalone" file link:
#+begin_src
Describe this picture

[[file:/path/to/screenshot.png]]

Focus specifically on the text content.
#+end_src

- "Standalone" file link with description:
#+begin_src 
Describe this picture

[[file:/path/to/screenshot.png][some picture]]

Focus specifically on the text content.
#+end_src

- "Standalone", angle file link:
#+begin_src 
Describe this picture

<file:/path/to/screenshot.png>

Focus specifically on the text content.
#+end_src

The following links are *not valid*, and the text of the link will be sent instead of the file contents:

- Inline link:
#+begin_src 
Describe this [[file:/path/to/screenshot.png][picture]].

Focus specifically on the text content.
#+end_src

- Link not "standalone":
#+begin_src
Describe this picture: 
[[file:/path/to/screenshot.png]]
Focus specifically on the text content.
#+end_src

- Not a valid Org link:
#+begin_src 
Describe the picture

file:/path/to/screenshot.png
#+end_src

Similar criteria apply to Markdown chat buffers.

#+html: </details>
#+html: <details><summary>
**** Save and restore your chat sessions
#+html: </summary>

Saving the file will save the state of the conversation as well.  To resume the chat, open the file and turn on =gptel-mode= before editing the buffer.

#+html: </details>
*** Setting options (backend, model, request parameters, system prompts and more)

Most gptel options can be set from gptel's transient menu, available by calling =gptel-send= with a prefix-argument, or via =gptel-menu=.  To change their default values in your configuration, see [[*Additional Configuration]].  Chat buffer-specific options are also available via the header-line in chat buffers.

# TODO Remove this when writing the manual.
Selecting a model and backend can be done interactively via the =-m= command of =gptel-menu=.  Available registered models are prefixed by the name of their backend with a string like =ChatGPT:gpt-4o-mini=, where =ChatGPT= is the backend name you used to register it and =gpt-4o-mini= is the name of the model.

*** Include more context with requests

By default, gptel will query the LLM with the active region or the buffer contents up to the cursor.  Often it can be helpful to provide the LLM with additional context from outside the current buffer. For example, when you're in a chat buffer but want to ask questions about a (possibly changing) code buffer and auxiliary project files.

You can include additional text regions, buffers or files with gptel's queries.  This additional context is "live" and not a snapshot.  Once added, the regions, buffers or files are scanned and included at the time of each query.  When using multi-modal models, added files can be of any supported type -- typically images.

You can add a selected region, buffer or file to gptel's context from the menu, or call =gptel-add=.  (To add a file use =gptel-add= in Dired or use the dedicated =gptel-add-file= command.)

You can examine the active context from the menu:
#+html: <img src="https://github.com/karthink/gptel/assets/8607532/63cd7fc8-6b3e-42ae-b6ca-06ff935bae9c" align="center" alt="Image showing gptel's menu with the "inspect context" command.">

And then browse through or remove context from the context buffer:
#+html: <img src="https://github.com/karthink/gptel/assets/8607532/79a5ffe8-3d63-4bf7-9bf6-0457ab61bf2a" align="center" alt="Image showing gptel's context buffer.">

*** Rewrite, refactor or fill in a region

In any buffer: with a region selected, you can modify text, rewrite prose or refactor code with =gptel-rewrite=.  Example with prose:

#+html: <p align="center">
https://github.com/user-attachments/assets/e3b436b3-9bde-4c1f-b2ce-3f7df1984933
#+html: </p>

The result is previewed over the original text.  By default, the buffer is not modified.

Pressing =RET= or clicking in the rewritten region should give you a list of options: you can *diff*, *ediff*, *merge* or *accept* the replacement.  Example with code:

#+html: <p align="center">
https://github.com/user-attachments/assets/4067fdb8-85d3-4264-9b64-d727353f68f9
#+html: </p>

*Acting on the LLM response*:

If you would like one of these things to happen automatically, you can customize =gptel-rewrite-default-action=.

These options are also available from =gptel-rewrite=:

#+html: <img src="https://github.com/user-attachments/assets/589785b9-aa3f-414a-98dd-d26b7509de08" align="center" />

And you can call them directly when the cursor is in the rewritten region:

#+html: <img src="https://github.com/user-attachments/assets/f5b3ca47-e146-45fe-8584-f11035fa4dbc" align="center" />

*** Extra Org mode conveniences

gptel offers a few extra conveniences in Org mode.

***** Limit conversation context to an Org heading

You can limit the conversation context to an Org heading with the command =gptel-org-set-topic=.

(This sets an Org property (=GPTEL_TOPIC=) under the heading.  You can also add this property manually instead.)
  
***** Use branching context in Org mode (tree of conversations)

You can have branching conversations in Org mode, where each hierarchical outline path through the document is a separate conversation branch.  This is also useful for limiting the context size of each query.  See the variable =gptel-org-branching-context=.

Note: using this option requires Org 9.6.7 or higher to be available.  The [[https://github.com/ultronozm/ai-org-chat.el][ai-org-chat]] package uses gptel to provide this branching conversation behavior for older versions of Org.
  
***** Save gptel parameters to Org headings (reproducible chats)

You can declare the gptel model, backend, temperature, system message and other parameters as Org properties with the command =gptel-org-set-properties=.  gptel queries under the corresponding heading will always use these settings, allowing you to create mostly reproducible LLM chat notebooks, and to have simultaneous chats with different models, model settings and directives under different Org headings.

** FAQ
#+html: <details><summary>
**** I want to use gptel in a way that's not supported by =gptel-send= or the options menu
#+html: </summary>

gptel's default usage pattern is simple, and will stay this way: Read input in any buffer and insert the response below it.  Some custom behavior is possible with the transient menu (=C-u M-x gptel-send=).

For more programmable usage, gptel provides a general =gptel-request= function that accepts a custom prompt and a callback to act on the response. You can use this to build custom workflows not supported by =gptel-send=.  See the documentation of =gptel-request=, and the [[https://github.com/karthink/gptel/wiki/Defining-custom-gptel-commands][wiki]] for examples.

#+html: </details>
#+html: <details><summary>
**** I want the window to scroll automatically as the response is inserted
#+html: </summary>

To be minimally annoying, gptel does not move the cursor by default.  Add the following to your configuration to enable auto-scrolling.

#+begin_src emacs-lisp
(add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)
#+end_src

#+html: </details>
#+html: <details><summary>
**** I want the cursor to move to the next prompt after the response is inserted
#+html: </summary>

To be minimally annoying, gptel does not move the cursor by default.  Add the following to your configuration to move the cursor:

#+begin_src emacs-lisp
(add-hook 'gptel-post-response-functions 'gptel-end-of-response)
#+end_src

You can also call =gptel-end-of-response= as a command at any time.


#+html: </details>
#+html: <details><summary>
**** I want to change the formatting of the prompt and LLM response
#+html: </summary>

For dedicated chat buffers: customize =gptel-prompt-prefix-alist= and =gptel-response-prefix-alist=.  You can set a different pair for each major-mode.

Anywhere in Emacs: Use =gptel-pre-response-hook= and =gptel-post-response-functions=, which see.

#+html: </details>
#+html: <details><summary>
**** I want the transient menu options to be saved so I only need to set them once
#+html: </summary>

Any model options you set are saved for the current buffer.  But the redirection options in the menu are set for the next query only:

#+html: <img src="https://github.com/karthink/gptel/assets/8607532/2ecc6be9-aa52-4287-a739-ba06e1369ec2" alt="https://github.com/karthink/gptel/assets/8607532/2ecc6be9-aa52-4287-a739-ba06e1369ec2">

You can make them persistent across this Emacs session by pressing ~C-x C-s~:

#+html: <img src="https://github.com/karthink/gptel/assets/8607532/b8bcb6ad-c974-41e1-9336-fdba0098a2fe" alt="https://github.com/karthink/gptel/assets/8607532/b8bcb6ad-c974-41e1-9336-fdba0098a2fe">

(You can also cycle through presets you've saved with ~C-x p~ and ~C-x n~.)

Now these will be enabled whenever you send a query from the transient menu.  If you want to use these saved options without invoking the transient menu, you can use a keyboard macro:

#+begin_src emacs-lisp
;; Replace with your key to invoke the transient menu:
(keymap-global-set "<f6>" "C-u C-c <return> <return>")
#+end_src

Or see this [[https://github.com/karthink/gptel/wiki/Commonly-requested-features#save-transient-flags][wiki entry]].

#+html: </details>
#+html: <details><summary>
**** Can I change the transient menu key bindings?

Yes, see =transient-suffix-put=.  This changes the key to select a backend/model from "-m" to "M" in gptel's menu:
#+begin_src emacs-lisp
(transient-suffix-put 'gptel-menu (kbd "-m") :key "M")
#+end_src

**** How does gptel distinguish between user prompts and LLM responses?
#+html: </summary>

gptel uses [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Text-Properties.html][text-properties]] to watermark LLM responses.  Thus this text is interpreted as a response even if you copy it into another buffer.  In regular buffers (buffers without =gptel-mode= enabled), you can turn off this tracking by unsetting =gptel-track-responses=.

When restoring a chat state from a file on disk, gptel will apply these properties from saved metadata in the file when you turn on =gptel-mode=.

gptel does /not/ use any prefix or semantic/syntax element in the buffer (such as headings) to separate prompts and responses.  The reason for this is that gptel aims to integrate as seamlessly as possible into your regular Emacs usage: LLM interaction is not the objective, it's just another tool at your disposal.  So requiring a bunch of "user" and "assistant" tags in the buffer is noisy and restrictive. If you want these demarcations, you can customize =gptel-prompt-prefix-alist= and =gptel-response-prefix-alist=.  Note that these prefixes are for your readability only and purely cosmetic.

#+html: </details>
#+html: <details><summary>
**** (Doom Emacs) Sending a query from the gptel menu fails because of a key conflict with Org mode
#+html: </summary>

Doom binds ~RET~ in Org mode to =+org/dwim-at-point=, which appears to conflict with gptel's transient menu bindings for some reason.

Two solutions:
- Press ~C-m~ instead of the return key.
- Change the send key from return to a key of your choice:
  #+begin_src emacs-lisp
  (transient-suffix-put 'gptel-menu (kbd "RET") :key "<f8>")
  #+end_src

#+html: </details>
#+html: <details><summary>
**** (ChatGPT) I get the error "(HTTP/2 429) You exceeded your current quota"
#+html:</summary>

#+begin_quote
(HTTP/2 429) You exceeded your current quota, please check your plan and billing details.
#+end_quote

Using the ChatGPT (or any OpenAI) API requires [[https://platform.openai.com/account/billing/overview][adding credit to your account]].

#+html: </details>
#+html: <details><summary>
**** Why another LLM client?
#+html: </summary>

Other Emacs clients for LLMs prescribe the format of the interaction (a comint shell, org-babel blocks, etc).  I wanted:

1. Something that is as free-form as possible: query the model using any text in any buffer, and redirect the response as required.  Using a dedicated =gptel= buffer just adds some visual flair to the interaction.
2. Integration with org-mode, not using a walled-off org-babel block, but as regular text.  This way the model can generate code blocks that I can run.

#+html: </details>
#+html: <details><summary>
** Additional Configuration
:PROPERTIES:
:ID:       f885adac-58a3-4eba-a6b7-91e9e7a17829
:END:
#+html: </summary>

#+begin_src emacs-lisp :exports none :results list
(let ((all))
  (mapatoms (lambda (sym)
              (when (and (string-match-p "^gptel-[^-]" (symbol-name sym))
                         (get sym 'variable-documentation))
                (push sym all))))
  all)
#+end_src

|----------------------+--------------------------------------------------------------------|
| *Connection options* |                                                                    |
|----------------------+--------------------------------------------------------------------|
| =gptel-use-curl=     | Use Curl (default), fallback to Emacs' built-in =url=.             |
| =gptel-proxy=        | Proxy server for requests, passed to curl via =--proxy=.           |
| =gptel-api-key=      | Variable/function that returns the API key for the active backend. |
|----------------------+--------------------------------------------------------------------|

|-----------------------+---------------------------------------------------------|
| *LLM request options* | /(Note: not supported uniformly across LLMs)/           |
|-----------------------+---------------------------------------------------------|
| =gptel-backend=       | Default LLM Backend.                                    |
| =gptel-model=         | Default model to use, depends on the backend.           |
| =gptel-stream=        | Enable streaming responses, if the backend supports it. |
| =gptel-directives=    | Alist of system directives, can switch on the fly.      |
| =gptel-max-tokens=    | Maximum token count (in query + response).              |
| =gptel-temperature=   | Randomness in response text, 0 to 2.                    |
| =gptel-use-context=   | How/whether to include additional context               |
|-----------------------+---------------------------------------------------------|

|--------------------------------+----------------------------------------------------------------|
| *Chat UI options*              |                                                                |
|--------------------------------+----------------------------------------------------------------|
| =gptel-default-mode=           | Major mode for dedicated chat buffers.                         |
| =gptel-track-response=         | Distinguish between user messages and LLM responses?           |
| =gptel-track-media=            | Send images or other media from links?                         |
| =gptel-prompt-prefix-alist=    | Text inserted before queries.                                  |
| =gptel-response-prefix-alist=  | Text inserted before responses.                                |
| =gptel-use-header-line=        | Display status messages in header-line (default) or minibuffer |
| =gptel-display-buffer-action=  | Placement of the gptel chat buffer.                            |
|--------------------------------+----------------------------------------------------------------|

|-------------------------------+-------------------------------------------------------|
| *Org mode UI options*         |                                                       |
|-------------------------------+-------------------------------------------------------|
| =gptel-org-branching-context= | Make each outline path a separate conversation branch |
|-------------------------------+-------------------------------------------------------|

|---------------------------------+-------------------------------------------------------------|
| *Hooks for customization*       |                                                             |
|---------------------------------+-------------------------------------------------------------|
| =gptel-save-state-hook=         | Runs before saving the chat state to a file on disk         |
| =gptel-pre-response-hook=       | Runs before inserting the LLM response into the buffer      |
| =gptel-post-response-functions= | Runs after inserting the full LLM response into the buffer  |
| =gptel-post-stream-hook=        | Runs after each streaming insertion                         |
| =gptel-context-wrap-function=   | To include additional context formatted your way            |
| =gptel-rewrite-default-action=  | Automatically diff, ediff, merge or replace refactored text |
|---------------------------------+-------------------------------------------------------------|

#+html: </details>

** COMMENT Will you add feature X?

Maybe, I'd like to experiment a bit more first.  Features added since the inception of this package include
- Curl support (=gptel-use-curl=)
- Streaming responses (=gptel-stream=)
- Cancelling requests in progress (=gptel-abort=)
- General API for writing your own commands (=gptel-request=, [[https://github.com/karthink/gptel/wiki/Defining-custom-gptel-commands][wiki]])
- Dispatch menus using Transient (=gptel-send= with a prefix arg)
- Specifying the conversation context size
- GPT-4 support
- Response redirection (to the echo area, another buffer, etc)
- A built-in refactor/rewrite prompt
- Limiting conversation context to Org headings using properties (#58)
- Saving and restoring chats (#17)
- Support for local LLMs.

Features being considered or in the pipeline:
- Fully stateless design (#17)

** Alternatives

Other Emacs clients for LLMs include

- [[https://github.com/ahyatt/llm][llm]]: llm provides a uniform API across language model providers for building LLM clients in Emacs, and is intended as a library for use by package authors.  For similar scripting purposes, gptel provides the command =gptel-request=, which see.
- [[https://github.com/s-kostyaev/ellama][Ellama]]: A full-fledged LLM client built on llm, that supports many LLM providers (Ollama, Open AI, Vertex, GPT4All and more).  Its usage differs from gptel in that it provides separate commands for dozens of common tasks, like general chat, summarizing code/text, refactoring code, improving grammar, translation and so on.
- [[https://github.com/xenodium/chatgpt-shell][chatgpt-shell]]: comint-shell based interaction with ChatGPT.  Also supports DALL-E, executable code blocks in the responses, and more.
- [[https://github.com/rksm/org-ai][org-ai]]: Interaction through special =#+begin_ai ... #+end_ai= Org-mode blocks.  Also supports DALL-E, querying ChatGPT with the contents of project files, and more.

There are several more: [[https://github.com/MichaelBurge/leafy-mode][leafy-mode]], [[https://github.com/iwahbe/chat.el][chat.el]], [[https://github.com/stuhlmueller/gpt.el][gpt.el]],  [[https://github.com/AnselmC/le-gpt.el][le-gpt]], [[https://github.com/stevemolitor/robby][robby]].

*** Packages using gptel

gptel is a general-purpose package for chat and ad-hoc LLM interaction.  The following packages use gptel to provide additional or specialized functionality:

- [[https://github.com/karthink/gptel-quick][gptel-quick]]: Quickly look up the region or text at point.
- [[https://github.com/daedsidog/evedel][Evedel]]: Instructed LLM Programmer/Assistant
- [[https://github.com/lanceberge/elysium][Elysium]]: Automatically apply AI-generated changes as you code
- [[https://github.com/kamushadenes/gptel-extensions.el][gptel-extensions]]: Extra utility functions for gptel
- [[https://github.com/kamushadenes/ai-blog.el][ai-blog.el]]: Streamline generation of blog posts in Hugo
- [[https://github.com/douo/magit-gptcommit][magit-gptcommit]]: Generate Commit Messages within magit-status Buffer using gptel
- [[https://github.com/armindarvish/consult-omni][consult-omni]]: Versatile multi-source search package.  It includes gptel as one of its many sources.
- [[https://github.com/ultronozm/ai-org-chat.el][ai-org-chat]]: Provides branching conversations in Org buffers using gptel.  (Note that gptel includes this feature as well (see =gptel-org-branching-context=), but requires a recent version of Org mode (9.67 or later) to be installed.)
- [[https://github.com/rob137/Corsair][Corsair]]: Helps gather text to populate LLM prompts for gptel.

** COMMENT Older Breaking Changes

- =gptel-post-response-hook= has been renamed to =gptel-post-response-functions=, and functions in this hook are now called with two arguments: the start and end buffer positions of the response.  This should make it easy to act on the response text without having to locate it first.

- Possible breakage, see #120: If streaming responses stop working for you after upgrading to v0.5, try reinstalling gptel and deleting its native comp eln cache in =native-comp-eln-load-path=.

- The user option =gptel-host= is deprecated.  If the defaults don't work for you, use =gptel-make-openai= (which see) to customize server settings.

- =gptel-api-key-from-auth-source= now searches for the API key using the host address for the active LLM backend, /i.e./ "api.openai.com" when using ChatGPT.  You may need to update your =~/.authinfo=.

** Acknowledgments

- [[https://github.com/meain][Abin Simon]] for extensive feedback on improving gptel's directives and UI.
- [[https://github.com/algal][Alexis Gallagher]] and [[https://github.com/d1egoaz][Diego Alvarez]] for fixing a nasty multi-byte bug with =url-retrieve=.
- [[https://github.com/tarsius][Jonas Bernoulli]] for the Transient library.
- [[https://github.com/daedsidog][daedsidog]] for adding context support to gptel.
- [[https://github.com/Aquan1412][Aquan1412]] for adding PrivateGPT support to gptel.
- [[https://github.com/r0man][r0man]] for improving gptel's Curl integration.

# Local Variables:
# toc-org-max-depth: 4
# eval: (and (fboundp 'toc-org-mode) (toc-org-mode 1))
# End:
