421 lines
13 KiB
Org Mode
421 lines
13 KiB
Org Mode
#+TITLE: forge-llm
|
|
#+AUTHOR: Roger Gonzalez
|
|
#+EMAIL: roger@rogs.me
|
|
|
|
* forge-llm
|
|
:PROPERTIES:
|
|
:ID: 81db1fd1-a5db-4201-9113-72889f7c7829
|
|
:END:
|
|
|
|
[[https://melpa.org/#/forge-llm][file:https://melpa.org/packages/forge-llm-badge.svg]]
|
|
[[https://gitlab.com/rogs/forge-llm/badges/master/pipeline.svg]]
|
|
|
|
Generate Pull Request descriptions for Forge using LLM providers through the [[https://github.com/ahyatt/llm][llm]] package.
|
|
|
|
[[https://gitlab.com/uploads/-/system/project/avatar/67959042/logo.png]]
|
|
|
|
** Overview
|
|
:PROPERTIES:
|
|
:ID: e5e5a1d0-cf5a-4f45-8d4c-f2f75339bf9a
|
|
:END:
|
|
|
|
~forge-llm~ is an Emacs package that integrates Large Language Models (LLMs) with Forge, a Magit interface to GitHub and GitLab forges. This package helps you generate high-quality Pull Request descriptions based on your git diff and repository PR templates.
|
|
|
|
Main features:
|
|
- Automatically finds and uses your repository's PR template
|
|
- Generates PR descriptions based on git diffs between branches
|
|
- Seamless integration with Forge's PR creation workflow
|
|
- Supports any LLM provider supported by the ~llm~ package
|
|
- Stream LLM responses in real-time
|
|
|
|
** Dependencies
|
|
:PROPERTIES:
|
|
:ID: f30fedc1-a24a-4308-bc78-6f9c01857c18
|
|
:END:
|
|
|
|
- [[https://magit.vc/][Magit]] and [[https://github.com/magit/forge][Forge]]
|
|
- [[https://github.com/ahyatt/llm][llm]]
|
|
- Emacs 25.1+
|
|
|
|
** Installation
|
|
:PROPERTIES:
|
|
:ID: a4cfca4c-6029-445a-9e1d-88293ddaaff7
|
|
:END:
|
|
|
|
*** Using MELPA (Recommended)
|
|
:PROPERTIES:
|
|
:ID: 0e561e53-10f6-4a0b-90e3-46094124aeb2
|
|
:END:
|
|
|
|
The easiest way to install ~forge-llm~ is via MELPA. Ensure you have MELPA configured in your Emacs setup (it's included by default in many distributions like Doom Emacs and Spacemacs).
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package forge-llm
|
|
:ensure t
|
|
:after forge
|
|
:config
|
|
(forge-llm-setup))
|
|
#+end_src
|
|
|
|
*** Using straight.el with use-package
|
|
:PROPERTIES:
|
|
:ID: 0c4a74cd-f752-4b3f-a729-0cc5a34f3d38
|
|
:END:
|
|
|
|
If you use ~straight.el~ to manage your packages, it can install ~forge-llm~ directly from MELPA. Ensure MELPA is included in your ~straight-recipe-repositories~ or ~straight-recipe-sources~.
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package forge-llm
|
|
;; straight.el will fetch this from MELPA if :ensure t is used
|
|
;; and straight.el is configured as the handler for use-package.
|
|
:ensure t
|
|
:after forge
|
|
:config
|
|
(forge-llm-setup))
|
|
#+end_src
|
|
|
|
*** Using Doom Emacs
|
|
:PROPERTIES:
|
|
:ID: 6c2a34d5-8e1a-4f7e-9c2b-1d9e7b8f3a1d
|
|
:END:
|
|
|
|
**** Basic Setup
|
|
:PROPERTIES:
|
|
:ID: f7a2b3c4-d5e6-4f7a-8b9c-0d1e2f3a4b5c
|
|
:END:
|
|
|
|
1. Add the following to your ~packages.el~ (ensure MELPA is enabled in your Doom configuration, which is usually the default):
|
|
|
|
#+begin_src emacs-lisp
|
|
(package! forge-llm)
|
|
(package! llm) ; Dependency
|
|
#+end_src
|
|
|
|
2. Add somewhere in your ~config.el~:
|
|
|
|
#+begin_src emacs-lisp
|
|
;; Load and setup forge-llm after forge is loaded
|
|
(after! forge
|
|
(require 'forge-llm)
|
|
(forge-llm-setup))
|
|
|
|
;; Configure your LLM provider (example using OpenAI)
|
|
;; Place this somewhere appropriate in your config.el
|
|
(require 'llm-openai) ; Or your preferred LLM provider
|
|
(setq forge-llm-llm-provider (make-llm-openai :key "YOUR-OPENAI-KEY")) ; Replace with your key/provider setup
|
|
#+end_src
|
|
|
|
3. Run ~doom sync~ to install the package.
|
|
|
|
**** Keybindings
|
|
:PROPERTIES:
|
|
:ID: 3e4f5a6b-7c8d-9e0f-1a2b-3c4d5e6f7a8b
|
|
:END:
|
|
|
|
The package automatically sets up Doom Emacs keybindings when Doom is detected:
|
|
|
|
- ~SPC m g~ - Generate PR description in a separate buffer
|
|
- ~SPC m p~ - Generate PR description at point
|
|
- ~SPC m t~ - Insert PR template at point
|
|
|
|
No additional configuration is needed for these keybindings to work.
|
|
|
|
*** Manual installation
|
|
:PROPERTIES:
|
|
:ID: b91cfecf-04a3-43c8-96d3-dea082e5ed6e
|
|
:END:
|
|
|
|
Clone the repository:
|
|
|
|
#+begin_src shell
|
|
git clone https://gitlab.com/rogs/forge-llm.git ~/.emacs.d/site-lisp/forge-llm
|
|
#+end_src
|
|
|
|
Add to your Emacs configuration:
|
|
|
|
#+begin_src emacs-lisp
|
|
(add-to-list 'load-path "~/.emacs.d/site-lisp/forge-llm")
|
|
(require 'forge-llm)
|
|
(forge-llm-setup)
|
|
#+end_src
|
|
|
|
** Setting up LLM providers
|
|
:PROPERTIES:
|
|
:ID: 842282e1-4760-4687-96a1-4c15adb9a13d
|
|
:END:
|
|
|
|
~forge-llm~ depends on the [[https://github.com/ahyatt/llm][llm]] package for LLM integration. You'll need to set up at least one LLM provider. Please refer to the [[https://github.com/ahyatt/llm?tab=readme-ov-file#setting-up-providers][llm documentation]] for detailed instructions.
|
|
|
|
Some of the providers supported by the ~llm~ package include:
|
|
- OpenAI
|
|
- Anthropic (Claude)
|
|
- Google (Gemini, Vertex AI)
|
|
- Azure OpenAI
|
|
- GitHub Models
|
|
- Ollama (for local models like Llama, Mistral, etc.)
|
|
- GPT4All (for local models)
|
|
- llama.cpp (via OpenAI compatible endpoint)
|
|
- Deepseek
|
|
- Generic OpenAI-compatible endpoints
|
|
|
|
See the [[https://github.com/ahyatt/llm?tab=readme-ov-file#setting-up-providers][llm documentation]] for the complete list and specific setup steps.
|
|
|
|
*** Example: OpenAI provider
|
|
:PROPERTIES:
|
|
:ID: 108c5560-65ad-49e1-8c02-d4c0493bb2b2
|
|
:END:
|
|
|
|
First, create an [[https://platform.openai.com/account/api-keys][OpenAI API key]]. Then configure the ~llm~ OpenAI provider:
|
|
|
|
#+begin_src emacs-lisp
|
|
(require 'llm-openai)
|
|
(setq forge-llm-llm-provider (make-llm-openai :key "YOUR-OPENAI-KEY"))
|
|
#+end_src
|
|
|
|
*** Example: Anthropic provider
|
|
:PROPERTIES:
|
|
:ID: b9728ac5-f5c0-4d6b-8d3e-a4b7c3d9e1f0
|
|
:END:
|
|
|
|
To use Claude models from Anthropic:
|
|
|
|
#+begin_src emacs-lisp
|
|
(require 'llm-claude)
|
|
(setq forge-llm-llm-provider (make-llm-claude :key "YOUR-ANTHROPIC-KEY" :chat-model "claude-3-7-sonnet-20250219"))
|
|
#+end_src
|
|
|
|
*** Using auth-source for API keys (recommended)
|
|
:PROPERTIES:
|
|
:ID: 59f84b84-ce44-4208-8531-56992cae847e
|
|
:END:
|
|
|
|
For better security, use Emacs ~auth-source~ to store your API keys:
|
|
|
|
#+begin_src emacs-lisp
|
|
(use-package llm
|
|
:ensure t
|
|
:config
|
|
(setq llm-warn-on-nonfree nil))
|
|
|
|
(require 'llm-openai)
|
|
|
|
(use-package forge-llm
|
|
:ensure t
|
|
:after (forge llm)
|
|
:custom
|
|
(forge-llm-llm-provider
|
|
(make-llm-openai
|
|
:key (auth-source-pick-first-password
|
|
:host "api.openai.com"
|
|
:user "apikey")))
|
|
:config
|
|
(forge-llm-setup))
|
|
#+end_src
|
|
|
|
Content of ~.authinfo~ or ~.authinfo.gpg~:
|
|
#+begin_src
|
|
machine api.openai.com login apikey password YOUR-API-KEY-HERE
|
|
#+end_src
|
|
|
|
** Usage
|
|
:PROPERTIES:
|
|
:ID: e6753914-01ee-41e9-bcdf-f3d6e75ee451
|
|
:END:
|
|
|
|
After setting up ~forge-llm~, the following commands will be available in Forge's pull request creation buffer:
|
|
|
|
| Key binding | Command | Description |
|
|
|------------------------+--------------------------------------------+-------------------------------------------------------|
|
|
| C-c C-l g | forge-llm-generate-pr-description | Generate a PR description (output to separate buffer) |
|
|
| C-c C-l p | forge-llm-generate-pr-description-at-point | Generate a PR description at the current point |
|
|
| C-c C-l t | forge-llm-insert-template-at-point | Insert the PR template at the current point |
|
|
| SPC m g (Doom Emacs) | forge-llm-generate-pr-description | Generate a PR description (output to separate buffer) |
|
|
| SPC m p (Doom Emacs) | forge-llm-generate-pr-description-at-point | Generate a PR description at the current point |
|
|
| SPC m t (Doom Emacs) | forge-llm-insert-template-at-point | Insert the PR template at the current point |
|
|
|
|
*** Demo: Generate PR description in a new buffer
|
|
:PROPERTIES:
|
|
:ID: 8d7e1f6a-3b2c-4a9e-8d7e-1f6a3b2c4a9e
|
|
:END:
|
|
|
|
Pressing ~C-c C-l g~ will generate a PR description and display it in a separate buffer:
|
|
|
|
[[https://gitlab.com/-/project/67959042/uploads/3eed67e0b188d040906d30b6b6cc3ec6/generate-pr-desc.gif][file:https://gitlab.com/-/project/67959042/uploads/3eed67e0b188d040906d30b6b6cc3ec6/generate-pr-desc.gif]]
|
|
|
|
/Click the image to view in full screen/
|
|
|
|
*** Demo: Generate PR description at point
|
|
:PROPERTIES:
|
|
:ID: 9e5d4f8b-4eab-8798-9e5d-4f8b4eab8798
|
|
:END:
|
|
|
|
Pressing ~C-c C-l p~ will generate a PR description and insert it directly at the cursor position:
|
|
|
|
[[https://gitlab.com/-/project/67959042/uploads/9e5d4f8b4eab87989eafca9f58baa467/generate-pr-at-point.gif][file:https://gitlab.com/-/project/67959042/uploads/9e5d4f8b4eab87989eafca9f58baa467/generate-pr-at-point.gif]]
|
|
|
|
/Click the image to view in full screen/
|
|
|
|
*** Workflow:
|
|
:PROPERTIES:
|
|
:ID: d745d788-793a-4847-95d7-4f5105bc654d
|
|
:END:
|
|
1. Create a PR using Forge as normal (~forge-create-pullreq~)
|
|
2. In the PR creation buffer, position your cursor where you want to insert the PR description
|
|
3. Press ~C-c C-l p~ to generate and insert a PR description based on your changes
|
|
4. Edit the description as needed and submit the PR
|
|
|
|
*** Canceling Generation:
|
|
:PROPERTIES:
|
|
:ID: 7ddfeaab-31a3-4476-b770-7c9751566d88
|
|
:END:
|
|
If you need to cancel an in-progress LLM request:
|
|
- ~M-x forge-llm-cancel-request~
|
|
|
|
** Customization
|
|
:PROPERTIES:
|
|
:ID: baff250b-65a2-48cf-ace8-af38996bd865
|
|
:END:
|
|
|
|
You can customize various aspects of ~forge-llm~ through the following variables:
|
|
|
|
*** PR Template Configuration
|
|
:PROPERTIES:
|
|
:ID: ccb75625-c64d-47ad-adbe-77862b4ebbb5
|
|
:END:
|
|
|
|
- ~forge-llm-pr-template-paths~ - List of possible paths for PR/MR templates relative to repo root
|
|
#+begin_src emacs-lisp
|
|
(setq forge-llm-pr-template-paths
|
|
'(".github/PULL_REQUEST_TEMPLATE.md"
|
|
".github/pull_request_template.md"
|
|
"docs/pull_request_template.md"
|
|
".gitlab/merge_request_templates/default.md"))
|
|
#+end_src
|
|
|
|
- ~forge-llm-default-pr-template~ - Default PR template to use when no template is found in the repository
|
|
|
|
*** LLM Provider Configuration
|
|
:PROPERTIES:
|
|
:ID: 8c3c77fb-a6ae-47bb-8c2b-2b82c2364d81
|
|
:END:
|
|
|
|
- ~forge-llm-llm-provider~ - LLM provider to use. Can be a provider object or a function that returns a provider object
|
|
(See the [[https://github.com/ahyatt/llm][llm package]] documentation for how to create provider objects).
|
|
#+begin_src emacs-lisp
|
|
(setq forge-llm-llm-provider (make-llm-openai :key "YOUR-API-KEY"))
|
|
#+end_src
|
|
|
|
- ~forge-llm-temperature~ - Temperature for LLM responses (nil for provider default)
|
|
#+begin_src emacs-lisp
|
|
(setq forge-llm-temperature 0.7)
|
|
#+end_src
|
|
|
|
- ~forge-llm-max-tokens~ - Maximum number of tokens for LLM responses (nil for provider default)
|
|
#+begin_src emacs-lisp
|
|
(setq forge-llm-max-tokens 1024)
|
|
#+end_src
|
|
|
|
- ~forge-llm-max-diff-size~ - Maximum size in characters for git diffs sent to the LLM (nil for no truncation)
|
|
#+begin_src emacs-lisp
|
|
;; Default is 50000, set to nil to disable truncation
|
|
(setq forge-llm-max-diff-size 100000) ; Increase to 100K characters
|
|
;; Or disable truncation completely
|
|
(setq forge-llm-max-diff-size nil)
|
|
#+end_src
|
|
|
|
*** Prompt Configuration
|
|
:PROPERTIES:
|
|
:ID: f0cb4a2b-d919-4fe0-b286-317b93084174
|
|
:END:
|
|
|
|
- ~forge-llm-pr-description-prompt~ - Prompt used to generate a PR description with the LLM. This prompt is formatted with the PR template and git diff.
|
|
|
|
You can customize this prompt to match your project's PR description style:
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq forge-llm-pr-description-prompt
|
|
"Generate a PR description for the following changes.
|
|
PR template:
|
|
%s
|
|
|
|
Git diff:
|
|
```
|
|
%s
|
|
```
|
|
|
|
Please generate a PR description that follows our team's style.")
|
|
#+end_src
|
|
|
|
** Troubleshooting
|
|
:PROPERTIES:
|
|
:ID: 30489ac7-98ed-4820-a780-83c239e427f6
|
|
:END:
|
|
|
|
- If you're having issues with the LLM provider, you can enable debug logging for ~llm~ by setting ~llm-log~ to ~t~.
|
|
- Check the ~*forge-llm-debug-prompt*~ buffer to see the exact prompt being sent to the LLM.
|
|
- Check the ~*forge-llm-output*~ buffer to see the raw output from the LLM.
|
|
|
|
*** Common Issues:
|
|
:PROPERTIES:
|
|
:ID: 4b2fd630-290e-4a95-8315-e8db4b6f4217
|
|
:END:
|
|
|
|
- *Error: "No LLM provider configured"*
|
|
- Make sure you've set ~forge-llm-llm-provider~ to a valid provider object.
|
|
- Ensure your API key is correct.
|
|
|
|
- *Error: "Failed to generate git diff"*
|
|
- Ensure you're in a repository with valid head and base branches.
|
|
- Check if the current directory is within a git repository.
|
|
|
|
- *PR Generation is too slow*
|
|
- Consider using a faster model (like GPT-3.5-turbo instead of GPT-4).
|
|
- Reduce ~forge-llm-max-tokens~ to limit the response size.
|
|
|
|
- *PR template not found*
|
|
- Check if your PR template is in one of the paths listed in ~forge-llm-pr-template-paths~.
|
|
- Add your custom template path if needed.
|
|
|
|
** TO-DO:
|
|
:PROPERTIES:
|
|
:ID: 97dad50e-0d25-42aa-9fe6-5e6402256454
|
|
:END:
|
|
- Add more examples and use cases
|
|
|
|
** Contributing
|
|
:PROPERTIES:
|
|
:ID: 398ecc9e-30c2-4af4-afc5-c793ab3bedaa
|
|
:END:
|
|
|
|
Contributions are welcome! Please feel free to submit a Merge Request.
|
|
|
|
*** Development Setup
|
|
:PROPERTIES:
|
|
:ID: 237ac5d2-d323-4b7d-9c51-54760a3ccc53
|
|
:END:
|
|
|
|
1. Clone the repository:
|
|
#+begin_src shell
|
|
git clone https://gitlab.com/rogs/forge-llm.git
|
|
cd forge-llm
|
|
#+end_src
|
|
|
|
2. Install dependencies for development:
|
|
- Ensure you have forge and llm packages
|
|
|
|
** Acknowledgments
|
|
:PROPERTIES:
|
|
:ID: b5d4c3e2-f1a0-4b9c-8d7e-6f5a4b3c2d1e
|
|
:END:
|
|
|
|
This project was heavily inspired by [[https://github.com/douo/magit-gptcommit][magit-gptcommit]]. Check it out! This package works very well with forge-llm.
|
|
|
|
Another huge inspiration was [[https://github.com/xenodium][xenodium]], with their Emacs package [[https://github.com/xenodium/chatgpt-shell][chatgpt-shell]].
|
|
|
|
** License
|
|
:PROPERTIES:
|
|
:ID: 14189649-a22f-4cf8-9850-9a8bb62456d3
|
|
:END:
|
|
|
|
This project is licensed under the GNU General Public License version 3 - see the LICENSE file for details.
|