fix: re-implement prompt logger (#2574)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -459,8 +459,7 @@ M._defaults = {
|
|||||||
},
|
},
|
||||||
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
||||||
enabled = true, -- toggle logging entirely
|
enabled = true, -- toggle logging entirely
|
||||||
log_dir = Utils.join_paths(vim.fn.stdpath("cache"), "avante_prompts"), -- directory where logs are saved
|
log_dir = vim.fn.stdpath("cache"), -- directory where logs are saved
|
||||||
fortune_cookie_on_success = false, -- shows a random fortune after each logged prompt (requires `fortune` installed)
|
|
||||||
next_prompt = {
|
next_prompt = {
|
||||||
normal = "<C-n>", -- load the next (newer) prompt log in normal mode
|
normal = "<C-n>", -- load the next (newer) prompt log in normal mode
|
||||||
insert = "<C-n>",
|
insert = "<C-n>",
|
||||||
|
|||||||
@@ -2674,6 +2674,7 @@ function Sidebar:create_input_container()
|
|||||||
self.handle_submit = handle_submit
|
self.handle_submit = handle_submit
|
||||||
|
|
||||||
self.containers.input:mount()
|
self.containers.input:mount()
|
||||||
|
PromptLogger.init()
|
||||||
|
|
||||||
local function place_sign_at_first_line(bufnr)
|
local function place_sign_at_first_line(bufnr)
|
||||||
local group = "avante_input_prompt_group"
|
local group = "avante_input_prompt_group"
|
||||||
@@ -2739,6 +2740,11 @@ function Sidebar:create_input_container()
|
|||||||
place_sign_at_first_line(self.containers.input.bufnr)
|
place_sign_at_first_line(self.containers.input.bufnr)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
|
||||||
|
group = self.augroup,
|
||||||
|
buffer = self.containers.input.bufnr,
|
||||||
|
callback = function() PromptLogger.update_current_input() end,
|
||||||
|
})
|
||||||
|
|
||||||
api.nvim_create_autocmd("QuitPre", {
|
api.nvim_create_autocmd("QuitPre", {
|
||||||
group = self.augroup,
|
group = self.augroup,
|
||||||
|
|||||||
@@ -1,98 +1,92 @@
|
|||||||
local Config = require("avante.config")
|
local Config = require("avante.config")
|
||||||
local Utils = require("avante.utils")
|
local Utils = require("avante.utils")
|
||||||
|
|
||||||
|
-- last one in entries is always to hold current input
|
||||||
|
local entries, idx = {}, 0
|
||||||
|
|
||||||
---@class avante.utils.promptLogger
|
---@class avante.utils.promptLogger
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
function M.init()
|
||||||
|
entries = {}
|
||||||
|
local dir = Config.prompt_logger.log_dir
|
||||||
|
local log_file = Utils.join_paths(dir, "avante_prompts.log")
|
||||||
|
local file = io.open(log_file, "r")
|
||||||
|
if file then
|
||||||
|
local content = file:read("*a"):gsub("\n$", "")
|
||||||
|
file:close()
|
||||||
|
|
||||||
|
local lines = vim.split(content, "\n", { plain = true })
|
||||||
|
for _, line in ipairs(lines) do
|
||||||
|
local ok, entry = pcall(vim.fn.json_decode, line)
|
||||||
|
if ok and entry and entry.time and entry.input then table.insert(entries, entry) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(entries, { input = "" })
|
||||||
|
idx = #entries - 1
|
||||||
|
end
|
||||||
|
|
||||||
function M.log_prompt(request)
|
function M.log_prompt(request)
|
||||||
local log_dir = Config.prompt_logger.log_dir
|
local log_dir = Config.prompt_logger.log_dir
|
||||||
local log_file = Utils.join_paths(log_dir, "avante_prompt_" .. os.date("%Y%m%d_%H%M%S") .. ".log")
|
local log_file = Utils.join_paths(log_dir, "avante_prompts.log")
|
||||||
|
|
||||||
if vim.fn.isdirectory(log_dir) == 0 then vim.fn.mkdir(log_dir, "p") end
|
if vim.fn.isdirectory(log_dir) == 0 then vim.fn.mkdir(log_dir, "p") end
|
||||||
|
|
||||||
|
local entry = {
|
||||||
|
time = Utils.get_timestamp(),
|
||||||
|
input = request,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Remove any existing entries with the same input
|
||||||
|
if #entries > 1 then
|
||||||
|
for i = #entries - 1, 1, -1 do
|
||||||
|
if entries[i].input == entry.input then table.remove(entries, i) end
|
||||||
|
end
|
||||||
|
-- Add the new entry
|
||||||
|
table.insert(entries, #entries, entry)
|
||||||
|
idx = #entries - 1
|
||||||
|
else
|
||||||
|
table.insert(entries, entry)
|
||||||
|
end
|
||||||
|
|
||||||
local file = io.open(log_file, "w")
|
local file = io.open(log_file, "w")
|
||||||
if file then
|
if file then
|
||||||
file:write(request)
|
-- Write all entries to the log file, except the last one
|
||||||
file:close()
|
for i = 1, #entries - 1, 1 do
|
||||||
if Config.prompt_logger and Config.prompt_logger.fortune_cookie_on_success then
|
file:write(vim.fn.json_encode(entries[i]) .. "\n")
|
||||||
local handle = io.popen("fortune -s -n 100")
|
|
||||||
if handle then
|
|
||||||
local fortune_msg = handle:read("*a")
|
|
||||||
handle:close()
|
|
||||||
if fortune_msg and #fortune_msg > 0 then vim.notify(fortune_msg, vim.log.levels.INFO, { title = "" }) end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
file:close()
|
||||||
else
|
else
|
||||||
vim.notify("Failed to log prompt", vim.log.levels.ERROR)
|
vim.notify("Failed to log prompt", vim.log.levels.ERROR)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cache + helper
|
|
||||||
local logs, idx = {}, 0
|
|
||||||
|
|
||||||
local function refresh_logs()
|
|
||||||
local dir = Config.prompt_logger.log_dir
|
|
||||||
logs = vim.fn.glob(Utils.join_paths(dir, "avante_prompt_*.log"), false, true)
|
|
||||||
table.sort(logs, function(a, b) -- newest first
|
|
||||||
return a > b
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param step integer 0 = keep | 1 = newer | -1 = older
|
|
||||||
local function load_log(step)
|
|
||||||
if #logs == 0 then refresh_logs() end
|
|
||||||
if #logs == 0 then
|
|
||||||
vim.notify("No prompt logs found 🤷", vim.log.levels.WARN)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
idx = (idx + step) -- turn wheel
|
|
||||||
if idx < 1 then idx = #logs end -- wrap around
|
|
||||||
if idx > #logs then idx = 1 end
|
|
||||||
|
|
||||||
local fp = io.open(logs[idx], "r")
|
|
||||||
if not fp then
|
|
||||||
vim.notify("Could not open " .. logs[idx], vim.log.levels.ERROR)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local content = fp:read("*a")
|
|
||||||
fp:close()
|
|
||||||
|
|
||||||
local buf = vim.api.nvim_get_current_buf()
|
|
||||||
vim.api.nvim_buf_set_lines(buf, 0, -1, false, vim.split(content, "\n", { plain = true }))
|
|
||||||
vim.bo[buf].modifiable = true
|
|
||||||
vim.b[buf].avante_logpath = logs[idx]
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.next_log() load_log(1) end
|
|
||||||
|
|
||||||
function M.prev_log() load_log(-1) end
|
|
||||||
|
|
||||||
local function _read_log(delta)
|
local function _read_log(delta)
|
||||||
if #logs == 0 then refresh_logs() end
|
-- index of array starts from 1 in lua, while this idx starts from 0
|
||||||
if #logs == 0 then return nil end
|
idx = ((idx - delta) % #entries + #entries) % #entries
|
||||||
|
|
||||||
local target = idx + delta
|
return entries[idx + 1]
|
||||||
if target < 1 then target = 1 end
|
|
||||||
if target > #logs then target = #logs end
|
|
||||||
|
|
||||||
idx = target
|
|
||||||
|
|
||||||
local fp = io.open(logs[idx], "r")
|
|
||||||
if not fp then return nil end
|
|
||||||
local txt = fp:read("*a")
|
|
||||||
fp:close()
|
|
||||||
return { txt = txt, path = logs[idx] }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.on_log_retrieve(delta)
|
function M.on_log_retrieve(delta)
|
||||||
return function()
|
return function()
|
||||||
local res = _read_log(delta)
|
local res = _read_log(delta)
|
||||||
if not res then
|
if not res or not res.input then
|
||||||
vim.notify("No logs available", vim.log.levels.WARN)
|
vim.notify("No log entry found.", vim.log.levels.WARN)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(res.txt, "\n", { plain = true }))
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(res.input, "\n", { plain = true }))
|
||||||
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
vim.api.nvim_win_set_cursor(
|
||||||
|
0,
|
||||||
|
{ vim.api.nvim_buf_line_count(0), #vim.api.nvim_buf_get_lines(0, -2, -1, false)[1] }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.update_current_input()
|
||||||
|
if idx == #entries - 1 then
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
|
||||||
|
entries[#entries].input = table.concat(lines, "\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user