Skip to content

Commit 8e2d86a

Browse files
authored
feat: add Anthropic extended thinking support (#278)
* add thinking capabilities for Anthropic models * remove redundant header * clean up thinking determination logic * cleaner way of keeping track of thinking state * disable anthropic thinking for topic creation
1 parent 9d08aec commit 8e2d86a

File tree

3 files changed

+43
-10
lines changed

3 files changed

+43
-10
lines changed

lua/gp/config.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ local config = {
171171
-- system prompt (use this to specify the persona/role of the AI)
172172
system_prompt = require("gp.defaults").chat_system_prompt,
173173
},
174+
{
175+
provider = "anthropic",
176+
name = "ChatClaude-Sonnet-4-Thinking",
177+
chat = true,
178+
command = false,
179+
-- string with model name or table with model name and parameters
180+
model = { model = "claude-sonnet-4-20250514", thinking_budget = 1024 },
181+
-- system prompt (use this to specify the persona/role of the AI)
182+
system_prompt = require("gp.defaults").chat_system_prompt,
183+
},
174184
{
175185
provider = "anthropic",
176186
name = "ChatClaude-3-5-Haiku",

lua/gp/dispatcher.lua

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ D.prepare_payload = function(messages, model, provider)
158158
temperature = model.temperature and math.max(0, math.min(2, model.temperature)) or nil,
159159
top_p = model.top_p and math.max(0, math.min(1, model.top_p)) or nil,
160160
}
161+
162+
if model.thinking_budget ~= nil then
163+
payload.thinking = {
164+
type = "enabled",
165+
budget_tokens = model.thinking_budget
166+
}
167+
end
168+
161169
return payload
162170
end
163171

@@ -230,6 +238,7 @@ local query = function(buf, provider, payload, handler, on_exit, callback)
230238

231239
local out_reader = function()
232240
local buffer = ""
241+
local anthropic_thinking = false -- local state for Anthropic thinking blocks
233242

234243
---@param lines_chunk string
235244
local function process_lines(lines_chunk)
@@ -252,14 +261,24 @@ local query = function(buf, provider, payload, handler, on_exit, callback)
252261
end
253262
end
254263

255-
if qt.provider == "anthropic" and line:match('"text":') then
264+
if qt.provider == "anthropic" and (line:match('"text":') or line:match('"thinking"')) then
256265
if line:match("content_block_start") or line:match("content_block_delta") then
257266
line = vim.json.decode(line)
258-
if line.delta and line.delta.text then
259-
content = line.delta.text
267+
if line.content_block then
268+
if line.content_block.type == "thinking" then
269+
anthropic_thinking = true
270+
content = "<think>"
271+
elseif line.content_block.type == "text" and anthropic_thinking then
272+
anthropic_thinking = false
273+
content = "</think>\n\n"
274+
end
260275
end
261-
if line.content_block and line.content_block.text then
262-
content = line.content_block.text
276+
if line.delta then
277+
if line.delta.type == "thinking_delta" then
278+
content = line.delta.thinking or ""
279+
elseif line.delta.type == "text_delta" then
280+
content = line.delta.text or ""
281+
end
263282
end
264283
end
265284
end
@@ -382,8 +401,6 @@ local query = function(buf, provider, payload, handler, on_exit, callback)
382401
"x-api-key: " .. bearer,
383402
"-H",
384403
"anthropic-version: 2023-06-01",
385-
"-H",
386-
"anthropic-beta: messages-2023-12-15",
387404
}
388405
elseif provider == "azure" then
389406
headers = {

lua/gp/init.lua

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,11 +1159,17 @@ M.chat_respond = function(params)
11591159
local topic_buf = vim.api.nvim_create_buf(false, true)
11601160
local topic_handler = M.dispatcher.create_handler(topic_buf, nil, 0, false, "", false)
11611161

1162-
-- call the model
1162+
-- call the model (remove thinking_budget for Anthropic topic generation)
1163+
local topic_model = headers.model or agent.model
1164+
local provider = headers.provider or agent.provider
1165+
if provider == "anthropic" and topic_model.thinking_budget then
1166+
topic_model = vim.deepcopy(topic_model)
1167+
topic_model.thinking_budget = nil
1168+
end
11631169
M.dispatcher.query(
11641170
nil,
1165-
headers.provider or agent.provider,
1166-
M.dispatcher.prepare_payload(messages, headers.model or agent.model, headers.provider or agent.provider),
1171+
provider,
1172+
M.dispatcher.prepare_payload(messages, topic_model, provider),
11671173
topic_handler,
11681174
vim.schedule_wrap(function()
11691175
-- get topic from invisible buffer

0 commit comments

Comments
 (0)