dotfiles/nvim/.config/nvim/lua/modules/llm.lua
Marty Oehme 6aa8aefe0e
nvim: Add vectorcode codecompanion extension
Installs vectorcode (the cli program) using uv (if `uv` is available on
the system), to provide a RAG tool for your repositories. Can then be
used in codecompanion to provide better coding feedback.
2025-12-12 09:50:38 +01:00

338 lines
10 KiB
Lua

return {
{
-- NOTE: Requires manual auth with ':Copilot auth' or 'GH_COPILOT_TOKEN' set as envvar
"zbirenbaum/copilot.lua",
dependencies = {
"AndreM222/copilot-lualine",
{ -- show completions in blink
"saghen/blink.cmp",
optional = true,
dependencies = {
{
"fang2hou/blink-copilot",
opts = {
auto_refresh = {
backward = false,
forward = false,
},
},
},
},
opts = {
sources = {
default = { "copilot" },
providers = {
copilot = {
name = "copilot",
module = "blink-copilot",
score_offset = 100,
async = true,
},
},
},
},
},
},
cmd = "Copilot",
event = { "InsertEnter", "VeryLazy" },
opts = {
panel = { layout = { position = "bottom" } },
suggestion = { keymap = { accept = "<M-p>" } },
logger = { print_log_level = vim.log.levels.ERROR },
},
config = function(_, opts)
require("copilot").setup(opts)
-- TODO: See also https://github.com/zbirenbaum/copilot.lua/issues/302 for potential
-- better solutions.
-- TODO: also Find way of having a 'toggle' for mapping below.
-- Current copilot.lua exposed 'toggle' command does NOT do the same.
require("copilot.command").disable()
end,
keys = {
{
"<leader>aC",
function()
require("copilot.panel").setup()
require("copilot.panel").open({})
require("copilot.panel").refresh()
end,
desc = "Open copilot panel",
silent = true,
mode = { "n" },
},
{
"<leader>ap",
function()
require("copilot.command").enable()
end,
desc = "Enable copilot",
silent = true,
mode = { "n" },
},
{
"<leader>aP",
function()
require("copilot.command").disable()
end,
desc = "Disable copilot",
silent = true,
mode = { "n" },
},
},
},
{
"olimorris/codecompanion.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
"zbirenbaum/copilot.lua",
{ "ibhagwan/fzf-lua", optional = true },
"ravitemer/codecompanion-history.nvim",
"jinzhongjia/codecompanion-gitcommit.nvim",
{
"Davidyz/VectorCode",
cond = vim.fn.executable("uv") == 1,
version = "*",
build = 'uv tool install -U "vectorcode[mcp,lsp]"',
dependencies = { "nvim-lua/plenary.nvim" },
opts = {
async_backend = "lsp", -- requires cli install as `uv tool install vectorcode[lsp]`
},
},
{ -- enable mcp server agent extensions
"ravitemer/mcphub.nvim",
build = "bundled_build.lua",
opts = {
use_bundled_binary = true,
},
cmd = "MCPHub",
keys = {
{
"<leader>va",
"<cmd>MCPHub<cr>",
desc = "MCP Hub",
silent = true,
},
},
},
},
init = function(_)
if require("core.util").is_available("which-key") then
require("which-key").add({ "<leader>a", group = "codecompanion" })
end
require("personal.ccp-fidget"):init()
end,
opts = {
strategies = {
chat = { adapter = "groq" },
inline = { adapter = "copilot" },
cmd = { adapter = "groq" },
},
adapters = {
http = {
opts = {
show_defaults = true, -- TODO: set to false to only enable working, but does not show copilot then
show_model_choices = true,
},
groq = function()
return require("codecompanion.adapters").extend("openai", {
env = {
api_key = "GROQ_API_KEY",
},
name = "Groq",
url = "https://api.groq.com/openai/v1/chat/completions",
schema = {
model = {
default = "moonshotai/kimi-k2-instruct-0905",
choices = {
-- production models
"openai/gpt-oss-120b",
"moonshotai/kimi-k2-instruct-0905",
"llama-3.3-70b-versatile",
"llama-3.1-8b-instant",
"meta-llama/llama-guard-4-12b",
"openai/gpt-oss-20b",
-- preview models
"meta-llama/llama-4-maverick-17b-128e-instruct",
"meta-llama/llama-4-scout-17b-16e-instruct",
"qwen/qwen3-32b",
},
},
},
max_tokens = {
default = 4096,
},
temperature = {
default = 1,
},
})
end,
gemini = function()
return require("codecompanion.adapters").extend("gemini", {
env = {
api_key = "GEMINI_API_KEY",
},
})
end,
},
},
display = {
action_palette = {
provider = "fzf_lua",
},
},
extensions = {
history = {
enabled = true,
opts = {
auto_save = true,
expiration_days = 14,
picker = "fzf-lua",
delete_on_clearing_chat = true,
},
},
gitcommit = {
enabled = true,
callback = "codecompanion._extensions.gitcommit",
opts = {
add_slash_command = true,
buffer = {
enabled = true,
keymap = "<leader>ag",
},
},
},
mcphub = {
callback = "mcphub.extensions.codecompanion",
opts = {
show_results_in_chat = true,
make_tools = true, -- Make individual tools (@server__tool) and server groups (@server) from MCP servers
make_vars = true, -- Make individual resources into #variables
make_slash_commands = true, -- Make individual prompts into /slash commands
show_server_tools_in_chat = true, -- Show individual tools in chat completion (when make_tools=true)
add_mcp_prefix_to_tool_names = false, -- Add mcp__ prefix (e.g `@mcp__github`, `@mcp__neovim__list_issues`)
show_result_in_chat = true, -- Show tool results directly in chat buffer
},
},
vectorcode = {},
},
prompt_library = {
["DevOps strategy"] = {
strategy = "chat",
description = "Senior devops engineer explains high-level solutions.",
opts = { short_name = "devops" },
prompts = {
{
role = "system",
content = "You are a Senior DevOps engineer working at a professional company. Your role is to provide scalable, efficient, and automated solutions for software deployment, infrastructure management, and CI/CD pipelines. First problem is: Creating an MVP quickly, suggest the best DevOps practices, including infrastructure setup, deployment strategies, automation tools, and cost-effective scaling solutions. Reply in English using professional tone for everyone.",
},
},
},
["Code Reviewer Chat"] = {
strategy = "chat",
description = "Get your code reviewed by an 'experienced' developer.",
opts = { short_name = "review" },
prompts = {
{
role = "system",
content = "I want you to act as a Code reviewer who is experienced developer in the given code language. I will provide you with the code block or methods or code file along with the code language name, and I would like you to review the code and share the feedback, suggestions and alternative recommended approaches. Please write explanations behind the feedback or suggestions or alternative approaches.",
},
},
},
["HackerNews Review"] = {
strategy = "chat",
description = "Get your code reviewed by a jaded hackernews commenter.",
opts = { short_name = "hackernews" },
prompts = {
{
role = "system",
content = "I want you to act as a Code reviewer who is experienced developer in the given code language. I will provide you with the code block or methods or code file along with the code language name, and I would like you to review the code and share the feedback, suggestions and alternative recommended approaches as if you had read it on hackernews. Please be concise and do not give extraneous positives unless they truly are warranted. Provide explanations behind the feedback or suggestions or alternative approaches, in the succinct manner of hackernews comments.",
},
},
},
["Smart Paste"] = {
strategy = "inline",
description = "Paste code smartly",
opts = { short_name = "paste" },
prompts = {
{
role = "user",
content = [[
You are a smart code paste agent within Neovim.
## **Task:** Intelligently integrate content from the user's clipboard into the current buffer.
## **Instructions:**
- You may receive code in various programming languages or even natural language instructions.
- If the clipboard content is in a different language than the current buffer, translate it to the appropriate language smartly.
- If the clipboard content contains pseudo code generate code accordingly.
- If the clipboard content contains natural language instructions, interpret and follow them to modify the code in the current buffer.
- **ONLY** generate the **new** lines of code required for seamless integration.
- Ensure the inserted code is syntactically correct and logically consistent with the existing code.
- Do **NOT** include surrounding code or line numbers.
- Make sure all brackets and quotes are closed properly.
## **Output:**
- Provide only the necessary lines of code for insertion.
- If you can't generate code just return nothing.
- Ensure the response is proper and well-formatted.
]],
},
{
role = "user",
content = function(context)
local lines = require("codecompanion.helpers.actions").get_code(
1,
context.line_count,
{ show_line_numbers = true }
)
local selection_info = ""
local clipboard = vim.fn.getreg("+")
if context.is_visual then
selection_info = string.format(
"Currently selected lines: %d-%d",
context.start_line,
context.end_line
)
else
selection_info = string.format(
"Current cursor line: %d and Current cursor column is %d",
context.cursor_pos[1],
context.cursor_pos[2]
)
end
return string.format(
"I have the following code:\n\n```%s\n%s\n```\n\nClipboard content:\n\n```\n%s\n```\n\n%s",
context.filetype,
lines,
clipboard,
selection_info
)
end,
opts = {
contains_code = true,
},
},
},
},
},
},
keys = {
{ "<leader>aa", "<cmd>CodeCompanionActions<cr>", desc = "Actions", silent = true, mode = { "n", "v" } },
{ "<leader>ac", "<cmd>CodeCompanionChat Toggle<cr>", desc = "Toggle chat", silent = true },
{ "<leader>ac", "<cmd>CodeCompanionChat Add<cr>", desc = "Add to chat", silent = true, mode = "v" },
},
cmd = {
"CodeCompanionActions",
"CodeCompanionChat",
"CodeCompanion",
"CodeCompanionCmd",
"CodeCompanionGitCommit",
},
},
}