fixing configuration to change the windows

This commit is contained in:
2026-01-13 22:07:02 -05:00
parent 8a3ee81c3f
commit 6b25aef917
3 changed files with 132 additions and 288 deletions

View File

@@ -147,6 +147,24 @@ 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
---@param step string Description of what's happening
function M.thinking(step)

View File

@@ -24,6 +24,8 @@ local state = {
referenced_files = {},
target_width = nil, -- Store the target width to maintain it
agent_mode = false, -- Whether agent mode is enabled (can make file changes)
log_listener_id = nil, -- Listener ID for LLM logs
show_logs = true, -- Whether to show LLM logs in chat
}
--- Get the ask window configuration
@@ -59,6 +61,7 @@ local function create_output_buffer()
"║ C-Enter → send ║",
"║ C-n → new chat ║",
"║ C-f → add current file ║",
"║ L → toggle LLM logs ║",
"║ :CoderType → switch mode ║",
"║ q → close │ K/J → jump ║",
"╚═════════════════════════════════╝",
@@ -195,6 +198,11 @@ local function setup_output_keymaps(buf)
M.copy_last_response()
end, opts)
-- Toggle LLM logs with L
vim.keymap.set("n", "L", function()
M.toggle_logs()
end, opts)
-- Jump to input with i or J
vim.keymap.set("n", "i", function()
M.focus_input()
@@ -276,6 +284,88 @@ local function setup_width_autocmd()
})
end
--- Append log entry to output buffer
---@param entry table Log entry from agent/logs
local function append_log_to_output(entry)
if not state.show_logs then
return
end
if not state.output_buf or not vim.api.nvim_buf_is_valid(state.output_buf) then
return
end
-- Skip clear events
if entry.level == "clear" then
return
end
-- Format the log entry with icons
local icons = {
info = "",
debug = "🔍",
request = "📤",
response = "📥",
tool = "🔧",
error = "",
warning = "⚠️",
}
local icon = icons[entry.level] or ""
local formatted = string.format("[%s] %s %s", entry.timestamp, icon, entry.message)
vim.schedule(function()
if not state.output_buf or not vim.api.nvim_buf_is_valid(state.output_buf) then
return
end
vim.bo[state.output_buf].modifiable = true
local lines = vim.api.nvim_buf_get_lines(state.output_buf, 0, -1, false)
-- Add a subtle log line
table.insert(lines, " " .. formatted)
vim.api.nvim_buf_set_lines(state.output_buf, 0, -1, false, lines)
vim.bo[state.output_buf].modifiable = false
-- Scroll to bottom
if state.output_win and vim.api.nvim_win_is_valid(state.output_win) then
local line_count = vim.api.nvim_buf_line_count(state.output_buf)
pcall(vim.api.nvim_win_set_cursor, state.output_win, { line_count, 0 })
end
end)
end
--- Setup log listener for LLM logs
local function setup_log_listener()
-- Remove existing listener if any
if state.log_listener_id then
pcall(function()
local logs = require("codetyper.agent.logs")
logs.remove_listener(state.log_listener_id)
end)
state.log_listener_id = nil
end
-- Add new listener
local ok, logs = pcall(require, "codetyper.agent.logs")
if ok then
state.log_listener_id = logs.add_listener(append_log_to_output)
end
end
--- Remove log listener
local function remove_log_listener()
if state.log_listener_id then
pcall(function()
local logs = require("codetyper.agent.logs")
logs.remove_listener(state.log_listener_id)
end)
state.log_listener_id = nil
end
end
--- Open the ask panel
function M.open()
-- Use the is_open() function which validates window state
@@ -335,6 +425,9 @@ function M.open()
state.is_open = true
-- Setup log listener for LLM logs
setup_log_listener()
-- Setup autocmd to maintain width
setup_width_autocmd()
@@ -366,6 +459,9 @@ function M.open()
state.is_open = false
state.target_width = nil
-- Remove log listener
remove_log_listener()
-- Clean up autocmd groups
pcall(vim.api.nvim_del_augroup_by_id, close_group)
if ask_augroup then
@@ -466,6 +562,9 @@ end
--- Close the ask panel
function M.close()
-- Remove the log listener
remove_log_listener()
-- Remove the width maintenance autocmd first
if ask_augroup then
pcall(vim.api.nvim_del_augroup_by_id, ask_augroup)
@@ -796,6 +895,7 @@ function M.clear_history()
"║ C-Enter → send ║",
"║ C-n → new chat ║",
"║ C-f → add current file ║",
"║ L → toggle LLM logs ║",
"║ :CoderType → switch mode ║",
"║ q → close │ K/J → jump ║",
"╚═════════════════════════════════╝",
@@ -881,4 +981,18 @@ function M.get_history()
return state.history
end
--- Toggle LLM log visibility in chat
---@return boolean New state
function M.toggle_logs()
state.show_logs = not state.show_logs
utils.notify("LLM logs " .. (state.show_logs and "enabled" or "disabled"))
return state.show_logs
end
--- Check if logs are enabled
---@return boolean
function M.logs_enabled()
return state.show_logs
end
return M

