@@ -196,6 +196,22 @@ local function get_github_models_token(tag)
196196 return github_device_flow (tag , ' 178c6fc778ccc68e1d6a' , ' read:user copilot' )
197197end
198198
199+ --- Resolve the Copilot API base URL from token endpoint response.
200+ --- Falls back to the default api.githubcopilot.com if no business endpoint is found.
201+ --- @param token_body table The decoded JSON body from the token endpoint
202+ --- @return string base_url The base URL (no trailing slash )
203+ local function resolve_copilot_base_url (token_body )
204+ -- The token response may include an `endpoints` table with an `api` field
205+ -- pointing to the correct base URL for business/enterprise accounts,
206+ -- e.g. https://api.business.githubcopilot.com
207+ if token_body and token_body .endpoints and token_body .endpoints .api then
208+ local url = token_body .endpoints .api
209+ -- Strip trailing slash if present
210+ return url :gsub (' /$' , ' ' )
211+ end
212+ return ' https://api.githubcopilot.com'
213+ end
214+
199215--- Prepare input for Responses API
200216--- @param inputs CopilotChat.client.Message[]
201217--- @param opts CopilotChat.config.providers.Options
@@ -537,12 +553,19 @@ M.copilot = {
537553 error (err )
538554 end
539555
556+ -- Resolve the base URL from the token response so that business/enterprise
557+ -- accounts using *.business.githubcopilot.com are handled automatically.
558+ local base_url = resolve_copilot_base_url (response .body )
559+
540560 return {
541561 [' Authorization' ] = ' Bearer ' .. response .body .token ,
542562 [' Editor-Version' ] = EDITOR_VERSION ,
543563 [' Editor-Plugin-Version' ] = ' CopilotChat.nvim/*' ,
544564 [' Copilot-Integration-Id' ] = ' vscode-chat' ,
545565 [' x-github-api-version' ] = ' 2025-10-01' ,
566+ -- Store the resolved base URL in a custom header so that get_models,
567+ -- resolve_model, and get_url can read it without making another request.
568+ [' x-copilot-base-url' ] = base_url ,
546569 },
547570 response .body .expires_at
548571 end ,
@@ -598,9 +621,16 @@ M.copilot = {
598621 end ,
599622
600623 get_models = function (headers )
601- local response , err = curl .get (' https://api.githubcopilot.com/models' , {
624+ -- Use the resolved base URL carried in the custom header, falling back to
625+ -- the default if it is absent (e.g. during tests or manual calls).
626+ local base_url = headers [' x-copilot-base-url' ] or ' https://api.githubcopilot.com'
627+
628+ -- Build request headers without our internal routing header.
629+ local request_headers = vim .tbl_extend (' force' , headers , { [' x-copilot-base-url' ] = nil })
630+
631+ local response , err = curl .get (base_url .. ' /models' , {
602632 json_response = true ,
603- headers = headers ,
633+ headers = request_headers ,
604634 })
605635
606636 if err then
@@ -628,6 +658,9 @@ M.copilot = {
628658 policy = not model [' policy' ] or model [' policy' ][' state' ] == ' enabled' ,
629659 version = model .version ,
630660 use_responses = use_responses ,
661+ -- Carry the base URL into the model so get_url and resolve_model
662+ -- can use it without needing access to the headers again.
663+ base_url = base_url ,
631664 }
632665 end )
633666 :totable ()
@@ -643,8 +676,8 @@ M.copilot = {
643676
644677 for _ , model in ipairs (models ) do
645678 if not model .policy then
646- pcall (curl .post , ' https://api.githubcopilot.com /models/' .. model .id .. ' /policy' , {
647- headers = headers ,
679+ pcall (curl .post , base_url .. ' /models/' .. model .id .. ' /policy' , {
680+ headers = request_headers ,
648681 json_request = true ,
649682 body = { state = ' enabled' },
650683 })
@@ -656,6 +689,7 @@ M.copilot = {
656689 id = ' auto' ,
657690 name = ' Auto (Copilot)' ,
658691 description = ' Auto selects the best model for your request.' ,
692+ base_url = base_url ,
659693 })
660694
661695 return models
@@ -666,9 +700,12 @@ M.copilot = {
666700 return model
667701 end
668702
669- local url = ' https://api.githubcopilot.com/models/session'
703+ local base_url = headers [' x-copilot-base-url' ] or ' https://api.githubcopilot.com'
704+ local request_headers = vim .tbl_extend (' force' , headers , { [' x-copilot-base-url' ] = nil })
705+
706+ local url = base_url .. ' /models/session'
670707 local response , err = curl .post (url , {
671- headers = headers ,
708+ headers = request_headers ,
672709 body = { auto_mode = { model_hints = { ' auto' } } },
673710 json_response = true ,
674711 json_request = true ,
@@ -707,10 +744,14 @@ M.copilot = {
707744 end ,
708745
709746 get_url = function (opts )
747+ -- Use the base URL stored on the model (populated by get_models), falling
748+ -- back to the default for backwards compatibility.
749+ local base_url = (opts and opts .model and opts .model .base_url ) or ' https://api.githubcopilot.com'
750+
710751 if opts and opts .model and opts .model .use_responses then
711- return ' https://api.githubcopilot.com /responses'
752+ return base_url .. ' /responses'
712753 end
713- return ' https://api.githubcopilot.com /chat/completions'
754+ return base_url .. ' /chat/completions'
714755 end ,
715756}
716757
0 commit comments