n8n-nodes-github-copilot 3.38.25 → 3.38.26
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.d.ts +1 -1
- package/dist/credentials/GitHubCopilotApi.credentials.js +25 -25
- package/dist/nodes/GitHubCopilot/GitHubCopilot.node.d.ts +1 -1
- package/dist/nodes/GitHubCopilot/GitHubCopilot.node.js +166 -166
- package/dist/nodes/GitHubCopilotAuthHelper/GitHubCopilotAuthHelper.node.d.ts +1 -1
- package/dist/nodes/GitHubCopilotAuthHelper/GitHubCopilotAuthHelper.node.js +539 -539
- package/dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.d.ts +1 -1
- package/dist/nodes/GitHubCopilotChatAPI/GitHubCopilotChatAPI.node.js +46 -44
- package/dist/nodes/GitHubCopilotChatAPI/nodeProperties.d.ts +1 -1
- package/dist/nodes/GitHubCopilotChatAPI/nodeProperties.js +82 -82
- package/dist/nodes/GitHubCopilotChatAPI/utils/helpers.d.ts +2 -2
- package/dist/nodes/GitHubCopilotChatAPI/utils/helpers.js +26 -26
- package/dist/nodes/GitHubCopilotChatAPI/utils/imageProcessor.d.ts +2 -2
- package/dist/nodes/GitHubCopilotChatAPI/utils/imageProcessor.js +12 -12
- package/dist/nodes/GitHubCopilotChatAPI/utils/index.d.ts +4 -4
- package/dist/nodes/GitHubCopilotChatAPI/utils/mediaDetection.d.ts +3 -3
- package/dist/nodes/GitHubCopilotChatAPI/utils/mediaDetection.js +19 -19
- package/dist/nodes/GitHubCopilotChatAPI/utils/modelCapabilities.d.ts +1 -1
- package/dist/nodes/GitHubCopilotChatAPI/utils/modelCapabilities.js +23 -23
- package/dist/nodes/GitHubCopilotChatAPI/utils/types.d.ts +5 -5
- package/dist/nodes/GitHubCopilotChatModel/GitHubCopilotChatModel.node.d.ts +1 -1
- package/dist/nodes/GitHubCopilotChatModel/GitHubCopilotChatModel.node.js +115 -106
- package/dist/nodes/GitHubCopilotEmbeddings/GitHubCopilotEmbeddings.node.d.ts +1 -1
- package/dist/nodes/GitHubCopilotEmbeddings/GitHubCopilotEmbeddings.node.js +114 -114
- package/dist/nodes/GitHubCopilotOpenAI/GitHubCopilotOpenAI.node.d.ts +1 -1
- package/dist/nodes/GitHubCopilotOpenAI/GitHubCopilotOpenAI.node.js +74 -69
- package/dist/nodes/GitHubCopilotOpenAI/nodeProperties.d.ts +1 -1
- package/dist/nodes/GitHubCopilotOpenAI/nodeProperties.js +181 -181
- package/dist/nodes/GitHubCopilotOpenAI/utils/index.d.ts +2 -2
- package/dist/nodes/GitHubCopilotOpenAI/utils/openaiCompat.d.ts +10 -10
- package/dist/nodes/GitHubCopilotOpenAI/utils/openaiCompat.js +53 -53
- package/dist/nodes/GitHubCopilotOpenAI/utils/types.d.ts +12 -12
- package/dist/nodes/GitHubCopilotTest/GitHubCopilotTest.node.d.ts +1 -1
- package/dist/nodes/GitHubCopilotTest/GitHubCopilotTest.node.js +120 -116
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, ILoadOptionsFunctions, INodePropertyOptions } from
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
|
|
2
2
|
export declare class GitHubCopilotChatAPI implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
4
|
methods: {
|
|
@@ -10,21 +10,21 @@ const DynamicModelLoader_1 = require("../../shared/models/DynamicModelLoader");
|
|
|
10
10
|
class GitHubCopilotChatAPI {
|
|
11
11
|
constructor() {
|
|
12
12
|
this.description = {
|
|
13
|
-
displayName:
|
|
14
|
-
name:
|
|
15
|
-
icon:
|
|
16
|
-
group: [
|
|
13
|
+
displayName: 'GitHub Copilot Chat API',
|
|
14
|
+
name: 'gitHubCopilotChatAPI',
|
|
15
|
+
icon: 'file:../../shared/icons/copilot.svg',
|
|
16
|
+
group: ['transform'],
|
|
17
17
|
version: 1,
|
|
18
|
-
subtitle:
|
|
19
|
-
description:
|
|
18
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["model"]}}',
|
|
19
|
+
description: 'Use official GitHub Copilot Chat API with your subscription - access GPT-5, Claude, Gemini and more',
|
|
20
20
|
defaults: {
|
|
21
|
-
name:
|
|
21
|
+
name: 'GitHub Copilot Chat API',
|
|
22
22
|
},
|
|
23
|
-
inputs: [
|
|
24
|
-
outputs: [
|
|
23
|
+
inputs: ['main'],
|
|
24
|
+
outputs: ['main'],
|
|
25
25
|
credentials: [
|
|
26
26
|
{
|
|
27
|
-
name:
|
|
27
|
+
name: 'githubCopilotApi',
|
|
28
28
|
required: true,
|
|
29
29
|
},
|
|
30
30
|
],
|
|
@@ -44,21 +44,21 @@ class GitHubCopilotChatAPI {
|
|
|
44
44
|
const returnData = [];
|
|
45
45
|
for (let i = 0; i < items.length; i++) {
|
|
46
46
|
try {
|
|
47
|
-
const operation = this.getNodeParameter(
|
|
48
|
-
const modelSource = this.getNodeParameter(
|
|
47
|
+
const operation = this.getNodeParameter('operation', i);
|
|
48
|
+
const modelSource = this.getNodeParameter('modelSource', i, 'fromList');
|
|
49
49
|
let model;
|
|
50
|
-
if (modelSource ===
|
|
51
|
-
model = this.getNodeParameter(
|
|
52
|
-
if (!model || model.trim() ===
|
|
50
|
+
if (modelSource === 'custom') {
|
|
51
|
+
model = this.getNodeParameter('customModel', i);
|
|
52
|
+
if (!model || model.trim() === '') {
|
|
53
53
|
throw new Error("Custom model name is required when using 'Custom (Manual Entry)' mode");
|
|
54
54
|
}
|
|
55
55
|
console.log(`🔧 Using custom model: ${model}`);
|
|
56
56
|
}
|
|
57
57
|
else {
|
|
58
|
-
const selectedModel = this.getNodeParameter(
|
|
59
|
-
if (selectedModel ===
|
|
60
|
-
model = this.getNodeParameter(
|
|
61
|
-
if (!model || model.trim() ===
|
|
58
|
+
const selectedModel = this.getNodeParameter('model', i);
|
|
59
|
+
if (selectedModel === '__manual__') {
|
|
60
|
+
model = this.getNodeParameter('customModel', i);
|
|
61
|
+
if (!model || model.trim() === '') {
|
|
62
62
|
throw new Error("Custom model name is required when selecting '✏️ Enter Custom Model Name'");
|
|
63
63
|
}
|
|
64
64
|
console.log(`✏️ Using manually entered model: ${model}`);
|
|
@@ -68,16 +68,18 @@ class GitHubCopilotChatAPI {
|
|
|
68
68
|
console.log(`✅ Using model from list: ${model}`);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
if (operation ===
|
|
72
|
-
const userMessage = this.getNodeParameter(
|
|
73
|
-
const systemMessage = this.getNodeParameter(
|
|
74
|
-
const advancedOptions = this.getNodeParameter(
|
|
71
|
+
if (operation === 'chat') {
|
|
72
|
+
const userMessage = this.getNodeParameter('message', i);
|
|
73
|
+
const systemMessage = this.getNodeParameter('systemMessage', i, '');
|
|
74
|
+
const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
|
|
75
75
|
const enableRetry = advancedOptions.enableRetry !== false;
|
|
76
76
|
const maxRetries = advancedOptions.maxRetries || 3;
|
|
77
|
-
const includeMedia = this.getNodeParameter(
|
|
77
|
+
const includeMedia = this.getNodeParameter('includeMedia', i, false);
|
|
78
78
|
const modelInfo = GitHubCopilotModels_1.GitHubCopilotModelsManager.getModelByValue(model);
|
|
79
79
|
if (includeMedia) {
|
|
80
|
-
if (modelInfo &&
|
|
80
|
+
if (modelInfo &&
|
|
81
|
+
!(modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.capabilities.vision) &&
|
|
82
|
+
!(modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.capabilities.multimodal)) {
|
|
81
83
|
throw new Error(`Model ${model} does not support vision/image processing. Please select a model with vision capabilities.`);
|
|
82
84
|
}
|
|
83
85
|
else if (!modelInfo) {
|
|
@@ -87,47 +89,47 @@ class GitHubCopilotChatAPI {
|
|
|
87
89
|
const messages = [];
|
|
88
90
|
if (systemMessage) {
|
|
89
91
|
messages.push({
|
|
90
|
-
role:
|
|
92
|
+
role: 'system',
|
|
91
93
|
content: systemMessage,
|
|
92
94
|
});
|
|
93
95
|
}
|
|
94
96
|
if (includeMedia) {
|
|
95
|
-
const mediaSource = this.getNodeParameter(
|
|
96
|
-
const mediaFile = this.getNodeParameter(
|
|
97
|
-
const mediaUrl = this.getNodeParameter(
|
|
98
|
-
const mediaBinaryProperty = this.getNodeParameter(
|
|
97
|
+
const mediaSource = this.getNodeParameter('mediaSource', i);
|
|
98
|
+
const mediaFile = this.getNodeParameter('mediaFile', i, '');
|
|
99
|
+
const mediaUrl = this.getNodeParameter('mediaUrl', i, '');
|
|
100
|
+
const mediaBinaryProperty = this.getNodeParameter('mediaBinaryProperty', i, '');
|
|
99
101
|
if (userMessage.trim()) {
|
|
100
102
|
messages.push({
|
|
101
|
-
role:
|
|
103
|
+
role: 'user',
|
|
102
104
|
content: userMessage,
|
|
103
105
|
});
|
|
104
106
|
}
|
|
105
107
|
try {
|
|
106
108
|
const mediaResult = await (0, mediaDetection_1.processMediaFile)(this, i, mediaSource, mediaFile, mediaUrl, mediaBinaryProperty);
|
|
107
|
-
if (mediaResult.type ===
|
|
109
|
+
if (mediaResult.type === 'image' && mediaResult.dataUrl) {
|
|
108
110
|
messages.push({
|
|
109
|
-
role:
|
|
111
|
+
role: 'user',
|
|
110
112
|
content: mediaResult.dataUrl,
|
|
111
|
-
type:
|
|
113
|
+
type: 'file',
|
|
112
114
|
});
|
|
113
115
|
}
|
|
114
116
|
else {
|
|
115
117
|
messages.push({
|
|
116
|
-
role:
|
|
118
|
+
role: 'user',
|
|
117
119
|
content: `[Image processing failed: ${mediaResult.description}]`,
|
|
118
120
|
});
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
catch (error) {
|
|
122
124
|
messages.push({
|
|
123
|
-
role:
|
|
124
|
-
content: `[Media processing error: ${error instanceof Error ? error.message :
|
|
125
|
+
role: 'user',
|
|
126
|
+
content: `[Media processing error: ${error instanceof Error ? error.message : 'Unknown error'}]`,
|
|
125
127
|
});
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
else {
|
|
129
131
|
messages.push({
|
|
130
|
-
role:
|
|
132
|
+
role: 'user',
|
|
131
133
|
content: userMessage,
|
|
132
134
|
});
|
|
133
135
|
}
|
|
@@ -151,7 +153,7 @@ class GitHubCopilotChatAPI {
|
|
|
151
153
|
catch (error) {
|
|
152
154
|
const isLastAttempt = attempt >= totalAttempts;
|
|
153
155
|
const errorObj = error;
|
|
154
|
-
const is403Error = errorObj.status === 403 || ((_a = errorObj.message) === null || _a === void 0 ? void 0 : _a.includes(
|
|
156
|
+
const is403Error = errorObj.status === 403 || ((_a = errorObj.message) === null || _a === void 0 ? void 0 : _a.includes('403'));
|
|
155
157
|
if (is403Error && enableRetry && !isLastAttempt) {
|
|
156
158
|
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);
|
|
157
159
|
console.log(`GitHub Copilot API attempt ${attempt}/${totalAttempts} failed with 403, retrying in ${delay}ms...`);
|
|
@@ -167,11 +169,11 @@ class GitHubCopilotChatAPI {
|
|
|
167
169
|
throw new Error(`Failed to get response from GitHub Copilot API after ${totalAttempts} attempts (${retriesUsed} retries)`);
|
|
168
170
|
}
|
|
169
171
|
const result = {
|
|
170
|
-
message: ((_c = (_b = response.choices[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content) ||
|
|
172
|
+
message: ((_c = (_b = response.choices[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content) || '',
|
|
171
173
|
model,
|
|
172
174
|
operation,
|
|
173
175
|
usage: response.usage || null,
|
|
174
|
-
finish_reason: ((_d = response.choices[0]) === null || _d === void 0 ? void 0 : _d.finish_reason) ||
|
|
176
|
+
finish_reason: ((_d = response.choices[0]) === null || _d === void 0 ? void 0 : _d.finish_reason) || 'unknown',
|
|
175
177
|
retries: retriesUsed,
|
|
176
178
|
};
|
|
177
179
|
returnData.push({
|
|
@@ -182,12 +184,12 @@ class GitHubCopilotChatAPI {
|
|
|
182
184
|
}
|
|
183
185
|
catch (error) {
|
|
184
186
|
if (this.continueOnFail()) {
|
|
185
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
187
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
186
188
|
returnData.push({
|
|
187
189
|
json: {
|
|
188
190
|
error: errorMessage,
|
|
189
|
-
operation: this.getNodeParameter(
|
|
190
|
-
model: this.getNodeParameter(
|
|
191
|
+
operation: this.getNodeParameter('operation', i),
|
|
192
|
+
model: this.getNodeParameter('model', i),
|
|
191
193
|
},
|
|
192
194
|
pairedItem: { item: i },
|
|
193
195
|
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { INodeProperties } from
|
|
1
|
+
import { INodeProperties } from 'n8n-workflow';
|
|
2
2
|
export declare const nodeProperties: INodeProperties[];
|
|
@@ -4,53 +4,53 @@ exports.nodeProperties = void 0;
|
|
|
4
4
|
const ModelProperties_1 = require("../../shared/properties/ModelProperties");
|
|
5
5
|
exports.nodeProperties = [
|
|
6
6
|
{
|
|
7
|
-
displayName:
|
|
8
|
-
name:
|
|
9
|
-
type:
|
|
7
|
+
displayName: 'Operation',
|
|
8
|
+
name: 'operation',
|
|
9
|
+
type: 'options',
|
|
10
10
|
noDataExpression: true,
|
|
11
11
|
options: [
|
|
12
12
|
{
|
|
13
|
-
name:
|
|
14
|
-
value:
|
|
15
|
-
description:
|
|
13
|
+
name: 'Chat Completion',
|
|
14
|
+
value: 'chat',
|
|
15
|
+
description: 'Send messages to GitHub Copilot Chat API',
|
|
16
16
|
},
|
|
17
17
|
],
|
|
18
|
-
default:
|
|
18
|
+
default: 'chat',
|
|
19
19
|
},
|
|
20
20
|
...ModelProperties_1.CHAT_MODEL_PROPERTIES,
|
|
21
21
|
{
|
|
22
|
-
displayName:
|
|
23
|
-
name:
|
|
24
|
-
type:
|
|
22
|
+
displayName: 'Message',
|
|
23
|
+
name: 'message',
|
|
24
|
+
type: 'string',
|
|
25
25
|
typeOptions: {
|
|
26
26
|
rows: 4,
|
|
27
27
|
},
|
|
28
|
-
default:
|
|
29
|
-
placeholder:
|
|
30
|
-
description:
|
|
28
|
+
default: '',
|
|
29
|
+
placeholder: 'What can I help you with?',
|
|
30
|
+
description: 'The message to send to the AI model',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
displayName:
|
|
34
|
-
name:
|
|
35
|
-
type:
|
|
33
|
+
displayName: 'System Message',
|
|
34
|
+
name: 'systemMessage',
|
|
35
|
+
type: 'string',
|
|
36
36
|
typeOptions: {
|
|
37
37
|
rows: 3,
|
|
38
38
|
},
|
|
39
|
-
default:
|
|
40
|
-
placeholder:
|
|
41
|
-
description:
|
|
39
|
+
default: '',
|
|
40
|
+
placeholder: 'You are a helpful assistant...',
|
|
41
|
+
description: 'System message to set the behavior of the AI model',
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
displayName:
|
|
45
|
-
name:
|
|
46
|
-
type:
|
|
44
|
+
displayName: 'Include Image',
|
|
45
|
+
name: 'includeMedia',
|
|
46
|
+
type: 'boolean',
|
|
47
47
|
default: false,
|
|
48
|
-
description:
|
|
48
|
+
description: 'Whether to include an image file in the message. Supported formats: PNG, JPEG, GIF, WebP.',
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
displayName:
|
|
52
|
-
name:
|
|
53
|
-
type:
|
|
51
|
+
displayName: 'Image Source',
|
|
52
|
+
name: 'mediaSource',
|
|
53
|
+
type: 'options',
|
|
54
54
|
displayOptions: {
|
|
55
55
|
show: {
|
|
56
56
|
includeMedia: [true],
|
|
@@ -58,121 +58,121 @@ exports.nodeProperties = [
|
|
|
58
58
|
},
|
|
59
59
|
options: [
|
|
60
60
|
{
|
|
61
|
-
name:
|
|
62
|
-
value:
|
|
63
|
-
description:
|
|
61
|
+
name: 'Manual Input',
|
|
62
|
+
value: 'manual',
|
|
63
|
+
description: 'Provide image as base64 string or file path',
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
|
-
name:
|
|
67
|
-
value:
|
|
68
|
-
description:
|
|
66
|
+
name: 'URL',
|
|
67
|
+
value: 'url',
|
|
68
|
+
description: 'Download image from URL',
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
|
-
name:
|
|
72
|
-
value:
|
|
73
|
-
description:
|
|
71
|
+
name: 'Binary Data',
|
|
72
|
+
value: 'binary',
|
|
73
|
+
description: 'Use binary data from previous node',
|
|
74
74
|
},
|
|
75
75
|
],
|
|
76
|
-
default:
|
|
77
|
-
description:
|
|
76
|
+
default: 'manual',
|
|
77
|
+
description: 'Source of the image data',
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
|
-
displayName:
|
|
81
|
-
name:
|
|
82
|
-
type:
|
|
80
|
+
displayName: 'Image File',
|
|
81
|
+
name: 'mediaFile',
|
|
82
|
+
type: 'string',
|
|
83
83
|
displayOptions: {
|
|
84
84
|
show: {
|
|
85
85
|
includeMedia: [true],
|
|
86
|
-
mediaSource: [
|
|
86
|
+
mediaSource: ['manual'],
|
|
87
87
|
},
|
|
88
88
|
},
|
|
89
|
-
default:
|
|
90
|
-
placeholder:
|
|
91
|
-
description:
|
|
89
|
+
default: '',
|
|
90
|
+
placeholder: 'Paste base64 string or file path',
|
|
91
|
+
description: 'Image file as base64 string or file path. Supported formats: PNG, JPEG, GIF, WebP.',
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
|
-
displayName:
|
|
95
|
-
name:
|
|
96
|
-
type:
|
|
94
|
+
displayName: 'Image URL',
|
|
95
|
+
name: 'mediaUrl',
|
|
96
|
+
type: 'string',
|
|
97
97
|
displayOptions: {
|
|
98
98
|
show: {
|
|
99
99
|
includeMedia: [true],
|
|
100
|
-
mediaSource: [
|
|
100
|
+
mediaSource: ['url'],
|
|
101
101
|
},
|
|
102
102
|
},
|
|
103
|
-
default:
|
|
104
|
-
placeholder:
|
|
105
|
-
description:
|
|
103
|
+
default: '',
|
|
104
|
+
placeholder: 'https://example.com/image.jpg',
|
|
105
|
+
description: 'URL of the image file to download. Supported formats: PNG, JPEG, GIF, WebP.',
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
|
-
displayName:
|
|
109
|
-
name:
|
|
110
|
-
type:
|
|
108
|
+
displayName: 'Image Binary Property',
|
|
109
|
+
name: 'mediaBinaryProperty',
|
|
110
|
+
type: 'string',
|
|
111
111
|
displayOptions: {
|
|
112
112
|
show: {
|
|
113
113
|
includeMedia: [true],
|
|
114
|
-
mediaSource: [
|
|
114
|
+
mediaSource: ['binary'],
|
|
115
115
|
},
|
|
116
116
|
},
|
|
117
|
-
default:
|
|
118
|
-
placeholder:
|
|
119
|
-
description:
|
|
117
|
+
default: 'data',
|
|
118
|
+
placeholder: 'data',
|
|
119
|
+
description: 'Name of the binary property containing the image file',
|
|
120
120
|
},
|
|
121
121
|
{
|
|
122
|
-
displayName:
|
|
123
|
-
name:
|
|
124
|
-
type:
|
|
125
|
-
placeholder:
|
|
122
|
+
displayName: 'Advanced Options',
|
|
123
|
+
name: 'advancedOptions',
|
|
124
|
+
type: 'collection',
|
|
125
|
+
placeholder: 'Add Field',
|
|
126
126
|
default: {},
|
|
127
127
|
options: [
|
|
128
128
|
{
|
|
129
|
-
displayName:
|
|
130
|
-
name:
|
|
131
|
-
type:
|
|
129
|
+
displayName: 'Temperature',
|
|
130
|
+
name: 'temperature',
|
|
131
|
+
type: 'number',
|
|
132
132
|
typeOptions: {
|
|
133
133
|
minValue: 0,
|
|
134
134
|
maxValue: 2,
|
|
135
135
|
numberPrecision: 2,
|
|
136
136
|
},
|
|
137
137
|
default: 1,
|
|
138
|
-
description:
|
|
138
|
+
description: 'Controls randomness of the response. Higher values make output more random.',
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
|
-
displayName:
|
|
142
|
-
name:
|
|
143
|
-
type:
|
|
141
|
+
displayName: 'Max Tokens',
|
|
142
|
+
name: 'max_tokens',
|
|
143
|
+
type: 'number',
|
|
144
144
|
typeOptions: {
|
|
145
145
|
minValue: 1,
|
|
146
146
|
maxValue: 128000,
|
|
147
147
|
},
|
|
148
148
|
default: 4096,
|
|
149
|
-
description:
|
|
149
|
+
description: 'Maximum number of tokens to generate in the response',
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
|
-
displayName:
|
|
153
|
-
name:
|
|
154
|
-
type:
|
|
152
|
+
displayName: 'Top P',
|
|
153
|
+
name: 'top_p',
|
|
154
|
+
type: 'number',
|
|
155
155
|
typeOptions: {
|
|
156
156
|
minValue: 0,
|
|
157
157
|
maxValue: 1,
|
|
158
158
|
numberPrecision: 2,
|
|
159
159
|
},
|
|
160
160
|
default: 1,
|
|
161
|
-
description:
|
|
161
|
+
description: 'Alternative to temperature, controls diversity via nucleus sampling',
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
|
-
displayName:
|
|
165
|
-
name:
|
|
166
|
-
type:
|
|
164
|
+
displayName: 'Auto Retry on 403 Error',
|
|
165
|
+
name: 'enableRetry',
|
|
166
|
+
type: 'boolean',
|
|
167
167
|
default: true,
|
|
168
|
-
description:
|
|
168
|
+
description: 'Automatically retry requests when hitting TPM (Transactions Per Minute) quota limits (HTTP 403)',
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
|
-
displayName:
|
|
172
|
-
name:
|
|
173
|
-
type:
|
|
171
|
+
displayName: 'Max Retry Attempts',
|
|
172
|
+
name: 'maxRetries',
|
|
173
|
+
type: 'number',
|
|
174
174
|
default: 3,
|
|
175
|
-
description:
|
|
175
|
+
description: 'Maximum number of retry attempts for 403 errors',
|
|
176
176
|
displayOptions: {
|
|
177
177
|
show: {
|
|
178
178
|
enableRetry: [true],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IExecuteFunctions } from
|
|
2
|
-
import { CopilotResponse, RetryConfig, downloadFileFromUrl as sharedDownloadFileFromUrl, getFileFromBinary as sharedGetFileFromBinary, estimateTokens as sharedEstimateTokens } from
|
|
1
|
+
import { IExecuteFunctions } from 'n8n-workflow';
|
|
2
|
+
import { CopilotResponse, RetryConfig, downloadFileFromUrl as sharedDownloadFileFromUrl, getFileFromBinary as sharedGetFileFromBinary, estimateTokens as sharedEstimateTokens } from '../../../shared/utils/GitHubCopilotApiUtils';
|
|
3
3
|
export declare function makeApiRequest(context: IExecuteFunctions, endpoint: string, body: Record<string, unknown>, hasMedia?: boolean, retryConfig?: RetryConfig): Promise<CopilotResponse>;
|
|
4
4
|
export declare const downloadFileFromUrl: typeof sharedDownloadFileFromUrl;
|
|
5
5
|
export declare const getFileFromBinary: typeof sharedGetFileFromBinary;
|
|
@@ -13,36 +13,36 @@ exports.downloadFileFromUrl = GitHubCopilotApiUtils_1.downloadFileFromUrl;
|
|
|
13
13
|
exports.getFileFromBinary = GitHubCopilotApiUtils_1.getFileFromBinary;
|
|
14
14
|
exports.estimateTokens = GitHubCopilotApiUtils_1.estimateTokens;
|
|
15
15
|
function getImageMimeType(buffer) {
|
|
16
|
-
const firstBytes = buffer.toString(
|
|
17
|
-
if (firstBytes.startsWith(
|
|
18
|
-
return
|
|
19
|
-
if (firstBytes.startsWith(
|
|
20
|
-
return
|
|
21
|
-
if (firstBytes.startsWith(
|
|
22
|
-
return
|
|
23
|
-
if (firstBytes.startsWith(
|
|
24
|
-
return
|
|
25
|
-
return
|
|
16
|
+
const firstBytes = buffer.toString('hex', 0, 4);
|
|
17
|
+
if (firstBytes.startsWith('ffd8'))
|
|
18
|
+
return 'image/jpeg';
|
|
19
|
+
if (firstBytes.startsWith('8950'))
|
|
20
|
+
return 'image/png';
|
|
21
|
+
if (firstBytes.startsWith('4749'))
|
|
22
|
+
return 'image/gif';
|
|
23
|
+
if (firstBytes.startsWith('5249'))
|
|
24
|
+
return 'image/webp';
|
|
25
|
+
return 'application/octet-stream';
|
|
26
26
|
}
|
|
27
27
|
function getImageMimeTypeFromFilename(filename) {
|
|
28
|
-
const ext = filename.toLowerCase().split(
|
|
28
|
+
const ext = filename.toLowerCase().split('.').pop();
|
|
29
29
|
switch (ext) {
|
|
30
|
-
case
|
|
31
|
-
case
|
|
32
|
-
return
|
|
33
|
-
case
|
|
34
|
-
return
|
|
35
|
-
case
|
|
36
|
-
return
|
|
37
|
-
case
|
|
38
|
-
return
|
|
39
|
-
case
|
|
40
|
-
return
|
|
41
|
-
case
|
|
42
|
-
case
|
|
43
|
-
return
|
|
30
|
+
case 'jpg':
|
|
31
|
+
case 'jpeg':
|
|
32
|
+
return 'image/jpeg';
|
|
33
|
+
case 'png':
|
|
34
|
+
return 'image/png';
|
|
35
|
+
case 'gif':
|
|
36
|
+
return 'image/gif';
|
|
37
|
+
case 'webp':
|
|
38
|
+
return 'image/webp';
|
|
39
|
+
case 'bmp':
|
|
40
|
+
return 'image/bmp';
|
|
41
|
+
case 'tiff':
|
|
42
|
+
case 'tif':
|
|
43
|
+
return 'image/tiff';
|
|
44
44
|
default:
|
|
45
|
-
return
|
|
45
|
+
return 'application/octet-stream';
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
function validateFileSize(buffer, maxSize = 20 * 1024 * 1024) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IExecuteFunctions } from
|
|
2
|
-
import { ProcessedFileResult, OptimizationOptions } from
|
|
1
|
+
import { IExecuteFunctions } from 'n8n-workflow';
|
|
2
|
+
import { ProcessedFileResult, OptimizationOptions } from './types';
|
|
3
3
|
export declare function processImageFile(context: IExecuteFunctions, itemIndex: number, imageSource: string, imageFile?: string, imageUrl?: string, imageProperty?: string, optimization?: OptimizationOptions): Promise<ProcessedFileResult>;
|
|
4
4
|
export declare function compressImageToTokenLimit(base64Data: string, maxTokens?: number): string;
|
|
5
5
|
export declare function resizeImageDimensions(originalWidth: number, originalHeight: number, maxWidth?: number, maxHeight?: number): {
|
|
@@ -9,28 +9,28 @@ async function processImageFile(context, itemIndex, imageSource, imageFile, imag
|
|
|
9
9
|
let imageBuffer;
|
|
10
10
|
let filename;
|
|
11
11
|
switch (imageSource) {
|
|
12
|
-
case
|
|
12
|
+
case 'file':
|
|
13
13
|
if (!imageFile) {
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error('Image file content is required when source is "file"');
|
|
15
15
|
}
|
|
16
|
-
imageBuffer = Buffer.from(imageFile,
|
|
17
|
-
filename =
|
|
16
|
+
imageBuffer = Buffer.from(imageFile, 'base64');
|
|
17
|
+
filename = 'uploaded_image.jpg';
|
|
18
18
|
break;
|
|
19
|
-
case
|
|
19
|
+
case 'url':
|
|
20
20
|
if (!imageUrl) {
|
|
21
|
-
throw new Error(
|
|
21
|
+
throw new Error('Image URL is required when source is "url"');
|
|
22
22
|
}
|
|
23
23
|
imageBuffer = await (0, helpers_1.downloadFileFromUrl)(imageUrl);
|
|
24
|
-
filename = imageUrl.split(
|
|
24
|
+
filename = imageUrl.split('/').pop() || 'downloaded_image.jpg';
|
|
25
25
|
break;
|
|
26
|
-
case
|
|
26
|
+
case 'binary': {
|
|
27
27
|
if (!imageProperty) {
|
|
28
|
-
throw new Error(
|
|
28
|
+
throw new Error('Image property name is required when source is "binary"');
|
|
29
29
|
}
|
|
30
30
|
imageBuffer = await (0, helpers_1.getFileFromBinary)(context, itemIndex, imageProperty);
|
|
31
31
|
const items = context.getInputData();
|
|
32
32
|
const item = items[itemIndex];
|
|
33
|
-
filename = ((_b = (_a = item.binary) === null || _a === void 0 ? void 0 : _a[imageProperty]) === null || _b === void 0 ? void 0 : _b.fileName) ||
|
|
33
|
+
filename = ((_b = (_a = item.binary) === null || _a === void 0 ? void 0 : _a[imageProperty]) === null || _b === void 0 ? void 0 : _b.fileName) || 'binary_image.jpg';
|
|
34
34
|
break;
|
|
35
35
|
}
|
|
36
36
|
default:
|
|
@@ -40,14 +40,14 @@ async function processImageFile(context, itemIndex, imageSource, imageFile, imag
|
|
|
40
40
|
imageBuffer = await optimizeImage(imageBuffer, optimization);
|
|
41
41
|
}
|
|
42
42
|
(0, helpers_1.validateFileSize)(imageBuffer, 20480);
|
|
43
|
-
const base64Image = imageBuffer.toString(
|
|
43
|
+
const base64Image = imageBuffer.toString('base64');
|
|
44
44
|
const estimatedTokens = (0, helpers_1.estimateTokens)(base64Image);
|
|
45
45
|
if (estimatedTokens > 50000) {
|
|
46
46
|
const compressedBuffer = await optimizeImage(imageBuffer, {
|
|
47
47
|
quality: 70,
|
|
48
48
|
maxSizeKB: (optimization === null || optimization === void 0 ? void 0 : optimization.maxSizeKB) || 1024,
|
|
49
49
|
});
|
|
50
|
-
const compressedBase64 = compressedBuffer.toString(
|
|
50
|
+
const compressedBase64 = compressedBuffer.toString('base64');
|
|
51
51
|
const compressedTokens = (0, helpers_1.estimateTokens)(compressedBase64);
|
|
52
52
|
if (compressedTokens < estimatedTokens) {
|
|
53
53
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export type { RetryConfig } from
|
|
4
|
-
export * from
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './helpers';
|
|
3
|
+
export type { RetryConfig } from '../../../shared/utils/GitHubCopilotApiUtils';
|
|
4
|
+
export * from './imageProcessor';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { IExecuteFunctions } from
|
|
2
|
-
export declare function processMediaFile(context: IExecuteFunctions, itemIndex: number, source:
|
|
3
|
-
type:
|
|
1
|
+
import { IExecuteFunctions } from 'n8n-workflow';
|
|
2
|
+
export declare function processMediaFile(context: IExecuteFunctions, itemIndex: number, source: 'manual' | 'url' | 'binary', mediaFile?: string, mediaUrl?: string, binaryProperty?: string): Promise<{
|
|
3
|
+
type: 'image' | 'unknown';
|
|
4
4
|
dataUrl?: string;
|
|
5
5
|
description: string;
|
|
6
6
|
mimeType: string;
|