@ctera/n8n-nodes-ctera-ai 0.1.2 → 0.2.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.
- package/README.md +57 -2
- package/dist/nodes/CteraAi/CteraAi.node.js +164 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# n8n-nodes-ctera-ai
|
|
2
2
|
|
|
3
|
-
n8n community node for CTERA AI MCP integration - enables semantic search, chat, and expert discovery.
|
|
3
|
+
n8n community node for CTERA AI MCP integration - enables semantic search, file search, chat, and expert discovery.
|
|
4
4
|
|
|
5
5
|
[n8n](https://n8n.io/) is a workflow automation platform.
|
|
6
6
|
|
|
@@ -16,9 +16,62 @@ Then restart n8n. The **CTERA Data Intelligence** node will appear in your node
|
|
|
16
16
|
## Operations
|
|
17
17
|
|
|
18
18
|
- **List Experts** - Get all available AI experts (knowledge bases)
|
|
19
|
-
- **Semantic Search** - Search within an expert's knowledge base
|
|
19
|
+
- **Semantic Search** - Search within an expert's knowledge base (returns text chunks for RAG)
|
|
20
|
+
- **File Search** - Search files and return metadata with optional snippets (returns file-level results)
|
|
20
21
|
- **Chat** - Have a conversation with an AI expert
|
|
21
22
|
|
|
23
|
+
## File Search Operation
|
|
24
|
+
|
|
25
|
+
The File Search operation searches files within an expert's knowledge base and returns file-level metadata with optional content snippets.
|
|
26
|
+
|
|
27
|
+
### Parameters
|
|
28
|
+
|
|
29
|
+
| Parameter | Type | Default | Description |
|
|
30
|
+
|-----------|------|---------|-------------|
|
|
31
|
+
| Query | string | required | Search expression with free-text and optional `key:value` filters |
|
|
32
|
+
| Limit | number | 100 | Maximum number of results (max: 250) |
|
|
33
|
+
| Offset | number | 0 | Pagination offset |
|
|
34
|
+
| Sort By | select | relevance | Sort order: `relevance`, `modified_at`, `created_at`, `name` |
|
|
35
|
+
| Include Snippet | boolean | false | Include text snippet per file |
|
|
36
|
+
| Include Markdown | boolean | false | Include full markdown body per file |
|
|
37
|
+
|
|
38
|
+
### Search Expression Syntax
|
|
39
|
+
|
|
40
|
+
The query parameter supports free-text search combined with metadata filters:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
# Free-text search
|
|
44
|
+
API documentation
|
|
45
|
+
|
|
46
|
+
# Free-text with classifier filters
|
|
47
|
+
API documentation department:Engineering
|
|
48
|
+
|
|
49
|
+
# Multiple filters
|
|
50
|
+
security policy department:Legal urgency:high
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Output
|
|
54
|
+
|
|
55
|
+
Each file hit becomes a separate n8n item with the following fields:
|
|
56
|
+
|
|
57
|
+
| Field | Type | Description |
|
|
58
|
+
|-------|------|-------------|
|
|
59
|
+
| fileId | string | Document UUID |
|
|
60
|
+
| name | string | File name |
|
|
61
|
+
| path | string | File path |
|
|
62
|
+
| sizeBytes | number | File size in bytes |
|
|
63
|
+
| mimeType | string | MIME content type |
|
|
64
|
+
| createdAt | string | ISO timestamp of creation |
|
|
65
|
+
| modifiedAt | string | ISO timestamp of last modification |
|
|
66
|
+
| storageSystem | string | Storage system identifier |
|
|
67
|
+
| bucketOrShare | string | Bucket or share name |
|
|
68
|
+
| score | number | Relevance score (0-1) |
|
|
69
|
+
| standardMetadata | object | Standard file metadata (guid, dataset_id, permissions) |
|
|
70
|
+
| customMetadata | object | Custom metadata (classifier_tags, classifications) |
|
|
71
|
+
| snippet | string | Text snippet (when include_snippet=true) |
|
|
72
|
+
| markdownBody | string | Full markdown content (when include_markdown=true) |
|
|
73
|
+
| _meta | object | Pagination info (total, limit, offset) |
|
|
74
|
+
|
|
22
75
|
## Credentials
|
|
23
76
|
|
|
24
77
|
**1. Log into Admin UI** with your SSO credentials
|
|
@@ -45,6 +98,8 @@ curl -k -X POST "https://YOUR_ADMIN_URL/admin/api/mcp-tokens/generate" \
|
|
|
45
98
|
- **Daily Intelligence Reports** - Schedule searches across experts for recent updates
|
|
46
99
|
- **Q&A Chatbots** - Build webhook-based chatbots using the Chat operation
|
|
47
100
|
- **Document Discovery** - Monitor for new content and send notifications
|
|
101
|
+
- **File Metadata Analysis** - Use File Search to find files by metadata filters and process each result
|
|
102
|
+
- **Compliance Scanning** - Search for files matching specific classifier tags
|
|
48
103
|
|
|
49
104
|
## Resources
|
|
50
105
|
|
|
@@ -53,6 +53,11 @@ class CteraAi {
|
|
|
53
53
|
value: 'search',
|
|
54
54
|
description: 'Retrieve raw text chunks for Retrieval-Augmented Generation',
|
|
55
55
|
},
|
|
56
|
+
{
|
|
57
|
+
name: 'File Search (Files & Metadata)',
|
|
58
|
+
value: 'fileSearch',
|
|
59
|
+
description: 'Search files and return metadata with optional snippets',
|
|
60
|
+
},
|
|
56
61
|
{
|
|
57
62
|
name: 'Chat (Generative Answer)',
|
|
58
63
|
value: 'chat',
|
|
@@ -130,6 +135,80 @@ class CteraAi {
|
|
|
130
135
|
},
|
|
131
136
|
],
|
|
132
137
|
},
|
|
138
|
+
{
|
|
139
|
+
displayName: 'File Search Options',
|
|
140
|
+
name: 'fileSearchOptions',
|
|
141
|
+
type: 'collection',
|
|
142
|
+
placeholder: 'Add Option',
|
|
143
|
+
default: {},
|
|
144
|
+
displayOptions: {
|
|
145
|
+
show: {
|
|
146
|
+
operation: ['fileSearch'],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
options: [
|
|
150
|
+
{
|
|
151
|
+
displayName: 'Limit',
|
|
152
|
+
name: 'limit',
|
|
153
|
+
type: 'number',
|
|
154
|
+
default: 100,
|
|
155
|
+
description: 'Maximum number of results to return',
|
|
156
|
+
typeOptions: {
|
|
157
|
+
minValue: 1,
|
|
158
|
+
maxValue: 250,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
displayName: 'Offset',
|
|
163
|
+
name: 'offset',
|
|
164
|
+
type: 'number',
|
|
165
|
+
default: 0,
|
|
166
|
+
description: 'Pagination offset',
|
|
167
|
+
typeOptions: {
|
|
168
|
+
minValue: 0,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
displayName: 'Sort By',
|
|
173
|
+
name: 'sort_by',
|
|
174
|
+
type: 'options',
|
|
175
|
+
options: [
|
|
176
|
+
{
|
|
177
|
+
name: 'Relevance',
|
|
178
|
+
value: 'relevance',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'Modified Date',
|
|
182
|
+
value: 'modified_at',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: 'Created Date',
|
|
186
|
+
value: 'created_at',
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'Name',
|
|
190
|
+
value: 'name',
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
default: 'relevance',
|
|
194
|
+
description: 'Sort order for results',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
displayName: 'Include Snippet',
|
|
198
|
+
name: 'include_snippet',
|
|
199
|
+
type: 'boolean',
|
|
200
|
+
default: false,
|
|
201
|
+
description: 'Whether to return text snippet per file',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
displayName: 'Include Markdown',
|
|
205
|
+
name: 'include_markdown',
|
|
206
|
+
type: 'boolean',
|
|
207
|
+
default: false,
|
|
208
|
+
description: 'Whether to return full markdown body per file',
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
},
|
|
133
212
|
],
|
|
134
213
|
};
|
|
135
214
|
}
|
|
@@ -170,6 +249,28 @@ class CteraAi {
|
|
|
170
249
|
params.window_size = additionalOptions.window_size;
|
|
171
250
|
}
|
|
172
251
|
}
|
|
252
|
+
else if (operation === 'fileSearch') {
|
|
253
|
+
toolName = 'expert_file_search';
|
|
254
|
+
serverUrl = this.getNodeParameter('expertEndpointUrl', i);
|
|
255
|
+
const query = this.getNodeParameter('query', i);
|
|
256
|
+
const fileSearchOptions = this.getNodeParameter('fileSearchOptions', i, {});
|
|
257
|
+
params.query = query;
|
|
258
|
+
if (fileSearchOptions.limit !== undefined) {
|
|
259
|
+
params.limit = fileSearchOptions.limit;
|
|
260
|
+
}
|
|
261
|
+
if (fileSearchOptions.offset !== undefined) {
|
|
262
|
+
params.offset = fileSearchOptions.offset;
|
|
263
|
+
}
|
|
264
|
+
if (fileSearchOptions.sort_by) {
|
|
265
|
+
params.sort_by = fileSearchOptions.sort_by;
|
|
266
|
+
}
|
|
267
|
+
if (fileSearchOptions.include_snippet !== undefined) {
|
|
268
|
+
params.include_snippet = fileSearchOptions.include_snippet;
|
|
269
|
+
}
|
|
270
|
+
if (fileSearchOptions.include_markdown !== undefined) {
|
|
271
|
+
params.include_markdown = fileSearchOptions.include_markdown;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
173
274
|
else if (operation === 'chat') {
|
|
174
275
|
toolName = 'expert_chat';
|
|
175
276
|
serverUrl = this.getNodeParameter('expertEndpointUrl', i);
|
|
@@ -230,15 +331,69 @@ class CteraAi {
|
|
|
230
331
|
else {
|
|
231
332
|
result = parsedResponse.result;
|
|
232
333
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
334
|
+
// Handle fileSearch with fan-out pattern - each hit becomes a separate item
|
|
335
|
+
if (operation === 'fileSearch' && result && result.hits && Array.isArray(result.hits)) {
|
|
336
|
+
// Map snake_case to camelCase for n8n conventions
|
|
337
|
+
for (const hit of result.hits) {
|
|
338
|
+
returnData.push({
|
|
339
|
+
json: {
|
|
340
|
+
...items[i].json,
|
|
341
|
+
operation,
|
|
342
|
+
toolName,
|
|
343
|
+
// Map to camelCase field names
|
|
344
|
+
fileId: hit.id,
|
|
345
|
+
name: hit.name,
|
|
346
|
+
path: hit.path,
|
|
347
|
+
sizeBytes: hit.size_bytes,
|
|
348
|
+
mimeType: hit.mime_type,
|
|
349
|
+
createdAt: hit.created_at,
|
|
350
|
+
modifiedAt: hit.modified_at,
|
|
351
|
+
storageSystem: hit.storage_system,
|
|
352
|
+
bucketOrShare: hit.bucket_or_share,
|
|
353
|
+
score: hit.score,
|
|
354
|
+
standardMetadata: hit.standard_metadata,
|
|
355
|
+
customMetadata: hit.custom_metadata,
|
|
356
|
+
snippet: hit.snippet,
|
|
357
|
+
markdownBody: hit.markdown_body,
|
|
358
|
+
// Include pagination info from response
|
|
359
|
+
_meta: {
|
|
360
|
+
total: result.total,
|
|
361
|
+
limit: result.limit,
|
|
362
|
+
offset: result.offset,
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
pairedItem: { item: i },
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
// If no hits, still return an item indicating empty results
|
|
369
|
+
if (result.hits.length === 0) {
|
|
370
|
+
returnData.push({
|
|
371
|
+
json: {
|
|
372
|
+
...items[i].json,
|
|
373
|
+
operation,
|
|
374
|
+
toolName,
|
|
375
|
+
result: [],
|
|
376
|
+
_meta: {
|
|
377
|
+
total: result.total || 0,
|
|
378
|
+
limit: result.limit || 0,
|
|
379
|
+
offset: result.offset || 0,
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
pairedItem: { item: i },
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
returnData.push({
|
|
388
|
+
json: {
|
|
389
|
+
...items[i].json,
|
|
390
|
+
operation,
|
|
391
|
+
toolName,
|
|
392
|
+
result,
|
|
393
|
+
},
|
|
394
|
+
pairedItem: { item: i },
|
|
395
|
+
});
|
|
396
|
+
}
|
|
242
397
|
}
|
|
243
398
|
catch (error) {
|
|
244
399
|
if (this.continueOnFail()) {
|
package/package.json
CHANGED