n8n-nodes-github-copilot 3.23.0 โ 3.26.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.
|
@@ -83,6 +83,229 @@ async function listAvailableModels(token, enableRetry = true, maxRetries = 3) {
|
|
|
83
83
|
},
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
async function consolidatedModelTest(token, enableRetry = true, maxRetries = 3, testsPerModel = 5) {
|
|
87
|
+
const testStartTime = Date.now();
|
|
88
|
+
const testResults = {};
|
|
89
|
+
let totalTests = 0;
|
|
90
|
+
let successfulTests = 0;
|
|
91
|
+
let failedTests = 0;
|
|
92
|
+
try {
|
|
93
|
+
console.log('๐งช Starting Consolidated Model Test...');
|
|
94
|
+
const modelsResponse = await listAvailableModels(token, enableRetry, maxRetries);
|
|
95
|
+
if (!modelsResponse.success || !modelsResponse.data) {
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
timestamp: new Date().toISOString(),
|
|
99
|
+
error: 'Failed to fetch models list for consolidated test',
|
|
100
|
+
details: modelsResponse,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const availableModels = modelsResponse.data;
|
|
104
|
+
const testMessage = "Hello! Please respond with just 'OK' to confirm you're working.";
|
|
105
|
+
console.log(`๐ Testing ${availableModels.length} models, ${testsPerModel} times each...`);
|
|
106
|
+
for (const modelItem of availableModels) {
|
|
107
|
+
const model = modelItem;
|
|
108
|
+
const modelId = model.id || model.name;
|
|
109
|
+
const modelResults = {
|
|
110
|
+
modelInfo: {
|
|
111
|
+
id: modelId,
|
|
112
|
+
name: model.name || modelId,
|
|
113
|
+
vendor: model.vendor || 'unknown',
|
|
114
|
+
capabilities: model.capabilities || {},
|
|
115
|
+
},
|
|
116
|
+
tests: [],
|
|
117
|
+
summary: {
|
|
118
|
+
totalAttempts: 0,
|
|
119
|
+
successful: 0,
|
|
120
|
+
failed: 0,
|
|
121
|
+
successRate: 0,
|
|
122
|
+
avgResponseTime: 0,
|
|
123
|
+
avgTokensUsed: 0,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
console.log(`๐ Testing model: ${modelId}`);
|
|
127
|
+
for (let testNum = 1; testNum <= testsPerModel; testNum++) {
|
|
128
|
+
const testStart = Date.now();
|
|
129
|
+
totalTests++;
|
|
130
|
+
modelResults.summary.totalAttempts++;
|
|
131
|
+
try {
|
|
132
|
+
const response = await fetch(GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.getChatCompletionsUrl(), {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
headers: GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.getAuthHeaders(token),
|
|
135
|
+
body: JSON.stringify({
|
|
136
|
+
model: modelId,
|
|
137
|
+
messages: [
|
|
138
|
+
{
|
|
139
|
+
role: 'user',
|
|
140
|
+
content: testMessage
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
max_tokens: 10,
|
|
144
|
+
temperature: 0.1,
|
|
145
|
+
}),
|
|
146
|
+
});
|
|
147
|
+
const testEnd = Date.now();
|
|
148
|
+
const responseTime = testEnd - testStart;
|
|
149
|
+
if (response.ok) {
|
|
150
|
+
const data = await response.json();
|
|
151
|
+
successfulTests++;
|
|
152
|
+
modelResults.summary.successful++;
|
|
153
|
+
const choices = data.choices || [];
|
|
154
|
+
const firstChoice = choices[0] || {};
|
|
155
|
+
const message = firstChoice.message || {};
|
|
156
|
+
const usage = data.usage || {};
|
|
157
|
+
const testResult = {
|
|
158
|
+
testNumber: testNum,
|
|
159
|
+
success: true,
|
|
160
|
+
responseTime: responseTime,
|
|
161
|
+
response: message.content || 'No content',
|
|
162
|
+
usage: usage || null,
|
|
163
|
+
finishReason: firstChoice.finish_reason || 'unknown',
|
|
164
|
+
timestamp: new Date().toISOString(),
|
|
165
|
+
};
|
|
166
|
+
modelResults.tests.push(testResult);
|
|
167
|
+
const totalTokens = usage.total_tokens;
|
|
168
|
+
if (totalTokens) {
|
|
169
|
+
modelResults.summary.avgTokensUsed += totalTokens;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
const errorText = await response.text();
|
|
174
|
+
failedTests++;
|
|
175
|
+
modelResults.summary.failed++;
|
|
176
|
+
modelResults.tests.push({
|
|
177
|
+
testNumber: testNum,
|
|
178
|
+
success: false,
|
|
179
|
+
responseTime: responseTime,
|
|
180
|
+
error: `HTTP ${response.status}: ${errorText}`,
|
|
181
|
+
timestamp: new Date().toISOString(),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
const testEnd = Date.now();
|
|
187
|
+
const responseTime = testEnd - testStart;
|
|
188
|
+
failedTests++;
|
|
189
|
+
modelResults.summary.failed++;
|
|
190
|
+
modelResults.tests.push({
|
|
191
|
+
testNumber: testNum,
|
|
192
|
+
success: false,
|
|
193
|
+
responseTime: responseTime,
|
|
194
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
195
|
+
timestamp: new Date().toISOString(),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
199
|
+
}
|
|
200
|
+
const successfulResponses = modelResults.tests.filter((t) => {
|
|
201
|
+
const test = t;
|
|
202
|
+
return test.success === true;
|
|
203
|
+
});
|
|
204
|
+
if (successfulResponses.length > 0) {
|
|
205
|
+
const totalResponseTime = successfulResponses.reduce((sum, t) => {
|
|
206
|
+
const test = t;
|
|
207
|
+
return sum + (test.responseTime || 0);
|
|
208
|
+
}, 0);
|
|
209
|
+
modelResults.summary.avgResponseTime = Math.round(totalResponseTime / successfulResponses.length);
|
|
210
|
+
modelResults.summary.avgTokensUsed = Math.round(modelResults.summary.avgTokensUsed / successfulResponses.length);
|
|
211
|
+
}
|
|
212
|
+
modelResults.summary.successRate = Math.round((modelResults.summary.successful / modelResults.summary.totalAttempts) * 100);
|
|
213
|
+
testResults[modelId] = modelResults;
|
|
214
|
+
}
|
|
215
|
+
const testEndTime = Date.now();
|
|
216
|
+
const totalTestTime = testEndTime - testStartTime;
|
|
217
|
+
const consolidatedSummary = {
|
|
218
|
+
success: true,
|
|
219
|
+
timestamp: new Date().toISOString(),
|
|
220
|
+
testConfiguration: {
|
|
221
|
+
testsPerModel: testsPerModel,
|
|
222
|
+
totalModels: availableModels.length,
|
|
223
|
+
totalTests: totalTests,
|
|
224
|
+
retryEnabled: enableRetry,
|
|
225
|
+
maxRetries: maxRetries,
|
|
226
|
+
},
|
|
227
|
+
overallResults: {
|
|
228
|
+
totalTests: totalTests,
|
|
229
|
+
successfulTests: successfulTests,
|
|
230
|
+
failedTests: failedTests,
|
|
231
|
+
overallSuccessRate: Math.round((successfulTests / totalTests) * 100),
|
|
232
|
+
totalTestTime: totalTestTime,
|
|
233
|
+
avgTimePerTest: Math.round(totalTestTime / totalTests),
|
|
234
|
+
},
|
|
235
|
+
modelResults: testResults,
|
|
236
|
+
recommendations: generateTestRecommendations(testResults),
|
|
237
|
+
};
|
|
238
|
+
console.log('โ
Consolidated test completed successfully!');
|
|
239
|
+
return consolidatedSummary;
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
timestamp: new Date().toISOString(),
|
|
245
|
+
error: error instanceof Error ? error.message : 'Unknown error in consolidated test',
|
|
246
|
+
partialResults: testResults,
|
|
247
|
+
testDuration: Date.now() - testStartTime,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function generateTestRecommendations(testResults) {
|
|
252
|
+
const recommendations = [];
|
|
253
|
+
const modelStats = Object.entries(testResults).map(([modelId, results]) => {
|
|
254
|
+
const modelResult = results;
|
|
255
|
+
const summary = modelResult.summary;
|
|
256
|
+
const modelInfo = modelResult.modelInfo;
|
|
257
|
+
return {
|
|
258
|
+
modelId,
|
|
259
|
+
successRate: summary.successRate,
|
|
260
|
+
avgResponseTime: summary.avgResponseTime,
|
|
261
|
+
vendor: modelInfo.vendor,
|
|
262
|
+
};
|
|
263
|
+
});
|
|
264
|
+
const bestModels = modelStats
|
|
265
|
+
.filter(m => m.successRate === 100)
|
|
266
|
+
.sort((a, b) => a.avgResponseTime - b.avgResponseTime)
|
|
267
|
+
.slice(0, 3);
|
|
268
|
+
if (bestModels.length > 0) {
|
|
269
|
+
recommendations.push({
|
|
270
|
+
type: 'best_performance',
|
|
271
|
+
title: 'Top Performing Models (100% success rate)',
|
|
272
|
+
models: bestModels,
|
|
273
|
+
description: 'These models completed all tests successfully with fastest response times',
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
const problematicModels = modelStats.filter(m => m.successRate < 80);
|
|
277
|
+
if (problematicModels.length > 0) {
|
|
278
|
+
recommendations.push({
|
|
279
|
+
type: 'attention_needed',
|
|
280
|
+
title: 'Models Requiring Attention (< 80% success rate)',
|
|
281
|
+
models: problematicModels,
|
|
282
|
+
description: 'These models had reliability issues during testing',
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
const vendorStats = modelStats.reduce((acc, model) => {
|
|
286
|
+
const vendor = model.vendor;
|
|
287
|
+
if (!acc[vendor]) {
|
|
288
|
+
acc[vendor] = { count: 0, totalSuccessRate: 0, avgResponseTime: 0 };
|
|
289
|
+
}
|
|
290
|
+
const stats = acc[vendor];
|
|
291
|
+
stats.count++;
|
|
292
|
+
stats.totalSuccessRate += model.successRate;
|
|
293
|
+
stats.avgResponseTime += model.avgResponseTime;
|
|
294
|
+
return acc;
|
|
295
|
+
}, {});
|
|
296
|
+
Object.keys(vendorStats).forEach(vendor => {
|
|
297
|
+
const vendorData = vendorStats[vendor];
|
|
298
|
+
vendorData.avgSuccessRate = Math.round(vendorData.totalSuccessRate / vendorData.count);
|
|
299
|
+
vendorData.avgResponseTime = Math.round(vendorData.avgResponseTime / vendorData.count);
|
|
300
|
+
});
|
|
301
|
+
recommendations.push({
|
|
302
|
+
type: 'vendor_analysis',
|
|
303
|
+
title: 'Performance by Vendor',
|
|
304
|
+
vendors: vendorStats,
|
|
305
|
+
description: 'Comparative analysis of model performance by vendor',
|
|
306
|
+
});
|
|
307
|
+
return recommendations;
|
|
308
|
+
}
|
|
86
309
|
class GitHubCopilotTest {
|
|
87
310
|
constructor() {
|
|
88
311
|
this.description = {
|
|
@@ -116,28 +339,59 @@ class GitHubCopilotTest {
|
|
|
116
339
|
value: 'listModels',
|
|
117
340
|
description: 'Get all models available for your GitHub Copilot subscription',
|
|
118
341
|
},
|
|
342
|
+
{
|
|
343
|
+
name: 'Consolidated Model Test',
|
|
344
|
+
value: 'consolidatedTest',
|
|
345
|
+
description: 'Test all available models 5 times each and generate comprehensive report โ ๏ธ This test may take up to 2 minutes to complete',
|
|
346
|
+
},
|
|
119
347
|
],
|
|
120
348
|
default: 'listModels',
|
|
121
349
|
description: 'Select the test function to execute',
|
|
122
350
|
},
|
|
123
351
|
{
|
|
124
|
-
displayName: '
|
|
125
|
-
name: '
|
|
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',
|
|
352
|
+
displayName: 'Tests Per Model',
|
|
353
|
+
name: 'testsPerModel',
|
|
133
354
|
type: 'number',
|
|
134
|
-
default:
|
|
135
|
-
description: '
|
|
355
|
+
default: 5,
|
|
356
|
+
description: 'Number of times to test each model (affects accuracy of results)',
|
|
136
357
|
displayOptions: {
|
|
137
358
|
show: {
|
|
138
|
-
|
|
359
|
+
testFunction: ['consolidatedTest'],
|
|
139
360
|
},
|
|
140
361
|
},
|
|
362
|
+
typeOptions: {
|
|
363
|
+
minValue: 1,
|
|
364
|
+
maxValue: 20,
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
displayName: 'Advanced Options',
|
|
369
|
+
name: 'advancedOptions',
|
|
370
|
+
type: 'collection',
|
|
371
|
+
placeholder: 'Add Option',
|
|
372
|
+
default: {},
|
|
373
|
+
description: 'Additional options for the test execution',
|
|
374
|
+
options: [
|
|
375
|
+
{
|
|
376
|
+
displayName: 'Auto Retry on 403 Error',
|
|
377
|
+
name: 'enableRetry',
|
|
378
|
+
type: 'boolean',
|
|
379
|
+
default: true,
|
|
380
|
+
description: 'Automatically retry requests when hitting TPM (Transactions Per Minute) quota limits (HTTP 403)',
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
displayName: 'Max Retry Attempts',
|
|
384
|
+
name: 'maxRetries',
|
|
385
|
+
type: 'number',
|
|
386
|
+
default: 3,
|
|
387
|
+
description: 'Maximum number of retry attempts for 403 errors',
|
|
388
|
+
displayOptions: {
|
|
389
|
+
show: {
|
|
390
|
+
enableRetry: [true],
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
],
|
|
141
395
|
},
|
|
142
396
|
],
|
|
143
397
|
};
|
|
@@ -148,8 +402,12 @@ class GitHubCopilotTest {
|
|
|
148
402
|
for (let i = 0; i < items.length; i++) {
|
|
149
403
|
try {
|
|
150
404
|
const testFunction = this.getNodeParameter('testFunction', i);
|
|
151
|
-
const
|
|
152
|
-
const
|
|
405
|
+
const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
|
|
406
|
+
const enableRetry = advancedOptions.enableRetry !== false;
|
|
407
|
+
const maxRetries = advancedOptions.maxRetries || 3;
|
|
408
|
+
const testsPerModel = testFunction === 'consolidatedTest'
|
|
409
|
+
? this.getNodeParameter('testsPerModel', i)
|
|
410
|
+
: 5;
|
|
153
411
|
const credentials = await this.getCredentials('githubCopilotApi', i);
|
|
154
412
|
if (!(credentials === null || credentials === void 0 ? void 0 : credentials.token)) {
|
|
155
413
|
throw new Error(GitHubCopilotEndpoints_1.GITHUB_COPILOT_API.ERRORS.CREDENTIALS_REQUIRED);
|
|
@@ -163,6 +421,9 @@ class GitHubCopilotTest {
|
|
|
163
421
|
case 'listModels':
|
|
164
422
|
result = await listAvailableModels(token, enableRetry, maxRetries);
|
|
165
423
|
break;
|
|
424
|
+
case 'consolidatedTest':
|
|
425
|
+
result = await consolidatedModelTest(token, enableRetry, maxRetries, testsPerModel);
|
|
426
|
+
break;
|
|
166
427
|
default:
|
|
167
428
|
throw new Error(`Unknown test function: ${testFunction}`);
|
|
168
429
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.26.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",
|