n8n-nodes-github-copilot 3.20.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GitHubCopilotApi = void 0;
4
+ const GitHubCopilotEndpoints_1 = require("../shared/utils/GitHubCopilotEndpoints");
4
5
  class GitHubCopilotApi {
5
6
  constructor() {
6
7
  this.name = 'githubCopilotApi';
@@ -39,8 +40,8 @@ class GitHubCopilotApi {
39
40
  };
40
41
  this.test = {
41
42
  request: {
42
- baseURL: 'https://api.githubcopilot.com',
43
- url: '/models',
43
+ baseURL: GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.BASE_URL,
44
+ url: GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ENDPOINTS.MODELS,
44
45
  method: 'GET',
45
46
  },
46
47
  };
@@ -49,7 +49,7 @@ class GitHubCopilot {
49
49
  this.description = {
50
50
  displayName: 'GitHub Copilot',
51
51
  name: 'gitHubCopilot',
52
- icon: 'file:githubcopilot.svg',
52
+ icon: 'file:../../shared/icons/copilot.svg',
53
53
  group: ['transform'],
54
54
  version: 1,
55
55
  subtitle: '={{$parameter["operation"]}}',
@@ -5,6 +5,7 @@ const utils_1 = require("./utils");
5
5
  const nodeProperties_1 = require("./nodeProperties");
6
6
  const mediaDetection_1 = require("./utils/mediaDetection");
7
7
  const GitHubCopilotModels_1 = require("../../shared/models/GitHubCopilotModels");
8
+ const GitHubCopilotEndpoints_1 = require("../../shared/utils/GitHubCopilotEndpoints");
8
9
  class GitHubCopilotChatAPI {
9
10
  constructor() {
10
11
  this.description = {
@@ -30,7 +31,7 @@ class GitHubCopilotChatAPI {
30
31
  };
31
32
  }
32
33
  async execute() {
33
- var _a, _b, _c;
34
+ var _a, _b, _c, _d;
34
35
  const items = this.getInputData();
35
36
  const returnData = [];
36
37
  for (let i = 0; i < items.length; i++) {
@@ -41,6 +42,8 @@ class GitHubCopilotChatAPI {
41
42
  const userMessage = this.getNodeParameter('message', i);
42
43
  const systemMessage = this.getNodeParameter('systemMessage', i, '');
43
44
  const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
45
+ const enableRetry = advancedOptions.enableRetry !== false;
46
+ const maxRetries = advancedOptions.maxRetries || 3;
44
47
  const includeMedia = this.getNodeParameter('includeMedia', i, false);
45
48
  const modelInfo = GitHubCopilotModels_1.GitHubCopilotModelsManager.getModelByValue(model);
46
49
  if (includeMedia) {
@@ -104,13 +107,36 @@ class GitHubCopilotChatAPI {
104
107
  ...advancedOptions,
105
108
  };
106
109
  const hasMedia = includeMedia;
107
- const response = await (0, utils_1.makeApiRequest)(this, '/chat/completions', requestBody, hasMedia);
110
+ let response = null;
111
+ let attempt = 1;
112
+ while (attempt <= maxRetries + 1) {
113
+ try {
114
+ response = await (0, utils_1.makeApiRequest)(this, GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ENDPOINTS.CHAT_COMPLETIONS, requestBody, hasMedia);
115
+ break;
116
+ }
117
+ catch (error) {
118
+ const isLastAttempt = attempt >= maxRetries + 1;
119
+ const errorObj = error;
120
+ const is403Error = errorObj.status === 403 || ((_a = errorObj.message) === null || _a === void 0 ? void 0 : _a.includes('403'));
121
+ if (is403Error && enableRetry && !isLastAttempt) {
122
+ const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);
123
+ console.log(`GitHub Copilot API attempt ${attempt} failed with 403, retrying in ${delay}ms...`);
124
+ await new Promise(resolve => setTimeout(resolve, delay));
125
+ attempt++;
126
+ continue;
127
+ }
128
+ throw error;
129
+ }
130
+ }
131
+ if (!response) {
132
+ throw new Error('Failed to get response from GitHub Copilot API after all retry attempts');
133
+ }
108
134
  const result = {
109
- message: ((_b = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.content) || '',
135
+ message: ((_c = (_b = response.choices[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content) || '',
110
136
  model,
111
137
  operation,
112
138
  usage: response.usage || null,
113
- finish_reason: ((_c = response.choices[0]) === null || _c === void 0 ? void 0 : _c.finish_reason) || 'unknown',
139
+ finish_reason: ((_d = response.choices[0]) === null || _d === void 0 ? void 0 : _d.finish_reason) || 'unknown',
114
140
  };
115
141
  returnData.push({
116
142
  json: result,
@@ -167,6 +167,25 @@ exports.nodeProperties = [
167
167
  default: 1,
168
168
  description: 'Alternative to temperature, controls diversity via nucleus sampling',
169
169
  },
170
+ {
171
+ displayName: 'Auto Retry on 403 Error',
172
+ name: 'enableRetry',
173
+ type: 'boolean',
174
+ default: true,
175
+ description: 'Automatically retry requests when hitting TPM (Transactions Per Minute) quota limits (HTTP 403)',
176
+ },
177
+ {
178
+ displayName: 'Max Retry Attempts',
179
+ name: 'maxRetries',
180
+ type: 'number',
181
+ default: 3,
182
+ description: 'Maximum number of retry attempts for 403 errors',
183
+ displayOptions: {
184
+ show: {
185
+ enableRetry: [true],
186
+ },
187
+ },
188
+ },
170
189
  ],
171
190
  },
172
191
  ];
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GitHubCopilotChatModel = void 0;
4
4
  const openai_1 = require("@langchain/openai");
5
5
  const GitHubCopilotModels_1 = require("../../shared/models/GitHubCopilotModels");
6
+ const GitHubCopilotEndpoints_1 = require("../../shared/utils/GitHubCopilotEndpoints");
6
7
  class GitHubCopilotChatModel {
7
8
  constructor() {
8
9
  this.description = {
@@ -98,6 +99,25 @@ class GitHubCopilotChatModel {
98
99
  rows: 3,
99
100
  },
100
101
  },
102
+ {
103
+ displayName: 'Auto Retry on 403 Error',
104
+ name: 'enableRetry',
105
+ type: 'boolean',
106
+ default: true,
107
+ description: 'Automatically retry requests when hitting TPM (Transactions Per Minute) quota limits (HTTP 403)',
108
+ },
109
+ {
110
+ displayName: 'Max Retry Attempts',
111
+ name: 'maxRetries',
112
+ type: 'number',
113
+ default: 3,
114
+ description: 'Maximum number of retry attempts for 403 errors',
115
+ displayOptions: {
116
+ show: {
117
+ enableRetry: [true],
118
+ },
119
+ },
120
+ },
101
121
  ],
102
122
  },
103
123
  ],
@@ -130,8 +150,9 @@ class GitHubCopilotChatModel {
130
150
  temperature: options.temperature || 0.7,
131
151
  maxTokens: Math.min(options.maxTokens || 1000, (safeModelInfo === null || safeModelInfo === void 0 ? void 0 : safeModelInfo.capabilities.maxOutputTokens) || 4096),
132
152
  topP: options.topP || 1,
153
+ maxRetries: options.enableRetry !== false ? (options.maxRetries || 3) : 0,
133
154
  configuration: {
134
- baseURL: 'https://api.githubcopilot.com',
155
+ baseURL: GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.BASE_URL,
135
156
  apiKey: token,
136
157
  defaultHeaders: {
137
158
  'User-Agent': 'GitHubCopilotChat/1.0.0 n8n/3.10.1',
@@ -1,60 +1,87 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GitHubCopilotTest = void 0;
4
- async function listAvailableModels(token) {
5
- var _a, _b;
6
- try {
7
- const response = await fetch('https://api.githubcopilot.com/models', {
8
- method: 'GET',
9
- headers: {
10
- 'Authorization': `Bearer ${token}`,
11
- 'Accept': 'application/json',
12
- 'Content-Type': 'application/json',
13
- },
14
- });
15
- if (!response.ok) {
16
- const errorText = await response.text();
17
- throw new Error(`API Error ${response.status}: ${errorText}`);
4
+ const GitHubCopilotEndpoints_1 = require("../../shared/utils/GitHubCopilotEndpoints");
5
+ async function listAvailableModels(token, enableRetry = true, maxRetries = 3) {
6
+ const retryInfo = {
7
+ attempts: 1,
8
+ retries: [],
9
+ totalDelay: 0,
10
+ };
11
+ for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
12
+ try {
13
+ const response = await fetch(GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.getModelsUrl(), {
14
+ method: 'GET',
15
+ headers: GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.getAuthHeaders(token),
16
+ });
17
+ if (!response.ok) {
18
+ const errorText = await response.text();
19
+ if (GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.isTpmQuotaError(response.status) && enableRetry && attempt <= maxRetries) {
20
+ const delay = GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.getRetryDelay(attempt);
21
+ retryInfo.retries.push({
22
+ attempt: attempt,
23
+ error: `HTTP ${response.status}: ${errorText}`,
24
+ delay: delay,
25
+ timestamp: new Date().toISOString(),
26
+ });
27
+ retryInfo.totalDelay += delay;
28
+ retryInfo.attempts = attempt + 1;
29
+ console.log(`Attempt ${attempt} failed with 403, retrying in ${delay}ms...`);
30
+ await new Promise(resolve => setTimeout(resolve, delay));
31
+ continue;
32
+ }
33
+ throw new Error(`API Error ${response.status}: ${errorText}`);
34
+ }
35
+ const data = await response.json();
36
+ const summary = {
37
+ success: true,
38
+ timestamp: new Date().toISOString(),
39
+ retryInfo: {
40
+ totalAttempts: retryInfo.attempts,
41
+ totalRetries: retryInfo.retries.length,
42
+ totalDelay: retryInfo.totalDelay,
43
+ retryDetails: retryInfo.retries,
44
+ retryEnabled: enableRetry,
45
+ maxRetries: maxRetries,
46
+ },
47
+ ...data,
48
+ };
49
+ return summary;
18
50
  }
19
- const data = await response.json();
20
- const enabledModels = ((_a = data.data) === null || _a === void 0 ? void 0 : _a.filter((model) => model.model_picker_enabled !== false)) || [];
21
- const modelsByProvider = {};
22
- enabledModels.forEach((model) => {
23
- const provider = model.name.split('/')[0] || 'unknown';
24
- if (!modelsByProvider[provider]) {
25
- modelsByProvider[provider] = [];
51
+ catch (error) {
52
+ if (attempt >= maxRetries + 1 || !enableRetry) {
53
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
54
+ return {
55
+ success: false,
56
+ timestamp: new Date().toISOString(),
57
+ error: errorMessage,
58
+ details: 'Failed to fetch models from GitHub Copilot API',
59
+ retryInfo: {
60
+ totalAttempts: retryInfo.attempts,
61
+ totalRetries: retryInfo.retries.length,
62
+ totalDelay: retryInfo.totalDelay,
63
+ retryDetails: retryInfo.retries,
64
+ retryEnabled: enableRetry,
65
+ maxRetries: maxRetries,
66
+ },
67
+ };
26
68
  }
27
- modelsByProvider[provider].push({
28
- id: model.id,
29
- name: model.name,
30
- displayName: model.display_name,
31
- capabilities: model.capabilities || [],
32
- });
33
- });
34
- const summary = {
35
- success: true,
36
- timestamp: new Date().toISOString(),
37
- totalModels: ((_b = data.data) === null || _b === void 0 ? void 0 : _b.length) || 0,
38
- enabledModels: enabledModels.length,
39
- modelsByProvider,
40
- models: enabledModels.map((model) => ({
41
- id: model.id,
42
- name: model.name,
43
- displayName: model.display_name,
44
- capabilities: model.capabilities || [],
45
- })),
46
- };
47
- return summary;
48
- }
49
- catch (error) {
50
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
51
- return {
52
- success: false,
53
- timestamp: new Date().toISOString(),
54
- error: errorMessage,
55
- details: 'Failed to fetch models from GitHub Copilot API',
56
- };
69
+ }
57
70
  }
71
+ return {
72
+ success: false,
73
+ timestamp: new Date().toISOString(),
74
+ error: 'Maximum retry attempts exceeded',
75
+ details: 'Failed to fetch models after all retry attempts',
76
+ retryInfo: {
77
+ totalAttempts: retryInfo.attempts,
78
+ totalRetries: retryInfo.retries.length,
79
+ totalDelay: retryInfo.totalDelay,
80
+ retryDetails: retryInfo.retries,
81
+ retryEnabled: enableRetry,
82
+ maxRetries: maxRetries,
83
+ },
84
+ };
58
85
  }
59
86
  class GitHubCopilotTest {
60
87
  constructor() {
@@ -93,6 +120,25 @@ class GitHubCopilotTest {
93
120
  default: 'listModels',
94
121
  description: 'Select the test function to execute',
95
122
  },
123
+ {
124
+ displayName: 'Auto Retry on 403 Error',
125
+ name: 'enableRetry',
126
+ type: 'boolean',
127
+ default: true,
128
+ description: 'Automatically retry requests when hitting TPM (Transactions Per Minute) quota limits (HTTP 403)',
129
+ },
130
+ {
131
+ displayName: 'Max Retry Attempts',
132
+ name: 'maxRetries',
133
+ type: 'number',
134
+ default: 3,
135
+ description: 'Maximum number of retry attempts for 403 errors',
136
+ displayOptions: {
137
+ show: {
138
+ enableRetry: [true],
139
+ },
140
+ },
141
+ },
96
142
  ],
97
143
  };
98
144
  }
@@ -102,18 +148,20 @@ class GitHubCopilotTest {
102
148
  for (let i = 0; i < items.length; i++) {
103
149
  try {
104
150
  const testFunction = this.getNodeParameter('testFunction', i);
151
+ const enableRetry = this.getNodeParameter('enableRetry', i);
152
+ const maxRetries = this.getNodeParameter('maxRetries', i);
105
153
  const credentials = await this.getCredentials('githubCopilotApi', i);
106
154
  if (!(credentials === null || credentials === void 0 ? void 0 : credentials.token)) {
107
- throw new Error('GitHub Copilot API credentials are required');
155
+ throw new Error(GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ERRORS.CREDENTIALS_REQUIRED);
108
156
  }
109
157
  const token = credentials.token;
110
- if (!token.startsWith('gho_')) {
111
- throw new Error('Invalid token format. GitHub Copilot API requires tokens starting with "gho_"');
158
+ if (!GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.validateToken(token)) {
159
+ throw new Error(GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ERRORS.INVALID_TOKEN);
112
160
  }
113
161
  let result = {};
114
162
  switch (testFunction) {
115
163
  case 'listModels':
116
- result = await listAvailableModels(token);
164
+ result = await listAvailableModels(token, enableRetry, maxRetries);
117
165
  break;
118
166
  default:
119
167
  throw new Error(`Unknown test function: ${testFunction}`);
@@ -0,0 +1,34 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
2
+ <defs>
3
+ <linearGradient id="copilotGradient" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" style="stop-color:#1f6feb;stop-opacity:1" />
5
+ <stop offset="100%" style="stop-color:#0969da;stop-opacity:1" />
6
+ </linearGradient>
7
+ </defs>
8
+
9
+ <!-- GitHub Copilot inspired icon -->
10
+ <circle cx="12" cy="12" r="11" fill="url(#copilotGradient)" stroke="#ffffff" stroke-width="1"/>
11
+
12
+ <!-- Copilot face -->
13
+ <ellipse cx="12" cy="10" rx="8" ry="6" fill="#ffffff" opacity="0.9"/>
14
+
15
+ <!-- Eyes -->
16
+ <circle cx="9" cy="9" r="1.5" fill="#1f6feb"/>
17
+ <circle cx="15" cy="9" r="1.5" fill="#1f6feb"/>
18
+
19
+ <!-- Light reflection in eyes -->
20
+ <circle cx="9.5" cy="8.5" r="0.5" fill="#ffffff"/>
21
+ <circle cx="15.5" cy="8.5" r="0.5" fill="#ffffff"/>
22
+
23
+ <!-- Mouth/Interface line -->
24
+ <path d="M8 12 L16 12" stroke="#1f6feb" stroke-width="1.5" stroke-linecap="round"/>
25
+
26
+ <!-- Code brackets -->
27
+ <path d="M6 15 L8 17 L6 19" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
28
+ <path d="M18 15 L16 17 L18 19" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
29
+
30
+ <!-- AI indicator dots -->
31
+ <circle cx="10" cy="17" r="0.5" fill="#ffffff" opacity="0.8"/>
32
+ <circle cx="12" cy="17" r="0.5" fill="#ffffff" opacity="0.6"/>
33
+ <circle cx="14" cy="17" r="0.5" fill="#ffffff" opacity="0.4"/>
34
+ </svg>
@@ -9,6 +9,7 @@ exports.validateFileSize = validateFileSize;
9
9
  exports.estimateTokens = estimateTokens;
10
10
  exports.validateTokenLimit = validateTokenLimit;
11
11
  exports.truncateToTokenLimit = truncateToTokenLimit;
12
+ const GitHubCopilotEndpoints_1 = require("./GitHubCopilotEndpoints");
12
13
  async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = false) {
13
14
  var _a;
14
15
  const credentials = await context.getCredentials('githubCopilotApi');
@@ -42,7 +43,7 @@ async function makeGitHubCopilotRequest(context, endpoint, body, hasMedia = fals
42
43
  headers,
43
44
  body: JSON.stringify(body),
44
45
  };
45
- const response = await fetch(`https://api.githubcopilot.com${endpoint}`, options);
46
+ const response = await fetch(`${GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.BASE_URL}${endpoint}`, options);
46
47
  if (!response.ok) {
47
48
  const errorText = await response.text();
48
49
  const tokenPrefix = token.substring(0, 4);
@@ -0,0 +1,67 @@
1
+ export declare const GITHUB_COPILOT_API: {
2
+ readonly BASE_URL: "https://api.githubcopilot.com";
3
+ readonly GITHUB_BASE_URL: "https://api.github.com";
4
+ readonly ENDPOINTS: {
5
+ readonly MODELS: "/models";
6
+ readonly CHAT_COMPLETIONS: "/chat/completions";
7
+ readonly ORG_BILLING: (org: string) => string;
8
+ readonly ORG_SEATS: (org: string) => string;
9
+ readonly USER_COPILOT: "/user/copilot_access";
10
+ };
11
+ readonly URLS: {
12
+ readonly MODELS: "https://api.githubcopilot.com/models";
13
+ readonly CHAT_COMPLETIONS: "https://api.githubcopilot.com/chat/completions";
14
+ readonly ORG_BILLING: (org: string) => string;
15
+ readonly ORG_SEATS: (org: string) => string;
16
+ readonly USER_COPILOT: "https://api.github.com/user/copilot_access";
17
+ };
18
+ readonly HEADERS: {
19
+ readonly DEFAULT: {
20
+ readonly Accept: "application/json";
21
+ readonly 'Content-Type': "application/json";
22
+ };
23
+ readonly WITH_AUTH: (token: string) => {
24
+ Authorization: string;
25
+ Accept: string;
26
+ 'Content-Type': string;
27
+ };
28
+ readonly VSCODE_CLIENT: {
29
+ readonly 'User-Agent': "VSCode-Copilot";
30
+ readonly 'X-GitHub-Api-Version': "2022-11-28";
31
+ };
32
+ };
33
+ readonly RATE_LIMITS: {
34
+ readonly TPM_RETRY_DELAY_BASE: 1000;
35
+ readonly TPM_RETRY_MAX_DELAY: 10000;
36
+ readonly DEFAULT_MAX_RETRIES: 3;
37
+ readonly EXPONENTIAL_BACKOFF_FACTOR: 2;
38
+ };
39
+ readonly STATUS_CODES: {
40
+ readonly OK: 200;
41
+ readonly UNAUTHORIZED: 401;
42
+ readonly FORBIDDEN: 403;
43
+ readonly NOT_FOUND: 404;
44
+ readonly TOO_MANY_REQUESTS: 429;
45
+ readonly INTERNAL_SERVER_ERROR: 500;
46
+ };
47
+ readonly ERRORS: {
48
+ readonly INVALID_TOKEN: "Invalid token format. GitHub Copilot API requires tokens starting with \"gho_\"";
49
+ readonly CREDENTIALS_REQUIRED: "GitHub Copilot API credentials are required";
50
+ readonly TPM_QUOTA_EXCEEDED: "TPM (Transactions Per Minute) quota exceeded";
51
+ readonly API_ERROR: (status: number, message: string) => string;
52
+ };
53
+ };
54
+ export type GitHubCopilotEndpoint = keyof typeof GITHUB_COPILOT_API.ENDPOINTS;
55
+ export type GitHubCopilotUrl = keyof typeof GITHUB_COPILOT_API.URLS;
56
+ export type GitHubCopilotStatusCode = typeof GITHUB_COPILOT_API.STATUS_CODES[keyof typeof GITHUB_COPILOT_API.STATUS_CODES];
57
+ export declare class GitHubCopilotEndpoints {
58
+ static getModelsUrl(): string;
59
+ static getChatCompletionsUrl(): string;
60
+ static getOrgBillingUrl(org: string): string;
61
+ static getOrgSeatsUrl(org: string): string;
62
+ static getUserCopilotUrl(): string;
63
+ static getAuthHeaders(token: string, includeVSCodeHeaders?: boolean): Record<string, string>;
64
+ static getRetryDelay(attempt: number): number;
65
+ static isTpmQuotaError(statusCode: number): boolean;
66
+ static validateToken(token: string): boolean;
67
+ }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubCopilotEndpoints = exports.GITHUB_COPILOT_API = void 0;
4
+ exports.GITHUB_COPILOT_API = {
5
+ BASE_URL: 'https://api.githubcopilot.com',
6
+ GITHUB_BASE_URL: 'https://api.github.com',
7
+ ENDPOINTS: {
8
+ MODELS: '/models',
9
+ CHAT_COMPLETIONS: '/chat/completions',
10
+ ORG_BILLING: (org) => `/orgs/${org}/copilot/billing`,
11
+ ORG_SEATS: (org) => `/orgs/${org}/copilot/billing/seats`,
12
+ USER_COPILOT: '/user/copilot_access',
13
+ },
14
+ URLS: {
15
+ MODELS: 'https://api.githubcopilot.com/models',
16
+ CHAT_COMPLETIONS: 'https://api.githubcopilot.com/chat/completions',
17
+ ORG_BILLING: (org) => `https://api.github.com/orgs/${org}/copilot/billing`,
18
+ ORG_SEATS: (org) => `https://api.github.com/orgs/${org}/copilot/billing/seats`,
19
+ USER_COPILOT: 'https://api.github.com/user/copilot_access',
20
+ },
21
+ HEADERS: {
22
+ DEFAULT: {
23
+ 'Accept': 'application/json',
24
+ 'Content-Type': 'application/json',
25
+ },
26
+ WITH_AUTH: (token) => ({
27
+ 'Authorization': `Bearer ${token}`,
28
+ 'Accept': 'application/json',
29
+ 'Content-Type': 'application/json',
30
+ }),
31
+ VSCODE_CLIENT: {
32
+ 'User-Agent': 'VSCode-Copilot',
33
+ 'X-GitHub-Api-Version': '2022-11-28',
34
+ },
35
+ },
36
+ RATE_LIMITS: {
37
+ TPM_RETRY_DELAY_BASE: 1000,
38
+ TPM_RETRY_MAX_DELAY: 10000,
39
+ DEFAULT_MAX_RETRIES: 3,
40
+ EXPONENTIAL_BACKOFF_FACTOR: 2,
41
+ },
42
+ STATUS_CODES: {
43
+ OK: 200,
44
+ UNAUTHORIZED: 401,
45
+ FORBIDDEN: 403,
46
+ NOT_FOUND: 404,
47
+ TOO_MANY_REQUESTS: 429,
48
+ INTERNAL_SERVER_ERROR: 500,
49
+ },
50
+ ERRORS: {
51
+ INVALID_TOKEN: 'Invalid token format. GitHub Copilot API requires tokens starting with "gho_"',
52
+ CREDENTIALS_REQUIRED: 'GitHub Copilot API credentials are required',
53
+ TPM_QUOTA_EXCEEDED: 'TPM (Transactions Per Minute) quota exceeded',
54
+ API_ERROR: (status, message) => `API Error ${status}: ${message}`,
55
+ },
56
+ };
57
+ class GitHubCopilotEndpoints {
58
+ static getModelsUrl() {
59
+ return exports.GITHUB_COPILOT_API.URLS.MODELS;
60
+ }
61
+ static getChatCompletionsUrl() {
62
+ return exports.GITHUB_COPILOT_API.URLS.CHAT_COMPLETIONS;
63
+ }
64
+ static getOrgBillingUrl(org) {
65
+ return exports.GITHUB_COPILOT_API.URLS.ORG_BILLING(org);
66
+ }
67
+ static getOrgSeatsUrl(org) {
68
+ return exports.GITHUB_COPILOT_API.URLS.ORG_SEATS(org);
69
+ }
70
+ static getUserCopilotUrl() {
71
+ return exports.GITHUB_COPILOT_API.URLS.USER_COPILOT;
72
+ }
73
+ static getAuthHeaders(token, includeVSCodeHeaders = false) {
74
+ const headers = exports.GITHUB_COPILOT_API.HEADERS.WITH_AUTH(token);
75
+ if (includeVSCodeHeaders) {
76
+ return {
77
+ ...headers,
78
+ ...exports.GITHUB_COPILOT_API.HEADERS.VSCODE_CLIENT,
79
+ };
80
+ }
81
+ return headers;
82
+ }
83
+ static getRetryDelay(attempt) {
84
+ const delay = exports.GITHUB_COPILOT_API.RATE_LIMITS.TPM_RETRY_DELAY_BASE *
85
+ Math.pow(exports.GITHUB_COPILOT_API.RATE_LIMITS.EXPONENTIAL_BACKOFF_FACTOR, attempt - 1);
86
+ return Math.min(delay, exports.GITHUB_COPILOT_API.RATE_LIMITS.TPM_RETRY_MAX_DELAY);
87
+ }
88
+ static isTpmQuotaError(statusCode) {
89
+ return statusCode === exports.GITHUB_COPILOT_API.STATUS_CODES.FORBIDDEN;
90
+ }
91
+ static validateToken(token) {
92
+ return typeof token === 'string' && token.startsWith('gho_');
93
+ }
94
+ }
95
+ exports.GitHubCopilotEndpoints = GitHubCopilotEndpoints;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "3.20.0",
3
+ "version": "3.23.0",
4
4
  "description": "n8n community node for GitHub Copilot with CLI integration, Chat API access, and AI Chat Model for workflows - access GPT-5, Claude, Gemini and more using your Copilot subscription",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",