@@ -2,6 +2,98 @@ import { randomUUID } from "node:crypto"
22
33import type { State } from "./state"
44
5+ export const isOpencodeOauthApp = ( ) : boolean => {
6+ return process . env . COPILOT_API_OAUTH_APP === "opencode"
7+ }
8+
9+ export const normalizeDomain = ( input : string ) : string => {
10+ return input
11+ . trim ( )
12+ . replace ( / ^ h t t p s ? : \/ \/ / u, "" )
13+ . replace ( / \/ + $ / u, "" )
14+ }
15+
16+ export const getEnterpriseDomain = ( ) : string | null => {
17+ const raw = ( process . env . COPILOT_API_ENTERPRISE_URL ?? "" ) . trim ( )
18+ if ( ! raw ) return null
19+ const normalized = normalizeDomain ( raw )
20+ return normalized || null
21+ }
22+
23+ export const getGitHubBaseUrl = ( ) : string => {
24+ const resolvedDomain = getEnterpriseDomain ( )
25+ return resolvedDomain ? `https://${ resolvedDomain } ` : GITHUB_BASE_URL
26+ }
27+
28+ export const getGitHubApiBaseUrl = ( ) : string => {
29+ const resolvedDomain = getEnterpriseDomain ( )
30+ return resolvedDomain ?
31+ `https://${ resolvedDomain } /api/v3`
32+ : GITHUB_API_BASE_URL
33+ }
34+
35+ export const getOpencodeOauthHeaders = ( ) : Record < string , string > => {
36+ return {
37+ Accept : "application/json" ,
38+ "Content-Type" : "application/json" ,
39+ "User-Agent" :
40+ "opencode/1.2.16 ai-sdk/provider-utils/3.0.21 runtime/bun/1.3.10, opencode/1.2.16" ,
41+ }
42+ }
43+
44+ export const getOauthUrls = ( ) : {
45+ deviceCodeUrl : string
46+ accessTokenUrl : string
47+ } => {
48+ const githubBaseUrl = getGitHubBaseUrl ( )
49+
50+ return {
51+ deviceCodeUrl : `${ githubBaseUrl } /login/device/code` ,
52+ accessTokenUrl : `${ githubBaseUrl } /login/oauth/access_token` ,
53+ }
54+ }
55+
56+ interface OauthAppConfig {
57+ clientId : string
58+ headers : Record < string , string >
59+ scope : string
60+ }
61+
62+ export const getOauthAppConfig = ( ) : OauthAppConfig => {
63+ if ( isOpencodeOauthApp ( ) ) {
64+ return {
65+ clientId : OPENCODE_GITHUB_CLIENT_ID ,
66+ headers : getOpencodeOauthHeaders ( ) ,
67+ scope : GITHUB_APP_SCOPES ,
68+ }
69+ }
70+
71+ return {
72+ clientId : GITHUB_CLIENT_ID ,
73+ headers : standardHeaders ( ) ,
74+ scope : GITHUB_APP_SCOPES ,
75+ }
76+ }
77+
78+ export const prepareInteractionHeaders = (
79+ sessionId : string | undefined ,
80+ isSubagent : boolean ,
81+ headers : Record < string , string > ,
82+ ) => {
83+ const sendInteractionHeaders = ! isOpencodeOauthApp ( )
84+
85+ if ( isSubagent ) {
86+ headers [ "x-initiator" ] = "agent"
87+ if ( sendInteractionHeaders ) {
88+ headers [ "x-interaction-type" ] = "conversation-subagent"
89+ }
90+ }
91+
92+ if ( sessionId && sendInteractionHeaders ) {
93+ headers [ "x-interaction-id" ] = sessionId
94+ }
95+ }
96+
597export const standardHeaders = ( ) => ( {
698 "content-type" : "application/json" ,
799 accept : "application/json" ,
@@ -13,15 +105,34 @@ const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`
13105
14106const API_VERSION = "2025-10-01"
15107
16- export const copilotBaseUrl = ( state : State ) =>
17- state . accountType === "individual" ?
18- "https://api.githubcopilot.com"
19- : `https://api.${ state . accountType } .githubcopilot.com`
108+ export const copilotBaseUrl = ( state : State ) => {
109+ const enterpriseDomain = getEnterpriseDomain ( )
110+ if ( enterpriseDomain ) {
111+ return `https://copilot-api.${ enterpriseDomain } `
112+ }
113+
114+ return state . accountType === "individual" ?
115+ "https://api.githubcopilot.com"
116+ : `https://api.${ state . accountType } .githubcopilot.com`
117+ }
118+
20119export const copilotHeaders = (
21120 state : State ,
22121 requestId ?: string ,
23122 vision : boolean = false ,
24123) => {
124+ if ( isOpencodeOauthApp ( ) ) {
125+ const headers : Record < string , string > = {
126+ Authorization : `Bearer ${ state . copilotToken } ` ,
127+ ...getOpencodeOauthHeaders ( ) ,
128+ "Openai-Intent" : "conversation-edits" ,
129+ }
130+
131+ if ( vision ) headers [ "Copilot-Vision-Request" ] = "true"
132+
133+ return headers
134+ }
135+
25136 const requestIdValue = requestId ?? randomUUID ( )
26137 const headers : Record < string , string > = {
27138 Authorization : `Bearer ${ state . copilotToken } ` ,
@@ -65,3 +176,4 @@ export const githubHeaders = (state: State) => ({
65176export const GITHUB_BASE_URL = "https://github.com"
66177export const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98"
67178export const GITHUB_APP_SCOPES = [ "read:user" ] . join ( " " )
179+ export const OPENCODE_GITHUB_CLIENT_ID = "Ov23li8tweQw6odWQebz"
0 commit comments