Skip to content

Commit

Permalink
fix: Gracefully handle errors from copilot (CopilotC-Nvim#154)
Browse files Browse the repository at this point in the history
  • Loading branch information
deathbeam authored Mar 11, 2024
1 parent f41acfb commit c5b0f79
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 47 deletions.
38 changes: 27 additions & 11 deletions lua/CopilotChat/context.lua
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,30 @@ function M.build_outline(bufnr)
}
end

---@class CopilotChat.context.find_for_query.opts
---@field context string?
---@field prompt string
---@field selection string?
---@field filename string
---@field filetype string
---@field bufnr number
---@field on_done function
---@field on_error function?

--- Find items for a query
---@param copilot CopilotChat.Copilot
---@param context string?
---@param prompt string
---@param selection string?
---@param filename string
---@param filetype string
---@param bufnr number
---@param on_done function
function M.find_for_query(copilot, context, prompt, selection, filename, filetype, bufnr, on_done)
local outline = {}
---@param opts CopilotChat.context.find_for_query.opts
function M.find_for_query(copilot, opts)
local context = opts.context
local prompt = opts.prompt
local selection = opts.selection
local filename = opts.filename
local filetype = opts.filetype
local bufnr = opts.bufnr
local on_done = opts.on_done
local on_error = opts.on_error

local outline = {}
if context == 'buffers' then
-- For multiiple buffers, only make outlines
outline = vim.tbl_map(
Expand Down Expand Up @@ -206,14 +218,17 @@ function M.find_for_query(copilot, context, prompt, selection, filename, filetyp
end

copilot:embed(outline, {
on_error = on_error,
on_done = function(out)
log.debug(string.format('Got %s embeddings', #out))

out = vim.tbl_filter(function(item)
return item ~= nil
end, out)
if #out == 0 then
on_done({})
return
end

log.debug(string.format('Got %s embeddings', #out))
copilot:embed({
{
prompt = prompt,
Expand All @@ -222,6 +237,7 @@ function M.find_for_query(copilot, context, prompt, selection, filename, filetyp
filetype = filetype,
},
}, {
on_error = on_error,
on_done = function(query_out)
local query = query_out[1]
log.debug('Prompt:', query.prompt)
Expand Down
43 changes: 18 additions & 25 deletions lua/CopilotChat/copilot.lua
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ function Copilot:ask(prompt, opts)
role = 'user',
})

local errored = false
local full_response = ''

self.current_job_on_cancel = on_done
Expand All @@ -375,25 +376,27 @@ function Copilot:ask(prompt, opts)
proxy = self.proxy,
insecure = self.allow_insecure,
on_error = function(err)
err = vim.inspect(err)
log.error('Failed to get response: ' .. err)
err = 'Failed to get response: ' .. vim.inspect(err)
log.error(err)
if on_error then
on_error(err)
end
end,
stream = function(err, line)
if not line or errored then
return
end

if err then
log.error('Failed to stream response: ' .. tostring(err))
err = 'Failed to get response: ' .. vim.inspect(err)
errored = true
log.error(err)
if on_error then
on_error(err)
end
return
end

if not line then
return
end

line = line:gsub('data: ', '')
if line == '' then
return
Expand All @@ -420,10 +423,8 @@ function Copilot:ask(prompt, opts)
})

if not ok then
log.error('Failed parse response: ' .. tostring(content))
if on_error then
on_error(content)
end
err = 'Failed parse response: ' .. vim.inspect(content)
log.error(err)
return
end

Expand Down Expand Up @@ -489,11 +490,8 @@ function Copilot:embed(inputs, opts)
proxy = self.proxy,
insecure = self.allow_insecure,
on_error = function(err)
err = vim.inspect(err)
log.error('Failed to get response: ' .. err)
if on_error then
on_error(err)
end
err = 'Failed to get response: ' .. vim.inspect(err)
log.error(err)
resolve()
end,
callback = function(response)
Expand All @@ -503,11 +501,8 @@ function Copilot:embed(inputs, opts)
end

if response.status ~= 200 then
local err = vim.inspect(response)
log.error('Failed to get response: ' .. err)
if on_error then
on_error(err)
end
local err = 'Failed to get response: ' .. vim.inspect(response)
log.error(err)
resolve()
return
end
Expand All @@ -520,10 +515,8 @@ function Copilot:embed(inputs, opts)
})

if not ok then
log.error('Failed parse response: ' .. tostring(content))
if on_error then
on_error(tostring(content))
end
local err = vim.inspect(content)
log.error('Failed parse response: ' .. err)
resolve()
return
end
Expand Down
30 changes: 19 additions & 11 deletions lua/CopilotChat/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,22 @@ function M.ask(prompt, config, source)
end
updated_prompt = string.gsub(updated_prompt, '@buffers?%s*', '')

context.find_for_query(
state.copilot,
selected_context,
updated_prompt,
selection.lines,
filetype,
filename,
state.source.bufnr,
function(embeddings)
local function on_error(err)
append('\n\n **Error** ' .. config.separator .. '\n\n')
append('```\n' .. err .. '\n```')
append('\n\n' .. config.separator .. '\n\n')
show_help()
end

context.find_for_query(state.copilot, {
context = selected_context,
prompt = updated_prompt,
selection = selection.lines,
filename = filename,
filetype = filetype,
bufnr = state.source.bufnr,
on_error = on_error,
on_done = function(embeddings)
state.copilot:ask(updated_prompt, {
selection = selection.lines,
embeddings = embeddings,
Expand All @@ -352,6 +359,7 @@ function M.ask(prompt, config, source)
system_prompt = system_prompt,
model = config.model,
temperature = config.temperature,
on_error = on_error,
on_done = function(_, token_count)
if tiktoken.available() and token_count and token_count > 0 then
append('\n\n' .. token_count .. ' tokens used')
Expand All @@ -363,8 +371,8 @@ function M.ask(prompt, config, source)
append(token)
end,
})
end
)
end,
})
end

--- Reset the chat window and show the help message.
Expand Down

0 comments on commit c5b0f79

Please sign in to comment.