@deepidealab/n8n-nodes-tracira 0.2.0 → 0.3.2

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.
@@ -3,21 +3,76 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Tracira = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  const baseUrl = 'https://www.tracira.com/api';
6
- const logDisplay = {
7
- resource: ['execution'],
6
+ const logResourceDisplay = {
7
+ resource: ['log'],
8
+ };
9
+ const apiDisplay = {
10
+ resource: ['api'],
11
+ };
12
+ const logOperationDisplay = {
13
+ resource: ['log'],
8
14
  operation: ['log'],
9
15
  };
10
16
  const getDisplay = {
11
- resource: ['execution'],
17
+ resource: ['log'],
12
18
  operation: ['get'],
13
19
  };
14
20
  const getAllDisplay = {
15
- resource: ['execution'],
21
+ resource: ['log'],
16
22
  operation: ['getAll'],
17
23
  };
24
+ const setDecisionDisplay = {
25
+ resource: ['log'],
26
+ operation: ['setDecision'],
27
+ };
28
+ const apiCallDisplay = {
29
+ resource: ['api'],
30
+ operation: ['call'],
31
+ };
18
32
  function stripEmpty(data) {
19
33
  return Object.fromEntries(Object.entries(data).filter(([, value]) => value !== '' && value !== undefined && value !== null));
20
34
  }
35
+ function normalizeApiPath(path) {
36
+ if (!path.trim())
37
+ return '/';
38
+ if (path.startsWith('http://') || path.startsWith('https://')) {
39
+ throw new n8n_workflow_1.ApplicationError('Use a path relative to https://www.tracira.com/api, for example /logs');
40
+ }
41
+ return path.startsWith('/') ? path : `/${path}`;
42
+ }
43
+ function parseJsonObject(text, fieldName) {
44
+ if (!text.trim())
45
+ return {};
46
+ let parsed;
47
+ try {
48
+ parsed = JSON.parse(text);
49
+ }
50
+ catch {
51
+ throw new n8n_workflow_1.ApplicationError(`${fieldName} must be valid JSON`);
52
+ }
53
+ if (parsed === null || Array.isArray(parsed) || typeof parsed !== 'object') {
54
+ throw new n8n_workflow_1.ApplicationError(`${fieldName} must be a JSON object`);
55
+ }
56
+ return parsed;
57
+ }
58
+ function parseOptionalJsonBody(text) {
59
+ const trimmed = text.trim();
60
+ if (!trimmed)
61
+ return undefined;
62
+ try {
63
+ return JSON.parse(trimmed);
64
+ }
65
+ catch {
66
+ return text;
67
+ }
68
+ }
69
+ function mapFullResponse(response) {
70
+ return {
71
+ statusCode: response.statusCode,
72
+ headers: response.headers,
73
+ body: response.body,
74
+ };
75
+ }
21
76
  class Tracira {
22
77
  constructor() {
23
78
  this.description = {
@@ -27,7 +82,7 @@ class Tracira {
27
82
  group: ['transform'],
28
83
  version: 1,
29
84
  subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
30
- description: 'Log and inspect Tracira AI execution data',
85
+ description: 'Log and inspect Tracira AI log data',
31
86
  codex: {
32
87
  categories: ['AI'],
33
88
  resources: {
@@ -63,11 +118,15 @@ class Tracira {
63
118
  noDataExpression: true,
64
119
  options: [
65
120
  {
66
- name: 'Execution',
67
- value: 'execution',
121
+ name: 'Log',
122
+ value: 'log',
123
+ },
124
+ {
125
+ name: 'API',
126
+ value: 'api',
68
127
  },
69
128
  ],
70
- default: 'execution',
129
+ default: 'log',
71
130
  },
72
131
  {
73
132
  displayName: 'Operation',
@@ -75,53 +134,107 @@ class Tracira {
75
134
  type: 'options',
76
135
  noDataExpression: true,
77
136
  displayOptions: {
78
- show: {
79
- resource: ['execution'],
80
- },
137
+ show: logResourceDisplay,
81
138
  },
82
139
  options: [
83
140
  {
84
141
  name: 'Log',
85
142
  value: 'log',
86
- action: 'Log an execution',
87
- description: 'Send an AI execution to Tracira for evaluation',
143
+ action: 'Log an AI output',
144
+ description: 'Send an AI output to Tracira for evaluation',
88
145
  },
89
146
  {
90
147
  name: 'Get',
91
148
  value: 'get',
92
- action: 'Get an execution',
93
- description: 'Fetch a single execution by ID',
149
+ action: 'Get a log',
150
+ description: 'Fetch a single log by ID',
94
151
  },
95
152
  {
96
153
  name: 'Get Many',
97
154
  value: 'getAll',
98
- action: 'Get many an execution',
99
- description: 'List executions from Tracira',
155
+ action: 'Get many logs',
156
+ description: 'List logs from Tracira',
157
+ },
158
+ {
159
+ name: 'Set Decision',
160
+ value: 'setDecision',
161
+ action: 'Set a decision for a log',
162
+ description: 'Approve or reject a flagged log',
100
163
  },
101
164
  ],
102
165
  default: 'log',
103
166
  },
104
167
  {
105
- displayName: 'Execution ID',
106
- name: 'executionId',
168
+ displayName: 'Operation',
169
+ name: 'operation',
170
+ type: 'options',
171
+ noDataExpression: true,
172
+ displayOptions: {
173
+ show: apiDisplay,
174
+ },
175
+ options: [
176
+ {
177
+ name: 'Call',
178
+ value: 'call',
179
+ action: 'Make an API call',
180
+ description: 'Perform an arbitrary authenticated Tracira API request',
181
+ },
182
+ ],
183
+ default: 'call',
184
+ },
185
+ {
186
+ displayName: 'Log ID',
187
+ name: 'logId',
107
188
  type: 'string',
108
189
  required: true,
109
190
  default: '',
110
191
  displayOptions: {
111
192
  show: getDisplay,
112
193
  },
113
- description: 'The execution ID to fetch',
194
+ description: 'The log ID to fetch',
195
+ },
196
+ {
197
+ displayName: 'Log ID',
198
+ name: 'decisionLogId',
199
+ type: 'string',
200
+ required: true,
201
+ default: '',
202
+ displayOptions: {
203
+ show: setDecisionDisplay,
204
+ },
205
+ description: 'The log ID to approve or reject',
206
+ },
207
+ {
208
+ displayName: 'Decision',
209
+ name: 'decision',
210
+ type: 'options',
211
+ required: true,
212
+ default: 'approved',
213
+ displayOptions: {
214
+ show: setDecisionDisplay,
215
+ },
216
+ options: [
217
+ {
218
+ name: 'Approved',
219
+ value: 'approved',
220
+ },
221
+ {
222
+ name: 'Rejected',
223
+ value: 'rejected',
224
+ },
225
+ ],
226
+ description: 'The human review decision to record',
114
227
  },
115
228
  {
116
- displayName: 'Flow',
117
- name: 'flowName',
229
+ displayName: 'Project',
230
+ name: 'projectName',
118
231
  type: 'string',
119
232
  required: true,
120
233
  default: '',
121
234
  displayOptions: {
122
- show: logDisplay,
235
+ show: logOperationDisplay,
123
236
  },
124
- description: 'The Tracira flow name for this execution',
237
+ description: 'The Tracira project name for this log',
125
238
  },
126
239
  {
127
240
  displayName: 'Output',
@@ -133,7 +246,7 @@ class Tracira {
133
246
  required: true,
134
247
  default: '',
135
248
  displayOptions: {
136
- show: logDisplay,
249
+ show: logOperationDisplay,
137
250
  },
138
251
  description: 'The AI-generated output to evaluate in Tracira',
139
252
  },
@@ -146,19 +259,19 @@ class Tracira {
146
259
  },
147
260
  default: '',
148
261
  displayOptions: {
149
- show: logDisplay,
262
+ show: logOperationDisplay,
150
263
  },
151
264
  description: 'Optional prompt or input text that produced the output',
152
265
  },
153
266
  {
154
- displayName: 'Check',
155
- name: 'checkName',
267
+ displayName: 'Task',
268
+ name: 'taskName',
156
269
  type: 'string',
157
270
  default: '',
158
271
  displayOptions: {
159
- show: logDisplay,
272
+ show: logOperationDisplay,
160
273
  },
161
- description: 'Optional Tracira check name',
274
+ description: 'Optional Tracira task name',
162
275
  },
163
276
  {
164
277
  displayName: 'Model',
@@ -166,9 +279,9 @@ class Tracira {
166
279
  type: 'string',
167
280
  default: '',
168
281
  displayOptions: {
169
- show: logDisplay,
282
+ show: logOperationDisplay,
170
283
  },
171
- description: 'Optional AI model name to record with the execution',
284
+ description: 'Optional AI model name to record with the log',
172
285
  },
173
286
  {
174
287
  displayName: 'Options',
@@ -177,7 +290,7 @@ class Tracira {
177
290
  placeholder: 'Add Option',
178
291
  default: {},
179
292
  displayOptions: {
180
- show: logDisplay,
293
+ show: logOperationDisplay,
181
294
  },
182
295
  options: [
183
296
  {
@@ -186,6 +299,20 @@ class Tracira {
186
299
  type: 'string',
187
300
  default: '',
188
301
  },
302
+ {
303
+ displayName: 'Callback Events',
304
+ name: 'callbackEvents',
305
+ type: 'options',
306
+ default: 'all',
307
+ options: [
308
+ { name: 'All Events (Default)', value: 'all' },
309
+ { name: 'Flagged & Errors Only', value: 'flagged_error' },
310
+ { name: 'Flagged, Errors & Decisions', value: 'flagged_error_decisions' },
311
+ { name: 'Human Decisions Only', value: 'decisions' },
312
+ { name: 'Pass Only', value: 'pass' },
313
+ ],
314
+ description: 'Controls which events trigger the Callback URL. Only used when Callback URL is set.',
315
+ },
189
316
  {
190
317
  displayName: 'Callback URL',
191
318
  name: 'callbackUrl',
@@ -204,18 +331,18 @@ class Tracira {
204
331
  type: 'number',
205
332
  default: 0,
206
333
  },
207
- {
208
- displayName: 'Execution ID',
209
- name: 'id',
210
- type: 'string',
211
- default: '',
212
- },
213
334
  {
214
335
  displayName: 'Latency',
215
336
  name: 'latencyMs',
216
337
  type: 'number',
217
338
  default: 0,
218
339
  },
340
+ {
341
+ displayName: 'Log ID',
342
+ name: 'id',
343
+ type: 'string',
344
+ default: '',
345
+ },
219
346
  {
220
347
  displayName: 'Metadata JSON',
221
348
  name: 'metadataJson',
@@ -224,7 +351,7 @@ class Tracira {
224
351
  rows: 4,
225
352
  },
226
353
  default: '',
227
- description: 'Optional JSON object to store as execution metadata',
354
+ description: 'Optional JSON object to store as log metadata',
228
355
  },
229
356
  {
230
357
  displayName: 'Session ID',
@@ -238,6 +365,13 @@ class Tracira {
238
365
  type: 'string',
239
366
  default: '',
240
367
  },
368
+ {
369
+ displayName: 'Sync Mode (Wait for Verdict)',
370
+ name: 'sync',
371
+ type: 'boolean',
372
+ default: false,
373
+ description: 'Whether to wait for evaluation to complete before continuing. Off (default): n8n continues immediately, Tracira evaluates in the background. On: n8n waits for the full verdict so you can branch on status/verdict.',
374
+ },
241
375
  ],
242
376
  },
243
377
  {
@@ -250,31 +384,32 @@ class Tracira {
250
384
  },
251
385
  options: [
252
386
  { name: 'All', value: '' },
253
- { name: 'Success', value: 'success' },
387
+ { name: 'Error', value: 'error' },
254
388
  { name: 'Flagged', value: 'flagged' },
255
- { name: 'Failed', value: 'failed' },
389
+ { name: 'Pass', value: 'pass' },
390
+ { name: 'Pending', value: 'pending' },
256
391
  ],
257
- description: 'Filter executions by status',
392
+ description: 'Filter logs by status',
258
393
  },
259
394
  {
260
- displayName: 'Flow',
261
- name: 'flowFilter',
395
+ displayName: 'Project',
396
+ name: 'projectFilter',
262
397
  type: 'string',
263
398
  default: '',
264
399
  displayOptions: {
265
400
  show: getAllDisplay,
266
401
  },
267
- description: 'Filter executions to a specific flow name',
402
+ description: 'Filter logs to a specific project name',
268
403
  },
269
404
  {
270
- displayName: 'Check',
271
- name: 'checkFilter',
405
+ displayName: 'Task',
406
+ name: 'taskFilter',
272
407
  type: 'string',
273
408
  default: '',
274
409
  displayOptions: {
275
410
  show: getAllDisplay,
276
411
  },
277
- description: 'Filter executions to a specific check name',
412
+ description: 'Filter logs to a specific task name',
278
413
  },
279
414
  {
280
415
  displayName: 'Search Query',
@@ -284,7 +419,7 @@ class Tracira {
284
419
  displayOptions: {
285
420
  show: getAllDisplay,
286
421
  },
287
- description: 'Search across flow, check, model, and context IDs',
422
+ description: 'Search across project, task, model, and context IDs',
288
423
  },
289
424
  {
290
425
  displayName: 'From',
@@ -294,7 +429,7 @@ class Tracira {
294
429
  displayOptions: {
295
430
  show: getAllDisplay,
296
431
  },
297
- description: 'Only include executions at or after this date',
432
+ description: 'Only include logs at or after this date',
298
433
  },
299
434
  {
300
435
  displayName: 'To',
@@ -304,7 +439,7 @@ class Tracira {
304
439
  displayOptions: {
305
440
  show: getAllDisplay,
306
441
  },
307
- description: 'Only include executions up to this date',
442
+ description: 'Only include logs up to this date',
308
443
  },
309
444
  {
310
445
  displayName: 'Limit',
@@ -363,6 +498,74 @@ class Tracira {
363
498
  },
364
499
  ],
365
500
  },
501
+ {
502
+ displayName: 'Path',
503
+ name: 'apiPath',
504
+ type: 'string',
505
+ required: true,
506
+ default: '/logs',
507
+ displayOptions: {
508
+ show: apiCallDisplay,
509
+ },
510
+ description: 'Path relative to https://www.tracira.com/api',
511
+ },
512
+ {
513
+ displayName: 'Method',
514
+ name: 'apiMethod',
515
+ type: 'options',
516
+ required: true,
517
+ default: 'GET',
518
+ displayOptions: {
519
+ show: apiCallDisplay,
520
+ },
521
+ options: [
522
+ { name: 'DELETE', value: 'DELETE' },
523
+ { name: 'GET', value: 'GET' },
524
+ { name: 'PATCH', value: 'PATCH' },
525
+ { name: 'POST', value: 'POST' },
526
+ { name: 'PUT', value: 'PUT' },
527
+ ],
528
+ description: 'HTTP method to use',
529
+ },
530
+ {
531
+ displayName: 'Headers JSON',
532
+ name: 'apiHeadersJson',
533
+ type: 'string',
534
+ typeOptions: {
535
+ rows: 4,
536
+ },
537
+ default: '{}',
538
+ displayOptions: {
539
+ show: apiCallDisplay,
540
+ },
541
+ description: 'Optional JSON object of request headers. Authorization is added automatically.',
542
+ },
543
+ {
544
+ displayName: 'Query String JSON',
545
+ name: 'apiQueryJson',
546
+ type: 'string',
547
+ typeOptions: {
548
+ rows: 4,
549
+ },
550
+ default: '{}',
551
+ displayOptions: {
552
+ show: apiCallDisplay,
553
+ },
554
+ description: 'Optional JSON object of query-string parameters',
555
+ },
556
+ {
557
+ displayName: 'Body',
558
+ name: 'apiBody',
559
+ type: 'string',
560
+ typeOptions: {
561
+ rows: 6,
562
+ },
563
+ default: '',
564
+ displayOptions: {
565
+ show: apiCallDisplay,
566
+ },
567
+ description: 'Optional request body. JSON text is parsed automatically; other text is sent as-is.',
568
+ },
366
569
  ],
367
570
  };
368
571
  }
@@ -371,9 +574,10 @@ class Tracira {
371
574
  const returnData = [];
372
575
  for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
373
576
  try {
577
+ const resource = this.getNodeParameter('resource', itemIndex);
374
578
  const operation = this.getNodeParameter('operation', itemIndex);
375
579
  let requestOptions;
376
- if (operation === 'log') {
580
+ if (resource === 'log' && operation === 'log') {
377
581
  const options = this.getNodeParameter('options', itemIndex, {});
378
582
  let metadata;
379
583
  if (options.metadataJson) {
@@ -390,13 +594,14 @@ class Tracira {
390
594
  method: 'POST',
391
595
  url: `${baseUrl}/webhook`,
392
596
  body: stripEmpty({
393
- flow: this.getNodeParameter('flowName', itemIndex),
597
+ project: this.getNodeParameter('projectName', itemIndex),
394
598
  output: this.getNodeParameter('output', itemIndex),
395
599
  input: this.getNodeParameter('input', itemIndex, ''),
396
- check: this.getNodeParameter('checkName', itemIndex, ''),
600
+ task: this.getNodeParameter('taskName', itemIndex, ''),
397
601
  model: this.getNodeParameter('modelName', itemIndex, ''),
398
602
  actorId: options.actorId,
399
603
  callbackUrl: options.callbackUrl,
604
+ callbackEvents: options.callbackEvents,
400
605
  confidence: options.confidence,
401
606
  costUsd: options.costUsd,
402
607
  id: options.id,
@@ -404,25 +609,26 @@ class Tracira {
404
609
  metadata,
405
610
  sessionId: options.sessionId,
406
611
  subjectId: options.subjectId,
612
+ sync: options.sync,
407
613
  }),
408
614
  };
409
615
  }
410
- else if (operation === 'get') {
411
- const executionId = this.getNodeParameter('executionId', itemIndex);
616
+ else if (resource === 'log' && operation === 'get') {
617
+ const logId = this.getNodeParameter('logId', itemIndex);
412
618
  requestOptions = {
413
619
  method: 'GET',
414
- url: `${baseUrl}/executions/${encodeURIComponent(executionId)}`,
620
+ url: `${baseUrl}/logs/${encodeURIComponent(logId)}`,
415
621
  };
416
622
  }
417
- else {
623
+ else if (resource === 'log' && operation === 'getAll') {
418
624
  const filters = this.getNodeParameter('filters', itemIndex, {});
419
625
  requestOptions = {
420
626
  method: 'GET',
421
- url: `${baseUrl}/executions`,
627
+ url: `${baseUrl}/logs`,
422
628
  qs: stripEmpty({
423
629
  status: this.getNodeParameter('status', itemIndex, ''),
424
- flow: this.getNodeParameter('flowFilter', itemIndex, ''),
425
- check: this.getNodeParameter('checkFilter', itemIndex, ''),
630
+ project: this.getNodeParameter('projectFilter', itemIndex, ''),
631
+ task: this.getNodeParameter('taskFilter', itemIndex, ''),
426
632
  q: this.getNodeParameter('query', itemIndex, ''),
427
633
  from: this.getNodeParameter('from', itemIndex, ''),
428
634
  to: this.getNodeParameter('to', itemIndex, ''),
@@ -434,15 +640,50 @@ class Tracira {
434
640
  }),
435
641
  };
436
642
  }
643
+ else if (resource === 'log' && operation === 'setDecision') {
644
+ const logId = this.getNodeParameter('decisionLogId', itemIndex);
645
+ const decision = this.getNodeParameter('decision', itemIndex);
646
+ requestOptions = {
647
+ method: 'PATCH',
648
+ url: `${baseUrl}/logs/${encodeURIComponent(logId)}/decision`,
649
+ body: {
650
+ decision,
651
+ },
652
+ };
653
+ }
654
+ else if (resource === 'api' && operation === 'call') {
655
+ const headers = parseJsonObject(this.getNodeParameter('apiHeadersJson', itemIndex, '{}'), 'Headers JSON');
656
+ const qs = parseJsonObject(this.getNodeParameter('apiQueryJson', itemIndex, '{}'), 'Query String JSON');
657
+ const body = parseOptionalJsonBody(this.getNodeParameter('apiBody', itemIndex, ''));
658
+ requestOptions = {
659
+ method: this.getNodeParameter('apiMethod', itemIndex),
660
+ url: `${baseUrl}${normalizeApiPath(this.getNodeParameter('apiPath', itemIndex))}`,
661
+ headers,
662
+ qs,
663
+ body,
664
+ returnFullResponse: true,
665
+ };
666
+ }
667
+ else {
668
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported Tracira operation: ${resource}/${operation}`, {
669
+ itemIndex,
670
+ });
671
+ }
437
672
  const response = await this.helpers.httpRequestWithAuthentication.call(this, 'traciraApi', requestOptions);
438
- if (operation === 'getAll' && Array.isArray(response === null || response === void 0 ? void 0 : response.executions)) {
439
- for (const execution of response.executions) {
673
+ if (resource === 'log' && operation === 'getAll' && Array.isArray(response === null || response === void 0 ? void 0 : response.executions)) {
674
+ for (const log of response.executions) {
440
675
  returnData.push({
441
- json: execution,
676
+ json: log,
442
677
  pairedItem: itemIndex,
443
678
  });
444
679
  }
445
680
  }
681
+ else if (resource === 'api' && operation === 'call' && (response === null || response === void 0 ? void 0 : response.statusCode)) {
682
+ returnData.push({
683
+ json: mapFullResponse(response),
684
+ pairedItem: itemIndex,
685
+ });
686
+ }
446
687
  else {
447
688
  returnData.push({
448
689
  json: response,