A tasteful LLM plugin.
- Clean and snappy Vim buffer based chat interface
- Local storage for chat history, with Telescope integration
- Code rewrite command with unified diff
- Live streaming of tokens
- Pure Lua OpenAI client and diff algorithm
You'll need a plugin manager (such as lazy), and an OpenAI compatible LLM API (such as OpenRouter).
Example configuration with lazy.nvim:
{
"nathom/delphi.nvim",
keys = {
{ "<leader><cr>", "<Plug>(DelphiChatSend)", desc = "Delphi: send chat" },
{ "<leader>r", "<Plug>(DelphiRewriteSelection)", mode = "x", desc = "Delphi: rewrite selection" },
{ "<leader>a", "<Plug>(DelphiRewriteAccept)", desc = "Delphi: accept rewrite" },
{ "<leader>R", "<Plug>(DelphiRewriteReject)", desc = "Delphi: reject rewrite" },
{ "<Esc><Esc>", "<Plug>(DelphiPromptCancel)", mode = { "n", "i" }, desc = "Delphi: cancel prompt" },
},
opts = {
chat = { default_model = "gemini_25" },
rewrite = { default_model = "kimi_k2" },
models = {
gemini_25 = {
base_url = "https://openrouter.ai/api/v1",
api_key_env_var = "OPENROUTER_API_KEY",
model_name = "google/gemini-2.5-pro",
},
kimi_k2 = {
base_url = "https://openrouter.ai/api/v1",
api_key_env_var = "OPENROUTER_API_KEY",
model_name = "moonshotai/kimi-k2",
},
},
},
dependencies = { "nvim-lua/plenary.nvim" },
}
In this case, delphi will expect your OpenRouter API keys under the environment variable OPENROUTER_API_KEY
.
Type :Chat
to open up a chat buffer. If one is already open
in your Neovim instance, it will switch to that buffer. If you want to create a new chat regardless, use :Chat new
.
Example blank chat buffer:
---
model: kimi_k2
temperature: 0.7
---
System:
User:
To send a message to the model, type text below User:
, switch to normal mode, and trigger <Plug>(DelphiChatSend)
.
---
model: kimi_k2
temperature: 0.7
---
System:
User:
Is it worth switching to Neovim?
You should see the model's response being streamed in live.
---
model: kimi_k2
temperature: 0.7
---
System:
User:
Is it worth switching to Neovim?
Assistant:
Short answer
If you already know Vim and are happy with it, you probably don’t *need* to switch—but if you enjoy experimenting,
want modern features without waiting for Bram to merge them, or are starting from scratch, Neovim is almost always the better choice today.
Below is a practical “decision matrix” so you can decide whether the switch is worth the one-time migration cost for *you*.
...
The system prompt can usually be left empty, as the provider will set a reasonable one for you.
You have two options:
- Use
:Telescope delphi chats
- Run
:Chat list
to view the ids and titles of chats, and:Chat go <id>
to open them
This command allows the LLM to rewrite a selected block of code according to your instructions. It will display a unified diff, which is updated as tokens are streamed in.
To use it
- open a buffer with some text
- highlight a few lines in Visual Lines mode (shift-V)
- trigger
<Plug>(DelphiRewriteSelection)
, which should open a popup - instruct the model, hit
ENTER
- accept or reject the changes via
<Plug>(DelphiRewriteAccept)
or<Plug>(DelphiRewriteReject)
These are the schema:
---@class Model
---@field base_url string
---@field api_key_env_var string
---@field model_name string
---@field temperature number
---@class Config
---@field models table<string, Model>
---@field allow_env_var_config boolean
---@field chat { system_prompt: string, default_model: string?, headers: { system: string, user: string, assistant: string } }
---@field rewrite { system_prompt: string, default_model: string?, prompt_template: string }
These are the default opts:
opts = {
models = {},
allow_env_var_config = false,
chat = {
system_prompt = "",
default_model = nil,
headers = {
system = "System:",
user = "User:",
assistant = "Assistant:",
},
},
rewrite = {
default_model = nil,
system_prompt = [[
You are an expert refactoring assistant. You ALWAYS respond with the rewritten code or text enclosed in <delphi:refactored_code> tags:
<delphi:refactored_code>
...
</delphi:refactored_code>]],
prompt_template = [[
Full file for context:
<delphi:current_file>
{{file_text}}
</delphi:current_file>
Selected lines ({{selection_start_lnum}}:{{selection_end_lnum}}):
<delphi:selected_lines>
{{selected_text}}
</delphi:selected_lines>
Instruction: {{user_instructions}}. Return ONLY the refactored code inside <delphi:refactored_code> tags. Preserve formatting unless told otherwise. Try to keep the diff minimal while following the instructions exactly.]],
},
}
```