Skip to content

Commit 47a52d7

Browse files
authored
Feature: add Claude support (#29)
* feat: add claude backend * docs: add Claude docs
1 parent 61d86ff commit 47a52d7

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

doc/cmp-ai.txt

+26
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,32 @@ To use Tabby:
258258
You will also need to make sure you have the Tabby api key in your environment,
259259
`TABBY_API_KEY`.
260260

261+
To use Claude:
262+
263+
>lua
264+
local cmp_ai = require('cmp_ai.config')
265+
266+
cmp_ai:setup({
267+
max_lines = 1000,
268+
provider = 'Claude',
269+
provider_options = {
270+
model = 'claude-3-5-sonnet-20240620',
271+
},
272+
notify = true,
273+
notify_callback = function(msg)
274+
vim.notify(msg)
275+
end,
276+
run_on_every_keystroke = true,
277+
ignored_file_types = {
278+
-- default is not to ignore
279+
-- uncomment to ignore in lua:
280+
-- lua = true
281+
},
282+
})
283+
<
284+
285+
You will also need to make sure you have the Anthropic api key in your environment,
286+
`CLAUDE_API_KEY`.
261287

262288
NOTIFY ~
263289

lua/cmp_ai/backends/claude.lua

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
local requests = require('cmp_ai.requests')
2+
3+
Claude = requests:new(nil)
4+
BASE_URL = 'https://api.anthropic.com/v1/messages'
5+
6+
function Claude:new(o, params)
7+
o = o or {}
8+
setmetatable(o, self)
9+
self.__index = self
10+
self.params = vim.tbl_deep_extend('keep', params or {}, {
11+
-- Custom params for claude
12+
})
13+
14+
self.api_key = os.getenv('CLAUDE_API_KEY')
15+
if not self.api_key then
16+
vim.schedule(function()
17+
vim.notify('CLAUDE_API_KEY environment variable not set', vim.log.levels.ERROR)
18+
end)
19+
self.api_key = 'NO_KEY'
20+
end
21+
self.headers = {
22+
'x-api-key: ' .. self.api_key,
23+
}
24+
return o
25+
end
26+
27+
function Claude:complete(lines_before, lines_after, cb)
28+
if not self.api_key then
29+
vim.schedule(function()
30+
vim.notify('CLAUDE_API_KEY environment variable not set', vim.log.levels.ERROR)
31+
end)
32+
return
33+
end
34+
35+
local data = {
36+
messages = {
37+
{
38+
role = 'system',
39+
content = [=[You are a coding companion.
40+
You need to suggest code for the language ]=] .. vim.o.filetype .. [=[
41+
Given some code prefix and suffix for context, output code which should follow the prefix code.
42+
You should only output valid code in the language ]=] .. vim.o.filetype .. [=[
43+
. to clearly define a code block, including white space, we will wrap the code block
44+
with tags.
45+
Make sure to respect the white space and indentation rules of the language.
46+
Do not output anything in plain language, make sure you only use the relevant programming language verbatim.
47+
For example, consider the following request:
48+
<begin_code_prefix>def print_hello():<end_code_prefix><begin_code_suffix>\n return<end_code_suffix><begin_code_middle>
49+
Your answer should be:
50+
51+
print("Hello")<end_code_middle>
52+
]=],
53+
},
54+
{
55+
role = 'user',
56+
content = '<begin_code_prefix>' .. lines_before .. '<end_code_prefix>' .. '<begin_code_suffix>' .. lines_after .. '<end_code_suffix><begin_code_middle>',
57+
},
58+
},
59+
}
60+
61+
data = vim.tbl_deep_extend('keep', data, self.params)
62+
self:Get(BASE_URL, self.headers, data, function(answer)
63+
local new_data = {}
64+
if answer.choices then
65+
for _, response in ipairs(answer.choices) do
66+
local entry = response.message.content:gsub('<end_code_middle>', '')
67+
entry = entry:gsub('```', '')
68+
table.insert(new_data, entry)
69+
end
70+
end
71+
cb(new_data)
72+
end)
73+
end
74+
75+
function Claude:test()
76+
self:complete('def factorial(n)\n if', ' return ans\n', function(data)
77+
dump(data)
78+
end)
79+
end
80+
81+
return Claude

0 commit comments

Comments
 (0)