n8n-nodes-github-copilot 3.18.1 → 3.22.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.
- package/dist/credentials/GitHubCopilotApi.credentials.js +3 -2
- package/dist/nodes/GitHubCopilot/GitHubCopilot.node.js +83 -4
- package/dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js +1 -1
- package/dist/nodes/GitHubCopilotChatModel/GitHubCopilotChatModel.node.js +3 -2
- package/dist/nodes/GitHubCopilotTest/GitHubCopilotTest.node.d.ts +5 -0
- package/dist/nodes/GitHubCopilotTest/GitHubCopilotTest.node.js +193 -0
- package/dist/nodes/GitHubCopilotTest/copilot.svg +34 -0
- package/dist/shared/utils/GitHubCopilotApiUtils.js +2 -1
- package/dist/shared/utils/GitHubCopilotEndpoints.d.ts +67 -0
- package/dist/shared/utils/GitHubCopilotEndpoints.js +95 -0
- package/package.json +3 -2
|
@@ -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:
|
|
43
|
-
url:
|
|
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
|
};
|
|
@@ -102,6 +102,18 @@ class GitHubCopilot {
|
|
|
102
102
|
description: 'Get shell command suggestions from GitHub Copilot',
|
|
103
103
|
action: 'Get shell command suggestions',
|
|
104
104
|
},
|
|
105
|
+
{
|
|
106
|
+
name: 'Revise',
|
|
107
|
+
value: 'revise',
|
|
108
|
+
description: 'Revise and improve existing code or commands',
|
|
109
|
+
action: 'Revise code or commands',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'Rate Response',
|
|
113
|
+
value: 'rating',
|
|
114
|
+
description: 'Rate a previous GitHub Copilot response',
|
|
115
|
+
action: 'Rate response',
|
|
116
|
+
},
|
|
105
117
|
],
|
|
106
118
|
default: 'suggest',
|
|
107
119
|
},
|
|
@@ -181,6 +193,59 @@ class GitHubCopilot {
|
|
|
181
193
|
placeholder: 'Any additional context or constraints...',
|
|
182
194
|
description: 'Optional additional context to provide better suggestions',
|
|
183
195
|
},
|
|
196
|
+
{
|
|
197
|
+
displayName: 'Original Code/Command',
|
|
198
|
+
name: 'originalCode',
|
|
199
|
+
type: 'string',
|
|
200
|
+
typeOptions: {
|
|
201
|
+
rows: 4,
|
|
202
|
+
},
|
|
203
|
+
required: true,
|
|
204
|
+
default: '',
|
|
205
|
+
placeholder: 'Enter the original code or command to revise...',
|
|
206
|
+
description: 'The original code or command that you want to improve',
|
|
207
|
+
displayOptions: {
|
|
208
|
+
show: {
|
|
209
|
+
operation: ['revise'],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
displayName: 'Rating',
|
|
215
|
+
name: 'rating',
|
|
216
|
+
type: 'options',
|
|
217
|
+
options: [
|
|
218
|
+
{ name: 'Very Good', value: 'very-good' },
|
|
219
|
+
{ name: 'Good', value: 'good' },
|
|
220
|
+
{ name: 'Fair', value: 'fair' },
|
|
221
|
+
{ name: 'Poor', value: 'poor' },
|
|
222
|
+
],
|
|
223
|
+
required: true,
|
|
224
|
+
default: 'good',
|
|
225
|
+
description: 'Rate the GitHub Copilot response',
|
|
226
|
+
displayOptions: {
|
|
227
|
+
show: {
|
|
228
|
+
operation: ['rating'],
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
displayName: 'Response to Rate',
|
|
234
|
+
name: 'responseToRate',
|
|
235
|
+
type: 'string',
|
|
236
|
+
typeOptions: {
|
|
237
|
+
rows: 3,
|
|
238
|
+
},
|
|
239
|
+
required: true,
|
|
240
|
+
default: '',
|
|
241
|
+
placeholder: 'Enter the GitHub Copilot response you want to rate...',
|
|
242
|
+
description: 'The GitHub Copilot response that you want to rate',
|
|
243
|
+
displayOptions: {
|
|
244
|
+
show: {
|
|
245
|
+
operation: ['rating'],
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
184
249
|
],
|
|
185
250
|
};
|
|
186
251
|
}
|
|
@@ -220,11 +285,11 @@ class GitHubCopilot {
|
|
|
220
285
|
fullPrompt = `[${language}] ${fullPrompt}`;
|
|
221
286
|
}
|
|
222
287
|
const escapedSuggestPrompt = fullPrompt.replace(/'/g, `'"'"'`);
|
|
223
|
-
command =
|
|
288
|
+
command = `gh copilot suggest '${escapedSuggestPrompt}'`;
|
|
224
289
|
break;
|
|
225
290
|
case 'explain':
|
|
226
291
|
const escapedExplainPrompt = fullPrompt.replace(/'/g, `'"'"'`);
|
|
227
|
-
command =
|
|
292
|
+
command = `gh copilot explain '${escapedExplainPrompt}'`;
|
|
228
293
|
break;
|
|
229
294
|
case 'shell':
|
|
230
295
|
const commandType = this.getNodeParameter('commandType', i);
|
|
@@ -246,7 +311,19 @@ class GitHubCopilot {
|
|
|
246
311
|
shellPrompt = fullPrompt;
|
|
247
312
|
}
|
|
248
313
|
const escapedShellPrompt = shellPrompt.replace(/'/g, `'"'"'`);
|
|
249
|
-
command =
|
|
314
|
+
command = `gh copilot suggest '${escapedShellPrompt}' --type shell`;
|
|
315
|
+
break;
|
|
316
|
+
case 'revise':
|
|
317
|
+
const originalCode = this.getNodeParameter('originalCode', i);
|
|
318
|
+
const revisePrompt = `${fullPrompt}\n\nOriginal code/command:\n${originalCode}`;
|
|
319
|
+
const escapedRevisePrompt = revisePrompt.replace(/'/g, `'"'"'`);
|
|
320
|
+
command = `gh copilot revise '${escapedRevisePrompt}'`;
|
|
321
|
+
break;
|
|
322
|
+
case 'rating':
|
|
323
|
+
const rating = this.getNodeParameter('rating', i);
|
|
324
|
+
const responseToRate = this.getNodeParameter('responseToRate', i);
|
|
325
|
+
const escapedResponseToRate = responseToRate.replace(/'/g, `'"'"'`);
|
|
326
|
+
command = `gh copilot rate '${escapedResponseToRate}' --rating ${rating}`;
|
|
250
327
|
break;
|
|
251
328
|
default:
|
|
252
329
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`);
|
|
@@ -259,7 +336,6 @@ class GitHubCopilot {
|
|
|
259
336
|
try {
|
|
260
337
|
const envVars = {
|
|
261
338
|
...process.env,
|
|
262
|
-
HOME: '/opt/n8n-source/packages/cli/bin',
|
|
263
339
|
};
|
|
264
340
|
if (useToken) {
|
|
265
341
|
envVars.GH_TOKEN = githubToken;
|
|
@@ -316,6 +392,9 @@ class GitHubCopilot {
|
|
|
316
392
|
tokenPrefix: useToken ? githubToken.substring(0, 4) + '...' : 'none',
|
|
317
393
|
language: operation === 'suggest' ? this.getNodeParameter('language', i) : undefined,
|
|
318
394
|
commandType: operation === 'shell' ? this.getNodeParameter('commandType', i) : undefined,
|
|
395
|
+
originalCode: operation === 'revise' ? this.getNodeParameter('originalCode', i) : undefined,
|
|
396
|
+
rating: operation === 'rating' ? this.getNodeParameter('rating', i) : undefined,
|
|
397
|
+
responseToRate: operation === 'rating' ? this.getNodeParameter('responseToRate', i) : undefined,
|
|
319
398
|
output: processedOutput,
|
|
320
399
|
cliRawOutput: stdout,
|
|
321
400
|
cliStderr: stderr || undefined,
|
|
@@ -10,7 +10,7 @@ class GitHubCopilotChatAPI {
|
|
|
10
10
|
this.description = {
|
|
11
11
|
displayName: 'GitHub Copilot Chat API',
|
|
12
12
|
name: 'gitHubCopilotChatAPI',
|
|
13
|
-
icon: 'file
|
|
13
|
+
icon: 'file:../../../shared/icons/copilot.svg',
|
|
14
14
|
group: ['AI'],
|
|
15
15
|
version: 1,
|
|
16
16
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["model"]}}',
|
|
@@ -3,12 +3,13 @@ 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 = {
|
|
9
10
|
displayName: 'GitHub Copilot Chat Model',
|
|
10
11
|
name: 'gitHubCopilotChatModel',
|
|
11
|
-
icon: 'file
|
|
12
|
+
icon: 'file:../../shared/icons/copilot.svg',
|
|
12
13
|
group: ['transform'],
|
|
13
14
|
version: 1,
|
|
14
15
|
description: 'GitHub Copilot chat model for AI workflows - access GPT-5, Claude, Gemini and more using your Copilot subscription',
|
|
@@ -131,7 +132,7 @@ class GitHubCopilotChatModel {
|
|
|
131
132
|
maxTokens: Math.min(options.maxTokens || 1000, (safeModelInfo === null || safeModelInfo === void 0 ? void 0 : safeModelInfo.capabilities.maxOutputTokens) || 4096),
|
|
132
133
|
topP: options.topP || 1,
|
|
133
134
|
configuration: {
|
|
134
|
-
baseURL:
|
|
135
|
+
baseURL: GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.BASE_URL,
|
|
135
136
|
apiKey: token,
|
|
136
137
|
defaultHeaders: {
|
|
137
138
|
'User-Agent': 'GitHubCopilotChat/1.0.0 n8n/3.10.1',
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class GitHubCopilotTest implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GitHubCopilotTest = void 0;
|
|
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;
|
|
50
|
+
}
|
|
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
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
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
|
+
};
|
|
85
|
+
}
|
|
86
|
+
class GitHubCopilotTest {
|
|
87
|
+
constructor() {
|
|
88
|
+
this.description = {
|
|
89
|
+
displayName: 'GitHub Copilot Test',
|
|
90
|
+
name: 'gitHubCopilotTest',
|
|
91
|
+
icon: 'file:../../shared/icons/copilot.svg',
|
|
92
|
+
group: ['AI'],
|
|
93
|
+
version: 1,
|
|
94
|
+
subtitle: '={{$parameter["testFunction"]}}',
|
|
95
|
+
description: 'Test GitHub Copilot API credentials with predefined functions',
|
|
96
|
+
defaults: {
|
|
97
|
+
name: 'GitHub Copilot Test',
|
|
98
|
+
},
|
|
99
|
+
inputs: ["main"],
|
|
100
|
+
outputs: ["main"],
|
|
101
|
+
credentials: [
|
|
102
|
+
{
|
|
103
|
+
name: 'githubCopilotApi',
|
|
104
|
+
required: true,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
properties: [
|
|
108
|
+
{
|
|
109
|
+
displayName: 'Test Function',
|
|
110
|
+
name: 'testFunction',
|
|
111
|
+
type: 'options',
|
|
112
|
+
noDataExpression: true,
|
|
113
|
+
options: [
|
|
114
|
+
{
|
|
115
|
+
name: 'List Available Models',
|
|
116
|
+
value: 'listModels',
|
|
117
|
+
description: 'Get all models available for your GitHub Copilot subscription',
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
default: 'listModels',
|
|
121
|
+
description: 'Select the test function to execute',
|
|
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
|
+
},
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async execute() {
|
|
146
|
+
const items = this.getInputData();
|
|
147
|
+
const returnData = [];
|
|
148
|
+
for (let i = 0; i < items.length; i++) {
|
|
149
|
+
try {
|
|
150
|
+
const testFunction = this.getNodeParameter('testFunction', i);
|
|
151
|
+
const enableRetry = this.getNodeParameter('enableRetry', i);
|
|
152
|
+
const maxRetries = this.getNodeParameter('maxRetries', i);
|
|
153
|
+
const credentials = await this.getCredentials('githubCopilotApi', i);
|
|
154
|
+
if (!(credentials === null || credentials === void 0 ? void 0 : credentials.token)) {
|
|
155
|
+
throw new Error(GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ERRORS.CREDENTIALS_REQUIRED);
|
|
156
|
+
}
|
|
157
|
+
const token = credentials.token;
|
|
158
|
+
if (!GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.validateToken(token)) {
|
|
159
|
+
throw new Error(GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ERRORS.INVALID_TOKEN);
|
|
160
|
+
}
|
|
161
|
+
let result = {};
|
|
162
|
+
switch (testFunction) {
|
|
163
|
+
case 'listModels':
|
|
164
|
+
result = await listAvailableModels(token, enableRetry, maxRetries);
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
throw new Error(`Unknown test function: ${testFunction}`);
|
|
168
|
+
}
|
|
169
|
+
returnData.push({
|
|
170
|
+
json: result,
|
|
171
|
+
pairedItem: { item: i },
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
176
|
+
if (this.continueOnFail()) {
|
|
177
|
+
returnData.push({
|
|
178
|
+
json: {
|
|
179
|
+
error: errorMessage,
|
|
180
|
+
testFunction: this.getNodeParameter('testFunction', i),
|
|
181
|
+
},
|
|
182
|
+
pairedItem: { item: i },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return [returnData];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
exports.GitHubCopilotTest = GitHubCopilotTest;
|
|
@@ -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(
|
|
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
|
-
|
|
3
|
+
"version": "3.22.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",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"nodes": [
|
|
33
33
|
"dist/nodes/GitHubCopilot/GitHubCopilot.node.js",
|
|
34
34
|
"dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js",
|
|
35
|
-
"dist/nodes/GitHubCopilotChatModel/GitHubCopilotChatModel.node.js"
|
|
35
|
+
"dist/nodes/GitHubCopilotChatModel/GitHubCopilotChatModel.node.js",
|
|
36
|
+
"dist/nodes/GitHubCopilotTest/GitHubCopilotTest.node.js"
|
|
36
37
|
]
|
|
37
38
|
},
|
|
38
39
|
"keywords": [
|