n8n-nodes-github-copilot 4.2.1 → 4.3.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.
@@ -0,0 +1,10 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
2
+ export declare class GitHubCopilotPGVector implements INodeType {
3
+ description: INodeTypeDescription;
4
+ methods: {
5
+ loadOptions: {
6
+ getAvailableEmbeddingModels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
7
+ };
8
+ };
9
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
10
+ }
@@ -0,0 +1,421 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubCopilotPGVector = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const OAuthTokenManager_1 = require("../../shared/utils/OAuthTokenManager");
6
+ const GitHubCopilotEndpoints_1 = require("../../shared/utils/GitHubCopilotEndpoints");
7
+ const DynamicModelLoader_1 = require("../../shared/models/DynamicModelLoader");
8
+ const EmbeddingsApiUtils_1 = require("../../shared/utils/EmbeddingsApiUtils");
9
+ class GitHubCopilotPGVector {
10
+ constructor() {
11
+ this.description = {
12
+ displayName: 'GitHub Copilot PGVector',
13
+ name: 'gitHubCopilotPGVector',
14
+ icon: 'file:../../shared/icons/copilot.svg',
15
+ group: ['transform'],
16
+ version: 1,
17
+ subtitle: '={{$parameter["operation"]}}',
18
+ description: 'GitHub Copilot Embeddings for Postgres PGVector Store',
19
+ defaults: {
20
+ name: 'GitHub Copilot PGVector',
21
+ },
22
+ inputs: ['main'],
23
+ outputs: ['main'],
24
+ credentials: [
25
+ {
26
+ name: 'githubCopilotApi',
27
+ required: true,
28
+ },
29
+ {
30
+ name: 'postgres',
31
+ required: true,
32
+ },
33
+ ],
34
+ properties: [
35
+ {
36
+ displayName: 'Operation',
37
+ name: 'operation',
38
+ type: 'options',
39
+ noDataExpression: true,
40
+ options: [
41
+ {
42
+ name: 'Insert Documents',
43
+ value: 'insert',
44
+ description: 'Insert documents with embeddings into PGVector',
45
+ action: 'Insert documents into PGVector',
46
+ },
47
+ {
48
+ name: 'Search Similar',
49
+ value: 'search',
50
+ description: 'Search for similar documents using vector similarity',
51
+ action: 'Search similar documents',
52
+ },
53
+ {
54
+ name: 'Create Table',
55
+ value: 'createTable',
56
+ description: 'Create PGVector table with embeddings column',
57
+ action: 'Create PGVector table',
58
+ },
59
+ ],
60
+ default: 'insert',
61
+ },
62
+ {
63
+ displayName: 'Embedding Model',
64
+ name: 'model',
65
+ type: 'options',
66
+ typeOptions: {
67
+ loadOptionsMethod: 'getAvailableEmbeddingModels',
68
+ },
69
+ options: [
70
+ {
71
+ name: 'Text Embedding 3 Small',
72
+ value: 'text-embedding-3-small',
73
+ description: "OpenAI's text-embedding-3-small model (recommended)",
74
+ },
75
+ {
76
+ name: 'Text Embedding Ada 002',
77
+ value: 'text-embedding-ada-002',
78
+ description: 'Legacy embedding model',
79
+ },
80
+ ],
81
+ default: 'text-embedding-3-small',
82
+ description: 'Embedding model to use',
83
+ },
84
+ {
85
+ displayName: 'Table Name',
86
+ name: 'tableName',
87
+ type: 'string',
88
+ default: 'documents',
89
+ required: true,
90
+ placeholder: 'documents',
91
+ description: 'Name of the PGVector table',
92
+ displayOptions: {
93
+ show: {
94
+ operation: ['insert', 'search', 'createTable'],
95
+ },
96
+ },
97
+ },
98
+ {
99
+ displayName: 'Text Field',
100
+ name: 'textField',
101
+ type: 'string',
102
+ default: 'text',
103
+ required: true,
104
+ placeholder: 'text',
105
+ description: 'Field name containing the text to embed',
106
+ displayOptions: {
107
+ show: {
108
+ operation: ['insert'],
109
+ },
110
+ },
111
+ },
112
+ {
113
+ displayName: 'Metadata Fields',
114
+ name: 'metadataFields',
115
+ type: 'string',
116
+ default: '',
117
+ placeholder: 'title,author,date',
118
+ description: 'Comma-separated list of metadata fields to store (optional)',
119
+ displayOptions: {
120
+ show: {
121
+ operation: ['insert'],
122
+ },
123
+ },
124
+ },
125
+ {
126
+ displayName: 'Query Text',
127
+ name: 'queryText',
128
+ type: 'string',
129
+ default: '',
130
+ required: true,
131
+ placeholder: 'Search query text',
132
+ description: 'Text to search for similar documents',
133
+ displayOptions: {
134
+ show: {
135
+ operation: ['search'],
136
+ },
137
+ },
138
+ },
139
+ {
140
+ displayName: 'Limit',
141
+ name: 'limit',
142
+ type: 'number',
143
+ default: 10,
144
+ description: 'Maximum number of results to return',
145
+ displayOptions: {
146
+ show: {
147
+ operation: ['search'],
148
+ },
149
+ },
150
+ },
151
+ {
152
+ displayName: 'Distance Threshold',
153
+ name: 'distanceThreshold',
154
+ type: 'number',
155
+ default: 1.0,
156
+ description: 'Maximum cosine distance for results (0-2, lower is more similar)',
157
+ displayOptions: {
158
+ show: {
159
+ operation: ['search'],
160
+ },
161
+ },
162
+ typeOptions: {
163
+ minValue: 0,
164
+ maxValue: 2,
165
+ numberPrecision: 2,
166
+ },
167
+ },
168
+ {
169
+ displayName: 'Vector Dimensions',
170
+ name: 'vectorDimensions',
171
+ type: 'number',
172
+ default: 1536,
173
+ description: 'Number of dimensions for the embedding vector',
174
+ displayOptions: {
175
+ show: {
176
+ operation: ['createTable'],
177
+ },
178
+ },
179
+ },
180
+ {
181
+ displayName: 'Options',
182
+ name: 'options',
183
+ type: 'collection',
184
+ placeholder: 'Add Option',
185
+ default: {},
186
+ options: [
187
+ {
188
+ displayName: 'Dimensions',
189
+ name: 'dimensions',
190
+ type: 'number',
191
+ default: 1536,
192
+ description: 'The number of dimensions for the embedding (text-embedding-3-small supports 512-1536)',
193
+ typeOptions: {
194
+ minValue: 1,
195
+ maxValue: 1536,
196
+ },
197
+ },
198
+ {
199
+ displayName: 'Embedding Column Name',
200
+ name: 'embeddingColumn',
201
+ type: 'string',
202
+ default: 'embedding',
203
+ description: 'Name of the column storing embeddings',
204
+ },
205
+ {
206
+ displayName: 'ID Column Name',
207
+ name: 'idColumn',
208
+ type: 'string',
209
+ default: 'id',
210
+ description: 'Name of the ID column',
211
+ },
212
+ {
213
+ displayName: 'Text Column Name',
214
+ name: 'textColumn',
215
+ type: 'string',
216
+ default: 'content',
217
+ description: 'Name of the column storing text content',
218
+ },
219
+ {
220
+ displayName: 'Batch Size',
221
+ name: 'batchSize',
222
+ type: 'number',
223
+ default: 10,
224
+ description: 'Number of documents to process in each batch',
225
+ typeOptions: {
226
+ minValue: 1,
227
+ maxValue: 100,
228
+ },
229
+ },
230
+ {
231
+ displayName: 'Enable Retry',
232
+ name: 'enableRetry',
233
+ type: 'boolean',
234
+ default: true,
235
+ description: 'Whether to retry on TPM quota errors (403)',
236
+ },
237
+ ],
238
+ },
239
+ ],
240
+ };
241
+ this.methods = {
242
+ loadOptions: {
243
+ async getAvailableEmbeddingModels() {
244
+ return await DynamicModelLoader_1.loadAvailableEmbeddingModels.call(this);
245
+ },
246
+ },
247
+ };
248
+ }
249
+ async execute() {
250
+ const items = this.getInputData();
251
+ const returnData = [];
252
+ const operation = this.getNodeParameter('operation', 0);
253
+ const postgresCredentials = await this.getCredentials('postgres', 0);
254
+ const githubCredentials = await this.getCredentials('githubCopilotApi', 0);
255
+ const githubToken = githubCredentials.token;
256
+ if (!GitHubCopilotEndpoints_1.GitHubCopilotEndpoints.validateToken(githubToken)) {
257
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Invalid GitHub token format. Token must start with 'gho_' or 'github_pat_'");
258
+ }
259
+ const oauthToken = await OAuthTokenManager_1.OAuthTokenManager.getValidOAuthToken(githubToken);
260
+ const tableName = this.getNodeParameter('tableName', 0);
261
+ const model = this.getNodeParameter('model', 0);
262
+ const options = this.getNodeParameter('options', 0, {});
263
+ const { Client } = require('pg');
264
+ const pgClient = new Client({
265
+ host: postgresCredentials.host,
266
+ port: postgresCredentials.port,
267
+ user: postgresCredentials.user,
268
+ password: postgresCredentials.password,
269
+ database: postgresCredentials.database,
270
+ });
271
+ try {
272
+ await pgClient.connect();
273
+ switch (operation) {
274
+ case 'createTable': {
275
+ const vectorDimensions = this.getNodeParameter('vectorDimensions', 0);
276
+ const embeddingColumn = options.embeddingColumn || 'embedding';
277
+ const idColumn = options.idColumn || 'id';
278
+ const textColumn = options.textColumn || 'content';
279
+ await pgClient.query('CREATE EXTENSION IF NOT EXISTS vector');
280
+ const createTableQuery = `
281
+ CREATE TABLE IF NOT EXISTS ${tableName} (
282
+ ${idColumn} SERIAL PRIMARY KEY,
283
+ ${textColumn} TEXT NOT NULL,
284
+ metadata JSONB,
285
+ ${embeddingColumn} vector(${vectorDimensions}),
286
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
287
+ );
288
+
289
+ CREATE INDEX IF NOT EXISTS ${tableName}_${embeddingColumn}_idx
290
+ ON ${tableName} USING ivfflat (${embeddingColumn} vector_cosine_ops)
291
+ WITH (lists = 100);
292
+ `;
293
+ await pgClient.query(createTableQuery);
294
+ returnData.push({
295
+ json: {
296
+ success: true,
297
+ message: `Table ${tableName} created with ${vectorDimensions} dimensions`,
298
+ table: tableName,
299
+ dimensions: vectorDimensions,
300
+ },
301
+ });
302
+ break;
303
+ }
304
+ case 'insert': {
305
+ const textField = this.getNodeParameter('textField', 0);
306
+ const metadataFieldsStr = this.getNodeParameter('metadataFields', 0, '');
307
+ const metadataFields = metadataFieldsStr
308
+ ? metadataFieldsStr.split(',').map((f) => f.trim())
309
+ : [];
310
+ const batchSize = options.batchSize || 10;
311
+ const embeddingColumn = options.embeddingColumn || 'embedding';
312
+ const textColumn = options.textColumn || 'content';
313
+ const dimensions = options.dimensions;
314
+ for (let i = 0; i < items.length; i += batchSize) {
315
+ const batch = items.slice(i, Math.min(i + batchSize, items.length));
316
+ const texts = batch.map((item) => String(item.json[textField]));
317
+ const requestBody = {
318
+ model,
319
+ input: texts,
320
+ };
321
+ if (dimensions) {
322
+ requestBody.dimensions = dimensions;
323
+ }
324
+ const embeddingResponse = await (0, EmbeddingsApiUtils_1.executeEmbeddingsRequest)(oauthToken, requestBody, options.enableRetry !== false, 3);
325
+ for (let j = 0; j < batch.length; j++) {
326
+ const item = batch[j];
327
+ const embedding = embeddingResponse.data[j].embedding;
328
+ const text = texts[j];
329
+ const metadata = {};
330
+ metadataFields.forEach((field) => {
331
+ if (item.json[field] !== undefined) {
332
+ metadata[field] = item.json[field];
333
+ }
334
+ });
335
+ const insertQuery = `
336
+ INSERT INTO ${tableName} (${textColumn}, metadata, ${embeddingColumn})
337
+ VALUES ($1, $2, $3)
338
+ RETURNING *
339
+ `;
340
+ const result = await pgClient.query(insertQuery, [
341
+ text,
342
+ JSON.stringify(metadata),
343
+ `[${embedding.join(',')}]`,
344
+ ]);
345
+ returnData.push({
346
+ json: {
347
+ success: true,
348
+ id: result.rows[0].id,
349
+ text: text.substring(0, 100) + (text.length > 100 ? '...' : ''),
350
+ dimensions: embedding.length,
351
+ },
352
+ pairedItem: { item: i + j },
353
+ });
354
+ }
355
+ }
356
+ break;
357
+ }
358
+ case 'search': {
359
+ const queryText = this.getNodeParameter('queryText', 0);
360
+ const limit = this.getNodeParameter('limit', 0);
361
+ const distanceThreshold = this.getNodeParameter('distanceThreshold', 0);
362
+ const embeddingColumn = options.embeddingColumn || 'embedding';
363
+ const textColumn = options.textColumn || 'content';
364
+ const dimensions = options.dimensions;
365
+ const requestBody = {
366
+ model,
367
+ input: [queryText],
368
+ };
369
+ if (dimensions) {
370
+ requestBody.dimensions = dimensions;
371
+ }
372
+ const embeddingResponse = await (0, EmbeddingsApiUtils_1.executeEmbeddingsRequest)(oauthToken, requestBody, options.enableRetry !== false, 3);
373
+ const queryEmbedding = embeddingResponse.data[0].embedding;
374
+ const searchQuery = `
375
+ SELECT
376
+ *,
377
+ (${embeddingColumn} <=> $1::vector) as distance
378
+ FROM ${tableName}
379
+ WHERE (${embeddingColumn} <=> $1::vector) < $2
380
+ ORDER BY ${embeddingColumn} <=> $1::vector
381
+ LIMIT $3
382
+ `;
383
+ const searchResult = await pgClient.query(searchQuery, [
384
+ `[${queryEmbedding.join(',')}]`,
385
+ distanceThreshold,
386
+ limit,
387
+ ]);
388
+ searchResult.rows.forEach((row) => {
389
+ returnData.push({
390
+ json: {
391
+ id: row.id,
392
+ text: row[textColumn],
393
+ metadata: row.metadata,
394
+ distance: row.distance,
395
+ similarity: 1 - row.distance / 2,
396
+ },
397
+ });
398
+ });
399
+ break;
400
+ }
401
+ }
402
+ }
403
+ catch (error) {
404
+ if (this.continueOnFail()) {
405
+ returnData.push({
406
+ json: {
407
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
408
+ },
409
+ });
410
+ }
411
+ else {
412
+ throw error;
413
+ }
414
+ }
415
+ finally {
416
+ await pgClient.end();
417
+ }
418
+ return [returnData];
419
+ }
420
+ }
421
+ exports.GitHubCopilotPGVector = GitHubCopilotPGVector;
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "n8n community node for GitHub Copilot with CLI, Chat API, AI Chat Model, and n8n v2 Chat Hub integration - access GPT-5, Claude Sonnet 4.5, Gemini and more using your Copilot subscription",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-github-copilot",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "n8n community node for GitHub Copilot with CLI, Chat API, AI Chat Model, and n8n v2 Chat Hub integration - access GPT-5, Claude Sonnet 4.5, Gemini and more using your Copilot subscription",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/sufficit/n8n-nodes-github-copilot",