From 55c199107f61386de821abcb8e4c2ea628277120 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Wed, 4 Dec 2024 22:47:57 +0100 Subject: [PATCH] refactor: optimize context handling and content blocks Improve memory usage and performance by: - Replace original field with outline in context struct - Increase TOP_SYMBOLS limit from 64 to 100 - Optimize content block generation to avoid unnecessary string operations - Simplify embedding messages generation by removing file grouping - Use outline content when available for more efficient context handling --- lua/CopilotChat/context.lua | 13 +++---- lua/CopilotChat/copilot.lua | 69 +++++++++++++----------------------- lua/CopilotChat/ui/debug.lua | 2 +- 3 files changed, 31 insertions(+), 53 deletions(-) diff --git a/lua/CopilotChat/context.lua b/lua/CopilotChat/context.lua index b1232f97..3afd906b 100644 --- a/lua/CopilotChat/context.lua +++ b/lua/CopilotChat/context.lua @@ -11,7 +11,7 @@ ---@field content string ---@field filename string ---@field filetype string ----@field original string? +---@field outline string? ---@field symbols table? ---@field embedding table? @@ -64,7 +64,7 @@ local OFF_SIDE_RULE_LANGUAGES = { 'fsharp', } -local TOP_SYMBOLS = 64 +local TOP_SYMBOLS = 100 local TOP_RELATED = 20 local MULTI_FILE_THRESHOLD = 5 @@ -204,6 +204,7 @@ end ---@param ft string ---@return CopilotChat.context.embed local function build_outline(content, filename, ft) + ---@type CopilotChat.context.embed local output = { filename = filename, filetype = ft, @@ -269,8 +270,7 @@ local function build_outline(content, filename, ft) parse_node(root) if #outline_lines > 0 then - output.original = content - output.content = table.concat(outline_lines, '\n') + output.outline = table.concat(outline_lines, '\n') output.symbols = symbols end @@ -571,10 +571,7 @@ function M.filter_embeddings(copilot, prompt, embeddings) log.debug(string.format('%s: %s - %s', i, item.score, item.filename)) end - -- Return embeddings with original content - return vim.tbl_map(function(item) - return vim.tbl_extend('force', item, { content = item.original or item.content }) - end, embeddings) + return embeddings end return M diff --git a/lua/CopilotChat/copilot.lua b/lua/CopilotChat/copilot.lua index e6eeef09..af77d57d 100644 --- a/lua/CopilotChat/copilot.lua +++ b/lua/CopilotChat/copilot.lua @@ -78,23 +78,23 @@ end --- Generate content block with line numbers, truncating if necessary ---@param content string: The content +---@param outline string?: The outline ---@param threshold number: The threshold for truncation ---@param start_line number|nil: The starting line number ---@return string -local function generate_content_block(content, threshold, start_line) - local lines = vim.split(content, '\n') - local total_chars = 0 - - for i, line in ipairs(lines) do - total_chars = total_chars + #line - if total_chars > threshold then - lines = vim.list_slice(lines, 1, i) - table.insert(lines, TRUNCATED) - break - end +local function generate_content_block(content, outline, threshold, start_line) + local total_chars = #content + if total_chars > threshold and outline then + content = outline + total_chars = #content + end + if total_chars > threshold then + content = content:sub(1, threshold) + content = content .. '\n' .. TRUNCATED end if start_line ~= -1 then + local lines = vim.split(content, '\n') local total_lines = #lines local max_length = #tostring(total_lines) for i, line in ipairs(lines) do @@ -102,9 +102,11 @@ local function generate_content_block(content, threshold, start_line) string.format('%' .. max_length .. 'd', i - 1 + (start_line or 1)) lines[i] = formatted_line_number .. ': ' .. line end + + return table.concat(lines, '\n') end - return table.concat(lines, '\n') + return content end --- Generate messages for the given selection @@ -133,7 +135,7 @@ local function generate_selection_messages(selection) .. string.format( '```%s\n%s\n```', filetype, - generate_content_block(content, BIG_FILE_THRESHOLD, selection.start_line) + generate_content_block(content, nil, BIG_FILE_THRESHOLD, selection.start_line) ) if selection.diagnostics then @@ -170,40 +172,18 @@ end --- Generate messages for the given embeddings --- @param embeddings table local function generate_embeddings_messages(embeddings) - local files = {} - for _, embedding in ipairs(embeddings) do - local filename = embedding.filename or 'unknown' - if not files[filename] then - files[filename] = {} - end - table.insert(files[filename], embedding) - end - - local out = {} - - for filename, group in pairs(files) do - local filetype = group[1].filetype or 'text' - table.insert(out, { - context = string.format(CONTEXT_FORMAT, filename, filename), + return vim.tbl_map(function(embedding) + return { + context = string.format(CONTEXT_FORMAT, embedding.filename, embedding.filename), content = string.format( '# FILE:%s CONTEXT\n```%s\n%s\n```', - filename:upper(), - filetype, - generate_content_block( - table.concat( - vim.tbl_map(function(e) - return vim.trim(e.content) - end, group), - '\n' - ), - BIG_FILE_THRESHOLD - ) + embedding.filename:upper(), + embedding.filetype or 'text', + generate_content_block(embedding.content, embedding.outline, BIG_FILE_THRESHOLD) ), role = 'user', - }) - end - - return out + } + end, embeddings) end local function generate_ask_request( @@ -275,7 +255,8 @@ local function generate_embedding_request(inputs, model, threshold) return { dimensions = 512, input = vim.tbl_map(function(embedding) - local content = generate_content_block(embedding.content, threshold, -1) + local content = + generate_content_block(embedding.outline or embedding.content, nil, threshold, -1) if embedding.filetype == 'raw' then return content else diff --git a/lua/CopilotChat/ui/debug.lua b/lua/CopilotChat/ui/debug.lua index 16f9893c..9172b714 100644 --- a/lua/CopilotChat/ui/debug.lua +++ b/lua/CopilotChat/ui/debug.lua @@ -49,7 +49,7 @@ local function build_debug_info() table.insert(lines, 'Current buffer outline:') table.insert(lines, '`' .. buf.filename .. '`') table.insert(lines, '```' .. buf.filetype) - local outline_lines = vim.split(buf.content, '\n') + local outline_lines = vim.split(buf.outline or buf.content, '\n') for _, line in ipairs(outline_lines) do table.insert(lines, line) end