Skip to content

Commit a10ae92

Browse files
authored
feat(nvim): Implement wildcard tool opts for CodeCompanion (#232)
* refactor(nvim): Enable wildcard tool opts for CodeCompanion * fix(nvim): Use correct tool opts getter for summary system prompt * refactor(nvim): Move `process_result` to `query_tool.lua` * refactor(nvim): Refactor tool opts merging logic for CodeCompanion
1 parent a9a72b7 commit a10ae92

7 files changed

Lines changed: 234 additions & 200 deletions

File tree

lua/codecompanion/_extensions/vectorcode/init.lua

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,44 @@
1212
local vc_config = require("vectorcode.config")
1313
local logger = vc_config.logger
1414

15-
local use_lsp = vc_config.get_user_config().async_backend == "lsp"
16-
1715
---@type VectorCode.CodeCompanion.ExtensionOpts|{}
1816
local default_extension_opts = {
1917
tool_opts = {
20-
ls = { use_lsp = use_lsp, requires_approval = false, include_in_toolbox = true },
21-
query = { use_lsp = use_lsp, requires_approval = false, include_in_toolbox = true },
22-
vectorise = {
23-
use_lsp = use_lsp,
24-
requires_approval = true,
25-
include_in_toolbox = true,
26-
},
27-
files_ls = {
28-
use_lsp = use_lsp,
29-
requires_approval = false,
30-
include_in_toolbox = false,
31-
},
32-
files_rm = {
33-
use_lsp = use_lsp,
34-
requires_approval = true,
35-
include_in_toolbox = false,
36-
},
18+
-- NOTE: the other default opts are defined in the source code files of the tools.
19+
-- `include_in_toolbox` is here so that the extension setup works as expected.
20+
21+
ls = { include_in_toolbox = true },
22+
query = { include_in_toolbox = true },
23+
vectorise = { include_in_toolbox = true },
24+
files_ls = {},
25+
files_rm = {},
3726
},
3827
tool_group = { enabled = true, collapse = true, extras = {} },
3928
}
4029

4130
---@type sub_cmd[]
4231
local valid_tools = { "ls", "query", "vectorise", "files_ls", "files_rm" }
4332

33+
---@param tool_opts table<sub_cmd, VectorCode.CodeCompanion.ToolOpts>
34+
---@return table<sub_cmd, VectorCode.CodeCompanion.ToolOpts>
35+
local function merge_tool_opts(tool_opts)
36+
local wildcard_opts = tool_opts["*"]
37+
if wildcard_opts then
38+
for tool_name, opts in pairs(tool_opts) do
39+
if tool_name ~= "*" then
40+
tool_opts[tool_name] = vim.tbl_deep_extend("force", wildcard_opts, opts)
41+
end
42+
end
43+
end
44+
return tool_opts
45+
end
46+
4447
---@type CodeCompanion.Extension
4548
local M = {
4649
---@param opts VectorCode.CodeCompanion.ExtensionOpts
4750
setup = vc_config.check_cli_wrap(function(opts)
4851
opts = vim.tbl_deep_extend("force", default_extension_opts, opts or {})
52+
opts.tool_opts = merge_tool_opts(opts.tool_opts)
4953
logger.info("Received codecompanion extension opts:\n", opts)
5054
local cc_config = require("codecompanion.config").config
5155
local cc_integration = require("vectorcode.integrations").codecompanion.chat

lua/vectorcode/integrations/codecompanion/common.lua

Lines changed: 0 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -5,83 +5,6 @@ local vc_config = require("vectorcode.config")
55
local notify_opts = vc_config.notify_opts
66
local logger = vc_config.logger
77

8-
---@type VectorCode.CodeCompanion.QueryToolOpts
9-
local default_query_options = {
10-
max_num = { chunk = -1, document = -1 },
11-
default_num = { chunk = 50, document = 10 },
12-
no_duplicate = true,
13-
chunk_mode = false,
14-
summarise = {
15-
enabled = false,
16-
query_augmented = true,
17-
system_prompt = [[You are an expert and experienced code analyzer and summarizer. Your primary task is to analyze provided source code, which will be given as a list of XML objects, and generate a comprehensive, well-structured Markdown summary. This summary will serve as a concise source of information for others to quickly understand how the code works and how to interact with it, without needing to delve into the full source code.
18-
19-
Input Format:
20-
Each XML object represents either a full file or a chunk of a file, containing the following tags:
21-
- `<path>...</path>`: The absolute file path of the source code.
22-
- `<document>...</document>`: The full content of a source code file. This tag will not coexist with `<chunk>`.
23-
- `<chunk>...</chunk>`: A segment of source code from a file. This tag will not coexist with `<document>`.
24-
- `<start_line>...</start_line>` and `<end_line>...</end_line>`: These tags will be present only when a `<chunk>` tag is used, indicating the starting and ending line numbers of the chunk within its respective file.
25-
26-
Your goal is to process each of these XML objects. If multiple chunks belong to the same file, you must synthesize them to form a cohesive understanding of that file. Generate a single Markdown summary that combines insights from all provided objects.
27-
28-
Markdown Structure:
29-
30-
Top-Level Header (#): The absolute or relative file path of the source code.
31-
32-
Secondary Headers (##): For each top-level symbol (e.g., functions, classes, global variables) defined directly within the source code file that are importable or includable by other programs.
33-
34-
Tertiary Headers (###): For symbols nested one level deep within a secondary header's symbol (e.g., methods within a class, inner functions).
35-
36-
Quaternary Headers (####): For symbols nested two levels deep (e.g., a function defined within a method of a class).
37-
38-
Continue this pattern, incrementing the header level for each deeper level of nesting.
39-
40-
Content for Each Section:
41-
42-
Descriptive Summary: Each header section (from secondary headers downwards) must contain a concise and informative summary of the symbol defined by that header.
43-
44-
For Functions/Methods: Explain their purpose, parameters (including types), return values (including types), high-level implementation details, and any significant side effects or core logic. For example, if summarizing a sorting function, include the sorting algorithm used. If summarizing a function that makes an HTTP request, mention the network library employed.
45-
46-
For Classes: Describe the class's role, its main responsibilities, and key characteristics.
47-
48-
For Variables (global or within scope): State their purpose, type (if discernible), and initial value or common usage.
49-
50-
For Modules/Files (under the top-level header): Provide an overall description of the file's purpose, its main components, and its role within the larger project (if context is available).
51-
52-
General Guidelines:
53-
54-
Clarity and Conciseness: Summaries should be easy to understand, avoiding jargon where possible, and as brief as possible while retaining essential information. The full summary MUST NOT be longer than the original code input. When quoting a symbol in the code, include the line numbers where possible.
55-
56-
Accuracy: Ensure the summary accurately reflects the code's functionality.
57-
58-
Focus on Public Interface/Behavior: Prioritize describing what a function/class does and how it's used. Only include details about symbols (variables, functions, classes) that are importable/includable by other programs. DO NOT include local variables and functions that are not accessible by other functions outside their immediate scope.
59-
60-
No Code Snippets: Do not include any actual code snippets in the summary. Focus solely on descriptive text. If you need to refer to a specific element for context (e.g., in an error description), describe it and provide line numbers for reference from the source code.
61-
62-
Syntax/Semantic Errors: If the code contains syntax or semantic errors, describe them clearly within the summary, indicating the nature of the error.
63-
64-
Language Agnostic: Adapt the summary to the specific programming language of the provided source code (e.g., Python, JavaScript, Java, C++, etc.).
65-
66-
Handle Edge Cases/Dependencies: If a symbol relies heavily on external dependencies or handles specific edge cases, briefly mention these if they are significant to its overall function.
67-
68-
Information Source: There will be no extra information available to you. Provide the summary solely based on the provided XML objects.
69-
70-
Omit meaningless results: For an xml object that contains no meaningful information, you're free to omit it, but please leave a sentence in the summary saying that you did this.
71-
72-
No extra reply: Your reply should solely consist of the summary. Do not say anything else.
73-
74-
Merge chunks from the same file: When there are chunks that belong to the same file, merge their content so that they're grouped under the same top level header.
75-
]],
76-
},
77-
}
78-
79-
---@type VectorCode.CodeCompanion.LsToolOpts
80-
local default_ls_options = {}
81-
82-
---@type VectorCode.CodeCompanion.VectoriseToolOpts
83-
local default_vectorise_options = {}
84-
858
local TOOL_RESULT_SOURCE = "VectorCodeToolResult"
869

8710
return {
@@ -96,102 +19,6 @@ return {
9619
return table.concat(vim.iter(t):flatten(math.huge):totable(), "\n")
9720
end,
9821

99-
---@param opts VectorCode.CodeCompanion.LsToolOpts|{}|nil
100-
---@return VectorCode.CodeCompanion.LsToolOpts
101-
get_ls_tool_opts = function(opts)
102-
opts = vim.tbl_deep_extend("force", default_ls_options, opts or {})
103-
logger.info(
104-
string.format(
105-
"Loading `vectorcode_ls` with the following opts:\n%s",
106-
vim.inspect(opts)
107-
)
108-
)
109-
return opts
110-
end,
111-
112-
---@param opts VectorCode.CodeCompanion.VectoriseToolOpts|{}|nil
113-
---@return VectorCode.CodeCompanion.VectoriseToolOpts
114-
get_vectorise_tool_opts = function(opts)
115-
opts = vim.tbl_deep_extend("force", default_vectorise_options, opts or {})
116-
logger.info(
117-
string.format(
118-
"Loading `vectorcode_vectorise` with the following opts:\n%s",
119-
vim.inspect(opts)
120-
)
121-
)
122-
return opts
123-
end,
124-
125-
---@param opts VectorCode.CodeCompanion.QueryToolOpts|{}|nil
126-
---@return VectorCode.CodeCompanion.QueryToolOpts
127-
get_query_tool_opts = function(opts)
128-
if opts == nil or opts.use_lsp == nil then
129-
opts = vim.tbl_deep_extend(
130-
"force",
131-
opts or {},
132-
{ use_lsp = vc_config.get_user_config().async_backend == "lsp" }
133-
)
134-
end
135-
opts = vim.tbl_deep_extend("force", default_query_options, opts)
136-
if type(opts.default_num) == "table" then
137-
if opts.chunk_mode then
138-
opts.default_num = opts.default_num.chunk
139-
else
140-
opts.default_num = opts.default_num.document
141-
end
142-
assert(
143-
type(opts.default_num) == "number",
144-
"default_num should be an integer or a table: {chunk: integer, document: integer}"
145-
)
146-
end
147-
if type(opts.max_num) == "table" then
148-
if opts.chunk_mode then
149-
opts.max_num = opts.max_num.chunk
150-
else
151-
opts.max_num = opts.max_num.document
152-
end
153-
assert(
154-
type(opts.max_num) == "number",
155-
"max_num should be an integer or a table: {chunk: integer, document: integer}"
156-
)
157-
end
158-
logger.info(
159-
string.format(
160-
"Loading `vectorcode_query` with the following opts:\n%s",
161-
vim.inspect(opts)
162-
)
163-
)
164-
return opts
165-
end,
166-
167-
---@param result VectorCode.QueryResult
168-
---@return string
169-
process_result = function(result)
170-
-- TODO: Unify the handling of summarised and non-summarised result
171-
local llm_message
172-
if result.chunk then
173-
-- chunk mode
174-
llm_message =
175-
string.format("<path>%s</path><chunk>%s</chunk>", result.path, result.chunk)
176-
if result.start_line and result.end_line then
177-
llm_message = llm_message
178-
.. string.format(
179-
"<start_line>%d</start_line><end_line>%d</end_line>",
180-
result.start_line,
181-
result.end_line
182-
)
183-
end
184-
else
185-
-- full document mode
186-
llm_message = string.format(
187-
"<path>%s</path><content>%s</content>",
188-
result.path,
189-
result.document
190-
)
191-
end
192-
return llm_message
193-
end,
194-
19522
---@param use_lsp boolean
19623
---@return VectorCode.JobRunner
19724
initialise_runner = function(use_lsp)

lua/vectorcode/integrations/codecompanion/files_ls_tool.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
---@module "codecompanion"
22

33
local cc_common = require("vectorcode.integrations.codecompanion.common")
4+
local vc_config = require("vectorcode.config")
5+
6+
local default_opts = {
7+
use_lsp = vc_config.get_user_config().async_backend == "lsp",
8+
requires_approval = false,
9+
include_in_toolbox = false,
10+
}
411

512
---@param opts VectorCode.CodeCompanion.FilesLsToolOpts
613
---@return CodeCompanion.Agent.Tool
714
return function(opts)
15+
opts = vim.tbl_deep_extend("force", default_opts, opts or {})
816
local job_runner =
917
require("vectorcode.integrations.codecompanion.common").initialise_runner(
1018
opts.use_lsp

lua/vectorcode/integrations/codecompanion/files_rm_tool.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
---@module "codecompanion"
22

33
local cc_common = require("vectorcode.integrations.codecompanion.common")
4+
local vc_config = require("vectorcode.config")
5+
6+
local default_opts = {
7+
use_lsp = vc_config.get_user_config().async_backend == "lsp",
8+
requires_approval = true,
9+
include_in_toolbox = false,
10+
}
411

512
---@alias FilesRmArgs { paths: string[], project_root: string }
613

714
---@param opts VectorCode.CodeCompanion.FilesRmToolOpts
815
---@return CodeCompanion.Agent.Tool
916
return function(opts)
17+
opts = vim.tbl_deep_extend("force", default_opts, opts or {})
18+
1019
local tool_name = "vectorcode_files_rm"
1120
local job_runner = cc_common.initialise_runner(opts.use_lsp)
1221

lua/vectorcode/integrations/codecompanion/ls_tool.lua

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,33 @@
22

33
local cc_common = require("vectorcode.integrations.codecompanion.common")
44
local vectorcode = require("vectorcode")
5+
local vc_config = require("vectorcode.config")
6+
local logger = vc_config.logger
7+
8+
---@type VectorCode.CodeCompanion.LsToolOpts
9+
local default_ls_options = {
10+
use_lsp = vc_config.get_user_config().async_backend == "lsp",
11+
requires_approval = false,
12+
include_in_toolbox = true,
13+
}
14+
15+
---@param opts VectorCode.CodeCompanion.LsToolOpts|{}|nil
16+
---@return VectorCode.CodeCompanion.LsToolOpts
17+
local get_ls_tool_opts = function(opts)
18+
opts = vim.tbl_deep_extend("force", default_ls_options, opts or {})
19+
logger.info(
20+
string.format(
21+
"Loading `vectorcode_ls` with the following opts:\n%s",
22+
vim.inspect(opts)
23+
)
24+
)
25+
return opts
26+
end
527

628
---@param opts VectorCode.CodeCompanion.LsToolOpts
729
---@return CodeCompanion.Agent.Tool
830
return function(opts)
9-
opts = cc_common.get_ls_tool_opts(opts)
31+
opts = get_ls_tool_opts(opts)
1032
local job_runner =
1133
require("vectorcode.integrations.codecompanion.common").initialise_runner(
1234
opts.use_lsp

0 commit comments

Comments
 (0)