fix: remove copilot provider (#318)

This commit is contained in:
yetone 2024-08-28 20:51:20 +08:00 committed by GitHub
parent b661269b5b
commit bfa203018e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 22 additions and 464 deletions

View File

@ -1,32 +0,0 @@
param (
[string]$Version = "luajit"
)
$BuildDir = "build"
$BuildFromSource = $true
function Build-FromSource($feature) {
if (-not (Test-Path $BuildDir)) {
New-Item -ItemType Directory -Path $BuildDir | Out-Null
}
$tempDir = Join-Path $BuildDir "lua-tiktoken-temp"
git clone --branch v0.2.2 --depth 1 https://github.com/gptlang/lua-tiktoken.git $tempDir
Push-Location $tempDir
cargo build --features=$feature
Pop-Location
$targetFile = "tiktoken_core.dll"
Copy-Item (Join-Path $tempDir "target\debug\tiktoken_core.dll") (Join-Path $BuildDir $targetFile)
Remove-Item -Recurse -Force $tempDir
}
function Main {
Write-Host "Building for $Version..."
Build-FromSource $Version
}
# Run the main function
Main

View File

@ -1,44 +1,3 @@
UNAME := $(shell uname)
ARCH := $(shell uname -m)
ifeq ($(UNAME), Linux)
OS := linux
EXT := so
else ifeq ($(UNAME), Darwin)
OS := macOS
EXT := dylib
else
$(error Unsupported operating system: $(UNAME))
endif
LUA_VERSIONS := luajit lua51
BUILD_DIR := build
BUILD_FROM_SOURCE := false
all: luajit
luajit: $(BUILD_DIR)/tiktoken_core.$(EXT)
lua51: $(BUILD_DIR)/tiktoken_core-lua51.$(EXT)
define build_from_source
if [ -d "$(BUILD_DIR)/lua-tiktoken-temp" ]; then rm -rf $(BUILD_DIR)/lua-tiktoken-temp; fi
git clone --branch v0.2.2 --depth 1 https://github.com/gptlang/lua-tiktoken.git $(BUILD_DIR)/lua-tiktoken-temp
cd $(BUILD_DIR)/lua-tiktoken-temp && cargo build --features=$1
cp $(BUILD_DIR)/lua-tiktoken-temp/target/debug/libtiktoken_core.$(EXT) $(BUILD_DIR)/tiktoken_core.$(EXT)
rm -rf $(BUILD_DIR)/lua-tiktoken-temp
endef
$(BUILD_DIR)/tiktoken_core.$(EXT): $(BUILD_DIR)
$(call build_from_source,luajit)
$(BUILD_DIR)/tiktoken_core-lua51.$(EXT): $(BUILD_DIR)
$(call build_from_source,lua51)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
clean:
rm -rf $(BUILD_DIR)
luacheck:
luacheck `find -name "*.lua"` --codes

View File

@ -23,7 +23,6 @@ Install `avante.nvim` using [lazy.nvim](https://github.com/folke/lazy.nvim):
{
"yetone/avante.nvim",
event = "VeryLazy",
build = "make", -- This is Optional, only if you want to use tiktoken_core to calculate tokens count
opts = {
-- add any opts here
},
@ -50,7 +49,6 @@ For Windows users, change the build command to the following:
{
"yetone/avante.nvim",
event = "VeryLazy",
build = "powershell -ExecutionPolicy Bypass -File Build-LuaTiktoken.ps1", -- This is Optional, only if you want to use tiktoken_core to calculate tokens count
-- rest of the config
}
```
@ -59,11 +57,6 @@ For Windows users, change the build command to the following:
>
> `avante.nvim` is currently only compatible with Neovim 0.10.0 or later. Please ensure that your Neovim version meets these requirements before proceeding.
> [!IMPORTANT]
>
> If your neovim doesn't use LuaJIT, then change `build` to `make lua51`. By default running make will install luajit.
> Avante.nvim will now requires cargo to build tiktoken_core from source.
> [!NOTE]
>
> `render-markdown.nvim` is an optional dependency that is used to render the markdown content of the chat history. Make sure to also include `Avante` as a filetype
@ -85,8 +78,8 @@ _See [config.lua#L9](./lua/avante/config.lua) for the full config_
```lua
{
---@alias Provider "openai" | "claude" | "azure" | "copilot" | "cohere" | [string]
provider = "claude",
---@alias Provider "openai" | "claude" | "azure" | "cohere" | [string]
provider = "claude", -- Only recommend using Claude
claude = {
endpoint = "https://api.anthropic.com",
model = "claude-3-5-sonnet-20240620",
@ -150,9 +143,16 @@ Given its early stage, `avante.nvim` currently supports the following basic func
> [!IMPORTANT]
>
> Avante will only support OpenAI (and its variants including copilot and azure), and Claude out-of-the-box due to its high code quality generation.
> Avante will only support Claude, and OpenAI (and its variants including azure)out-of-the-box due to its high code quality generation.
> For all OpenAI-compatible providers, see [wiki](https://github.com/yetone/avante.nvim/wiki) for more details.
> [!IMPORTANT]
>
> Due to the poor performance of other models, avante.nvim only recommends using the claude-3.5-sonnet model.
> All features can only be guaranteed to work properly on the claude-3.5-sonnet model.
> We do not accept changes to the code or prompts to accommodate other models. Otherwise, it will greatly increase our maintenance costs.
> We hope everyone can understand. Thank you!
> [!IMPORTANT]
>
> For most consistency between neovim session, it is recommended to set the environment variables in your shell file.
@ -248,7 +248,7 @@ We would like to express our heartfelt gratitude to the contributors of the foll
| Nvim Plugin | Functionality | Where did we use |
| --- | --- | --- |
| [git-conflict.nvim](https://github.com/akinsho/git-conflict.nvim) | Diff comparison functionality | https://github.com/yetone/avante.nvim/blob/main/lua/avante/diff.lua |
| [CopilotChat.nvim](https://github.com/CopilotC-Nvim/CopilotChat.nvim) | Request logic for Copilot's API | https://github.com/yetone/avante.nvim/blob/main/lua/avante/providers/copilot.lua |
| [ChatGPT.nvim](https://github.com/jackMort/ChatGPT.nvim) | Calculation of tokens count | https://github.com/yetone/avante.nvim/blob/main/lua/avante/utils/tokens.lua |
The high quality and ingenuity of these projects' source code have been immensely beneficial throughout our development process. We extend our sincere thanks and respect to the authors and contributors of these projects. It is the selfless dedication of the open-source community that drives projects like avante.nvim forward.

View File

@ -9,8 +9,8 @@ M.defaults = {
debug = false,
---Currently, default supported providers include "claude", "openai", "azure", "gemini"
---For custom provider, see README.md
---@alias Provider "openai" | "claude" | "azure" | "copilot" | "gemini" | string
provider = "claude",
---@alias Provider "claude" | "openai" | "azure" | "gemini" | string
provider = "claude", -- Only recommend using Claude
---@type AvanteSupportedProvider
openai = {
endpoint = "https://api.openai.com/v1",
@ -20,16 +20,6 @@ M.defaults = {
max_tokens = 4096,
["local"] = false,
},
---@type AvanteSupportedProvider
copilot = {
endpoint = "https://api.githubcopilot.com",
model = "gpt-4o-2024-05-13",
proxy = nil, -- [protocol://]host[:port] Use this proxy
allow_insecure = false, -- Allow insecure server connections
timeout = 30000, -- Timeout in milliseconds
temperature = 0,
max_tokens = 4096,
},
---@type AvanteAzureProvider
azure = {
endpoint = "", -- example: "https://<your-resource-name>.openai.azure.com"

View File

@ -72,35 +72,6 @@ end
H.augroup = api.nvim_create_augroup("avante_autocmds", { clear = true })
H.autocmds = function()
local ok, LazyConfig = pcall(require, "lazy.core.config")
if ok then
local name = "avante.nvim"
local load_path = function()
require("tiktoken_lib").load()
require("avante.tiktoken").setup("gpt-4o")
end
if LazyConfig.plugins[name] and LazyConfig.plugins[name]._.loaded then
vim.schedule(load_path)
else
api.nvim_create_autocmd("User", {
pattern = "LazyLoad",
callback = function(event)
if event.data == name then
load_path()
return true
end
end,
})
end
api.nvim_create_autocmd("User", {
pattern = "VeryLazy",
callback = load_path,
})
end
api.nvim_create_autocmd("TabEnter", {
group = H.augroup,
pattern = "*",

View File

@ -1,200 +0,0 @@
---@see https://github.com/B00TK1D/copilot-api/blob/main/api.py
local curl = require("plenary.curl")
local Path = require("plenary.path")
local Utils = require("avante.utils")
local Config = require("avante.config")
local P = require("avante.providers")
local O = require("avante.providers").openai
---@class AvanteProviderFunctor
local M = {}
---@class CopilotToken
---@field annotations_enabled boolean
---@field chat_enabled boolean
---@field chat_jetbrains_enabled boolean
---@field code_quote_enabled boolean
---@field codesearch boolean
---@field copilotignore_enabled boolean
---@field endpoints {api: string, ["origin-tracker"]: string, proxy: string, telemetry: string}
---@field expires_at integer
---@field individual boolean
---@field nes_enabled boolean
---@field prompt_8k boolean
---@field public_suggestions string
---@field refresh_in integer
---@field sku string
---@field snippy_load_test_enabled boolean
---@field telemetry string
---@field token string
---@field tracking_id string
---@field vsc_electron_fetcher boolean
---@field xcode boolean
---@field xcode_chat boolean
---
---@private
---@class AvanteCopilot: table<string, any>
---@field token? CopilotToken
---@field github_token? string
M.copilot = nil
local H = {}
---@return string | nil
H.find_config_path = function()
local config = vim.fn.expand("$XDG_CONFIG_HOME")
if config and vim.fn.isdirectory(config) > 0 then
return config
elseif vim.fn.has("win32") > 0 then
config = vim.fn.expand("~/AppData/Local")
if vim.fn.isdirectory(config) > 0 then
return config
end
else
config = vim.fn.expand("~/.config")
if vim.fn.isdirectory(config) > 0 then
return config
end
end
end
---@return string | nil
H.cached_token = function()
-- loading token from the environment only in GitHub Codespaces
local token = os.getenv("GITHUB_TOKEN")
local codespaces = os.getenv("CODESPACES")
if token and codespaces then
return token
end
-- loading token from the file
local config_path = H.find_config_path()
if not config_path then
return nil
end
-- token can be sometimes in apps.json sometimes in hosts.json
local file_paths = {
config_path .. "/github-copilot/hosts.json",
config_path .. "/github-copilot/apps.json",
}
local fp = Path:new(vim
.iter(file_paths)
:filter(function(f)
return vim.fn.filereadable(f) == 1
end)
:next())
---@type table<string, any>
local creds = vim.json.decode(fp:read() or {})
---@type table<"token", string>
local value = vim
.iter(creds)
:filter(function(k, _)
return k:find("github.com")
end)
:fold({}, function(acc, _, v)
acc.token = v.oauth_token
return acc
end)
return value.token or nil
end
M.api_key_name = P.AVANTE_INTERNAL_KEY
M.has = function()
if Utils.has("copilot.lua") or Utils.has("copilot.vim") or H.cached_token() ~= nil then
return true
end
Utils.warn("copilot is not setup correctly. Please use copilot.lua or copilot.vim for authentication.")
return false
end
M.parse_message = function(opts)
local user_content = O.get_user_message(opts)
return {
{ role = "system", content = opts.system_prompt },
{ role = "user", content = user_content },
}
end
M.parse_response = O.parse_response
M.parse_curl_args = function(provider, code_opts)
M.refresh_token()
local base, body_opts = P.parse_config(provider)
return {
url = Utils.trim(base.endpoint, { suffix = "/" }) .. "/chat/completions",
timeout = base.timeout,
proxy = base.proxy,
insecure = base.allow_insecure,
headers = {
["Authorization"] = "Bearer " .. M.copilot.token.token,
["Content-Type"] = "application/json",
["Copilot-Integration-Id"] = "vscode-chat",
["editor-version"] = "Neovim/" .. vim.version().major .. "." .. vim.version().minor .. "." .. vim.version().patch,
},
body = vim.tbl_deep_extend("force", {
model = base.model,
n = 1,
top_p = 1,
stream = true,
messages = M.parse_message(code_opts),
}, body_opts),
}
end
M.on_error = function(result)
Utils.error("Received error from Copilot API: " .. result.body, { once = true, title = "Avante" })
Utils.debug(result)
end
M.refresh_token = function()
if not M.copilot.token or (M.copilot.token.expires_at and M.copilot.token.expires_at <= math.floor(os.time())) then
curl.get("https://api.github.com/copilot_internal/v2/token", {
timeout = Config.copilot.timeout,
headers = {
["Authorization"] = "token " .. M.copilot.github_token,
["Accept"] = "application/json",
["editor-version"] = "Neovim/"
.. vim.version().major
.. "."
.. vim.version().minor
.. "."
.. vim.version().patch,
},
proxy = Config.copilot.proxy,
insecure = Config.copilot.allow_insecure,
on_error = function(err)
error("Failed to get response: " .. vim.inspect(err))
end,
callback = function(output)
M.copilot.token = vim.json.decode(output.body)
vim.g.avante_login = true
end,
})
end
end
M.setup = function()
local github_token = H.cached_token()
if not github_token then
error(
"No GitHub token found, please use `:Copilot auth` to setup with `copilot.lua` or `:Copilot setup` with `copilot.vim`"
)
end
if not M.copilot then
M.copilot = { token = nil, github_token = github_token }
M.refresh_token()
end
end
return M

View File

@ -79,7 +79,6 @@ local Dressing = require("avante.ui.dressing")
---
---@class avante.Providers
---@field openai AvanteProviderFunctor
---@field copilot AvanteProviderFunctor
---@field claude AvanteProviderFunctor
---@field azure AvanteProviderFunctor
---@field gemini AvanteProviderFunctor
@ -312,7 +311,7 @@ function M.refresh(provider)
Utils.info("Switch to provider: " .. provider, { once = true, title = "Avante" })
end
local default_providers = { "openai", "claude", "azure", "gemini", "copilot" }
local default_providers = { "openai", "claude", "azure", "gemini" }
---@private
M.commands = function()
@ -369,7 +368,14 @@ end
---@param provider Provider
---@return AvanteProviderFunctor
M.get_config = function(provider)
local cur = Config.get_provider(provider or Config.provider)
provider = provider or Config.provider
if provider == "copilot" then
Utils.error(
"Sorry! We no longer support the copilot provider! Please use other providers!",
{ once = true, title = "Avante" }
)
end
local cur = Config.get_provider(provider)
return type(cur) == "function" and cur() or cur
end

View File

@ -1,109 +0,0 @@
-- NOTE: this file is copied from: https://github.com/CopilotC-Nvim/CopilotChat.nvim/blob/canary/lua/CopilotChat/tiktoken.lua
local curl = require("plenary.curl")
local tiktoken_core = nil
---Get the path of the cache directory
---@param fname string
---@return string
local function get_cache_path(fname)
return vim.fn.stdpath("cache") .. "/" .. fname
end
local function file_exists(name)
local f = io.open(name, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
--- Load tiktoken data from cache or download it
---@param model string
---@param done fun(path: string): nil
local function load_tiktoken_data(done, model)
local tiktoken_url = "https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken"
-- If model is gpt-4o, use o200k_base.tiktoken
if model ~= nil and vim.startswith(model, "gpt-4o") then
tiktoken_url = "https://openaipublic.blob.core.windows.net/encodings/o200k_base.tiktoken"
end
local async
---@cast async uv_async_t
async = vim.uv.new_async(function()
-- Take filename after the last slash of the url
local cache_path = get_cache_path(tiktoken_url:match(".+/(.+)"))
if not file_exists(cache_path) then
vim.schedule(function()
curl.get(tiktoken_url, {
output = cache_path,
})
done(cache_path)
end)
else
done(cache_path)
end
async:close()
end)
async:send()
end
local M = {}
---@param model string|nil
function M.setup(model)
local ok, core = pcall(require, "tiktoken_core")
if not ok then
return
end
load_tiktoken_data(function(path)
local special_tokens = {}
special_tokens["<|endoftext|>"] = 100257
special_tokens["<|fim_prefix|>"] = 100258
special_tokens["<|fim_middle|>"] = 100259
special_tokens["<|fim_suffix|>"] = 100260
special_tokens["<|endofprompt|>"] = 100276
local pat_str =
"(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\\r\\n\\p{L}\\p{N}]?\\p{L}+|\\p{N}{1,3}| ?[^\\s\\p{L}\\p{N}]+[\\r\\n]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+"
core.new(path, special_tokens, pat_str)
tiktoken_core = core
end, model)
end
function M.available()
return tiktoken_core ~= nil
end
---@param prompt string
---@return integer[] | nil
function M.encode(prompt)
if not tiktoken_core then
return nil
end
if not prompt or prompt == "" then
return nil
end
-- Check if prompt is a string
if type(prompt) ~= "string" then
error("Prompt must be a string")
end
return tiktoken_core.encode(prompt)
end
---@param prompt string
---@return integer
function M.count(prompt)
if not tiktoken_core then
return math.ceil(#prompt * 0.2) -- Fallback to 0.2 character count
end
local tokens = M.encode(prompt)
if not tokens then
return 0
end
return #tokens
end
return M

View File

@ -1,6 +1,4 @@
--Taken from https://github.com/jackMort/ChatGPT.nvim/blob/main/lua/chatgpt/flows/chat/tokens.lua
local Tiktoken = require("avante.tiktoken")
---@class avante.utils.tokens
local Tokens = {}
@ -13,9 +11,6 @@ local cost_per_token = {
---@param text string The text to calculate the number of tokens for.
---@return integer The number of tokens in the given text.
function Tokens.calculate_tokens(text)
if Tiktoken.available() then
return Tiktoken.count(text)
end
local tokens = 0
local current_token = ""
for char in text:gmatch(".") do

View File

@ -1,22 +0,0 @@
local M = {}
local function get_library_path()
local os_name = require("avante.utils").get_os_name()
local ext = os_name == "linux" and "so" or (os_name == "darwin" and "dylib" or "dll")
local dirname = string.sub(debug.getinfo(1).source, 2, #"/tiktoken_lib.lua" * -1)
return dirname .. ("../build/?.%s"):format(ext)
end
---@type fun(s: string): string
local trim_semicolon = function(s)
return s:sub(-1) == ";" and s:sub(1, -2) or s
end
M.load = function()
local library_path = get_library_path()
if not string.find(package.cpath, library_path, 1, true) then
package.cpath = trim_semicolon(package.cpath) .. ";" .. library_path
end
end
return M