Skip to content

Commit bce2b8a

Browse files
authored
feat(chat): add /fork slash command (#3078)
1 parent 4939f94 commit bce2b8a

4 files changed

Lines changed: 106 additions & 1 deletion

File tree

doc/codecompanion.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*codecompanion.txt* For NVIM v0.11 Last change: 2026 April 27
1+
*codecompanion.txt* For NVIM v0.11 Last change: 2026 April 29
22

33
==============================================================================
44
Table of Contents *codecompanion-table-of-contents*
@@ -4796,6 +4796,15 @@ instead of file contents.
47964796
Please note that these mappings may be different depending on your provider.
47974797

47984798

4799+
/FORK ~
4800+
4801+
The `fork` slash command, specific to `http` adapters, allows you to duplicate
4802+
the current chat buffer, copying the message history and preserving tools and
4803+
context in the process. This enables you to branch the conversation and
4804+
experiment with different prompts, models or even adapters without losing the
4805+
original conversation.
4806+
4807+
47994808
/HELP ~
48004809

48014810
The `help` slash command allows you to add content from a vim help file

doc/usage/chat-buffer/slash-commands.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ This slash command is also available in the [CLI prompt input](/usage/cli#slash-
6262

6363
Please note that these mappings may be different depending on your provider.
6464

65+
## /fork
66+
67+
The _fork_ slash command, specific to _http_ adapters, allows you to duplicate the current chat buffer, copying the message history and preserving tools and context in the process. This enables you to branch the conversation and experiment with different prompts, models or even adapters without losing the original conversation.
68+
6569
## /help
6670

6771
The _help_ slash command allows you to add content from a vim help file (`:h helpfile`), to the chat buffer, by searching for help tags. Currently this is only available for _Telescope_, _mini.pick_, _fzf_lua_ and _snacks.nvim_ providers. By default, the slash command will prompt you to trim a help file that is over 1,000 lines in length.

lua/codecompanion/config.lua

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,19 @@ If you are providing code changes, use the insert_edit_into_file tool (if availa
429429
provider = providers.pickers, -- telescope|fzf_lua|mini_pick|snacks|default
430430
},
431431
},
432+
["fork"] = {
433+
path = "interactions.chat.slash_commands.builtin.fork",
434+
description = "Fork the current chat into a new chat buffer",
435+
enabled = function(opts)
436+
if opts.adapter and opts.adapter.type == "http" then
437+
return true
438+
end
439+
return false
440+
end,
441+
opts = {
442+
contains_code = false,
443+
},
444+
},
432445
["file"] = {
433446
path = "interactions.shared.slash_commands.file",
434447
description = "Insert a file",
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
local config = require("codecompanion.config")
2+
local utils = require("codecompanion.utils")
3+
4+
---@class CodeCompanion.SlashCommand.Fork
5+
---@field Chat CodeCompanion.Chat
6+
---@field config table
7+
---@field context table
8+
local SlashCommand = {}
9+
10+
---@param args CodeCompanion.SlashCommandArgs
11+
function SlashCommand.new(args)
12+
local self = setmetatable({
13+
Chat = args.Chat,
14+
config = args.config,
15+
context = args.context,
16+
}, { __index = SlashCommand })
17+
18+
return self
19+
end
20+
21+
function SlashCommand:execute()
22+
if vim.tbl_isempty(self.Chat.messages) then
23+
return utils.notify("No messages to fork", vim.log.levels.WARN)
24+
end
25+
26+
vim.ui.input({ default = self.Chat.title, prompt = " Fork Title " }, function(name)
27+
if name == nil then
28+
return
29+
end
30+
self:output(name)
31+
end)
32+
end
33+
34+
---Fork the current chat into a new chat buffer
35+
---@param name string The name for the forked chat
36+
---@return nil
37+
function SlashCommand:output(name)
38+
local source = self.Chat
39+
40+
local messages = vim.deepcopy(source.messages or {})
41+
42+
-- Append an empty user message so that the chat starts with user input
43+
table.insert(messages, {
44+
content = "",
45+
role = config.constants.USER_ROLE,
46+
})
47+
48+
local title = (name ~= "") and name or ("Fork of: " .. (source.title or ("Chat " .. source.id)))
49+
50+
local Chat = require("codecompanion.interactions.chat")
51+
local forked = Chat.new({
52+
adapter = source.adapter,
53+
last_role = config.constants.USER_ROLE,
54+
messages = messages,
55+
settings = source.settings and vim.deepcopy(source.settings) or nil,
56+
stop_context_insertion = true,
57+
title = title,
58+
})
59+
60+
-- This ensures we respect any conditionals on the chat class
61+
if not forked then
62+
return
63+
end
64+
65+
forked:set_title(forked.title) -- Needed for description as well
66+
67+
local context_items = vim.deepcopy(source.context_items or {})
68+
if not vim.tbl_isempty(context_items) then
69+
forked.context_items = context_items
70+
end
71+
72+
forked.tool_registry.groups = vim.deepcopy(source.tool_registry.groups)
73+
forked.tool_registry.in_use = vim.deepcopy(source.tool_registry.in_use)
74+
forked.tool_registry.schemas = vim.deepcopy(source.tool_registry.schemas)
75+
76+
forked.context:render()
77+
end
78+
79+
return SlashCommand

0 commit comments

Comments
 (0)