n8n-nodes-cribops 0.1.5
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/LICENSE +21 -0
- package/README.md +319 -0
- package/dist/credentials/CribopsApi.credentials.d.ts +9 -0
- package/dist/credentials/CribopsApi.credentials.js +69 -0
- package/dist/nodes/Cribops/Cribops.node.d.ts +10 -0
- package/dist/nodes/Cribops/Cribops.node.js +568 -0
- package/dist/nodes/Cribops/cribops.svg +7 -0
- package/dist/nodes/CribopsTrigger/CribopsTrigger.node.d.ts +18 -0
- package/dist/nodes/CribopsTrigger/CribopsTrigger.node.js +248 -0
- package/dist/nodes/CribopsTrigger/cribopstrigger.svg +8 -0
- package/dist/package.json +59 -0
- package/dist/utils/CribopsHttp.d.ts +40 -0
- package/dist/utils/CribopsHttp.js +116 -0
- package/dist/utils/FileUtils.d.ts +36 -0
- package/dist/utils/FileUtils.js +165 -0
- package/package.json +59 -0
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Cribops = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const CribopsHttp_1 = require("../../utils/CribopsHttp");
|
|
6
|
+
class Cribops {
|
|
7
|
+
description = {
|
|
8
|
+
displayName: 'Cribops',
|
|
9
|
+
name: 'cribops',
|
|
10
|
+
icon: 'file:cribops.svg',
|
|
11
|
+
group: ['communication'],
|
|
12
|
+
version: 1,
|
|
13
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
14
|
+
description: 'Interact with Cribops AI agents',
|
|
15
|
+
defaults: {
|
|
16
|
+
name: 'Cribops',
|
|
17
|
+
},
|
|
18
|
+
inputs: ["main" /* NodeConnectionType.Main */],
|
|
19
|
+
outputs: ["main" /* NodeConnectionType.Main */],
|
|
20
|
+
credentials: [
|
|
21
|
+
{
|
|
22
|
+
name: 'cribopsApi',
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
requestDefaults: {
|
|
27
|
+
headers: {
|
|
28
|
+
Accept: 'application/json',
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
properties: [
|
|
33
|
+
{
|
|
34
|
+
displayName: 'Operation',
|
|
35
|
+
name: 'operation',
|
|
36
|
+
type: 'options',
|
|
37
|
+
noDataExpression: true,
|
|
38
|
+
options: [
|
|
39
|
+
{
|
|
40
|
+
name: 'Get Agent',
|
|
41
|
+
value: 'getAgent',
|
|
42
|
+
description: 'Get information about a specific agent',
|
|
43
|
+
action: 'Get information about a specific agent',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'List Agents',
|
|
47
|
+
value: 'listAgents',
|
|
48
|
+
description: 'List all available agents',
|
|
49
|
+
action: 'List all available agents',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'Reply to Conversation',
|
|
53
|
+
value: 'replyToConversation',
|
|
54
|
+
description: 'Reply to an existing conversation',
|
|
55
|
+
action: 'Reply to an existing conversation',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'Send Message',
|
|
59
|
+
value: 'sendMessage',
|
|
60
|
+
description: 'Send a message to a Cribops agent',
|
|
61
|
+
action: 'Send a message to a cribops agent',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'Send Typing Indicator',
|
|
65
|
+
value: 'sendTypingIndicator',
|
|
66
|
+
description: 'Send typing indicator to a conversation',
|
|
67
|
+
action: 'Send typing indicator to a conversation',
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
default: 'sendMessage',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
displayName: 'Agent',
|
|
74
|
+
name: 'agentId',
|
|
75
|
+
type: 'resourceLocator',
|
|
76
|
+
default: { mode: 'list', value: '' },
|
|
77
|
+
required: true,
|
|
78
|
+
displayOptions: {
|
|
79
|
+
show: {
|
|
80
|
+
operation: ['sendMessage', 'replyToConversation', 'getAgent', 'sendTypingIndicator'],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
modes: [
|
|
84
|
+
{
|
|
85
|
+
displayName: 'From List',
|
|
86
|
+
name: 'list',
|
|
87
|
+
type: 'list',
|
|
88
|
+
placeholder: 'Select an agent...',
|
|
89
|
+
typeOptions: {
|
|
90
|
+
searchListMethod: 'searchAgents',
|
|
91
|
+
searchable: true,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
displayName: 'By ID',
|
|
96
|
+
name: 'id',
|
|
97
|
+
type: 'string',
|
|
98
|
+
placeholder: 'agent_123',
|
|
99
|
+
validation: [
|
|
100
|
+
{
|
|
101
|
+
type: 'regex',
|
|
102
|
+
properties: {
|
|
103
|
+
regex: '^[a-zA-Z0-9_-]+$',
|
|
104
|
+
errorMessage: 'Agent ID must contain only letters, numbers, hyphens, and underscores',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
displayName: 'Conversation ID',
|
|
113
|
+
name: 'conversationId',
|
|
114
|
+
type: 'string',
|
|
115
|
+
required: true,
|
|
116
|
+
default: '',
|
|
117
|
+
placeholder: 'conversation_123',
|
|
118
|
+
displayOptions: {
|
|
119
|
+
show: {
|
|
120
|
+
operation: ['replyToConversation'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
description: 'ID of the conversation to reply to',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
displayName: 'Conversation ID',
|
|
127
|
+
name: 'conversationId',
|
|
128
|
+
type: 'string',
|
|
129
|
+
required: true,
|
|
130
|
+
default: '',
|
|
131
|
+
placeholder: 'conversation_123',
|
|
132
|
+
displayOptions: {
|
|
133
|
+
show: {
|
|
134
|
+
operation: ['sendTypingIndicator'],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
description: 'ID of the conversation to send typing indicator to',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
displayName: 'Typing',
|
|
141
|
+
name: 'typing',
|
|
142
|
+
type: 'boolean',
|
|
143
|
+
required: true,
|
|
144
|
+
default: true,
|
|
145
|
+
displayOptions: {
|
|
146
|
+
show: {
|
|
147
|
+
operation: ['sendTypingIndicator'],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
description: 'Whether to show typing indicator (true) or stop typing (false)',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
displayName: 'Message',
|
|
154
|
+
name: 'message',
|
|
155
|
+
type: 'string',
|
|
156
|
+
required: true,
|
|
157
|
+
default: '',
|
|
158
|
+
placeholder: 'Hello, how can you help me?',
|
|
159
|
+
displayOptions: {
|
|
160
|
+
show: {
|
|
161
|
+
operation: ['sendMessage', 'replyToConversation'],
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
description: 'The message to send',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
displayName: 'Conversation ID',
|
|
168
|
+
name: 'conversationId',
|
|
169
|
+
type: 'string',
|
|
170
|
+
default: '',
|
|
171
|
+
placeholder: 'conversation_123',
|
|
172
|
+
displayOptions: {
|
|
173
|
+
show: {
|
|
174
|
+
operation: ['sendMessage'],
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
description: 'ID of the conversation (leave empty to start a new conversation)',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
displayName: 'User ID',
|
|
181
|
+
name: 'userId',
|
|
182
|
+
type: 'string',
|
|
183
|
+
default: '',
|
|
184
|
+
placeholder: 'user_123',
|
|
185
|
+
displayOptions: {
|
|
186
|
+
show: {
|
|
187
|
+
operation: ['sendMessage'],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
description: 'ID of the user sending the message',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
displayName: 'File Attachment',
|
|
194
|
+
name: 'fileAttachment',
|
|
195
|
+
type: 'fixedCollection',
|
|
196
|
+
default: {},
|
|
197
|
+
placeholder: 'Add file attachment',
|
|
198
|
+
displayOptions: {
|
|
199
|
+
show: {
|
|
200
|
+
operation: ['sendMessage'],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
typeOptions: {
|
|
204
|
+
multipleValues: false,
|
|
205
|
+
},
|
|
206
|
+
options: [
|
|
207
|
+
{
|
|
208
|
+
name: 'file',
|
|
209
|
+
displayName: 'File',
|
|
210
|
+
values: [
|
|
211
|
+
{
|
|
212
|
+
displayName: 'File URL',
|
|
213
|
+
name: 'url',
|
|
214
|
+
type: 'string',
|
|
215
|
+
default: '',
|
|
216
|
+
placeholder: 'https://example.com/file.pdf',
|
|
217
|
+
description: 'URL of the file to attach',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
displayName: 'File Name',
|
|
221
|
+
name: 'name',
|
|
222
|
+
type: 'string',
|
|
223
|
+
default: '',
|
|
224
|
+
placeholder: 'document.pdf',
|
|
225
|
+
description: 'Name of the file (optional)',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
displayName: 'File Type',
|
|
229
|
+
name: 'type',
|
|
230
|
+
type: 'string',
|
|
231
|
+
default: '',
|
|
232
|
+
placeholder: 'application/pdf',
|
|
233
|
+
description: 'MIME type of the file (optional)',
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
displayName: 'Additional Fields',
|
|
241
|
+
name: 'additionalFields',
|
|
242
|
+
type: 'collection',
|
|
243
|
+
placeholder: 'Add Field',
|
|
244
|
+
default: {},
|
|
245
|
+
options: [
|
|
246
|
+
{
|
|
247
|
+
displayName: 'Metadata',
|
|
248
|
+
name: 'metadata',
|
|
249
|
+
type: 'fixedCollection',
|
|
250
|
+
placeholder: 'Add Metadata',
|
|
251
|
+
default: {},
|
|
252
|
+
typeOptions: {
|
|
253
|
+
multipleValues: true,
|
|
254
|
+
},
|
|
255
|
+
options: [
|
|
256
|
+
{
|
|
257
|
+
name: 'metadataValues',
|
|
258
|
+
displayName: 'Metadata',
|
|
259
|
+
values: [
|
|
260
|
+
{
|
|
261
|
+
displayName: 'Key',
|
|
262
|
+
name: 'key',
|
|
263
|
+
type: 'string',
|
|
264
|
+
default: '',
|
|
265
|
+
description: 'Metadata key',
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
displayName: 'Value',
|
|
269
|
+
name: 'value',
|
|
270
|
+
type: 'string',
|
|
271
|
+
default: '',
|
|
272
|
+
description: 'Metadata value',
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
displayName: 'Timeout',
|
|
280
|
+
name: 'timeout',
|
|
281
|
+
type: 'number',
|
|
282
|
+
default: 30000,
|
|
283
|
+
description: 'Request timeout in milliseconds',
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
methods = {
|
|
290
|
+
listSearch: {
|
|
291
|
+
searchAgents: async function (filter) {
|
|
292
|
+
const credentials = await this.getCredentials('cribopsApi');
|
|
293
|
+
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
294
|
+
baseUrl: credentials.baseUrl,
|
|
295
|
+
apiToken: credentials.apiToken,
|
|
296
|
+
});
|
|
297
|
+
try {
|
|
298
|
+
const agents = await cribopsHttp.getAgents();
|
|
299
|
+
const results = agents
|
|
300
|
+
.filter((agent) => !filter || agent.name.toLowerCase().includes(filter.toLowerCase()))
|
|
301
|
+
.map((agent) => ({
|
|
302
|
+
name: `${agent.name} (${agent.id})`,
|
|
303
|
+
value: agent.id,
|
|
304
|
+
}));
|
|
305
|
+
return {
|
|
306
|
+
results,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load agents: ${error}`, {
|
|
311
|
+
description: 'Make sure your API credentials are correct and the Cribops API is accessible',
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
async execute() {
|
|
318
|
+
const items = this.getInputData();
|
|
319
|
+
const results = [];
|
|
320
|
+
const credentials = await this.getCredentials('cribopsApi');
|
|
321
|
+
const cribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
322
|
+
baseUrl: credentials.baseUrl,
|
|
323
|
+
apiToken: credentials.apiToken,
|
|
324
|
+
});
|
|
325
|
+
for (let i = 0; i < items.length; i++) {
|
|
326
|
+
const operation = this.getNodeParameter('operation', i);
|
|
327
|
+
try {
|
|
328
|
+
let responseData;
|
|
329
|
+
switch (operation) {
|
|
330
|
+
case 'replyToConversation':
|
|
331
|
+
responseData = await replyToConversation(this, cribopsHttp, i);
|
|
332
|
+
break;
|
|
333
|
+
case 'sendMessage':
|
|
334
|
+
responseData = await sendMessage(this, cribopsHttp, i);
|
|
335
|
+
break;
|
|
336
|
+
case 'sendTypingIndicator':
|
|
337
|
+
responseData = await sendTypingIndicator(this, cribopsHttp, i);
|
|
338
|
+
break;
|
|
339
|
+
case 'getAgent':
|
|
340
|
+
responseData = await getAgent(this, cribopsHttp, i);
|
|
341
|
+
break;
|
|
342
|
+
case 'listAgents':
|
|
343
|
+
responseData = await listAgents(this, cribopsHttp, i);
|
|
344
|
+
break;
|
|
345
|
+
default:
|
|
346
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`, { itemIndex: i });
|
|
347
|
+
}
|
|
348
|
+
results.push({
|
|
349
|
+
json: responseData,
|
|
350
|
+
pairedItem: { item: i },
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
if (this.continueOnFail()) {
|
|
355
|
+
results.push({
|
|
356
|
+
json: {
|
|
357
|
+
error: error.message,
|
|
358
|
+
},
|
|
359
|
+
pairedItem: { item: i },
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return [results];
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
exports.Cribops = Cribops;
|
|
371
|
+
// Simple UUID v4 generator
|
|
372
|
+
function generateUUID() {
|
|
373
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
374
|
+
const r = Math.random() * 16 | 0;
|
|
375
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
376
|
+
return v.toString(16);
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
async function replyToConversation(executeFunctions, cribopsHttp, itemIndex) {
|
|
380
|
+
const agentId = executeFunctions.getNodeParameter('agentId', itemIndex, '', { extractValue: true });
|
|
381
|
+
const conversationId = executeFunctions.getNodeParameter('conversationId', itemIndex);
|
|
382
|
+
const message = executeFunctions.getNodeParameter('message', itemIndex);
|
|
383
|
+
// Get the response webhook URL from the input data
|
|
384
|
+
const inputData = executeFunctions.getInputData()[itemIndex];
|
|
385
|
+
let responseWebhook = inputData.json.response_webhook;
|
|
386
|
+
// If not found directly, check if it's in the original trigger data (passed through by typing indicator)
|
|
387
|
+
if (!responseWebhook && inputData.json._originalTriggerData) {
|
|
388
|
+
const originalTriggerData = inputData.json._originalTriggerData;
|
|
389
|
+
responseWebhook = originalTriggerData.response_webhook;
|
|
390
|
+
}
|
|
391
|
+
// If still not found, try to find it in the workflow execution data from the CribopsTrigger node
|
|
392
|
+
if (!responseWebhook) {
|
|
393
|
+
try {
|
|
394
|
+
const workflowData = executeFunctions.getWorkflowDataProxy(itemIndex);
|
|
395
|
+
const cribopsTriggerData = workflowData.$('Cribops Trigger');
|
|
396
|
+
if (cribopsTriggerData && cribopsTriggerData.item && cribopsTriggerData.item.json) {
|
|
397
|
+
responseWebhook = cribopsTriggerData.item.json.response_webhook;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
// Ignore errors if Cribops Trigger node is not found
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// Log the raw values to debug expression evaluation
|
|
405
|
+
console.log('Debug - agentId:', agentId);
|
|
406
|
+
console.log('Debug - conversationId:', conversationId);
|
|
407
|
+
console.log('Debug - message:', message);
|
|
408
|
+
console.log('Debug - responseWebhook:', responseWebhook);
|
|
409
|
+
// Check if expressions were not evaluated (contain literal expression syntax)
|
|
410
|
+
if (conversationId.includes('{{') || conversationId.includes('}}')) {
|
|
411
|
+
throw new n8n_workflow_1.NodeOperationError(executeFunctions.getNode(), `Conversation ID contains unevaluated expression: ${conversationId}. Please ensure the expression is properly formatted.`, { itemIndex });
|
|
412
|
+
}
|
|
413
|
+
if (!conversationId || conversationId.trim() === '') {
|
|
414
|
+
throw new n8n_workflow_1.NodeOperationError(executeFunctions.getNode(), 'Conversation ID is required but was empty', { itemIndex });
|
|
415
|
+
}
|
|
416
|
+
if (!responseWebhook) {
|
|
417
|
+
console.log('Warning: response_webhook not found in input data:', JSON.stringify(inputData.json, null, 2));
|
|
418
|
+
// Fallback: try to use the agent webhook endpoint
|
|
419
|
+
console.log('Falling back to agent webhook endpoint');
|
|
420
|
+
const fallbackMessageData = {
|
|
421
|
+
id: generateUUID(),
|
|
422
|
+
content: message,
|
|
423
|
+
conversationId: conversationId,
|
|
424
|
+
agentId: agentId,
|
|
425
|
+
type: 'agent_response',
|
|
426
|
+
timestamp: new Date().toISOString(),
|
|
427
|
+
};
|
|
428
|
+
return await cribopsHttp.sendMessage(agentId, fallbackMessageData);
|
|
429
|
+
}
|
|
430
|
+
// Try to get user_id and organization_id from trigger data
|
|
431
|
+
let userId = inputData.json.user_id || '';
|
|
432
|
+
let organizationId = inputData.json.organization_id || '';
|
|
433
|
+
// If not found, try to get from workflow data
|
|
434
|
+
if ((!userId || !organizationId) && responseWebhook) {
|
|
435
|
+
try {
|
|
436
|
+
const workflowData = executeFunctions.getWorkflowDataProxy(itemIndex);
|
|
437
|
+
const cribopsTriggerData = workflowData.$('Cribops Trigger');
|
|
438
|
+
if (cribopsTriggerData && cribopsTriggerData.item && cribopsTriggerData.item.json) {
|
|
439
|
+
userId = userId || cribopsTriggerData.item.json.user_id || '';
|
|
440
|
+
organizationId = organizationId || cribopsTriggerData.item.json.organization_id || '';
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
// Ignore errors
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const messageData = {
|
|
448
|
+
conversation_id: conversationId,
|
|
449
|
+
content: message,
|
|
450
|
+
message_id: generateUUID(),
|
|
451
|
+
timestamp: new Date().toISOString(),
|
|
452
|
+
// Include additional fields that might be needed
|
|
453
|
+
user_id: userId,
|
|
454
|
+
organization_id: organizationId,
|
|
455
|
+
};
|
|
456
|
+
try {
|
|
457
|
+
console.log('Debug - Response webhook URL:', responseWebhook);
|
|
458
|
+
console.log('Debug - Request body:', JSON.stringify(messageData, null, 2));
|
|
459
|
+
// Send to the response webhook URL
|
|
460
|
+
// Note: The standard workflow uses form parameters, not JSON
|
|
461
|
+
const formData = new URLSearchParams();
|
|
462
|
+
Object.keys(messageData).forEach(key => {
|
|
463
|
+
formData.append(key, String(messageData[key]));
|
|
464
|
+
});
|
|
465
|
+
const requestOptions = {
|
|
466
|
+
method: 'POST',
|
|
467
|
+
url: responseWebhook,
|
|
468
|
+
headers: {
|
|
469
|
+
'Authorization': `Bearer ${cribopsHttp['config'].apiToken}`,
|
|
470
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
471
|
+
},
|
|
472
|
+
body: formData.toString(),
|
|
473
|
+
json: false,
|
|
474
|
+
};
|
|
475
|
+
const response = await executeFunctions.helpers.httpRequest(requestOptions);
|
|
476
|
+
return response;
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
// Enhanced error logging for 422 errors
|
|
480
|
+
if (error.response?.status === 422) {
|
|
481
|
+
console.error('422 Error Details:');
|
|
482
|
+
console.error('Response body:', JSON.stringify(error.response.body, null, 2));
|
|
483
|
+
console.error('Request that failed:', {
|
|
484
|
+
agentId: agentId,
|
|
485
|
+
body: messageData,
|
|
486
|
+
conversationId: conversationId
|
|
487
|
+
});
|
|
488
|
+
const errorDetails = error.response.body?.errors || error.response.body?.message || 'Unknown validation error';
|
|
489
|
+
throw new n8n_workflow_1.NodeOperationError(executeFunctions.getNode(), `Validation error (422): ${JSON.stringify(errorDetails)}. ConversationId: "${conversationId}"`, { itemIndex, description: `Full error: ${JSON.stringify(error.response.body)}` });
|
|
490
|
+
}
|
|
491
|
+
throw new n8n_workflow_1.NodeOperationError(executeFunctions.getNode(), `Failed to reply to conversation: ${error instanceof Error ? error.message : String(error)}`, { itemIndex });
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async function sendMessage(executeFunctions, cribopsHttp, itemIndex) {
|
|
495
|
+
const agentId = executeFunctions.getNodeParameter('agentId', itemIndex, '', { extractValue: true });
|
|
496
|
+
const message = executeFunctions.getNodeParameter('message', itemIndex);
|
|
497
|
+
const conversationId = executeFunctions.getNodeParameter('conversationId', itemIndex, '');
|
|
498
|
+
const userId = executeFunctions.getNodeParameter('userId', itemIndex, '');
|
|
499
|
+
const fileAttachment = executeFunctions.getNodeParameter('fileAttachment', itemIndex, {});
|
|
500
|
+
const additionalFields = executeFunctions.getNodeParameter('additionalFields', itemIndex, {});
|
|
501
|
+
const messageData = {
|
|
502
|
+
id: generateUUID(),
|
|
503
|
+
content: message,
|
|
504
|
+
conversationId: conversationId || `conversation_${Date.now()}`,
|
|
505
|
+
userId: userId || undefined,
|
|
506
|
+
type: 'user_message',
|
|
507
|
+
timestamp: new Date().toISOString(),
|
|
508
|
+
};
|
|
509
|
+
// Add file attachment if provided
|
|
510
|
+
if (fileAttachment.file) {
|
|
511
|
+
const file = fileAttachment.file;
|
|
512
|
+
if (file.url) {
|
|
513
|
+
messageData.fileUrl = file.url;
|
|
514
|
+
messageData.fileName = file.name || 'file';
|
|
515
|
+
messageData.fileType = file.type || 'application/octet-stream';
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// Add metadata if provided
|
|
519
|
+
if (additionalFields.metadata) {
|
|
520
|
+
const metadata = additionalFields.metadata;
|
|
521
|
+
const metadataValues = metadata.metadataValues;
|
|
522
|
+
if (metadataValues && metadataValues.length > 0) {
|
|
523
|
+
messageData.metadata = {};
|
|
524
|
+
metadataValues.forEach((item) => {
|
|
525
|
+
messageData.metadata[item.key] = item.value;
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return await cribopsHttp.sendMessage(agentId, messageData);
|
|
530
|
+
}
|
|
531
|
+
async function getAgent(executeFunctions, cribopsHttp, itemIndex) {
|
|
532
|
+
const agentId = executeFunctions.getNodeParameter('agentId', itemIndex, '', { extractValue: true });
|
|
533
|
+
return await cribopsHttp.getAgent(agentId);
|
|
534
|
+
}
|
|
535
|
+
async function listAgents(executeFunctions, cribopsHttp, itemIndex) {
|
|
536
|
+
const agents = await cribopsHttp.getAgents();
|
|
537
|
+
return { agents, count: agents.length };
|
|
538
|
+
}
|
|
539
|
+
async function sendTypingIndicator(executeFunctions, cribopsHttp, itemIndex) {
|
|
540
|
+
const agentId = executeFunctions.getNodeParameter('agentId', itemIndex, '', { extractValue: true });
|
|
541
|
+
const conversationId = executeFunctions.getNodeParameter('conversationId', itemIndex);
|
|
542
|
+
const typing = executeFunctions.getNodeParameter('typing', itemIndex);
|
|
543
|
+
// Check if we have a response_webhook in the input data to extract the correct base URL
|
|
544
|
+
const inputData = executeFunctions.getInputData()[itemIndex];
|
|
545
|
+
const responseWebhook = inputData.json.response_webhook;
|
|
546
|
+
let typingResult;
|
|
547
|
+
if (responseWebhook) {
|
|
548
|
+
// Extract base URL from response webhook
|
|
549
|
+
const webhookUrl = new URL(responseWebhook);
|
|
550
|
+
const baseUrl = `${webhookUrl.protocol}//${webhookUrl.host}`;
|
|
551
|
+
// Create a temporary HTTP client with the correct base URL
|
|
552
|
+
const dynamicCribopsHttp = new CribopsHttp_1.CribopsHttp({
|
|
553
|
+
baseUrl: baseUrl,
|
|
554
|
+
apiToken: cribopsHttp['config'].apiToken,
|
|
555
|
+
});
|
|
556
|
+
typingResult = await dynamicCribopsHttp.sendTypingIndicator(agentId, conversationId, typing);
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
// Fallback to the configured base URL
|
|
560
|
+
typingResult = await cribopsHttp.sendTypingIndicator(agentId, conversationId, typing);
|
|
561
|
+
}
|
|
562
|
+
// Preserve the original trigger data for subsequent nodes
|
|
563
|
+
return {
|
|
564
|
+
...typingResult,
|
|
565
|
+
// Pass through the original trigger data so replyToConversation can access it
|
|
566
|
+
_originalTriggerData: inputData.json
|
|
567
|
+
};
|
|
568
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="60" height="60" rx="12" fill="#4F46E5"/>
|
|
3
|
+
<path d="M15 20C15 17.7909 16.7909 16 19 16H41C43.2091 16 45 17.7909 45 20V32C45 34.2091 43.2091 36 41 36H26L18 42V36H19C16.7909 36 15 34.2091 15 32V20Z" fill="white"/>
|
|
4
|
+
<circle cx="24" cy="26" r="2" fill="#4F46E5"/>
|
|
5
|
+
<circle cx="30" cy="26" r="2" fill="#4F46E5"/>
|
|
6
|
+
<circle cx="36" cy="26" r="2" fill="#4F46E5"/>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { INodeType, INodeTypeDescription, ITriggerFunctions, ITriggerResponse, IWebhookFunctions, IWebhookResponseData, IHookFunctions, ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
|
|
2
|
+
export declare class CribopsTrigger implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
methods: {
|
|
5
|
+
loadOptions: {
|
|
6
|
+
getAgents(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
webhookMethods: {
|
|
10
|
+
default: {
|
|
11
|
+
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
12
|
+
create(this: IHookFunctions): Promise<boolean>;
|
|
13
|
+
delete(this: IHookFunctions): Promise<boolean>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
trigger(this: ITriggerFunctions): Promise<ITriggerResponse>;
|
|
17
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
18
|
+
}
|