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: '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',
352
+ displayName: 'Tests Per Model',
353
+ name: 'testsPerModel',
133
354
  type: 'number',
134
- default: 3,
135
- description: 'Maximum number of retry attempts for 403 errors',
355
+ default: 5,
356
+ description: 'Number of times to test each model (affects accuracy of results)',
136
357
  displayOptions: {
137
358
  show: {
138
- enableRetry: [true],
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 enableRetry = this.getNodeParameter('enableRetry', i);
152
- const maxRetries = this.getNodeParameter('maxRetries', i);
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.23.0",
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",