migrating the logs file
This commit is contained in:
@@ -4,379 +4,31 @@
|
||||
|
||||
local M = {}
|
||||
|
||||
local params = require("codetyper.params.agents.logs")
|
||||
|
||||
---@class LogEntry
|
||||
---@field timestamp string ISO timestamp
|
||||
---@field level string "info" | "debug" | "request" | "response" | "tool" | "error"
|
||||
---@field message string Log message
|
||||
---@field data? table Optional structured data
|
||||
|
||||
---@class LogState
|
||||
---@field entries LogEntry[] All log entries
|
||||
---@field listeners table[] Functions to call when new entries are added
|
||||
---@field total_prompt_tokens number Running total of prompt tokens
|
||||
---@field total_response_tokens number Running total of response tokens
|
||||
|
||||
local state = {
|
||||
entries = {},
|
||||
listeners = {},
|
||||
total_prompt_tokens = 0,
|
||||
total_response_tokens = 0,
|
||||
current_provider = nil,
|
||||
current_model = nil,
|
||||
}
|
||||
|
||||
--- Get current timestamp
|
||||
---@return string
|
||||
local function get_timestamp()
|
||||
return os.date("%H:%M:%S")
|
||||
end
|
||||
|
||||
--- Add a log entry
|
||||
---@param level string Log level
|
||||
---@param message string Log message
|
||||
---@param data? table Optional data
|
||||
function M.log(level, message, data)
|
||||
local entry = {
|
||||
timestamp = get_timestamp(),
|
||||
level = level,
|
||||
message = message,
|
||||
data = data,
|
||||
}
|
||||
|
||||
table.insert(state.entries, entry)
|
||||
|
||||
-- Notify all listeners
|
||||
for _, listener in ipairs(state.listeners) do
|
||||
pcall(listener, entry)
|
||||
end
|
||||
end
|
||||
|
||||
--- Log info message
|
||||
---@param message string
|
||||
---@param data? table
|
||||
function M.info(message, data)
|
||||
M.log("info", message, data)
|
||||
end
|
||||
|
||||
--- Log debug message
|
||||
---@param message string
|
||||
---@param data? table
|
||||
function M.debug(message, data)
|
||||
M.log("debug", message, data)
|
||||
end
|
||||
|
||||
--- Log API request
|
||||
---@param provider string LLM provider
|
||||
---@param model string Model name
|
||||
---@param prompt_tokens? number Estimated prompt tokens
|
||||
function M.request(provider, model, prompt_tokens)
|
||||
state.current_provider = provider
|
||||
state.current_model = model
|
||||
|
||||
local msg = string.format("[%s] %s", provider:upper(), model)
|
||||
if prompt_tokens then
|
||||
msg = msg .. string.format(" | Prompt: ~%d tokens", prompt_tokens)
|
||||
end
|
||||
|
||||
M.log("request", msg, {
|
||||
provider = provider,
|
||||
model = model,
|
||||
prompt_tokens = prompt_tokens,
|
||||
})
|
||||
end
|
||||
|
||||
--- Log API response with token usage
|
||||
---@param prompt_tokens number Tokens used in prompt
|
||||
---@param response_tokens number Tokens in response
|
||||
---@param stop_reason? string Why the response stopped
|
||||
function M.response(prompt_tokens, response_tokens, stop_reason)
|
||||
state.total_prompt_tokens = state.total_prompt_tokens + prompt_tokens
|
||||
state.total_response_tokens = state.total_response_tokens + response_tokens
|
||||
|
||||
local msg = string.format(
|
||||
"Tokens: %d in / %d out | Total: %d in / %d out",
|
||||
prompt_tokens,
|
||||
response_tokens,
|
||||
state.total_prompt_tokens,
|
||||
state.total_response_tokens
|
||||
)
|
||||
|
||||
if stop_reason then
|
||||
msg = msg .. " | Stop: " .. stop_reason
|
||||
end
|
||||
|
||||
M.log("response", msg, {
|
||||
prompt_tokens = prompt_tokens,
|
||||
response_tokens = response_tokens,
|
||||
total_prompt = state.total_prompt_tokens,
|
||||
total_response = state.total_response_tokens,
|
||||
stop_reason = stop_reason,
|
||||
})
|
||||
end
|
||||
|
||||
--- Log tool execution
|
||||
---@param tool_name string Name of the tool
|
||||
---@param status string "start" | "success" | "error" | "approval"
|
||||
---@param details? string Additional details
|
||||
function M.tool(tool_name, status, details)
|
||||
local icons = params.icons
|
||||
|
||||
local msg = string.format("[%s] %s", icons[status] or status, tool_name)
|
||||
if details then
|
||||
msg = msg .. ": " .. details
|
||||
end
|
||||
|
||||
M.log("tool", msg, {
|
||||
tool = tool_name,
|
||||
status = status,
|
||||
details = details,
|
||||
})
|
||||
end
|
||||
|
||||
--- Log error
|
||||
---@param message string
|
||||
---@param data? table
|
||||
function M.error(message, data)
|
||||
M.log("error", "ERROR: " .. message, data)
|
||||
end
|
||||
|
||||
--- Log warning
|
||||
---@param message string
|
||||
---@param data? table
|
||||
function M.warning(message, data)
|
||||
M.log("warning", "WARN: " .. message, data)
|
||||
end
|
||||
|
||||
--- Add log entry (compatibility function for scheduler)
|
||||
--- Accepts {type = "info", message = "..."} format
|
||||
---@param entry table Log entry with type and message
|
||||
function M.add(entry)
|
||||
if entry.type == "clear" then
|
||||
M.clear()
|
||||
return
|
||||
end
|
||||
M.log(entry.type or "info", entry.message or "", entry.data)
|
||||
end
|
||||
|
||||
--- Log thinking/reasoning step (Claude Code style)
|
||||
---@param step string Description of what's happening
|
||||
function M.thinking(step)
|
||||
M.log("thinking", step)
|
||||
end
|
||||
|
||||
--- Log a reasoning/explanation message (shown prominently)
|
||||
---@param message string The reasoning message
|
||||
function M.reason(message)
|
||||
M.log("reason", message)
|
||||
end
|
||||
|
||||
--- Log file read operation
|
||||
---@param filepath string Path of file being read
|
||||
---@param lines? number Number of lines read
|
||||
function M.read(filepath, lines)
|
||||
local msg = string.format("Read(%s)", vim.fn.fnamemodify(filepath, ":~:."))
|
||||
if lines then
|
||||
msg = msg .. string.format("\n ⎿ Read %d lines", lines)
|
||||
end
|
||||
M.log("action", msg)
|
||||
end
|
||||
|
||||
--- Log explore/search operation
|
||||
---@param description string What we're exploring
|
||||
function M.explore(description)
|
||||
M.log("action", string.format("Explore(%s)", description))
|
||||
end
|
||||
|
||||
--- Log explore done
|
||||
---@param tool_uses number Number of tool uses
|
||||
---@param tokens number Tokens used
|
||||
---@param duration number Duration in seconds
|
||||
function M.explore_done(tool_uses, tokens, duration)
|
||||
M.log(
|
||||
"result",
|
||||
string.format(" ⎿ Done (%d tool uses · %.1fk tokens · %.1fs)", tool_uses, tokens / 1000, duration)
|
||||
)
|
||||
end
|
||||
|
||||
--- Log update/edit operation
|
||||
---@param filepath string Path of file being edited
|
||||
---@param added? number Lines added
|
||||
---@param removed? number Lines removed
|
||||
function M.update(filepath, added, removed)
|
||||
local msg = string.format("Update(%s)", vim.fn.fnamemodify(filepath, ":~:."))
|
||||
if added or removed then
|
||||
local parts = {}
|
||||
if added and added > 0 then
|
||||
table.insert(parts, string.format("Added %d lines", added))
|
||||
end
|
||||
if removed and removed > 0 then
|
||||
table.insert(parts, string.format("Removed %d lines", removed))
|
||||
end
|
||||
if #parts > 0 then
|
||||
msg = msg .. "\n ⎿ " .. table.concat(parts, ", ")
|
||||
end
|
||||
end
|
||||
M.log("action", msg)
|
||||
end
|
||||
|
||||
--- Log a task/step that's in progress
|
||||
---@param task string Task name
|
||||
---@param status string Status message (optional)
|
||||
function M.task(task, status)
|
||||
local msg = task
|
||||
if status then
|
||||
msg = msg .. " " .. status
|
||||
end
|
||||
M.log("task", msg)
|
||||
end
|
||||
|
||||
--- Log task completion
|
||||
---@param next_task? string Next task (optional)
|
||||
function M.task_done(next_task)
|
||||
local msg = " ⎿ Done"
|
||||
if next_task then
|
||||
msg = msg .. "\n✶ " .. next_task
|
||||
end
|
||||
M.log("result", msg)
|
||||
end
|
||||
|
||||
--- Register a listener for new log entries
|
||||
---@param callback fun(entry: LogEntry)
|
||||
---@return number Listener ID for removal
|
||||
function M.add_listener(callback)
|
||||
table.insert(state.listeners, callback)
|
||||
return #state.listeners
|
||||
end
|
||||
|
||||
--- Remove a listener
|
||||
---@param id number Listener ID
|
||||
function M.remove_listener(id)
|
||||
if id > 0 and id <= #state.listeners then
|
||||
table.remove(state.listeners, id)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get all log entries
|
||||
---@return LogEntry[]
|
||||
function M.get_entries()
|
||||
return state.entries
|
||||
end
|
||||
|
||||
--- Get token totals
|
||||
---@return number, number prompt_tokens, response_tokens
|
||||
function M.get_token_totals()
|
||||
return state.total_prompt_tokens, state.total_response_tokens
|
||||
end
|
||||
|
||||
--- Get current provider info
|
||||
---@return string?, string? provider, model
|
||||
function M.get_provider_info()
|
||||
return state.current_provider, state.current_model
|
||||
end
|
||||
|
||||
--- Clear all logs and reset counters
|
||||
function M.clear()
|
||||
state.entries = {}
|
||||
state.total_prompt_tokens = 0
|
||||
state.total_response_tokens = 0
|
||||
state.current_provider = nil
|
||||
state.current_model = nil
|
||||
|
||||
-- Notify listeners of clear
|
||||
for _, listener in ipairs(state.listeners) do
|
||||
pcall(listener, { level = "clear" })
|
||||
end
|
||||
end
|
||||
|
||||
--- Format entry for display
|
||||
---@param entry LogEntry
|
||||
---@return string
|
||||
function M.format_entry(entry)
|
||||
-- Claude Code style formatting for thinking/action entries
|
||||
local thinking_types = params.thinking_types
|
||||
local is_thinking = vim.tbl_contains(thinking_types, entry.level)
|
||||
|
||||
if is_thinking then
|
||||
local prefix = params.thinking_prefixes[entry.level] or "⏺"
|
||||
|
||||
if prefix ~= "" then
|
||||
return prefix .. " " .. entry.message
|
||||
else
|
||||
return entry.message
|
||||
end
|
||||
end
|
||||
|
||||
-- Traditional log format for other types
|
||||
local level_prefix = params.level_icons[entry.level] or "?"
|
||||
|
||||
local base = string.format("[%s] %s %s", entry.timestamp, level_prefix, entry.message)
|
||||
|
||||
-- If this is a response entry with raw_response, append the full response
|
||||
if entry.data and entry.data.raw_response then
|
||||
local response = entry.data.raw_response
|
||||
-- Add separator and the full response
|
||||
base = base .. "\n" .. string.rep("-", 40) .. "\n" .. response .. "\n" .. string.rep("-", 40)
|
||||
end
|
||||
|
||||
return base
|
||||
end
|
||||
|
||||
--- Format entry for display in chat (compact Claude Code style)
|
||||
---@param entry LogEntry
|
||||
---@return string|nil Formatted string or nil to skip
|
||||
function M.format_for_chat(entry)
|
||||
-- Skip certain log types in chat view
|
||||
local skip_types = { "debug", "queue", "patch" }
|
||||
if vim.tbl_contains(skip_types, entry.level) then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Claude Code style formatting
|
||||
local thinking_types = params.thinking_types
|
||||
if vim.tbl_contains(thinking_types, entry.level) then
|
||||
local prefix = params.thinking_prefixes[entry.level] or "⏺"
|
||||
|
||||
if prefix ~= "" then
|
||||
return prefix .. " " .. entry.message
|
||||
else
|
||||
return entry.message
|
||||
end
|
||||
end
|
||||
|
||||
-- Tool logs
|
||||
if entry.level == "tool" then
|
||||
return "⏺ " .. entry.message:gsub("^%[.-%] ", "")
|
||||
end
|
||||
|
||||
-- Info/success
|
||||
if entry.level == "info" or entry.level == "success" then
|
||||
return "⏺ " .. entry.message
|
||||
end
|
||||
|
||||
-- Errors
|
||||
if entry.level == "error" then
|
||||
return "⚠ " .. entry.message
|
||||
end
|
||||
|
||||
-- Request/response (compact)
|
||||
if entry.level == "request" then
|
||||
return "⏺ " .. entry.message
|
||||
end
|
||||
if entry.level == "response" then
|
||||
return " ⎿ " .. entry.message
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Estimate token count for a string (rough approximation)
|
||||
---@param text string
|
||||
---@return number
|
||||
function M.estimate_tokens(text)
|
||||
-- Rough estimate: ~4 characters per token for English text
|
||||
return math.ceil(#text / 4)
|
||||
end
|
||||
M.log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
M.clear = require("codetyper.adapters.nvim.ui.logs.clear")
|
||||
M.info = require("codetyper.adapters.nvim.ui.logs.info")
|
||||
M.debug = require("codetyper.adapters.nvim.ui.logs.debug")
|
||||
M.error = require("codetyper.adapters.nvim.ui.logs.error")
|
||||
M.warning = require("codetyper.adapters.nvim.ui.logs.warning")
|
||||
M.thinking = require("codetyper.adapters.nvim.ui.logs.thinking")
|
||||
M.reason = require("codetyper.adapters.nvim.ui.logs.reason")
|
||||
M.request = require("codetyper.adapters.nvim.ui.logs.request")
|
||||
M.response = require("codetyper.adapters.nvim.ui.logs.response")
|
||||
M.tool = require("codetyper.adapters.nvim.ui.logs.tool")
|
||||
M.add = require("codetyper.adapters.nvim.ui.logs.add")
|
||||
M.read = require("codetyper.adapters.nvim.ui.logs.read")
|
||||
M.explore = require("codetyper.adapters.nvim.ui.logs.explore")
|
||||
M.explore_done = require("codetyper.adapters.nvim.ui.logs.explore_done")
|
||||
M.update = require("codetyper.adapters.nvim.ui.logs.update")
|
||||
M.task = require("codetyper.adapters.nvim.ui.logs.task")
|
||||
M.task_done = require("codetyper.adapters.nvim.ui.logs.task_done")
|
||||
M.add_listener = require("codetyper.adapters.nvim.ui.logs.add_listener")
|
||||
M.remove_listener = require("codetyper.adapters.nvim.ui.logs.remove_listener")
|
||||
M.get_entries = require("codetyper.adapters.nvim.ui.logs.get_entries")
|
||||
M.get_token_totals = require("codetyper.adapters.nvim.ui.logs.get_token_totals")
|
||||
M.get_provider_info = require("codetyper.adapters.nvim.ui.logs.get_provider_info")
|
||||
M.format_entry = require("codetyper.adapters.nvim.ui.logs.format_entry")
|
||||
M.format_for_chat = require("codetyper.adapters.nvim.ui.logs.format_for_chat")
|
||||
M.estimate_tokens = require("codetyper.utils.estimate_tokens")
|
||||
|
||||
return M
|
||||
|
||||
15
lua/codetyper/adapters/nvim/ui/logs/add.lua
Normal file
15
lua/codetyper/adapters/nvim/ui/logs/add.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
local clear = require("codetyper.adapters.nvim.ui.logs.clear")
|
||||
|
||||
--- Add log entry (compatibility function for scheduler)
|
||||
--- Accepts {type = "info", message = "..."} format
|
||||
---@param entry table Log entry with type and message
|
||||
local function add(entry)
|
||||
if entry.type == "clear" then
|
||||
clear()
|
||||
return
|
||||
end
|
||||
log(entry.type or "info", entry.message or "", entry.data)
|
||||
end
|
||||
|
||||
return add
|
||||
11
lua/codetyper/adapters/nvim/ui/logs/add_listener.lua
Normal file
11
lua/codetyper/adapters/nvim/ui/logs/add_listener.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
local state = require("codetyper.state.state")
|
||||
|
||||
--- Register a listener for new log entries
|
||||
---@param callback fun(entry: LogEntry)
|
||||
---@return number listener_id Listener ID for removal
|
||||
local function add_listener(callback)
|
||||
table.insert(state.listeners, callback)
|
||||
return #state.listeners
|
||||
end
|
||||
|
||||
return add_listener
|
||||
16
lua/codetyper/adapters/nvim/ui/logs/clear.lua
Normal file
16
lua/codetyper/adapters/nvim/ui/logs/clear.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
local state = require("codetyper.state.state")
|
||||
|
||||
--- Clear all logs and reset counters
|
||||
local function clear()
|
||||
state.entries = {}
|
||||
state.total_prompt_tokens = 0
|
||||
state.total_response_tokens = 0
|
||||
state.current_provider = nil
|
||||
state.current_model = nil
|
||||
|
||||
for _, listener in ipairs(state.listeners) do
|
||||
pcall(listener, { level = "clear" })
|
||||
end
|
||||
end
|
||||
|
||||
return clear
|
||||
10
lua/codetyper/adapters/nvim/ui/logs/debug.lua
Normal file
10
lua/codetyper/adapters/nvim/ui/logs/debug.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log debug message
|
||||
---@param message string
|
||||
---@param data? table
|
||||
local function debug(message, data)
|
||||
log("debug", message, data)
|
||||
end
|
||||
|
||||
return debug
|
||||
10
lua/codetyper/adapters/nvim/ui/logs/error.lua
Normal file
10
lua/codetyper/adapters/nvim/ui/logs/error.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log error message
|
||||
---@param message string
|
||||
---@param data? table
|
||||
local function log_error(message, data)
|
||||
log("error", "ERROR: " .. message, data)
|
||||
end
|
||||
|
||||
return log_error
|
||||
9
lua/codetyper/adapters/nvim/ui/logs/explore.lua
Normal file
9
lua/codetyper/adapters/nvim/ui/logs/explore.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log explore/search operation
|
||||
---@param description string What we're exploring
|
||||
local function explore(description)
|
||||
log("action", string.format("Explore(%s)", description))
|
||||
end
|
||||
|
||||
return explore
|
||||
14
lua/codetyper/adapters/nvim/ui/logs/explore_done.lua
Normal file
14
lua/codetyper/adapters/nvim/ui/logs/explore_done.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log explore done with stats
|
||||
---@param tool_uses number Number of tool uses
|
||||
---@param tokens number Tokens used
|
||||
---@param duration number Duration in seconds
|
||||
local function explore_done(tool_uses, tokens, duration)
|
||||
log(
|
||||
"result",
|
||||
string.format(" ⎿ Done (%d tool uses · %.1fk tokens · %.1fs)", tool_uses, tokens / 1000, duration)
|
||||
)
|
||||
end
|
||||
|
||||
return explore_done
|
||||
30
lua/codetyper/adapters/nvim/ui/logs/format_entry.lua
Normal file
30
lua/codetyper/adapters/nvim/ui/logs/format_entry.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
local params = require("codetyper.params.agents.logs")
|
||||
|
||||
--- Format a log entry for display
|
||||
---@param entry LogEntry
|
||||
---@return string
|
||||
local function format_entry(entry)
|
||||
local thinking_types = params.thinking_types
|
||||
local is_thinking = vim.tbl_contains(thinking_types, entry.level)
|
||||
|
||||
if is_thinking then
|
||||
local prefix = params.thinking_prefixes[entry.level] or "⏺"
|
||||
if prefix ~= "" then
|
||||
return prefix .. " " .. entry.message
|
||||
else
|
||||
return entry.message
|
||||
end
|
||||
end
|
||||
|
||||
local level_prefix = params.level_icons[entry.level] or "?"
|
||||
local base = string.format("[%s] %s %s", entry.timestamp, level_prefix, entry.message)
|
||||
|
||||
if entry.data and entry.data.raw_response then
|
||||
local separator = string.rep("-", 40)
|
||||
base = base .. "\n" .. separator .. "\n" .. entry.data.raw_response .. "\n" .. separator
|
||||
end
|
||||
|
||||
return base
|
||||
end
|
||||
|
||||
return format_entry
|
||||
45
lua/codetyper/adapters/nvim/ui/logs/format_for_chat.lua
Normal file
45
lua/codetyper/adapters/nvim/ui/logs/format_for_chat.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
local params = require("codetyper.params.agents.logs")
|
||||
|
||||
--- Format entry for display in chat (compact Claude Code style)
|
||||
---@param entry LogEntry
|
||||
---@return string|nil formatted Formatted string or nil to skip
|
||||
local function format_for_chat(entry)
|
||||
local skip_types = { "debug", "queue", "patch" }
|
||||
if vim.tbl_contains(skip_types, entry.level) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local thinking_types = params.thinking_types
|
||||
if vim.tbl_contains(thinking_types, entry.level) then
|
||||
local prefix = params.thinking_prefixes[entry.level] or "⏺"
|
||||
if prefix ~= "" then
|
||||
return prefix .. " " .. entry.message
|
||||
else
|
||||
return entry.message
|
||||
end
|
||||
end
|
||||
|
||||
if entry.level == "tool" then
|
||||
return "⏺ " .. entry.message:gsub("^%[.-%] ", "")
|
||||
end
|
||||
|
||||
if entry.level == "info" or entry.level == "success" then
|
||||
return "⏺ " .. entry.message
|
||||
end
|
||||
|
||||
if entry.level == "error" then
|
||||
return "⚠ " .. entry.message
|
||||
end
|
||||
|
||||
if entry.level == "request" then
|
||||
return "⏺ " .. entry.message
|
||||
end
|
||||
|
||||
if entry.level == "response" then
|
||||
return " ⎿ " .. entry.message
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
return format_for_chat
|
||||
9
lua/codetyper/adapters/nvim/ui/logs/get_entries.lua
Normal file
9
lua/codetyper/adapters/nvim/ui/logs/get_entries.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
local state = require("codetyper.state.state")
|
||||
|
||||
--- Get all log entries
|
||||
---@return LogEntry[]
|
||||
local function get_entries()
|
||||
return state.entries
|
||||
end
|
||||
|
||||
return get_entries
|
||||
10
lua/codetyper/adapters/nvim/ui/logs/get_provider_info.lua
Normal file
10
lua/codetyper/adapters/nvim/ui/logs/get_provider_info.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local state = require("codetyper.state.state")
|
||||
|
||||
--- Get current provider info
|
||||
---@return string|nil provider
|
||||
---@return string|nil model
|
||||
local function get_provider_info()
|
||||
return state.current_provider, state.current_model
|
||||
end
|
||||
|
||||
return get_provider_info
|
||||
10
lua/codetyper/adapters/nvim/ui/logs/get_token_totals.lua
Normal file
10
lua/codetyper/adapters/nvim/ui/logs/get_token_totals.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local state = require("codetyper.state.state")
|
||||
|
||||
--- Get token totals
|
||||
---@return number prompt_tokens
|
||||
---@return number response_tokens
|
||||
local function get_token_totals()
|
||||
return state.total_prompt_tokens, state.total_response_tokens
|
||||
end
|
||||
|
||||
return get_token_totals
|
||||
10
lua/codetyper/adapters/nvim/ui/logs/info.lua
Normal file
10
lua/codetyper/adapters/nvim/ui/logs/info.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log info message
|
||||
---@param message string
|
||||
---@param data? table
|
||||
local function info(message, data)
|
||||
log("info", message, data)
|
||||
end
|
||||
|
||||
return info
|
||||
23
lua/codetyper/adapters/nvim/ui/logs/log.lua
Normal file
23
lua/codetyper/adapters/nvim/ui/logs/log.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local get_timestamp = require("codetyper.utils.get_timestamp")
|
||||
|
||||
--- Add a log entry and notify all listeners
|
||||
---@param level string Log level
|
||||
---@param message string Log message
|
||||
---@param data? table Optional data
|
||||
local function log(level, message, data)
|
||||
local entry = {
|
||||
timestamp = get_timestamp(),
|
||||
level = level,
|
||||
message = message,
|
||||
data = data,
|
||||
}
|
||||
|
||||
table.insert(state.entries, entry)
|
||||
|
||||
for _, listener in ipairs(state.listeners) do
|
||||
pcall(listener, entry)
|
||||
end
|
||||
end
|
||||
|
||||
return log
|
||||
14
lua/codetyper/adapters/nvim/ui/logs/read.lua
Normal file
14
lua/codetyper/adapters/nvim/ui/logs/read.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log file read operation
|
||||
---@param filepath string Path of file being read
|
||||
---@param lines? number Number of lines read
|
||||
local function read(filepath, lines)
|
||||
local message = string.format("Read(%s)", vim.fn.fnamemodify(filepath, ":~:."))
|
||||
if lines then
|
||||
message = message .. string.format("\n ⎿ Read %d lines", lines)
|
||||
end
|
||||
log("action", message)
|
||||
end
|
||||
|
||||
return read
|
||||
9
lua/codetyper/adapters/nvim/ui/logs/reason.lua
Normal file
9
lua/codetyper/adapters/nvim/ui/logs/reason.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log a reasoning/explanation message (shown prominently)
|
||||
---@param message string The reasoning message
|
||||
local function reason(message)
|
||||
log("reason", message)
|
||||
end
|
||||
|
||||
return reason
|
||||
11
lua/codetyper/adapters/nvim/ui/logs/remove_listener.lua
Normal file
11
lua/codetyper/adapters/nvim/ui/logs/remove_listener.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
local state = require("codetyper.state.state")
|
||||
|
||||
--- Remove a listener by ID
|
||||
---@param listener_id number Listener ID
|
||||
local function remove_listener(listener_id)
|
||||
if listener_id > 0 and listener_id <= #state.listeners then
|
||||
table.remove(state.listeners, listener_id)
|
||||
end
|
||||
end
|
||||
|
||||
return remove_listener
|
||||
24
lua/codetyper/adapters/nvim/ui/logs/request.lua
Normal file
24
lua/codetyper/adapters/nvim/ui/logs/request.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log API request
|
||||
---@param provider string LLM provider
|
||||
---@param model string Model name
|
||||
---@param prompt_tokens? number Estimated prompt tokens
|
||||
local function request(provider, model, prompt_tokens)
|
||||
state.current_provider = provider
|
||||
state.current_model = model
|
||||
|
||||
local message = string.format("[%s] %s", provider:upper(), model)
|
||||
if prompt_tokens then
|
||||
message = message .. string.format(" | Prompt: ~%d tokens", prompt_tokens)
|
||||
end
|
||||
|
||||
log("request", message, {
|
||||
provider = provider,
|
||||
model = model,
|
||||
prompt_tokens = prompt_tokens,
|
||||
})
|
||||
end
|
||||
|
||||
return request
|
||||
33
lua/codetyper/adapters/nvim/ui/logs/response.lua
Normal file
33
lua/codetyper/adapters/nvim/ui/logs/response.lua
Normal file
@@ -0,0 +1,33 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log API response with token usage
|
||||
---@param prompt_tokens number Tokens used in prompt
|
||||
---@param response_tokens number Tokens in response
|
||||
---@param stop_reason? string Why the response stopped
|
||||
local function response(prompt_tokens, response_tokens, stop_reason)
|
||||
state.total_prompt_tokens = state.total_prompt_tokens + prompt_tokens
|
||||
state.total_response_tokens = state.total_response_tokens + response_tokens
|
||||
|
||||
local message = string.format(
|
||||
"Tokens: %d in / %d out | Total: %d in / %d out",
|
||||
prompt_tokens,
|
||||
response_tokens,
|
||||
state.total_prompt_tokens,
|
||||
state.total_response_tokens
|
||||
)
|
||||
|
||||
if stop_reason then
|
||||
message = message .. " | Stop: " .. stop_reason
|
||||
end
|
||||
|
||||
log("response", message, {
|
||||
prompt_tokens = prompt_tokens,
|
||||
response_tokens = response_tokens,
|
||||
total_prompt = state.total_prompt_tokens,
|
||||
total_response = state.total_response_tokens,
|
||||
stop_reason = stop_reason,
|
||||
})
|
||||
end
|
||||
|
||||
return response
|
||||
14
lua/codetyper/adapters/nvim/ui/logs/task.lua
Normal file
14
lua/codetyper/adapters/nvim/ui/logs/task.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log a task/step that's in progress
|
||||
---@param task_name string Task name
|
||||
---@param status string|nil Status message
|
||||
local function task(task_name, status)
|
||||
local message = task_name
|
||||
if status then
|
||||
message = message .. " " .. status
|
||||
end
|
||||
log("task", message)
|
||||
end
|
||||
|
||||
return task
|
||||
13
lua/codetyper/adapters/nvim/ui/logs/task_done.lua
Normal file
13
lua/codetyper/adapters/nvim/ui/logs/task_done.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log task completion
|
||||
---@param next_task? string Next task
|
||||
local function task_done(next_task)
|
||||
local message = " ⎿ Done"
|
||||
if next_task then
|
||||
message = message .. "\n✶ " .. next_task
|
||||
end
|
||||
log("result", message)
|
||||
end
|
||||
|
||||
return task_done
|
||||
9
lua/codetyper/adapters/nvim/ui/logs/thinking.lua
Normal file
9
lua/codetyper/adapters/nvim/ui/logs/thinking.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log thinking/reasoning step
|
||||
---@param step string Description of what's happening
|
||||
local function thinking(step)
|
||||
log("thinking", step)
|
||||
end
|
||||
|
||||
return thinking
|
||||
23
lua/codetyper/adapters/nvim/ui/logs/tool.lua
Normal file
23
lua/codetyper/adapters/nvim/ui/logs/tool.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
local params = require("codetyper.params.agents.logs")
|
||||
|
||||
--- Log tool execution
|
||||
---@param tool_name string Name of the tool
|
||||
---@param status string "start" | "success" | "error" | "approval"
|
||||
---@param details? string Additional details
|
||||
local function tool(tool_name, status, details)
|
||||
local icons = params.icons
|
||||
|
||||
local message = string.format("[%s] %s", icons[status] or status, tool_name)
|
||||
if details then
|
||||
message = message .. ": " .. details
|
||||
end
|
||||
|
||||
log("tool", message, {
|
||||
tool = tool_name,
|
||||
status = status,
|
||||
details = details,
|
||||
})
|
||||
end
|
||||
|
||||
return tool
|
||||
24
lua/codetyper/adapters/nvim/ui/logs/update.lua
Normal file
24
lua/codetyper/adapters/nvim/ui/logs/update.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log update/edit operation
|
||||
---@param filepath string Path of file being edited
|
||||
---@param added? number Lines added
|
||||
---@param removed? number Lines removed
|
||||
local function update(filepath, added, removed)
|
||||
local message = string.format("Update(%s)", vim.fn.fnamemodify(filepath, ":~:."))
|
||||
if added or removed then
|
||||
local parts = {}
|
||||
if added and added > 0 then
|
||||
table.insert(parts, string.format("Added %d lines", added))
|
||||
end
|
||||
if removed and removed > 0 then
|
||||
table.insert(parts, string.format("Removed %d lines", removed))
|
||||
end
|
||||
if #parts > 0 then
|
||||
message = message .. "\n ⎿ " .. table.concat(parts, ", ")
|
||||
end
|
||||
end
|
||||
log("action", message)
|
||||
end
|
||||
|
||||
return update
|
||||
10
lua/codetyper/adapters/nvim/ui/logs/warning.lua
Normal file
10
lua/codetyper/adapters/nvim/ui/logs/warning.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
local log = require("codetyper.adapters.nvim.ui.logs.log")
|
||||
|
||||
--- Log warning message
|
||||
---@param message string
|
||||
---@param data? table
|
||||
local function warning(message, data)
|
||||
log("warning", "WARN: " .. message, data)
|
||||
end
|
||||
|
||||
return warning
|
||||
@@ -12,6 +12,11 @@ local state = {
|
||||
diff_buf = nil,
|
||||
diff_win = nil,
|
||||
is_open = false,
|
||||
listeners = {},
|
||||
total_prompt_tokens = 0,
|
||||
total_response_tokens = 0,
|
||||
current_provider = nil,
|
||||
current_model = nil,
|
||||
}
|
||||
|
||||
return state
|
||||
|
||||
8
lua/codetyper/utils/estimate_tokens.lua
Normal file
8
lua/codetyper/utils/estimate_tokens.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
--- Estimate token count for a string (rough approximation ~4 chars per token)
|
||||
---@param text string
|
||||
---@return number
|
||||
local function estimate_tokens(text)
|
||||
return math.ceil(#text / 4)
|
||||
end
|
||||
|
||||
return estimate_tokens
|
||||
7
lua/codetyper/utils/get_timestamp.lua
Normal file
7
lua/codetyper/utils/get_timestamp.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
--- Get current timestamp formatted as HH:MM:SS
|
||||
---@return string
|
||||
local function get_timestamp()
|
||||
return os.date("%H:%M:%S")
|
||||
end
|
||||
|
||||
return get_timestamp
|
||||
Reference in New Issue
Block a user