From de989b879b44e641c2098e470ee794ff97f0da90 Mon Sep 17 00:00:00 2001 From: jinzhongjia Date: Tue, 16 Sep 2025 13:05:05 +0800 Subject: [PATCH 1/3] refactor(gitcommit): improve auto-generation reliability for commit messages - enhance auto-generation mechanism with multiple event triggers - add stable timing detection for different Git tools - implement debounce and tracking to prevent duplicate generations - support graceful handling of buffer states and Git operations --- .../_extensions/gitcommit/buffer.lua | 132 ++++++++++++++---- 1 file changed, 102 insertions(+), 30 deletions(-) diff --git a/lua/codecompanion/_extensions/gitcommit/buffer.lua b/lua/codecompanion/_extensions/gitcommit/buffer.lua index 6fde474..12c5731 100644 --- a/lua/codecompanion/_extensions/gitcommit/buffer.lua +++ b/lua/codecompanion/_extensions/gitcommit/buffer.lua @@ -32,40 +32,112 @@ function Buffer.setup(opts) Buffer._setup_gitcommit_keymap(event.buf) if config.auto_generate then - -- Auto-generation triggers once when entering gitcommit window - -- Avoids race conditions with plugins like neogit - -- Skip auto-generation during git amend to preserve user intent - vim.api.nvim_create_autocmd("WinEnter", { + -- Auto-generation with stable timing detection for different Git tools + local auto_generate_attempted = false + local pending_timer = nil + + local function should_attempt_auto_generate(bufnr) + -- Don't attempt if we already successfully generated for this buffer + if auto_generate_attempted then + return false + end + + -- Ensure buffer is valid + if not vim.api.nvim_buf_is_valid(bufnr) then + return false + end + + -- Check if buffer already has commit message + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + local has_message = false + for _, line in ipairs(lines) do + if not line:match("^%s*#") and vim.trim(line) ~= "" then + has_message = true + break + end + end + + -- Skip if buffer already has content + if has_message then + return false + end + + -- Skip auto-generation during git amend operation + local should_skip_amend = config.skip_auto_generate_on_amend and Git.is_amending() + if should_skip_amend then + return false + end + + return true + end + + local function schedule_auto_generate(bufnr) + -- Cancel any pending timer to avoid multiple generations + if pending_timer then + pending_timer:stop() + pending_timer = nil + end + + -- Schedule generation with extended delay for stability + pending_timer = vim.defer_fn(function() + pending_timer = nil + if should_attempt_auto_generate(bufnr) then + auto_generate_attempted = true + Buffer._generate_and_insert_commit_message(bufnr) + end + end, config.auto_generate_delay + 300) -- Extra delay for window stability + end + + -- Multiple event triggers to ensure compatibility with different Git tools + local autocmd_opts = { buffer = event.buf, - once = true, - callback = function(args) - -- Defer execution to ensure other plugins finish UI setup - vim.defer_fn(function() - if not vim.api.nvim_buf_is_valid(args.buf) then - return - end + desc = "Auto-generate GitCommit message", + } - -- Check if buffer already has commit message - local lines = vim.api.nvim_buf_get_lines(args.buf, 0, -1, false) - local has_message = false - for _, line in ipairs(lines) do - if not line:match("^%s*#") and vim.trim(line) ~= "" then - has_message = true - break - end - end + -- Primary trigger: WinEnter (works with most tools) + vim.api.nvim_create_autocmd( + "WinEnter", + vim.tbl_extend("force", autocmd_opts, { + callback = function(args) + schedule_auto_generate(args.buf) + end, + }) + ) - -- Skip auto-generation if: - -- 1. Buffer already has commit message - -- 2. In git amend operation (user may want to keep existing message) - local should_skip_amend = config.skip_auto_generate_on_amend and Git.is_amending() - if not has_message and not should_skip_amend then - Buffer._generate_and_insert_commit_message(args.buf) + -- Secondary trigger: BufWinEnter (works with Fugitive) + vim.api.nvim_create_autocmd( + "BufWinEnter", + vim.tbl_extend("force", autocmd_opts, { + once = true, + callback = function(args) + schedule_auto_generate(args.buf) + end, + }) + ) + + -- Tertiary trigger: CursorMoved (fallback, with debouncing) + vim.api.nvim_create_autocmd( + "CursorMoved", + vim.tbl_extend("force", autocmd_opts, { + once = true, + callback = function(args) + schedule_auto_generate(args.buf) + end, + }) + ) + + -- Cleanup timer when buffer is deleted or unloaded + vim.api.nvim_create_autocmd( + { "BufDelete", "BufUnload" }, + vim.tbl_extend("force", autocmd_opts, { + callback = function() + if pending_timer then + pending_timer:stop() + pending_timer = nil end - end, config.auto_generate_delay) - end, - desc = "Auto-generate GitCommit message", - }) + end, + }) + ) end end, desc = "Setup GitCommit AI assistant", From a6e7383338c8bbf737a1904abb137063b4dd2340 Mon Sep 17 00:00:00 2001 From: jinzhongjia Date: Tue, 16 Sep 2025 14:24:48 +0800 Subject: [PATCH 2/3] refactor(gitcommit): optimize auto-generate event handling - consolidate autocmd callbacks to reduce code duplication - add configurable window stability delay - simplify autocmd registration with shared callback - remove redundant callback definitions in event triggers --- .../_extensions/gitcommit/buffer.lua | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/lua/codecompanion/_extensions/gitcommit/buffer.lua b/lua/codecompanion/_extensions/gitcommit/buffer.lua index 12c5731..5278a29 100644 --- a/lua/codecompanion/_extensions/gitcommit/buffer.lua +++ b/lua/codecompanion/_extensions/gitcommit/buffer.lua @@ -10,6 +10,7 @@ local default_config = { keymap = "gc", auto_generate = false, auto_generate_delay = 100, -- Default delay in ms + window_stability_delay = 300, -- Extra delay for window stability in ms skip_auto_generate_on_amend = true, -- Skip auto-generation during git commit --amend } @@ -85,46 +86,29 @@ function Buffer.setup(opts) auto_generate_attempted = true Buffer._generate_and_insert_commit_message(bufnr) end - end, config.auto_generate_delay + 300) -- Extra delay for window stability + end, config.auto_generate_delay + config.window_stability_delay) -- Extra delay for window stability + end + + -- Shared callback function for autocommands to reduce duplication + local autocmd_callback = function(args) + schedule_auto_generate(args.buf) end -- Multiple event triggers to ensure compatibility with different Git tools local autocmd_opts = { buffer = event.buf, desc = "Auto-generate GitCommit message", + callback = autocmd_callback, } -- Primary trigger: WinEnter (works with most tools) - vim.api.nvim_create_autocmd( - "WinEnter", - vim.tbl_extend("force", autocmd_opts, { - callback = function(args) - schedule_auto_generate(args.buf) - end, - }) - ) + vim.api.nvim_create_autocmd("WinEnter", autocmd_opts) -- Secondary trigger: BufWinEnter (works with Fugitive) - vim.api.nvim_create_autocmd( - "BufWinEnter", - vim.tbl_extend("force", autocmd_opts, { - once = true, - callback = function(args) - schedule_auto_generate(args.buf) - end, - }) - ) + vim.api.nvim_create_autocmd("BufWinEnter", autocmd_opts) -- Tertiary trigger: CursorMoved (fallback, with debouncing) - vim.api.nvim_create_autocmd( - "CursorMoved", - vim.tbl_extend("force", autocmd_opts, { - once = true, - callback = function(args) - schedule_auto_generate(args.buf) - end, - }) - ) + vim.api.nvim_create_autocmd("CursorMoved", autocmd_opts) -- Cleanup timer when buffer is deleted or unloaded vim.api.nvim_create_autocmd( From d582a321267106ee90fd656afbd86abdb31c47b1 Mon Sep 17 00:00:00 2001 From: jinzhongjia Date: Tue, 16 Sep 2025 14:29:38 +0800 Subject: [PATCH 3/3] docs: update documentation for memory and configuration features - Add new sections for memory configuration and usage - Update Claude Code, ACP, and adapter setup documentation - Remove treesitter dependency references - Update system prompt with more flexible language and date handling - Enhance documentation for prompt libraries and memory parsers --- codecompanion.txt | 588 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 552 insertions(+), 36 deletions(-) diff --git a/codecompanion.txt b/codecompanion.txt index 9e7af78..15a150b 100644 --- a/codecompanion.txt +++ b/codecompanion.txt @@ -1,4 +1,4 @@ -*codecompanion.txt* For NVIM v0.11 Last change: 2025 August 31 +*codecompanion.txt* For NVIM v0.11 Last change: 2025 September 14 ============================================================================== Table of Contents *codecompanion-table-of-contents* @@ -27,6 +27,7 @@ Table of Contents *codecompanion-table-of-contents* - Adapters |codecompanion-configuration-adapters| - Chat Buffer |codecompanion-configuration-chat-buffer| - Inline Assistant |codecompanion-configuration-inline-assistant| + - Memory |codecompanion-configuration-memory| - Prompt Library |codecompanion-configuration-prompt-library| - System Prompts |codecompanion-configuration-system-prompts| - Extensions |codecompanion-configuration-extensions| @@ -36,6 +37,7 @@ Table of Contents *codecompanion-table-of-contents* - Action Palette |codecompanion-usage-action-palette| - Chat Buffer |codecompanion-usage-chat-buffer| - Agents |codecompanion-usage-agents| + - Memory |codecompanion-usage-memory| - Tools |codecompanion-usage-tools| - Slash Commands |codecompanion-usage-slash-commands| - Variables |codecompanion-usage-variables| @@ -45,6 +47,7 @@ Table of Contents *codecompanion-table-of-contents* - Workflows |codecompanion-usage-workflows| 6. Extending |codecompanion-extending| - Creating Adapters |codecompanion-extending-creating-adapters| + - Creating Memory Parsers |codecompanion-extending-creating-memory-parsers| - Creating Prompts |codecompanion-extending-creating-prompts| - Creating Tools |codecompanion-extending-creating-tools| - Creating Workflows |codecompanion-extending-creating-workflows| @@ -64,10 +67,11 @@ FEATURES *codecompanion-welcome-features* - Copilot Chat meets Zed AI , in Neovim - Support for LLMs from Anthropic, Copilot, GitHub Models, DeepSeek, Gemini, Mistral AI, Novita, Ollama, OpenAI, Azure OpenAI, HuggingFace and xAI out of the box (or bring your own!) -- Support for Agent Client Protocol , enabling coding with agents like Gemini CLI +- Support for Agent Client Protocol , enabling coding with agents like Claude Code and Gemini CLI - User contributed and supported |codecompanion-configuration-adapters-community-adapters| - |codecompanion-usage-inline-assistant.html|, code creation and refactoring - |codecompanion-usage-chat-buffer-variables|, |codecompanion-usage-chat-buffer-slash-commands|, |codecompanion-usage-chat-buffer-tools| and |codecompanion-usage-workflows| to improve LLM output +- Support for |codecompanion-usage-chat-buffer-memory| files like `CLAUDE.md`, `.cursor/rules` and your own custom ones - Native |codecompanion-usage-chat-buffer-index-super-diff| for tracking agent edits - Built-in |codecompanion-usage-action-palette.html| for common tasks like advice on LSP errors and code explanations - Create your own |codecompanion-extending-prompts|, Variables and Slash Commands @@ -133,7 +137,6 @@ LAZY.NVIM ~ opts = {}, dependencies = { "nvim-lua/plenary.nvim", - "nvim-treesitter/nvim-treesitter", }, }, < @@ -149,7 +152,6 @@ PACKER ~ end, requires = { "nvim-lua/plenary.nvim", - "nvim-treesitter/nvim-treesitter", } }), < @@ -161,7 +163,6 @@ VIM-PLUG ~ call plug#begin() Plug 'nvim-lua/plenary.nvim' - Plug 'nvim-treesitter/nvim-treesitter' Plug 'olimorris/codecompanion.nvim' call plug#end() @@ -418,7 +419,8 @@ connect you to an LLM and **ACP** adapters which leverage the Agent Client Protocol to connect you to an agent. Refer to the |codecompanion-configuration-adapters| section to understand more -about working with adapters. +about working with adapters like +|codecompanion-configuration-adapters-setup-claude-code-via-acp|. SETTING AN API KEY ~ @@ -733,8 +735,22 @@ If you do not want to store secrets in plain text, prefix commands with `cmd:`: [!NOTE] In this example, we’re using the 1Password CLI to extract the Gemini API Key. You could also use gpg as outlined here -Environment variables can also be functions and as a parameter, they receive a -copy of the adapter itself. + +ENVIRONMENT VARIABLES ~ + +Setting environment variables within adapters is a key part of configuration. +The adapter `env` table lets you define values that will be interpolated into +the adapter’s URL, headers, parameters and other fields at runtime. + +Supported `env` value types: - **Plain environment variable name (string)**: if +the value is the name of an environment variable that has already been set +(e.g.� `"HOME"` or `"GEMINI_API_KEY"`), the plugin will read the value. - +**Command (string prefixed with cmd:)**: any value that starts with `cmd:` will +be executed via the shell. Example: `"cmd:op read +op://personal/Gemini/credential --no-newline"`. - **Function**: you can provide +a Lua function which returns a string and will be called with the adapter as +its sole argument. - **Schema reference (dot notation)**: you can reference +values from the adapter table (for example `"schema.model.default"`). CHANGING A MODEL ~ @@ -940,10 +956,18 @@ can set the `show_defaults` option to `false`: >lua require("codecompanion").setup({ adapters = { - opts = { - show_defaults = false, + acp = { + opts = { + show_defaults = false, + }, + -- Define your custom adapters here + }, + http = { + opts = { + show_defaults = false, + }, + -- Define your custom adapters here }, - -- Define your custom adapters here }, }) < @@ -972,7 +996,63 @@ adapter’s schema) will be automatically selected when changing adapters, and no model selection will be shown to the user. -EXAMPLE: USING OLLAMA REMOTELY ~ +SETUP: CLAUDE CODE VIA ACP ~ + +To use Claude Code within +CodeCompanion, you’ll need to take the following steps: + +1. Install Claude Code +2. Install the Zed ACP adapter for Claude Code + + +CLAUDE PRO SUBSCRIPTION + +1. In your CLI, run `claude setup-token`. You’ll be redirected to the Claude.ai website for authorization: + +2. Back in your CLI, copy the OAuth token (in yellow): + +3. In your CodeCompanion config, extend the `claude_code` adapter and include the OAuth token (see the section on |codecompanion--environment-variables| for other ways to do this): + +>lua + require("codecompanion").setup({ + adapters = { + acp = { + claude_code = function() + return require("codecompanion.adapters").extend("claude_code", { + env = { + CLAUDE_CODE_OAUTH_TOKEN = "my-oauth-token", + }, + }) + end, + }, + }, + }) +< + + +AN API KEY + +1. Create an API key in your Anthropic console. +2. In your CodeCompanion config, extend the `claude_code` adapter and set the `ANTHROPIC_API_KEY`: + +>lua + require("codecompanion").setup({ + adapters = { + acp = { + claude_code = function() + return require("codecompanion.adapters").extend("claude_code", { + env = { + ANTHROPIC_API_KEY = "my-api-key", + }, + }) + end, + }, + }, + }) +< + + +SETUP: USING OLLAMA REMOTELY ~ To use Ollama remotely, change the URL in the env table, set an API key and pass it via an "Authorization" header: @@ -1000,7 +1080,7 @@ pass it via an "Authorization" header: < -EXAMPLE: AZURE OPENAI ~ +SETUP: AZURE OPENAI ~ Below is an example of how you can leverage the `azure_openai` adapter within the plugin: @@ -1855,6 +1935,267 @@ Please see the |codecompanion-chat-buffer-diff| on the Chat Buffer page for configuration options. +MEMORY *codecompanion-configuration-memory* + +Fundamentally, memory is a way of adding persistent context to a chat buffer. +CodeCompanion uses `groups` to create a collection of files that can be added +to chats. Groups can also be linked to a `parser` which can offer +post-processing customization such as parsing file paths and adding them as +buffers or files to the chat buffer. + + +ENABLING MEMORY ~ + +By default, memory is not enabled in the chat buffer. To enable it: + +>lua + require("codecompanion").setup({ + memory = { + opts = { + chat = { + enabled = true, + }, + }, + }, + }) +< + +Once enabled, the plugin will look to load a common, or default, set of files +every time a chat buffer is created. An example set of these files are: + +- `.cursorrules` +- `.goosehints` +- `.rules` +- `CLAUDE.md` + + + [!INFO] Refer to the config.lua + + file for the full set of files included in the default group. +You can also conditionally determine if memory should be added to a chat +buffer: + +>lua + require("codecompanion").setup({ + memory = { + opts = { + chat = { + ---Function to determine if memory should be added to a chat buffer + ---This requires `enabled` to be true + ---@param chat CodeCompanion.Chat + ---@return boolean + condition = function(chat) + return chat.adapter.type ~= "acp" + end, + }, + }, + }, + }) +< + +The example above is taken from the config itself, as by default, the plugin +will not add memory to |codecompanion-usage-chat-buffer-agents| adapters. + + +WORKING WITH GROUPS ~ + +In the plugin, memory groups are a collection of files and/or directories. +Below is an example of what a `claude` group might look like: + +>lua + require("codecompanion").setup({ + memory = { + claude = { + description = "Memory files for Claude Code users", + files = { + "~/.claude/CLAUDE.md", + "CLAUDE.md", + "CLAUDE.local.md", + }, + }, + }, + }) +< + +You’ll notice that the file paths can be local to the current working +directory or point to an absolute location. + + +CONDITIONALLY ENABLING GROUPS + +You can also conditionally enable memory groups. For instance, the default +`CodeCompanion` group has the following conditional: + +>lua + require("codecompanion").setup({ + memory = { + CodeCompanion = { + description = "CodeCompanion plugin memory files", + ---@return boolean + enabled = function() + -- Don't show this to users who aren't working on CodeCompanion itself + return vim.fn.getcwd():find("codecompanion", 1, true) ~= nil + end, + files = {}, -- removed for brevity + }, + }, + }) +< + + +NESTING GROUPS + +It’s also possible to nest groups within a group. This can be a convenient +way of applying the same conditional to multiple groups alongside keeping your +config clean: + +>lua + require("codecompanion").setup({ + memory = { + CodeCompanion = { + description = "CodeCompanion plugin memory files", + parser = "claude", + files = { + ["acp"] = { + description = "The ACP implementation", + files = { + ".codecompanion/acp/acp.md", + }, + }, + }, + }, + }, + }) +< + +In the example above, the main group is `CodeCompanion` and a sub-group, `acp`, +sits within the files table. The `claude` parser sits across all of the groups. + +When using the `Action Palette` or the slash command, the plugin will extract +these nested groups and display them. + + +PARSERS ~ + + + [!NOTE] Parsers are an optional addition to memory in the plugin. +Currently, the plugin has two in-built parsers: + +- `claude` - which will import files into the chat buffer in the same way Claude Code does . Note, this requires memory to be `markdown` files +- `none` - a blank parser which can be used to overwrite parsers that have been set on the default memory groups + +Please see the guide on |codecompanion-extending-parsers| to understand how you +can create and apply your own. + + +APPLYING PARSERS + +You can apply parsers at a group level, to ensure that all files in the group +are parsed in the same way: + +>lua + require("codecompanion").setup({ + memory = { + claude = { + description = "Memory files for Claude Code users", + parser = "claude", + files = { + "CLAUDE.md", + "CLAUDE.local.md", + "~/.claude/CLAUDE.md", + }, + }, + }, + }) +< + +In the example above, every file within the group will be sent through the +`claude` parser before being added to the chat buffer. + +Alternatively, you can apply parsers at a file level. + +>lua + require("codecompanion").setup({ + memory = { + default = { + description = "Collection of common files for all projects", + files = { + { path = "CLAUDE.md", parser = "claude" }, + { path = "CLAUDE.local.md", parser = "claude" }, + { path = "~/.claude/CLAUDE.md", parser = "claude" }, + }, + }, + }, + }) +< + +Or combine both approaches, whereby the parsers at a file level will take +precedence. + + +DISABLING PARSERS + +To disable a parser against a memory group, simply assign it a parser of +`none`. + + +CHANGING DEFAULTS ~ + + +GROUPS + +The plugin will look to load the `default` memory group by default. This can be +changed by: + +>lua + require("codecompanion").setup({ + memory = { + opts = { + chat = { + default_memory = "my_new_group", + }, + }, + }, + }) +< + +Alternatively, you can select multiple groups: + +>lua + require("codecompanion").setup({ + memory = { + opts = { + chat = { + default_memory = { "default", "my_new_group" }, + }, + }, + }, + }) +< + + +BUFFERS AND FILES + +If a parsed memory group contains links to files and they are Neovim buffers, +you can set specific parameters, such as a +|codecompanion-usage-chat-buffer-variables-with-parameters|: + +>lua + require("codecompanion").setup({ + memory = { + opts = { + chat = { + default_params = "watch", -- watch|pin - when adding a buffer to the chat + }, + }, + }, + }) +< + + + [!NOTE] The `claude` parser has been specifically built to output linked files + that take advantage of this. + PROMPT LIBRARY *codecompanion-configuration-prompt-library* The plugin comes with a number of pre-built prompts. As per the config @@ -1950,22 +2291,21 @@ The plugin comes with the following system prompt: * Find relevant code to the user's query. * Propose fixes for test failures. * Answer questions about Neovim. - * Running tools. Follow the user's requirements carefully and to the letter. Use the context and attachments the user provides. Keep your answers short and impersonal, especially if the user's context is outside your core tasks. - All non-code text responses must be written in the English language. + All non-code text responses must be written in the ${language} language. Use Markdown formatting in your answers. Do not use H1 or H2 markdown headers. When suggesting code changes or new content, use Markdown code blocks. To start a code block, use 4 backticks. - After the backticks, add the programming language name. + After the backticks, add the programming language name as the language ID. + To close a code block, use 4 backticks on a new line. If the code modifies an existing file or should be placed at a specific location, add a line comment with 'filepath:' and the file path. If you want the user to decide where to place the code, do not add the file path comment. In the code block, use a line comment with '...existing code...' to indicate code that is already present in the file. - For code blocks use four backticks to start and end. - Putting this all together: + Code block example: ````languageId // filepath: /path/to/file // ...existing code... @@ -1974,20 +2314,21 @@ The plugin comes with the following system prompt: { changed code } // ...existing code... ```` + Ensure line comments use the correct syntax for the programming language (e.g. "#" for Python, "--" for Lua). + For code blocks use four backticks to start and end. Avoid wrapping the whole response in triple backticks. + Do not include diff formatting unless explicitly asked. Do not include line numbers in code blocks. - Multiple, different tools can be called as part of the same response. When given a task: - 1. Think step-by-step and, unless the user requests otherwise or the task is very simple, describe your plan in detailed pseudocode. - 2. Output the final code in a single code block, ensuring that only relevant code is included. + 1. Think step-by-step and, unless the user requests otherwise or the task is very simple, describe your plan in pseudocode. + 2. When outputting code blocks, ensure only relevant code is included, avoiding any repeating or unrelated code. 3. End your response with a short suggestion for the next user turn that directly supports continuing the conversation. - 4. Provide exactly one complete reply per conversation turn. - 5. If necessary, execute multiple tools in a single turn. - The current date is August 28, 2025. - The user's Neovim version is 0.12.0. - The user is working on a Mac machine. Please respond with system specific commands if applicable. + Additional context: + The current date is ${date}. + The user's Neovim version is ${version}. + The user is working on a ${os} machine. Please respond with system specific commands if applicable. < @@ -2039,14 +2380,18 @@ CHANGING SYSTEM PROMPTS ~ CHAT -The default system prompt can be changed with: +The chat system prompt can be changed with: >lua require("codecompanion").setup({ - opts = { - system_prompt = "My new system prompt" + strategies = { + chat = { + opts = { + system_prompt = "My new system prompt", + }, + }, }, - }), + }) < Alternatively, the system prompt can be a function. The `opts` parameter @@ -2070,7 +2415,7 @@ the language (`opts.language`) that the LLM should respond with: return string.format("I'm working on my %s machine", machine) end, }, - }), + }) < @@ -2336,10 +2681,10 @@ buffer with `:CodeCompanionChat Toggle` or `require("codecompanion").toggle()`. The chat buffer uses markdown as its syntax and `H2` headers separate the user and LLM’s responses. The plugin is turn-based, meaning that the user sends a response which is then followed by the LLM’s. The user’s responses are -parsed by nvim-treesitter -and sent via an adapter to an LLM for a response which is then streamed back -into the buffer. A response is sent to the LLM by pressing `` or ``. -This can of course be changed as per the |codecompanion--keymaps| section. +parsed by treesitter and sent via an adapter to an LLM for a response which is +then streamed back into the buffer. A response is sent to the LLM by pressing +`` or ``. This can of course be changed as per the +|codecompanion--keymaps| section. CHANGING ADAPTER ~ @@ -2483,6 +2828,7 @@ The keymaps available to the user in normal mode are: - `gd` to view/debug the chat buffer’s contents - `gD` to view the chat buffer’s super diff feature - `gf` to fold any codeblocks in the chat buffer +- `gM` to clear all memory from the chat buffer - `gp` to pin an item to the context in the chat buffer - `gr` to regenerate the last response - `gR` to go to the file under cursor. If the file is already opened, it’ll jump @@ -2574,6 +2920,93 @@ The |codecompanion-usage-chat-buffer-slash-commands.html-image| slash command can be leveraged to share images with the agent. +MEMORY *codecompanion-usage-memory* + +LLMs don’t retain memory between completions. In CodeCompanion, memory +provides persistent, reusable context for chat buffers, via the notion of +groups. + +Once |codecompanion-configuration-memory-enabling-memory|, there are many ways +that memory can be added to the chat buffer. + + +CREATING MEMORY ~ + +The plugin does not require memory to be in a specific filetype or even format +(unless you’re using the `claude` parser). This allows you to leverage mdc + files, markdown files +or good old plain text files. + +The location of the memory is also unimportant. The memory files could be local +to the project you’re working in. Or, they could reside in a separate +location on your disk. Just ensure the path is correct when you’re +|codecompanion-configuration-memory-working-with-groups| the memory group. + + +ADDING MEMORY ~ + + +WHEN OPENING THE CHAT BUFFER + +Memory can automatically be added to a chat buffer when it’s created. Simply +modify the `memory.opts.chat.default_memory` value to reflect the group(s) you +wish to add: + +>lua + require("codecompanion").setup({ + memory = { + opts = { + chat = { + default_memory = { "default", "claude "} + }, + }, + }, + }) +< + +Or, edit the group that resides in `memory.opts.chat.default_memory`: + +>lua + require("codecompanion").setup({ + memory = { + default = { + description = "My default group", + files = { + "CLAUDE.md", + "~/Code/Helpers/my_project_specific_help.md", + }, + }, + opts = { + chat = { + default_memory = "default", + }, + }, + }, + }) +< + + +WHILST IN THE CHAT BUFFER + +To add memory to an existing chat buffer, use the `/memory` slash command. This +will allow multiple memory groups to be added at a time. + + +FROM THE ACTION PALETTE + + + +There is also a `Chat with memory` action in the +|codecompanion-usage-action-palette|. This lists all of the memory groups in +the config that can be added to a new chat buffer. + + +CLEARING MEMORY + +Memory can also be cleared from a chat buffer via the `gM` keymap. Although +note, this will remove `ALL` context that’s been designated as `memory`. + + TOOLS *codecompanion-usage-tools* @@ -3055,6 +3488,12 @@ will always search in, alongside the current working directory. Currently the image picker is only available with `snacks.nvim` and the `vim.ui.select`. +/MEMORY ~ + +The `memory` slash command allows you to add +|codecompanion-usage-chat-buffer-memory| groups to the chat buffer. + + /NOW ~ The `now` slash command simply inserts the current datetime stamp into the chat @@ -4176,6 +4615,61 @@ support the OpenAI API standard for function calling, they can require some additional configuration to work as expected. +CREATING MEMORY PARSERS *codecompanion-extending-creating-memory-parsers* + +In CodeCompanion, parsers act on the contents of a memory file, carrying out +some post-processing activities and returning the content back to the memory +class. + +Parsers serve as an excellent way to apply modifications and extract metadata +prior to sharing them with an LLM. + + +STRUCTURE OF A PARSER ~ + +A parser has limited restrictions. It is simply required to return a function +that the `memory` class can execute, passing in the file to be processed as a +parameter: + +>lua + ---@class CodeCompanion.Chat.Memory.Parser + ---@field content string The content of the memory file + ---@field meta? { included_files: string[] } The filename of the memory file + + ---@param file CodeCompanion.Chat.Memory.ProcessedFile + ---@return CodeCompanion.Chat.Memory.Parser + return function(file) + -- Your logic + end +< + +As an output, the function must return a table containing a `content` key. + + +PROCESSING FILES ~ + +Parsers may also return a list of files to be shared with the LLM by the +`memory` class. To enable this, ensure that the parser returns a +`meta.included_files` array in its output: + +>lua + { + content = "Your parsed content", + meta = { + included_files = { + ".codecompanion/acp/acp_json_schema.json", + "./lua/codecompanion/acp/init.lua", + "./lua/codecompanion/adapters/acp/claude_code.lua", + "./lua/codecompanion/adapters/acp/helpers.lua", + "./lua/codecompanion/acp/prompt_builder.lua", + "./lua/codecompanion/strategies/chat/acp/handler.lua", + "./lua/codecompanion/strategies/chat/acp/request_permission.lua", + }, + }, + } +< + + CREATING PROMPTS *codecompanion-extending-creating-prompts* The purpose of this guide is to showcase how you can extend the functionality @@ -4650,6 +5144,25 @@ This can now accomplished, as per the example below: < +PROMPTS WITH MEMORY + +You can specify a default memory group to load with a prompt: + +>lua + ["Test Context"] = { + strategy = "chat", + description = "Add some context", + opts = { + -- Some options for brevity + default_memory = "my_custom_memory_group", + }, + prompts = { + -- Removed for brevity + } + }, +< + + CONCLUSION ~ Hopefully this serves as a useful introduction on how you can expand @@ -5590,7 +6103,10 @@ You can specify a specific adapter for a workflow prompt: strategy = "workflow", description = "My workflow", opts = { - adapter = "openai", -- Always use the OpenAI adapter for this workflow + adapter = { + name = "deepseek", + model = "deepseek-chat" + } }, -- Prompts go here },