n8n-nodes-qlik-cloud 1.0.4 → 1.0.7

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.
@@ -7,23 +7,70 @@ const index_1 = require("./resources/apps/index");
7
7
  const index_2 = require("./resources/assistants/index");
8
8
  const index_3 = require("./resources/audits/index");
9
9
  const index_4 = require("./resources/items/index");
10
+ const DEFAULT_PAGE_SIZE = 100;
11
+ function extractPageItems(response) {
12
+ const payload = response?.data ?? response;
13
+ if (Array.isArray(payload)) {
14
+ return payload;
15
+ }
16
+ if (payload === undefined || payload === null) {
17
+ return [];
18
+ }
19
+ return [payload];
20
+ }
21
+ function extractNextCursor(response) {
22
+ const nextLink = response?.links?.next;
23
+ const href = typeof nextLink === 'string' ? nextLink : nextLink?.href;
24
+ if (typeof href === 'string' && href.length) {
25
+ try {
26
+ const url = href.startsWith('http') ? new URL(href) : new URL(href, 'https://qlik.cloud');
27
+ return url.searchParams.get('next') ?? undefined;
28
+ }
29
+ catch {
30
+ return undefined;
31
+ }
32
+ }
33
+ if (typeof response?.next === 'string') {
34
+ return response.next;
35
+ }
36
+ if (typeof response?.meta?.next === 'string') {
37
+ return response.meta.next;
38
+ }
39
+ return undefined;
40
+ }
41
+ async function fetchPaginatedResults(context, endpoint, filters, limit, pageSize = DEFAULT_PAGE_SIZE) {
42
+ const collected = [];
43
+ let cursor;
44
+ do {
45
+ const qs = { ...filters };
46
+ const chunkSize = limit === undefined ? pageSize : Math.min(pageSize, limit - collected.length);
47
+ if (chunkSize <= 0) {
48
+ break;
49
+ }
50
+ qs.limit = chunkSize;
51
+ if (cursor) {
52
+ qs.next = cursor;
53
+ }
54
+ const response = await transport_1.qlikApiRequest.call(context, 'GET', endpoint, undefined, qs);
55
+ const pageItems = extractPageItems(response);
56
+ collected.push(...pageItems);
57
+ cursor = extractNextCursor(response);
58
+ } while (cursor && (limit === undefined || collected.length < limit));
59
+ return limit === undefined ? collected : collected.slice(0, limit);
60
+ }
10
61
  async function handleAppsResource(operation, context) {
11
62
  if (operation === 'getAll') {
12
63
  const returnAll = context.getNodeParameter('returnAll', 0);
13
64
  const limit = returnAll ? undefined : context.getNodeParameter('limit', 0);
14
65
  const options = context.getNodeParameter('options', 0);
15
66
  const qs = {};
16
- if (limit) {
17
- qs.limit = limit;
18
- }
19
67
  if (options.name) {
20
68
  qs.name = options.name;
21
69
  }
22
70
  if (options.spaceId) {
23
71
  qs.spaceId = options.spaceId;
24
72
  }
25
- const response = await transport_1.qlikApiRequest.call(context, 'GET', '/api/v1/apps', undefined, qs);
26
- return response.data || response;
73
+ return await fetchPaginatedResults(context, '/api/v1/apps', qs, limit);
27
74
  }
28
75
  if (operation === 'get') {
29
76
  const appId = context.getNodeParameter('appId', 0);
@@ -201,6 +248,28 @@ async function handleAssistantsResource(operation, context) {
201
248
  const body = { name };
202
249
  return await transport_1.qlikApiRequest.call(context, 'POST', `/api/v1/assistants/${assistantId}/threads`, body);
203
250
  }
251
+ if (operation === 'streamThread') {
252
+ const assistantId = context.getNodeParameter('assistantId', 0);
253
+ const threadId = context.getNodeParameter('threadId', 0);
254
+ const messages = context.getNodeParameter('messages', 0);
255
+ const options = context.getNodeParameter('options', 0);
256
+ const body = {
257
+ messages: typeof messages === 'string' ? JSON.parse(messages) : messages,
258
+ };
259
+ if (options.followUpContext) {
260
+ body.followUpContext = typeof options.followUpContext === 'string'
261
+ ? JSON.parse(options.followUpContext)
262
+ : options.followUpContext;
263
+ }
264
+ return await transport_1.qlikApiRequest.call(context, 'POST', `/api/v1/assistants/${assistantId}/threads/${threadId}/actions/stream`, body);
265
+ }
266
+ if (operation === 'invokeThread') {
267
+ const assistantId = context.getNodeParameter('assistantId', 0);
268
+ const threadId = context.getNodeParameter('threadId', 0);
269
+ const message = context.getNodeParameter('message', 0);
270
+ const body = { message };
271
+ return await transport_1.qlikApiRequest.call(context, 'POST', `/api/v1/assistants/${assistantId}/threads/${threadId}/actions/invoke`, body);
272
+ }
204
273
  if (operation === 'delete') {
205
274
  const assistantId = context.getNodeParameter('assistantId', 0);
206
275
  await transport_1.qlikApiRequest.call(context, 'DELETE', `/api/v1/assistants/${assistantId}`);
@@ -214,9 +283,6 @@ async function handleAuditsResource(operation, context) {
214
283
  const limit = returnAll ? undefined : context.getNodeParameter('limit', 0);
215
284
  const options = context.getNodeParameter('options', 0);
216
285
  const qs = {};
217
- if (limit) {
218
- qs.limit = limit;
219
- }
220
286
  if (options.eventType) {
221
287
  qs.eventType = options.eventType;
222
288
  }
@@ -232,8 +298,7 @@ async function handleAuditsResource(operation, context) {
232
298
  if (options.sort) {
233
299
  qs.sort = options.sort;
234
300
  }
235
- const response = await transport_1.qlikApiRequest.call(context, 'GET', '/api/v1/audits', undefined, qs);
236
- return response.data || response;
301
+ return await fetchPaginatedResults(context, '/api/v1/audits', qs, limit);
237
302
  }
238
303
  if (operation === 'get') {
239
304
  const auditId = context.getNodeParameter('auditId', 0);
@@ -259,9 +324,6 @@ async function handleItemsResource(operation, context) {
259
324
  const limit = returnAll ? undefined : context.getNodeParameter('limit', 0);
260
325
  const options = context.getNodeParameter('options', 0);
261
326
  const qs = {};
262
- if (limit) {
263
- qs.limit = limit;
264
- }
265
327
  if (options.name) {
266
328
  qs.name = options.name;
267
329
  }
@@ -277,8 +339,7 @@ async function handleItemsResource(operation, context) {
277
339
  if (options.sort) {
278
340
  qs.sort = options.sort;
279
341
  }
280
- const response = await transport_1.qlikApiRequest.call(context, 'GET', '/api/v1/items', undefined, qs);
281
- return response.data || response;
342
+ return await fetchPaginatedResults(context, '/api/v1/items', qs, limit);
282
343
  }
283
344
  if (operation === 'get') {
284
345
  const itemId = context.getNodeParameter('itemId', 0);
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" viewBox="0 0 71.39 29.74"><defs><style>.cls-2{stroke-width:0;fill:#54565a}</style></defs><path d="M70.47 27.52c.05-.07.07-.15.07-.24s-.02-.17-.07-.24-.1-.11-.16-.14a.38.38 0 0 0-.17-.04h-.66v1.31h.29v-.44h.29l.23.44h.32l-.27-.51a.47.47 0 0 0 .15-.13Zm-.71-.45h.27s.07.01.12.04c.04.03.07.08.07.16s-.02.14-.07.18c-.05.04-.09.06-.13.06h-.27v-.44Z" class="cls-2"/><path d="M71.28 26.97c-.07-.17-.17-.32-.31-.45-.13-.13-.28-.23-.45-.31s-.36-.11-.55-.11-.38.04-.55.11-.32.18-.45.31-.23.28-.3.45c-.07.17-.11.36-.11.55s.04.38.11.55c.07.17.17.32.3.45.13.13.28.23.45.31s.36.11.55.11.38-.04.55-.11.32-.18.45-.31.23-.28.31-.45c.07-.17.11-.36.11-.55s-.04-.38-.11-.55Zm-.37 1.1c-.1.16-.23.29-.39.39-.16.1-.34.15-.54.15s-.38-.05-.54-.15c-.16-.1-.29-.23-.39-.39-.1-.16-.15-.34-.15-.54s.05-.38.15-.54c.1-.16.23-.29.39-.39.16-.1.34-.15.54-.15s.38.05.54.15c.16.1.29.23.39.39.1.16.15.34.15.54s-.05.38-.15.54ZM34.9.65h2.96v28.32H34.9zM42.95 9.19h2.95v19.78h-2.95z" class="cls-2"/><circle cx="44.45" cy="2.67" r="2.02" class="cls-2"/><path d="M66.62 9.19h-4.11l-8.52 7.46-.02-16h-2.94v28.32h2.94v-9.14l8.75 9.14h4.1L56.39 18.39l10.23-9.2zM14.87 26.69c-6.53 0-11.82-5.29-11.82-11.82 0-2.77.96-5.32 2.55-7.34L3.44 5.34A14.922 14.922 0 0 0 0 14.87c0 8.21 6.66 14.87 14.87 14.87 3.56 0 6.83-1.25 9.39-3.34l-2.16-2.19c-2 1.55-4.5 2.47-7.23 2.47Z" class="cls-2"/><path fill="#009445" stroke-width="0" d="m26.31 24.34.17-.17a14.83 14.83 0 0 0 3.26-9.3C29.74 6.66 23.08 0 14.87 0c-3.54 0-6.79 1.24-9.34 3.3-.74.6-1.41 1.26-2.03 1.98-.02.02-.03.04-.05.06l2.16 2.19s.04-.05.06-.07c.59-.74 1.27-1.4 2.02-1.97a11.74 11.74 0 0 1 7.18-2.44c6.53 0 11.82 5.29 11.82 11.82 0 2.75-.94 5.29-2.52 7.3-.57.73-1.23 1.39-1.95 1.96l-.12.09 2.16 2.19 2.54 2.57h4.1l-4.59-4.64Z"/></svg>
@@ -11,4 +11,6 @@ export declare const assistantsListStartersDescription: INodeProperties[];
11
11
  export declare const assistantsCreateStarterDescription: INodeProperties[];
12
12
  export declare const assistantsListThreadsDescription: INodeProperties[];
13
13
  export declare const assistantsCreateThreadDescription: INodeProperties[];
14
+ export declare const assistantsStreamThreadDescription: INodeProperties[];
15
+ export declare const assistantsInvokeThreadDescription: INodeProperties[];
14
16
  export declare const assistantDescription: INodeProperties[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assistantDescription = exports.assistantsCreateThreadDescription = exports.assistantsListThreadsDescription = exports.assistantsCreateStarterDescription = exports.assistantsListStartersDescription = exports.assistantsDeleteDescription = exports.assistantsBulkSearchSourcesDescription = exports.assistantsGetFeedbackDescription = exports.assistantsSearchDescription = exports.assistantsUpdateDescription = exports.assistantsCreateDescription = exports.assistantsGetDescription = exports.assistantsGetAllDescription = void 0;
3
+ exports.assistantDescription = exports.assistantsInvokeThreadDescription = exports.assistantsStreamThreadDescription = exports.assistantsCreateThreadDescription = exports.assistantsListThreadsDescription = exports.assistantsCreateStarterDescription = exports.assistantsListStartersDescription = exports.assistantsDeleteDescription = exports.assistantsBulkSearchSourcesDescription = exports.assistantsGetFeedbackDescription = exports.assistantsSearchDescription = exports.assistantsUpdateDescription = exports.assistantsCreateDescription = exports.assistantsGetDescription = exports.assistantsGetAllDescription = void 0;
4
4
  // Get All Assistants
5
5
  exports.assistantsGetAllDescription = [
6
6
  {
@@ -510,6 +510,118 @@ exports.assistantsCreateThreadDescription = [
510
510
  description: 'The name of the thread',
511
511
  },
512
512
  ];
513
+ // Stream Thread
514
+ exports.assistantsStreamThreadDescription = [
515
+ {
516
+ displayName: 'Assistant ID',
517
+ name: 'assistantId',
518
+ type: 'string',
519
+ default: '',
520
+ required: true,
521
+ displayOptions: {
522
+ show: {
523
+ resource: ['assistants'],
524
+ operation: ['streamThread'],
525
+ },
526
+ },
527
+ description: 'The ID of the assistant',
528
+ },
529
+ {
530
+ displayName: 'Thread ID',
531
+ name: 'threadId',
532
+ type: 'string',
533
+ default: '',
534
+ required: true,
535
+ displayOptions: {
536
+ show: {
537
+ resource: ['assistants'],
538
+ operation: ['streamThread'],
539
+ },
540
+ },
541
+ description: 'The ID of the thread to stream',
542
+ },
543
+ {
544
+ displayName: 'Messages',
545
+ name: 'messages',
546
+ type: 'json',
547
+ default: '[]',
548
+ required: true,
549
+ displayOptions: {
550
+ show: {
551
+ resource: ['assistants'],
552
+ operation: ['streamThread'],
553
+ },
554
+ },
555
+ description: 'Array of message objects to send to the stream',
556
+ },
557
+ {
558
+ displayName: 'Options',
559
+ name: 'options',
560
+ type: 'collection',
561
+ placeholder: 'Add Option',
562
+ default: {},
563
+ displayOptions: {
564
+ show: {
565
+ resource: ['assistants'],
566
+ operation: ['streamThread'],
567
+ },
568
+ },
569
+ options: [
570
+ {
571
+ displayName: 'Follow Up Context (JSON)',
572
+ name: 'followUpContext',
573
+ type: 'json',
574
+ default: '{}',
575
+ description: 'Optional context for follow-up interactions',
576
+ },
577
+ ],
578
+ },
579
+ ];
580
+ // Invoke Thread
581
+ exports.assistantsInvokeThreadDescription = [
582
+ {
583
+ displayName: 'Assistant ID',
584
+ name: 'assistantId',
585
+ type: 'string',
586
+ default: '',
587
+ required: true,
588
+ displayOptions: {
589
+ show: {
590
+ resource: ['assistants'],
591
+ operation: ['invokeThread'],
592
+ },
593
+ },
594
+ description: 'The ID of the assistant',
595
+ },
596
+ {
597
+ displayName: 'Thread ID',
598
+ name: 'threadId',
599
+ type: 'string',
600
+ default: '',
601
+ required: true,
602
+ displayOptions: {
603
+ show: {
604
+ resource: ['assistants'],
605
+ operation: ['invokeThread'],
606
+ },
607
+ },
608
+ description: 'The ID of the thread to invoke',
609
+ },
610
+ {
611
+ displayName: 'Message',
612
+ name: 'message',
613
+ type: 'string',
614
+ default: '',
615
+ required: true,
616
+ displayOptions: {
617
+ show: {
618
+ resource: ['assistants'],
619
+ operation: ['invokeThread'],
620
+ },
621
+ },
622
+ description: 'The message to send to the thread',
623
+ },
624
+ ];
513
625
  exports.assistantDescription = [
514
626
  {
515
627
  displayName: 'Operation',
@@ -588,6 +700,18 @@ exports.assistantDescription = [
588
700
  action: 'Create an assistant thread',
589
701
  description: 'Create a new thread for the assistant',
590
702
  },
703
+ {
704
+ name: 'Stream Thread',
705
+ value: 'streamThread',
706
+ action: 'Stream thread conversation',
707
+ description: 'Stream messages to a thread with real-time responses',
708
+ },
709
+ {
710
+ name: 'Invoke Thread',
711
+ value: 'invokeThread',
712
+ action: 'Invoke thread action',
713
+ description: 'Send a message to a thread and get a response',
714
+ },
591
715
  {
592
716
  name: 'Delete',
593
717
  value: 'delete',
@@ -608,5 +732,7 @@ exports.assistantDescription = [
608
732
  ...exports.assistantsCreateStarterDescription,
609
733
  ...exports.assistantsListThreadsDescription,
610
734
  ...exports.assistantsCreateThreadDescription,
735
+ ...exports.assistantsStreamThreadDescription,
736
+ ...exports.assistantsInvokeThreadDescription,
611
737
  ...exports.assistantsDeleteDescription,
612
738
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-qlik-cloud",
3
- "version": "1.0.4",
3
+ "version": "1.0.7",
4
4
  "description": "n8n node for Qlik Cloud REST APIs integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,16 +12,87 @@ import { assistantDescription } from './resources/assistants/index';
12
12
  import { auditDescription } from './resources/audits/index';
13
13
  import { itemDescription } from './resources/items/index';
14
14
 
15
+ const DEFAULT_PAGE_SIZE = 100;
16
+
17
+ function extractPageItems(response: any): any[] {
18
+ const payload = response?.data ?? response;
19
+
20
+ if (Array.isArray(payload)) {
21
+ return payload;
22
+ }
23
+
24
+ if (payload === undefined || payload === null) {
25
+ return [];
26
+ }
27
+
28
+ return [payload];
29
+ }
30
+
31
+ function extractNextCursor(response: any): string | undefined {
32
+ const nextLink = response?.links?.next;
33
+ const href = typeof nextLink === 'string' ? nextLink : nextLink?.href;
34
+
35
+ if (typeof href === 'string' && href.length) {
36
+ try {
37
+ const url = href.startsWith('http') ? new URL(href) : new URL(href, 'https://qlik.cloud');
38
+ return url.searchParams.get('next') ?? undefined;
39
+ } catch {
40
+ return undefined;
41
+ }
42
+ }
43
+
44
+ if (typeof response?.next === 'string') {
45
+ return response.next;
46
+ }
47
+
48
+ if (typeof response?.meta?.next === 'string') {
49
+ return response.meta.next;
50
+ }
51
+
52
+ return undefined;
53
+ }
54
+
55
+ async function fetchPaginatedResults(
56
+ context: IExecuteFunctions,
57
+ endpoint: string,
58
+ filters: Record<string, any>,
59
+ limit?: number,
60
+ pageSize: number = DEFAULT_PAGE_SIZE,
61
+ ): Promise<any[]> {
62
+ const collected: any[] = [];
63
+ let cursor: string | undefined;
64
+
65
+ do {
66
+ const qs: Record<string, any> = { ...filters };
67
+ const chunkSize = limit === undefined ? pageSize : Math.min(pageSize, limit - collected.length);
68
+
69
+ if (chunkSize <= 0) {
70
+ break;
71
+ }
72
+
73
+ qs.limit = chunkSize;
74
+
75
+ if (cursor) {
76
+ qs.next = cursor;
77
+ }
78
+
79
+ const response = await qlikApiRequest.call(context, 'GET', endpoint, undefined, qs);
80
+ const pageItems = extractPageItems(response);
81
+ collected.push(...pageItems);
82
+
83
+ cursor = extractNextCursor(response);
84
+ } while (cursor && (limit === undefined || collected.length < limit));
85
+
86
+ return limit === undefined ? collected : collected.slice(0, limit);
87
+ }
88
+
15
89
  async function handleAppsResource(operation: string, context: IExecuteFunctions): Promise<any> {
16
90
  if (operation === 'getAll') {
17
91
  const returnAll = context.getNodeParameter('returnAll', 0) as boolean;
18
92
  const limit = returnAll ? undefined : (context.getNodeParameter('limit', 0) as number);
19
93
  const options = context.getNodeParameter('options', 0) as any;
20
94
 
21
- const qs: any = {};
22
- if (limit) {
23
- qs.limit = limit;
24
- }
95
+ const qs: Record<string, any> = {};
25
96
  if (options.name) {
26
97
  qs.name = options.name;
27
98
  }
@@ -29,8 +100,7 @@ async function handleAppsResource(operation: string, context: IExecuteFunctions)
29
100
  qs.spaceId = options.spaceId;
30
101
  }
31
102
 
32
- const response = await qlikApiRequest.call(context, 'GET', '/api/v1/apps', undefined, qs);
33
- return response.data || response;
103
+ return await fetchPaginatedResults(context, '/api/v1/apps', qs, limit);
34
104
  }
35
105
 
36
106
  if (operation === 'get') {
@@ -278,6 +348,44 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
278
348
  );
279
349
  }
280
350
 
351
+ if (operation === 'streamThread') {
352
+ const assistantId = context.getNodeParameter('assistantId', 0) as string;
353
+ const threadId = context.getNodeParameter('threadId', 0) as string;
354
+ const messages = context.getNodeParameter('messages', 0) as any;
355
+ const options = context.getNodeParameter('options', 0) as any;
356
+
357
+ const body: any = {
358
+ messages: typeof messages === 'string' ? JSON.parse(messages) : messages,
359
+ };
360
+ if (options.followUpContext) {
361
+ body.followUpContext = typeof options.followUpContext === 'string'
362
+ ? JSON.parse(options.followUpContext)
363
+ : options.followUpContext;
364
+ }
365
+
366
+ return await qlikApiRequest.call(
367
+ context,
368
+ 'POST',
369
+ `/api/v1/assistants/${assistantId}/threads/${threadId}/actions/stream`,
370
+ body,
371
+ );
372
+ }
373
+
374
+ if (operation === 'invokeThread') {
375
+ const assistantId = context.getNodeParameter('assistantId', 0) as string;
376
+ const threadId = context.getNodeParameter('threadId', 0) as string;
377
+ const message = context.getNodeParameter('message', 0) as string;
378
+
379
+ const body = { message };
380
+
381
+ return await qlikApiRequest.call(
382
+ context,
383
+ 'POST',
384
+ `/api/v1/assistants/${assistantId}/threads/${threadId}/actions/invoke`,
385
+ body,
386
+ );
387
+ }
388
+
281
389
  if (operation === 'delete') {
282
390
  const assistantId = context.getNodeParameter('assistantId', 0) as string;
283
391
  await qlikApiRequest.call(context, 'DELETE', `/api/v1/assistants/${assistantId}`);
@@ -293,10 +401,7 @@ async function handleAuditsResource(operation: string, context: IExecuteFunction
293
401
  const limit = returnAll ? undefined : (context.getNodeParameter('limit', 0) as number);
294
402
  const options = context.getNodeParameter('options', 0) as any;
295
403
 
296
- const qs: any = {};
297
- if (limit) {
298
- qs.limit = limit;
299
- }
404
+ const qs: Record<string, any> = {};
300
405
  if (options.eventType) {
301
406
  qs.eventType = options.eventType;
302
407
  }
@@ -313,8 +418,7 @@ async function handleAuditsResource(operation: string, context: IExecuteFunction
313
418
  qs.sort = options.sort;
314
419
  }
315
420
 
316
- const response = await qlikApiRequest.call(context, 'GET', '/api/v1/audits', undefined, qs);
317
- return response.data || response;
421
+ return await fetchPaginatedResults(context, '/api/v1/audits', qs, limit);
318
422
  }
319
423
 
320
424
  if (operation === 'get') {
@@ -346,10 +450,7 @@ async function handleItemsResource(operation: string, context: IExecuteFunctions
346
450
  const limit = returnAll ? undefined : (context.getNodeParameter('limit', 0) as number);
347
451
  const options = context.getNodeParameter('options', 0) as any;
348
452
 
349
- const qs: any = {};
350
- if (limit) {
351
- qs.limit = limit;
352
- }
453
+ const qs: Record<string, any> = {};
353
454
  if (options.name) {
354
455
  qs.name = options.name;
355
456
  }
@@ -366,8 +467,7 @@ async function handleItemsResource(operation: string, context: IExecuteFunctions
366
467
  qs.sort = options.sort;
367
468
  }
368
469
 
369
- const response = await qlikApiRequest.call(context, 'GET', '/api/v1/items', undefined, qs);
370
- return response.data || response;
470
+ return await fetchPaginatedResults(context, '/api/v1/items', qs, limit);
371
471
  }
372
472
 
373
473
  if (operation === 'get') {
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" viewBox="0 0 71.39 29.74"><defs><style>.cls-2{stroke-width:0;fill:#54565a}</style></defs><path d="M70.47 27.52c.05-.07.07-.15.07-.24s-.02-.17-.07-.24-.1-.11-.16-.14a.38.38 0 0 0-.17-.04h-.66v1.31h.29v-.44h.29l.23.44h.32l-.27-.51a.47.47 0 0 0 .15-.13Zm-.71-.45h.27s.07.01.12.04c.04.03.07.08.07.16s-.02.14-.07.18c-.05.04-.09.06-.13.06h-.27v-.44Z" class="cls-2"/><path d="M71.28 26.97c-.07-.17-.17-.32-.31-.45-.13-.13-.28-.23-.45-.31s-.36-.11-.55-.11-.38.04-.55.11-.32.18-.45.31-.23.28-.3.45c-.07.17-.11.36-.11.55s.04.38.11.55c.07.17.17.32.3.45.13.13.28.23.45.31s.36.11.55.11.38-.04.55-.11.32-.18.45-.31.23-.28.31-.45c.07-.17.11-.36.11-.55s-.04-.38-.11-.55Zm-.37 1.1c-.1.16-.23.29-.39.39-.16.1-.34.15-.54.15s-.38-.05-.54-.15c-.16-.1-.29-.23-.39-.39-.1-.16-.15-.34-.15-.54s.05-.38.15-.54c.1-.16.23-.29.39-.39.16-.1.34-.15.54-.15s.38.05.54.15c.16.1.29.23.39.39.1.16.15.34.15.54s-.05.38-.15.54ZM34.9.65h2.96v28.32H34.9zM42.95 9.19h2.95v19.78h-2.95z" class="cls-2"/><circle cx="44.45" cy="2.67" r="2.02" class="cls-2"/><path d="M66.62 9.19h-4.11l-8.52 7.46-.02-16h-2.94v28.32h2.94v-9.14l8.75 9.14h4.1L56.39 18.39l10.23-9.2zM14.87 26.69c-6.53 0-11.82-5.29-11.82-11.82 0-2.77.96-5.32 2.55-7.34L3.44 5.34A14.922 14.922 0 0 0 0 14.87c0 8.21 6.66 14.87 14.87 14.87 3.56 0 6.83-1.25 9.39-3.34l-2.16-2.19c-2 1.55-4.5 2.47-7.23 2.47Z" class="cls-2"/><path fill="#009445" stroke-width="0" d="m26.31 24.34.17-.17a14.83 14.83 0 0 0 3.26-9.3C29.74 6.66 23.08 0 14.87 0c-3.54 0-6.79 1.24-9.34 3.3-.74.6-1.41 1.26-2.03 1.98-.02.02-.03.04-.05.06l2.16 2.19s.04-.05.06-.07c.59-.74 1.27-1.4 2.02-1.97a11.74 11.74 0 0 1 7.18-2.44c6.53 0 11.82 5.29 11.82 11.82 0 2.75-.94 5.29-2.52 7.3-.57.73-1.23 1.39-1.95 1.96l-.12.09 2.16 2.19 2.54 2.57h4.1l-4.59-4.64Z"/></svg>
@@ -521,6 +521,120 @@ export const assistantsCreateThreadDescription: INodeProperties[] = [
521
521
  },
522
522
  ];
523
523
 
524
+ // Stream Thread
525
+ export const assistantsStreamThreadDescription: INodeProperties[] = [
526
+ {
527
+ displayName: 'Assistant ID',
528
+ name: 'assistantId',
529
+ type: 'string',
530
+ default: '',
531
+ required: true,
532
+ displayOptions: {
533
+ show: {
534
+ resource: ['assistants'],
535
+ operation: ['streamThread'],
536
+ },
537
+ },
538
+ description: 'The ID of the assistant',
539
+ },
540
+ {
541
+ displayName: 'Thread ID',
542
+ name: 'threadId',
543
+ type: 'string',
544
+ default: '',
545
+ required: true,
546
+ displayOptions: {
547
+ show: {
548
+ resource: ['assistants'],
549
+ operation: ['streamThread'],
550
+ },
551
+ },
552
+ description: 'The ID of the thread to stream',
553
+ },
554
+ {
555
+ displayName: 'Messages',
556
+ name: 'messages',
557
+ type: 'json',
558
+ default: '[]',
559
+ required: true,
560
+ displayOptions: {
561
+ show: {
562
+ resource: ['assistants'],
563
+ operation: ['streamThread'],
564
+ },
565
+ },
566
+ description: 'Array of message objects to send to the stream',
567
+ },
568
+ {
569
+ displayName: 'Options',
570
+ name: 'options',
571
+ type: 'collection',
572
+ placeholder: 'Add Option',
573
+ default: {},
574
+ displayOptions: {
575
+ show: {
576
+ resource: ['assistants'],
577
+ operation: ['streamThread'],
578
+ },
579
+ },
580
+ options: [
581
+ {
582
+ displayName: 'Follow Up Context (JSON)',
583
+ name: 'followUpContext',
584
+ type: 'json',
585
+ default: '{}',
586
+ description: 'Optional context for follow-up interactions',
587
+ },
588
+ ],
589
+ },
590
+ ];
591
+
592
+ // Invoke Thread
593
+ export const assistantsInvokeThreadDescription: INodeProperties[] = [
594
+ {
595
+ displayName: 'Assistant ID',
596
+ name: 'assistantId',
597
+ type: 'string',
598
+ default: '',
599
+ required: true,
600
+ displayOptions: {
601
+ show: {
602
+ resource: ['assistants'],
603
+ operation: ['invokeThread'],
604
+ },
605
+ },
606
+ description: 'The ID of the assistant',
607
+ },
608
+ {
609
+ displayName: 'Thread ID',
610
+ name: 'threadId',
611
+ type: 'string',
612
+ default: '',
613
+ required: true,
614
+ displayOptions: {
615
+ show: {
616
+ resource: ['assistants'],
617
+ operation: ['invokeThread'],
618
+ },
619
+ },
620
+ description: 'The ID of the thread to invoke',
621
+ },
622
+ {
623
+ displayName: 'Message',
624
+ name: 'message',
625
+ type: 'string',
626
+ default: '',
627
+ required: true,
628
+ displayOptions: {
629
+ show: {
630
+ resource: ['assistants'],
631
+ operation: ['invokeThread'],
632
+ },
633
+ },
634
+ description: 'The message to send to the thread',
635
+ },
636
+ ];
637
+
524
638
  export const assistantDescription: INodeProperties[] = [
525
639
  {
526
640
  displayName: 'Operation',
@@ -599,6 +713,18 @@ export const assistantDescription: INodeProperties[] = [
599
713
  action: 'Create an assistant thread',
600
714
  description: 'Create a new thread for the assistant',
601
715
  },
716
+ {
717
+ name: 'Stream Thread',
718
+ value: 'streamThread',
719
+ action: 'Stream thread conversation',
720
+ description: 'Stream messages to a thread with real-time responses',
721
+ },
722
+ {
723
+ name: 'Invoke Thread',
724
+ value: 'invokeThread',
725
+ action: 'Invoke thread action',
726
+ description: 'Send a message to a thread and get a response',
727
+ },
602
728
  {
603
729
  name: 'Delete',
604
730
  value: 'delete',
@@ -619,5 +745,7 @@ export const assistantDescription: INodeProperties[] = [
619
745
  ...assistantsCreateStarterDescription,
620
746
  ...assistantsListThreadsDescription,
621
747
  ...assistantsCreateThreadDescription,
748
+ ...assistantsStreamThreadDescription,
749
+ ...assistantsInvokeThreadDescription,
622
750
  ...assistantsDeleteDescription,
623
751
  ];