n8n-nodes-github-copilot 3.33.0 → 3.36.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/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js +27 -2
- package/dist/nodes/GitHubCopilotChatAPI/nodeProperties.js +53 -0
- package/dist/nodes/GitHubCopilotTest/GitHubCopilotTest.node.js +108 -0
- package/dist/package.json +1 -1
- package/dist/shared/models/DynamicModelLoader.d.ts +1 -1
- package/dist/shared/models/DynamicModelLoader.js +28 -6
- package/dist/shared/properties/ModelSelectionProperty.d.ts +4 -0
- package/dist/shared/properties/ModelSelectionProperty.js +42 -0
- package/dist/shared/utils/DynamicModelsManager.d.ts +4 -1
- package/dist/shared/utils/DynamicModelsManager.js +42 -8
- package/package.json +1 -1
|
@@ -45,7 +45,29 @@ class GitHubCopilotChatAPI {
|
|
|
45
45
|
for (let i = 0; i < items.length; i++) {
|
|
46
46
|
try {
|
|
47
47
|
const operation = this.getNodeParameter("operation", i);
|
|
48
|
-
const
|
|
48
|
+
const modelSource = this.getNodeParameter("modelSource", i, "fromList");
|
|
49
|
+
let model;
|
|
50
|
+
if (modelSource === "custom") {
|
|
51
|
+
model = this.getNodeParameter("customModel", i);
|
|
52
|
+
if (!model || model.trim() === "") {
|
|
53
|
+
throw new Error("Custom model name is required when using 'Custom (Manual Entry)' mode");
|
|
54
|
+
}
|
|
55
|
+
console.log(`🔧 Using custom model: ${model}`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const selectedModel = this.getNodeParameter("model", i);
|
|
59
|
+
if (selectedModel === "__manual__") {
|
|
60
|
+
model = this.getNodeParameter("customModel", i);
|
|
61
|
+
if (!model || model.trim() === "") {
|
|
62
|
+
throw new Error("Custom model name is required when selecting '✏️ Enter Custom Model Name'");
|
|
63
|
+
}
|
|
64
|
+
console.log(`✏️ Using manually entered model: ${model}`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
model = selectedModel;
|
|
68
|
+
console.log(`✅ Using model from list: ${model}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
49
71
|
if (operation === "chat") {
|
|
50
72
|
const userMessage = this.getNodeParameter("message", i);
|
|
51
73
|
const systemMessage = this.getNodeParameter("systemMessage", i, "");
|
|
@@ -55,9 +77,12 @@ class GitHubCopilotChatAPI {
|
|
|
55
77
|
const includeMedia = this.getNodeParameter("includeMedia", i, false);
|
|
56
78
|
const modelInfo = GitHubCopilotModels_1.GitHubCopilotModelsManager.getModelByValue(model);
|
|
57
79
|
if (includeMedia) {
|
|
58
|
-
if (!(modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.capabilities.vision) && !(modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.capabilities.multimodal)) {
|
|
80
|
+
if (modelInfo && !(modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.capabilities.vision) && !(modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.capabilities.multimodal)) {
|
|
59
81
|
throw new Error(`Model ${model} does not support vision/image processing. Please select a model with vision capabilities.`);
|
|
60
82
|
}
|
|
83
|
+
else if (!modelInfo) {
|
|
84
|
+
console.warn(`⚠️ Model ${model} not found in known models list. Vision capability unknown - proceeding anyway.`);
|
|
85
|
+
}
|
|
61
86
|
}
|
|
62
87
|
const messages = [];
|
|
63
88
|
if (systemMessage) {
|
|
@@ -17,6 +17,25 @@ exports.nodeProperties = [
|
|
|
17
17
|
],
|
|
18
18
|
default: "chat",
|
|
19
19
|
},
|
|
20
|
+
{
|
|
21
|
+
displayName: "Model Source",
|
|
22
|
+
name: "modelSource",
|
|
23
|
+
type: "options",
|
|
24
|
+
options: [
|
|
25
|
+
{
|
|
26
|
+
name: "From List (Auto-Discovered)",
|
|
27
|
+
value: "fromList",
|
|
28
|
+
description: "Select from available models based on your subscription",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "Custom (Manual Entry)",
|
|
32
|
+
value: "custom",
|
|
33
|
+
description: "Enter model name manually (use at your own risk)",
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
default: "fromList",
|
|
37
|
+
description: "Choose how to specify the model",
|
|
38
|
+
},
|
|
20
39
|
{
|
|
21
40
|
displayName: "Model",
|
|
22
41
|
name: "model",
|
|
@@ -26,6 +45,40 @@ exports.nodeProperties = [
|
|
|
26
45
|
},
|
|
27
46
|
default: GitHubCopilotModels_1.DEFAULT_MODELS.GENERAL,
|
|
28
47
|
description: "Select the GitHub Copilot model to use (loaded dynamically based on your subscription)",
|
|
48
|
+
displayOptions: {
|
|
49
|
+
show: {
|
|
50
|
+
modelSource: ["fromList"],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
displayName: "Custom Model Name",
|
|
56
|
+
name: "customModel",
|
|
57
|
+
type: "string",
|
|
58
|
+
default: "",
|
|
59
|
+
placeholder: "gpt-4o, claude-3.5-sonnet, grok-code-fast-1, etc.",
|
|
60
|
+
description: "Enter the model name manually. Use at your own risk if the model is not available in your subscription.",
|
|
61
|
+
hint: "Examples: gpt-4o, gpt-4o-mini, claude-3.5-sonnet, gemini-2.0-flash-exp, grok-code-fast-1",
|
|
62
|
+
displayOptions: {
|
|
63
|
+
show: {
|
|
64
|
+
modelSource: ["custom"],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
displayName: "Custom Model Name",
|
|
70
|
+
name: "customModel",
|
|
71
|
+
type: "string",
|
|
72
|
+
default: "",
|
|
73
|
+
placeholder: "gpt-4o, claude-3.5-sonnet, grok-code-fast-1, etc.",
|
|
74
|
+
description: "Enter the model name manually. This is useful for new/beta models not yet in the list.",
|
|
75
|
+
hint: "Examples: gpt-4o, gpt-4o-mini, claude-3.5-sonnet, gemini-2.0-flash-exp, grok-code-fast-1",
|
|
76
|
+
displayOptions: {
|
|
77
|
+
show: {
|
|
78
|
+
modelSource: ["fromList"],
|
|
79
|
+
model: ["__manual__"],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
29
82
|
},
|
|
30
83
|
{
|
|
31
84
|
displayName: "Message",
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GitHubCopilotTest = void 0;
|
|
4
4
|
const GitHubCopilotEndpoints_1 = require("../../shared/utils/GitHubCopilotEndpoints");
|
|
5
|
+
const DynamicModelsManager_1 = require("../../shared/utils/DynamicModelsManager");
|
|
6
|
+
const OAuthTokenManager_1 = require("../../shared/utils/OAuthTokenManager");
|
|
5
7
|
async function listAvailableModels(token, enableRetry = true, maxRetries = 3) {
|
|
6
8
|
const retryInfo = {
|
|
7
9
|
attempts: 1,
|
|
@@ -85,6 +87,104 @@ async function listAvailableModels(token, enableRetry = true, maxRetries = 3) {
|
|
|
85
87
|
},
|
|
86
88
|
};
|
|
87
89
|
}
|
|
90
|
+
async function refreshModelsCache(githubToken, enableRetry = true, maxRetries = 3) {
|
|
91
|
+
const startTime = Date.now();
|
|
92
|
+
try {
|
|
93
|
+
console.log("🔄 Starting models cache refresh...");
|
|
94
|
+
console.log("🔑 Generating OAuth token...");
|
|
95
|
+
const oauthToken = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
|
|
96
|
+
const cacheInfoBefore = DynamicModelsManager_1.DynamicModelsManager.getCacheInfo(oauthToken);
|
|
97
|
+
console.log("🗑️ Clearing existing cache...");
|
|
98
|
+
DynamicModelsManager_1.DynamicModelsManager.clearCache(oauthToken);
|
|
99
|
+
console.log("📥 Fetching fresh models from API...");
|
|
100
|
+
const models = await DynamicModelsManager_1.DynamicModelsManager.getAvailableModels(oauthToken);
|
|
101
|
+
const cacheInfoAfter = DynamicModelsManager_1.DynamicModelsManager.getCacheInfo(oauthToken);
|
|
102
|
+
const executionTime = Date.now() - startTime;
|
|
103
|
+
const modelsByVendor = {};
|
|
104
|
+
const capabilitiesCount = {
|
|
105
|
+
streaming: 0,
|
|
106
|
+
tools: 0,
|
|
107
|
+
vision: 0,
|
|
108
|
+
structured: 0,
|
|
109
|
+
parallel: 0,
|
|
110
|
+
reasoning: 0,
|
|
111
|
+
};
|
|
112
|
+
models.forEach((model) => {
|
|
113
|
+
var _a;
|
|
114
|
+
const vendor = model.vendor || "Unknown";
|
|
115
|
+
modelsByVendor[vendor] = (modelsByVendor[vendor] || 0) + 1;
|
|
116
|
+
if ((_a = model.capabilities) === null || _a === void 0 ? void 0 : _a.supports) {
|
|
117
|
+
const supports = model.capabilities.supports;
|
|
118
|
+
if (supports.streaming)
|
|
119
|
+
capabilitiesCount.streaming++;
|
|
120
|
+
if (supports.tool_calls)
|
|
121
|
+
capabilitiesCount.tools++;
|
|
122
|
+
if (supports.vision)
|
|
123
|
+
capabilitiesCount.vision++;
|
|
124
|
+
if (supports.structured_outputs)
|
|
125
|
+
capabilitiesCount.structured++;
|
|
126
|
+
if (supports.parallel_tool_calls)
|
|
127
|
+
capabilitiesCount.parallel++;
|
|
128
|
+
if (supports.max_thinking_budget)
|
|
129
|
+
capabilitiesCount.reasoning++;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
success: true,
|
|
134
|
+
operation: "refreshCache",
|
|
135
|
+
timestamp: new Date().toISOString(),
|
|
136
|
+
executionTime: `${executionTime}ms`,
|
|
137
|
+
message: "✅ Models cache refreshed successfully",
|
|
138
|
+
summary: {
|
|
139
|
+
totalModels: models.length,
|
|
140
|
+
modelsByVendor,
|
|
141
|
+
capabilities: capabilitiesCount,
|
|
142
|
+
},
|
|
143
|
+
cache: {
|
|
144
|
+
before: cacheInfoBefore ? {
|
|
145
|
+
cached: true,
|
|
146
|
+
modelsCount: cacheInfoBefore.modelsCount,
|
|
147
|
+
expiresIn: `${Math.round(cacheInfoBefore.expiresIn / 1000)}s`,
|
|
148
|
+
fetchedAt: cacheInfoBefore.fetchedAt,
|
|
149
|
+
} : {
|
|
150
|
+
cached: false,
|
|
151
|
+
message: "No cache existed before refresh",
|
|
152
|
+
},
|
|
153
|
+
after: cacheInfoAfter ? {
|
|
154
|
+
cached: true,
|
|
155
|
+
modelsCount: cacheInfoAfter.modelsCount,
|
|
156
|
+
expiresIn: `${Math.round(cacheInfoAfter.expiresIn / 1000)}s`,
|
|
157
|
+
fetchedAt: cacheInfoAfter.fetchedAt,
|
|
158
|
+
} : {
|
|
159
|
+
cached: false,
|
|
160
|
+
message: "Cache refresh failed",
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
models: models.map((model) => {
|
|
164
|
+
var _a;
|
|
165
|
+
return ({
|
|
166
|
+
id: model.id,
|
|
167
|
+
name: model.name || model.id,
|
|
168
|
+
vendor: model.vendor,
|
|
169
|
+
capabilities: ((_a = model.capabilities) === null || _a === void 0 ? void 0 : _a.supports) || {},
|
|
170
|
+
});
|
|
171
|
+
}),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
const executionTime = Date.now() - startTime;
|
|
176
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
operation: "refreshCache",
|
|
180
|
+
timestamp: new Date().toISOString(),
|
|
181
|
+
executionTime: `${executionTime}ms`,
|
|
182
|
+
error: errorMessage,
|
|
183
|
+
message: "❌ Failed to refresh models cache",
|
|
184
|
+
details: error instanceof Error ? error.stack : String(error),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
88
188
|
async function consolidatedModelTest(token, enableRetry = true, maxRetries = 3, testsPerModel = 5) {
|
|
89
189
|
const testStartTime = Date.now();
|
|
90
190
|
const testResults = {};
|
|
@@ -341,6 +441,11 @@ class GitHubCopilotTest {
|
|
|
341
441
|
value: "listModels",
|
|
342
442
|
description: "Get all models available for your GitHub Copilot subscription",
|
|
343
443
|
},
|
|
444
|
+
{
|
|
445
|
+
name: "Refresh Models Cache",
|
|
446
|
+
value: "refreshCache",
|
|
447
|
+
description: "Force refresh the cached models list (clears cache and fetches fresh data from API)",
|
|
448
|
+
},
|
|
344
449
|
{
|
|
345
450
|
name: "Consolidated Model Test",
|
|
346
451
|
value: "consolidatedTest",
|
|
@@ -423,6 +528,9 @@ class GitHubCopilotTest {
|
|
|
423
528
|
case "listModels":
|
|
424
529
|
result = await listAvailableModels(token, enableRetry, maxRetries);
|
|
425
530
|
break;
|
|
531
|
+
case "refreshCache":
|
|
532
|
+
result = await refreshModelsCache(token, enableRetry, maxRetries);
|
|
533
|
+
break;
|
|
426
534
|
case "consolidatedTest":
|
|
427
535
|
result = await consolidatedModelTest(token, enableRetry, maxRetries, testsPerModel);
|
|
428
536
|
break;
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.36.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",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ILoadOptionsFunctions, INodePropertyOptions } from "n8n-workflow";
|
|
2
|
-
export declare function loadAvailableModels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
2
|
+
export declare function loadAvailableModels(this: ILoadOptionsFunctions, forceRefresh?: boolean): Promise<INodePropertyOptions[]>;
|
|
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.loadAvailableModels = loadAvailableModels;
|
|
4
4
|
const DynamicModelsManager_1 = require("../utils/DynamicModelsManager");
|
|
5
5
|
const OAuthTokenManager_1 = require("../utils/OAuthTokenManager");
|
|
6
|
-
async function loadAvailableModels() {
|
|
6
|
+
async function loadAvailableModels(forceRefresh = false) {
|
|
7
7
|
try {
|
|
8
8
|
const credentials = await this.getCredentials("githubCopilotApi");
|
|
9
9
|
if (!credentials || !credentials.token) {
|
|
10
10
|
console.warn("⚠️ No credentials found for dynamic model loading");
|
|
11
|
-
return
|
|
11
|
+
return getDefaultModelsWithManualInput();
|
|
12
12
|
}
|
|
13
13
|
const githubToken = credentials.token;
|
|
14
14
|
let oauthToken;
|
|
@@ -17,18 +17,40 @@ async function loadAvailableModels() {
|
|
|
17
17
|
}
|
|
18
18
|
catch (error) {
|
|
19
19
|
console.error("❌ Failed to generate OAuth token for model loading:", error);
|
|
20
|
-
return
|
|
20
|
+
return getDefaultModelsWithManualInput();
|
|
21
|
+
}
|
|
22
|
+
if (forceRefresh) {
|
|
23
|
+
DynamicModelsManager_1.DynamicModelsManager.clearCache(oauthToken);
|
|
24
|
+
console.log("🔄 Force refreshing models list...");
|
|
21
25
|
}
|
|
22
26
|
const models = await DynamicModelsManager_1.DynamicModelsManager.getAvailableModels(oauthToken);
|
|
23
27
|
const options = DynamicModelsManager_1.DynamicModelsManager.modelsToN8nOptions(models);
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
const optionsWithManualInput = [
|
|
29
|
+
{
|
|
30
|
+
name: "✏️ Enter Custom Model Name",
|
|
31
|
+
value: "__manual__",
|
|
32
|
+
description: "Type your own model name (for new/beta models)",
|
|
33
|
+
},
|
|
34
|
+
...options,
|
|
35
|
+
];
|
|
36
|
+
console.log(`✅ Loaded ${options.length} models dynamically (+ manual input option)`);
|
|
37
|
+
return optionsWithManualInput;
|
|
26
38
|
}
|
|
27
39
|
catch (error) {
|
|
28
40
|
console.error("❌ Error loading dynamic models:", error);
|
|
29
|
-
return
|
|
41
|
+
return getDefaultModelsWithManualInput();
|
|
30
42
|
}
|
|
31
43
|
}
|
|
44
|
+
function getDefaultModelsWithManualInput() {
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
name: "✏️ Enter Custom Model Name",
|
|
48
|
+
value: "__manual__",
|
|
49
|
+
description: "Type your own model name (for new/beta models)",
|
|
50
|
+
},
|
|
51
|
+
...getDefaultModels(),
|
|
52
|
+
];
|
|
53
|
+
}
|
|
32
54
|
function getDefaultModels() {
|
|
33
55
|
return [
|
|
34
56
|
{
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.refreshTriggerProperty = exports.modelRefreshProperty = exports.modelSelectionProperty = void 0;
|
|
4
|
+
const GitHubCopilotModels_1 = require("../models/GitHubCopilotModels");
|
|
5
|
+
exports.modelSelectionProperty = {
|
|
6
|
+
displayName: "Model",
|
|
7
|
+
name: "model",
|
|
8
|
+
type: "options",
|
|
9
|
+
typeOptions: {
|
|
10
|
+
loadOptionsMethod: "getAvailableModels",
|
|
11
|
+
loadOptionsDependsOn: ["refresh"],
|
|
12
|
+
},
|
|
13
|
+
default: GitHubCopilotModels_1.DEFAULT_MODELS.GENERAL,
|
|
14
|
+
required: true,
|
|
15
|
+
description: "Select a model from your subscription or enter a custom model name",
|
|
16
|
+
placeholder: "Select model or type custom name (e.g., gpt-4o, claude-3.5-sonnet)",
|
|
17
|
+
hint: "Models are loaded based on your GitHub Copilot subscription. Use the refresh button to update the list.",
|
|
18
|
+
validateType: "string",
|
|
19
|
+
ignoreValidationDuringExecution: false,
|
|
20
|
+
};
|
|
21
|
+
exports.modelRefreshProperty = {
|
|
22
|
+
displayName: "Refresh Models",
|
|
23
|
+
name: "refreshModels",
|
|
24
|
+
type: "button",
|
|
25
|
+
typeOptions: {
|
|
26
|
+
action: "refreshModels",
|
|
27
|
+
},
|
|
28
|
+
default: "",
|
|
29
|
+
description: "Click to refresh the list of available models from your subscription",
|
|
30
|
+
displayOptions: {
|
|
31
|
+
show: {
|
|
32
|
+
operation: ["chat"],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
exports.refreshTriggerProperty = {
|
|
37
|
+
displayName: "Refresh Trigger",
|
|
38
|
+
name: "refresh",
|
|
39
|
+
type: "hidden",
|
|
40
|
+
default: 0,
|
|
41
|
+
description: "Internal field to trigger model list refresh",
|
|
42
|
+
};
|
|
@@ -3,7 +3,10 @@ interface CopilotModel {
|
|
|
3
3
|
name: string;
|
|
4
4
|
display_name?: string;
|
|
5
5
|
model_picker_enabled?: boolean;
|
|
6
|
-
capabilities?:
|
|
6
|
+
capabilities?: any;
|
|
7
|
+
vendor?: string;
|
|
8
|
+
version?: string;
|
|
9
|
+
preview?: boolean;
|
|
7
10
|
}
|
|
8
11
|
export declare class DynamicModelsManager {
|
|
9
12
|
private static cache;
|
|
@@ -33,9 +33,8 @@ class DynamicModelsManager {
|
|
|
33
33
|
throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`);
|
|
34
34
|
}
|
|
35
35
|
const data = (await response.json());
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return enabledModels;
|
|
36
|
+
console.log(`✅ Fetched ${data.data.length} models from API`);
|
|
37
|
+
return data.data;
|
|
39
38
|
}
|
|
40
39
|
static async getAvailableModels(oauthToken) {
|
|
41
40
|
const tokenHash = this.hashToken(oauthToken);
|
|
@@ -71,11 +70,46 @@ class DynamicModelsManager {
|
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
static modelsToN8nOptions(models) {
|
|
74
|
-
return models.map((model) =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
return models.map((model) => {
|
|
74
|
+
const badges = [];
|
|
75
|
+
if (model.capabilities) {
|
|
76
|
+
const supports = model.capabilities.supports || {};
|
|
77
|
+
if (supports.streaming)
|
|
78
|
+
badges.push("🔄 Streaming");
|
|
79
|
+
if (supports.tool_calls)
|
|
80
|
+
badges.push("🔧 Tools");
|
|
81
|
+
if (supports.vision)
|
|
82
|
+
badges.push("👁️ Vision");
|
|
83
|
+
if (supports.structured_outputs)
|
|
84
|
+
badges.push("📋 Structured");
|
|
85
|
+
if (supports.parallel_tool_calls)
|
|
86
|
+
badges.push("⚡ Parallel");
|
|
87
|
+
if (supports.max_thinking_budget)
|
|
88
|
+
badges.push("🧠 Reasoning");
|
|
89
|
+
}
|
|
90
|
+
const displayName = model.display_name || model.name || model.id;
|
|
91
|
+
const badgesText = badges.length > 0 ? ` [${badges.join(" • ")}]` : "";
|
|
92
|
+
let description = "";
|
|
93
|
+
if (model.capabilities) {
|
|
94
|
+
const limits = model.capabilities.limits || {};
|
|
95
|
+
const parts = [];
|
|
96
|
+
if (limits.max_context_window_tokens) {
|
|
97
|
+
parts.push(`Context: ${(limits.max_context_window_tokens / 1000).toFixed(0)}k`);
|
|
98
|
+
}
|
|
99
|
+
if (limits.max_output_tokens) {
|
|
100
|
+
parts.push(`Output: ${(limits.max_output_tokens / 1000).toFixed(0)}k`);
|
|
101
|
+
}
|
|
102
|
+
if (model.vendor) {
|
|
103
|
+
parts.push(`Provider: ${model.vendor}`);
|
|
104
|
+
}
|
|
105
|
+
description = parts.join(" • ");
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
name: `${displayName}${badgesText}`,
|
|
109
|
+
value: model.id,
|
|
110
|
+
description: description || undefined,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
79
113
|
}
|
|
80
114
|
static clearCache(oauthToken) {
|
|
81
115
|
const tokenHash = this.hashToken(oauthToken);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-github-copilot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.36.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",
|