Use this file to discover all available pages before exploring further.
Avante.nvim’s flexible provider system allows you to integrate any AI service that offers a REST API. This guide shows you how to create custom providers.
For non-OpenAI-compatible APIs, create a custom module:
-- ~/.config/nvim/lua/custom/my_provider.lualocal Utils = require("avante.utils")local Providers = require("avante.providers")---@class AvanteProviderFunctorlocal M = {}M.api_key_name = "MY_PROVIDER_API_KEY"M.role_map = { user = "user", assistant = "assistant",}function M:is_disable_stream() return falseendfunction M:parse_messages(opts) local messages = {} -- Convert Avante message format to your provider's format for _, msg in ipairs(opts.messages) do table.insert(messages, { role = self.role_map[msg.role], content = msg.content, }) end return messagesendfunction M:parse_curl_args(prompt_opts) local provider_conf, request_body = Providers.parse_config(self) -- Get API key local api_key = self.parse_api_key() if not api_key then Utils.error("API key not found") return nil end return { url = provider_conf.endpoint .. "/chat/completions", headers = { ["Content-Type"] = "application/json", ["Authorization"] = "Bearer " .. api_key, }, body = vim.tbl_deep_extend("force", { model = provider_conf.model, messages = self:parse_messages(prompt_opts), stream = true, }, request_body), }endfunction M:parse_response(ctx, data_stream, event_state, opts) local ok, json = pcall(vim.json.decode, data_stream) if not ok then return end -- Parse your provider's response format if json.choices and json.choices[1] then local delta = json.choices[1].delta if delta and delta.content then if opts.on_chunk then opts.on_chunk(delta.content) end end if json.choices[1].finish_reason then opts.on_stop({ reason = "complete" }) end endendreturn M
function M:transform_tool(tool) -- Convert Avante tool format to your provider's format local input_schema_properties, required = Utils.llm_tool_param_fields_to_json_schema(tool.param.fields) return { name = tool.name, description = tool.description, parameters = { type = "object", properties = input_schema_properties, required = required, }, }endfunction M:parse_curl_args(prompt_opts) -- ... existing code ... local tools = nil if prompt_opts.tools then tools = {} for _, tool in ipairs(prompt_opts.tools) do table.insert(tools, self:transform_tool(tool)) end end return { -- ... existing code ... body = { -- ... existing code ... tools = tools, }, }end
function M:parse_response(ctx, data_stream, event_state, opts) -- SSE format: data: {json} local json_str = data_stream:match("^data: (.+)$") if not json_str or json_str == "[DONE]" then opts.on_stop({ reason = "complete" }) return end local ok, json = pcall(vim.json.decode, json_str) if ok and json.choices then local delta = json.choices[1].delta if delta and delta.content then opts.on_chunk(delta.content) end endend
function M:parse_response(ctx, data_stream, event_state, opts) local ok, json = pcall(vim.json.decode, data_stream) if not ok then return end -- Handle your JSON formatend
function M.on_error(result) if result.status == 429 then -- Rate limit handling return end local ok, body = pcall(vim.json.decode, result.body) if ok and body.error then Utils.error(body.error.message, { title = "My Provider" }) else Utils.error("Request failed: " .. result.status) endend
M.support_prompt_caching = truefunction M:parse_curl_args(prompt_opts) -- Mark content for caching local messages = self:parse_messages(prompt_opts) if self.support_prompt_caching then messages[#messages].cache_control = { type = "ephemeral" } end return { body = { messages = messages } }end
-- ~/.config/nvim/lua/custom/my_provider.lualocal Utils = require("avante.utils")local Providers = require("avante.providers")---@class AvanteProviderFunctorlocal M = {}M.api_key_name = "MY_PROVIDER_API_KEY"M.role_map = { user = "user", assistant = "assistant" }function M:is_disable_stream() return false endfunction M:parse_messages(opts) local messages = {{ role = "system", content = opts.system_prompt }} for _, msg in ipairs(opts.messages) do table.insert(messages, { role = self.role_map[msg.role], content = type(msg.content) == "string" and msg.content or "", }) end return messagesendfunction M:parse_curl_args(prompt_opts) local provider_conf, request_body = Providers.parse_config(self) local api_key = self.parse_api_key() if not api_key then Utils.error("API key not set") return nil end return { url = provider_conf.endpoint .. "/chat/completions", headers = { ["Content-Type"] = "application/json", ["Authorization"] = "Bearer " .. api_key, }, body = vim.tbl_deep_extend("force", { model = provider_conf.model, messages = self:parse_messages(prompt_opts), stream = true, }, request_body), }endfunction M:parse_response(ctx, data_stream, event_state, opts) if data_stream == "[DONE]" then opts.on_stop({ reason = "complete" }) return end local ok, json = pcall(vim.json.decode, data_stream) if ok and json.choices and json.choices[1] then local delta = json.choices[1].delta if delta and delta.content then if opts.on_chunk then opts.on_chunk(delta.content) end end if json.choices[1].finish_reason then opts.on_stop({ reason = "complete" }) end endendreturn M