View File

@@ -361,292 +361,4 @@ function M.format_messages_for_claude(messages)
return formatted
end
--- Generate with tool use support for agentic mode
---@param messages table[] Conversation history
---@param context table Context information
---@param tool_definitions table Tool definitions
---@param callback fun(response: table|nil, error: string|nil) Callback with raw response
function M.generate_with_tools(messages, context, tool_definitions, callback)
local api_key = get_api_key()
if not api_key then
callback(nil, "Claude API key not configured")
return
end
local tools_module = require("codetyper.agent.tools")
local agent_prompts = require("codetyper.prompts.agent")
-- Build system prompt with agent instructions
local system_prompt = llm.build_system_prompt(context)
system_prompt = system_prompt .. "\n\n" .. agent_prompts.system
system_prompt = system_prompt .. "\n\n" .. agent_prompts.tool_instructions
-- Build request body with tools
local body = {
model = get_model(),
max_tokens = 4096,
system = system_prompt,
messages = M.format_messages_for_claude(messages),
tools = tools_module.to_claude_format(),
}
local json_body = vim.json.encode(body)
local cmd = {
"curl",
"-s",
"-X", "POST",
API_URL,
"-H", "Content-Type: application/json",
"-H", "x-api-key: " .. api_key,
"-H", "anthropic-version: 2023-06-01",
"-d", json_body,
}
vim.fn.jobstart(cmd, {
stdout_buffered = true,
on_stdout = function(_, data)
if not data or #data == 0 or (data[1] == "" and #data == 1) then
return
end
local response_text = table.concat(data, "\n")
local ok, response = pcall(vim.json.decode, response_text)
if not ok then
vim.schedule(function()
callback(nil, "Failed to parse Claude response")
end)
return
end
if response.error then
vim.schedule(function()
callback(nil, response.error.message or "Claude API error")
end)
return
end
-- Return raw response for parser to handle
vim.schedule(function()
callback(response, nil)
end)
end,
on_stderr = function(_, data)
if data and #data > 0 and data[1] ~= "" then
vim.schedule(function()
callback(nil, "Claude API request failed: " .. table.concat(data, "\n"))
end)
end
end,
on_exit = function(_, code)
if code ~= 0 then
vim.schedule(function()
callback(nil, "Claude API request failed with code: " .. code)
end)
end
end,
})
end
--- Format messages for Claude API
---@param messages table[] Internal message format
---@return table[] Claude API message format
function M.format_messages_for_claude(messages)
local formatted = {}
for _, msg in ipairs(messages) do
if msg.role == "user" then
if type(msg.content) == "table" then
-- Tool results
table.insert(formatted, {
role = "user",
content = msg.content,
})
else
table.insert(formatted, {
role = "user",
content = msg.content,
})
end
elseif msg.role == "assistant" then
-- Build content array for assistant messages
local content = {}
-- Add text if present
if msg.content and msg.content ~= "" then
table.insert(content, {
type = "text",
text = msg.content,
})
end
-- Add tool uses if present
if msg.tool_calls then
for _, tool_call in ipairs(msg.tool_calls) do
table.insert(content, {
type = "tool_use",
id = tool_call.id,
name = tool_call.name,
input = tool_call.parameters,
})
end
end
if #content > 0 then
table.insert(formatted, {
role = "assistant",
content = content,
})
end
end
end
return formatted
end
--- Generate with tool use support for agentic mode
---@param messages table[] Conversation history
---@param context table Context information
---@param tool_definitions table Tool definitions
---@param callback fun(response: table|nil, error: string|nil) Callback with raw response
function M.generate_with_tools(messages, context, tool_definitions, callback)
local api_key = get_api_key()
if not api_key then
callback(nil, "Claude API key not configured")
return
end
local tools_module = require("codetyper.agent.tools")
local agent_prompts = require("codetyper.prompts.agent")
-- Build system prompt with agent instructions
local system_prompt = llm.build_system_prompt(context)
system_prompt = system_prompt .. "\n\n" .. agent_prompts.system
system_prompt = system_prompt .. "\n\n" .. agent_prompts.tool_instructions
-- Build request body with tools
local body = {
model = get_model(),
max_tokens = 4096,
system = system_prompt,
messages = M.format_messages_for_claude(messages),
tools = tools_module.to_claude_format(),
}
local json_body = vim.json.encode(body)
local cmd = {
"curl",
"-s",
"-X", "POST",
API_URL,
"-H", "Content-Type: application/json",
"-H", "x-api-key: " .. api_key,
"-H", "anthropic-version: 2023-06-01",
"-d", json_body,
}
vim.fn.jobstart(cmd, {
stdout_buffered = true,
on_stdout = function(_, data)
if not data or #data == 0 or (data[1] == "" and #data == 1) then
return
end
local response_text = table.concat(data, "\n")
local ok, response = pcall(vim.json.decode, response_text)
if not ok then
vim.schedule(function()
callback(nil, "Failed to parse Claude response")
end)
return
end
if response.error then
vim.schedule(function()
callback(nil, response.error.message or "Claude API error")
end)
return
end
-- Return raw response for parser to handle
vim.schedule(function()
callback(response, nil)
end)
end,
on_stderr = function(_, data)
if data and #data > 0 and data[1] ~= "" then
vim.schedule(function()
callback(nil, "Claude API request failed: " .. table.concat(data, "\n"))
end)
end
end,
on_exit = function(_, code)
if code ~= 0 then
vim.schedule(function()
callback(nil, "Claude API request failed with code: " .. code)
end)
end
end,
})
end
--- Format messages for Claude API
---@param messages table[] Internal message format
---@return table[] Claude API message format
function M.format_messages_for_claude(messages)
local formatted = {}
for _, msg in ipairs(messages) do
if msg.role == "user" then
if type(msg.content) == "table" then
-- Tool results
table.insert(formatted, {
role = "user",
content = msg.content,
})
else
table.insert(formatted, {
role = "user",
content = msg.content,
})
end
elseif msg.role == "assistant" then
-- Build content array for assistant messages
local content = {}
-- Add text if present
if msg.content and msg.content ~= "" then
table.insert(content, {
type = "text",
text = msg.content,
})
end
-- Add tool uses if present
if msg.tool_calls then
for _, tool_call in ipairs(msg.tool_calls) do
table.insert(content, {
type = "tool_use",
id = tool_call.id,
name = tool_call.name,
input = tool_call.parameters,
})
end
end
if #content > 0 then
table.insert(formatted, {
role = "assistant",
content = content,
})
end
end
end
return formatted
end
return M