diff --git a/lua/gp/config.lua b/lua/gp/config.lua index 43cf729..cbfb196 100644 --- a/lua/gp/config.lua +++ b/lua/gp/config.lua @@ -171,6 +171,16 @@ local config = { -- system prompt (use this to specify the persona/role of the AI) system_prompt = require("gp.defaults").chat_system_prompt, }, + { + provider = "anthropic", + name = "ChatClaude-Sonnet-4-Thinking", + chat = true, + command = false, + -- string with model name or table with model name and parameters + model = { model = "claude-sonnet-4-20250514", thinking_budget = 1024 }, + -- system prompt (use this to specify the persona/role of the AI) + system_prompt = require("gp.defaults").chat_system_prompt, + }, { provider = "anthropic", name = "ChatClaude-3-5-Haiku", diff --git a/lua/gp/dispatcher.lua b/lua/gp/dispatcher.lua index c420977..7e2ab46 100644 --- a/lua/gp/dispatcher.lua +++ b/lua/gp/dispatcher.lua @@ -158,6 +158,14 @@ D.prepare_payload = function(messages, model, provider) temperature = model.temperature and math.max(0, math.min(2, model.temperature)) or nil, top_p = model.top_p and math.max(0, math.min(1, model.top_p)) or nil, } + + if model.thinking_budget ~= nil then + payload.thinking = { + type = "enabled", + budget_tokens = model.thinking_budget + } + end + return payload end @@ -230,6 +238,7 @@ local query = function(buf, provider, payload, handler, on_exit, callback) local out_reader = function() local buffer = "" + local anthropic_thinking = false -- local state for Anthropic thinking blocks ---@param lines_chunk string local function process_lines(lines_chunk) @@ -252,14 +261,24 @@ local query = function(buf, provider, payload, handler, on_exit, callback) end end - if qt.provider == "anthropic" and line:match('"text":') then + if qt.provider == "anthropic" and (line:match('"text":') or line:match('"thinking"')) then if line:match("content_block_start") or line:match("content_block_delta") then line = vim.json.decode(line) - if line.delta and line.delta.text then - content = line.delta.text + if line.content_block then + if line.content_block.type == "thinking" then + anthropic_thinking = true + content = "" + elseif line.content_block.type == "text" and anthropic_thinking then + anthropic_thinking = false + content = "\n\n" + end end - if line.content_block and line.content_block.text then - content = line.content_block.text + if line.delta then + if line.delta.type == "thinking_delta" then + content = line.delta.thinking or "" + elseif line.delta.type == "text_delta" then + content = line.delta.text or "" + end end end end @@ -382,8 +401,6 @@ local query = function(buf, provider, payload, handler, on_exit, callback) "x-api-key: " .. bearer, "-H", "anthropic-version: 2023-06-01", - "-H", - "anthropic-beta: messages-2023-12-15", } elseif provider == "azure" then headers = { diff --git a/lua/gp/init.lua b/lua/gp/init.lua index d693981..c05ab7f 100644 --- a/lua/gp/init.lua +++ b/lua/gp/init.lua @@ -1159,11 +1159,17 @@ M.chat_respond = function(params) local topic_buf = vim.api.nvim_create_buf(false, true) local topic_handler = M.dispatcher.create_handler(topic_buf, nil, 0, false, "", false) - -- call the model + -- call the model (remove thinking_budget for Anthropic topic generation) + local topic_model = headers.model or agent.model + local provider = headers.provider or agent.provider + if provider == "anthropic" and topic_model.thinking_budget then + topic_model = vim.deepcopy(topic_model) + topic_model.thinking_budget = nil + end M.dispatcher.query( nil, - headers.provider or agent.provider, - M.dispatcher.prepare_payload(messages, headers.model or agent.model, headers.provider or agent.provider), + provider, + M.dispatcher.prepare_payload(messages, topic_model, provider), topic_handler, vim.schedule_wrap(function() -- get topic from invisible buffer