Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ Custom providers can implement these methods:
-- Optional: Embeddings provider name or function
embed?: string|function,

-- Optional: Extra info about the provider displayed in info panel
get_info?(): string[]

-- Optional: Get extra request headers with optional expiration time
get_headers?(): table<string,string>, number?,

Expand Down
31 changes: 31 additions & 0 deletions lua/CopilotChat/client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,37 @@ function Client:models()
return self.model_cache
end

--- Get information about all providers
---@return table<string, string[]>
function Client:info()
local infos = {}
local now = math.floor(os.time())
local CACHE_TTL = 300 -- 5 minutes

for provider_name, provider in pairs(self.providers) do
if not provider.disabled and provider.get_info then
local cache = self.provider_cache[provider_name]
if cache and cache.info and cache.info_expires_at and cache.info_expires_at > now then
infos[provider_name] = cache.info
else
local ok, info = pcall(provider.get_info, self:authenticate(provider_name))
if ok then
infos[provider_name] = info
if cache then
cache.info = info
cache.info_expires_at = now + CACHE_TTL
end
else
log.warn('Failed to get info for provider ' .. provider_name .. ': ' .. info)
end
end
end
end

log.debug('Fetched provider infos:', #vim.tbl_keys(infos))
return infos
end

--- Ask a question to Copilot
---@param prompt string: The prompt to send to Copilot
---@param opts CopilotChat.client.AskOptions: Options for the request
Expand Down
10 changes: 10 additions & 0 deletions lua/CopilotChat/config/mappings.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local async = require('plenary.async')
local copilot = require('CopilotChat')
local client = require('CopilotChat.client')
local utils = require('CopilotChat.utils')

---@class CopilotChat.config.mappings.Diff
Expand Down Expand Up @@ -439,6 +440,7 @@ return {
local system_prompt = config.system_prompt

async.run(function()
local infos = client:info()
local selected_model = copilot.resolve_model(prompt, config)
local selected_tools, resolved_resources = copilot.resolve_functions(prompt, config)
selected_tools = vim.tbl_map(function(tool)
Expand All @@ -451,6 +453,14 @@ return {
table.insert(lines, '**Temp Files**: `' .. vim.fn.fnamemodify(os.tmpname(), ':h') .. '`')
table.insert(lines, '')

for provider, infolines in pairs(infos) do
table.insert(lines, '**Provider**: `' .. provider .. '`')
for _, line in ipairs(infolines) do
table.insert(lines, line)
end
table.insert(lines, '')
end

if source and utils.buf_valid(source.bufnr) then
local source_name = vim.api.nvim_buf_get_name(source.bufnr)
table.insert(lines, '**Source**: `' .. source_name .. '`')
Expand Down
51 changes: 51 additions & 0 deletions lua/CopilotChat/config/providers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ end
---@class CopilotChat.config.providers.Provider
---@field disabled nil|boolean
---@field get_headers nil|fun():table<string, string>,number?
---@field get_info nil|fun(headers:table):string[]
---@field get_models nil|fun(headers:table):table<CopilotChat.client.Model>
---@field embed nil|string|fun(inputs:table<string>, headers:table):table<CopilotChat.client.Embed>
---@field prepare_input nil|fun(inputs:table<CopilotChat.client.Message>, opts:CopilotChat.config.providers.Options):table
Expand Down Expand Up @@ -204,6 +205,56 @@ M.copilot = {
response.body.expires_at
end,

get_info = function(headers)
local response, err = utils.curl_get('https://api.github.com/copilot_internal/user', {
json_response = true,
headers = {
['Authorization'] = 'Token ' .. get_github_token('github_copilot'),
},
})

if err then
error(err)
end

local stats = response.body
local lines = {}

if not stats or not stats.quota_snapshots then
return { 'No Copilot stats available.' }
end

local function usage_line(name, snap)
if not snap then
return
end

table.insert(lines, string.format(' **%s**', name))

if snap.unlimited then
table.insert(lines, ' Usage: Unlimited')
else
local used = snap.entitlement - snap.remaining
local percent = snap.entitlement > 0 and (used / snap.entitlement * 100) or 0
table.insert(lines, string.format(' Usage: %d / %d (%.1f%%)', used, snap.entitlement, percent))
table.insert(lines, string.format(' Remaining: %d', snap.remaining))
if snap.overage_permitted ~= nil then
table.insert(lines, ' Overage: ' .. (snap.overage_permitted and 'Permitted' or 'Not Permitted'))
end
end
end

usage_line('Premium requests', stats.quota_snapshots.premium_interactions)
usage_line('Chat', stats.quota_snapshots.chat)
usage_line('Completions', stats.quota_snapshots.completions)

if stats.quota_reset_date then
table.insert(lines, string.format(' **Quota** resets on: %s', stats.quota_reset_date))
end

return lines
end,

get_models = function(headers)
local response, err = utils.curl_get('https://api.githubcopilot.com/models', {
json_response = true,
Expand Down
Loading