n8n-nodes-evolution-message-search 2.0.2 → 2.0.4

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.
@@ -5,6 +5,71 @@ exports.SearchMessages = void 0;
5
5
 
6
6
  const n8n_workflow_1 = require('n8n-workflow');
7
7
 
8
+ async function performSearch(ctx, itemIndex) {
9
+ const credentials = await ctx.getCredentials('evolutionApi');
10
+ const serverUrl = credentials['server-url'];
11
+ const apiKey = credentials.apikey;
12
+
13
+ const instanceName = ctx.getNodeParameter('instanceName', itemIndex);
14
+ const userConversationId = ctx.getNodeParameter('conversationId', itemIndex) || '';
15
+ const keywords = ctx.getNodeParameter('keywords', itemIndex) || '';
16
+ const dateFrom = ctx.getNodeParameter('dateFrom', itemIndex) || '';
17
+ const dateTo = ctx.getNodeParameter('dateTo', itemIndex) || '';
18
+ const pageSize = ctx.getNodeParameter('pageSize', itemIndex) || 10;
19
+ const page = ctx.getNodeParameter('page', itemIndex) || 1;
20
+
21
+ const skip = (page - 1) * pageSize;
22
+
23
+ const whereClause = {};
24
+ if (userConversationId) {
25
+ whereClause['key.remote'] = userConversationId;
26
+ }
27
+ if (keywords) {
28
+ whereClause['message.conversationMessage.text'] = { contains: keywords };
29
+ }
30
+ if (dateFrom || dateTo) {
31
+ whereClause['timestamp'] = {};
32
+ if (dateFrom) {
33
+ whereClause['timestamp']['gte'] = new Date(dateFrom).getTime() / 1000;
34
+ }
35
+ if (dateTo) {
36
+ whereClause['timestamp']['lte'] = new Date(dateTo).getTime() / 1000;
37
+ }
38
+ }
39
+
40
+ const body = {
41
+ where: whereClause,
42
+ take: pageSize,
43
+ skip: skip,
44
+ orderBy: { timestamp: 'desc' },
45
+ };
46
+
47
+ const cleanUrl = serverUrl.replace(/\/$/, '');
48
+ const response = await ctx.helpers.request({
49
+ method: 'POST',
50
+ uri: `${cleanUrl}/chat/findMessages/${instanceName}`,
51
+ body,
52
+ headers: {
53
+ 'Content-Type': 'application/json',
54
+ Accept: 'application/json',
55
+ apikey: apiKey,
56
+ },
57
+ json: true,
58
+ });
59
+
60
+ const messages = response.messages || response;
61
+ const total = messages.total || messages.length || 0;
62
+ const totalPages = Math.ceil(total / pageSize);
63
+
64
+ return {
65
+ total,
66
+ pages: totalPages,
67
+ currentPage: page,
68
+ pageSize,
69
+ records: Array.isArray(messages.records) ? messages.records : messages,
70
+ };
71
+ }
72
+
8
73
  class SearchMessages {
9
74
  constructor() {
10
75
  this.description = {
@@ -28,6 +93,16 @@ class SearchMessages {
28
93
  },
29
94
  ],
30
95
  properties: [
96
+ {
97
+ displayName: 'Tool Description',
98
+ name: 'toolDescription',
99
+ type: 'string',
100
+ typeOptions: {
101
+ rows: 4,
102
+ },
103
+ default: 'Search the WhatsApp message history of a conversation. ALL parameters are OPTIONAL except when explicitly needed:\n\n- Use ONLY keywords when user wants to find specific words/topics\n- Use ONLY dateFrom/dateTo when user asks about a time period (e.g. "last month", "yesterday")\n- Use BOTH keywords AND dates to combine topic search with time period\n- Use NONE when user wants recent messages (uses page 1)\n\nExamples:\n- "Did we talk about payment?" → use keywords="payment"\n- "What did we discuss last month?" → use dateFrom and dateTo only\n- "Anything about refund in January?" → use keywords="refund" + dateFrom/dateTo\n\nNavigation:\n- page: increase to see older messages (model can change)\n- pageSize: number of results per page (user-defined, do not change)',
104
+ description: 'Custom description shown to AI agent to help it understand how to use this tool',
105
+ },
31
106
  {
32
107
  displayName: 'Instance Name',
33
108
  name: 'instanceName',
@@ -42,7 +117,7 @@ class SearchMessages {
42
117
  type: 'string',
43
118
  required: false,
44
119
  default: '',
45
- description: 'WhatsApp conversation ID (JID). If empty, searches all conversations.',
120
+ description: 'WhatsApp conversation ID (JID). Leave empty to search all conversations.',
46
121
  placeholder: '5511999999999@s.whatsapp.net',
47
122
  },
48
123
  {
@@ -58,7 +133,8 @@ class SearchMessages {
58
133
  type: 'string',
59
134
  required: false,
60
135
  default: '',
61
- description: 'Search text in message content (model can set)',
136
+ description: 'OPTIONAL: Search text in message content. Leave empty to search by date only.',
137
+ placeholder: '={{ $fromAI("Keywords", "", "string") }}',
62
138
  },
63
139
  {
64
140
  displayName: 'Date From',
@@ -66,8 +142,8 @@ class SearchMessages {
66
142
  type: 'string',
67
143
  required: false,
68
144
  default: '',
69
- description: 'Start date for message search (model can set)',
70
- placeholder: '2024-01-01T00:00:00Z',
145
+ description: 'OPTIONAL: Start date (ISO format). Use when user mentions a time period. Leave empty to search all time.',
146
+ placeholder: '={{ $fromAI("Date_From", "", "string") }}',
71
147
  },
72
148
  {
73
149
  displayName: 'Date To',
@@ -75,8 +151,8 @@ class SearchMessages {
75
151
  type: 'string',
76
152
  required: false,
77
153
  default: '',
78
- description: 'End date for message search (model can set)',
79
- placeholder: '2024-12-31T23:59:59Z',
154
+ description: 'OPTIONAL: End date (ISO format). Use when user mentions a time period. Leave empty to search all time.',
155
+ placeholder: '={{ $fromAI("Date_To", "", "string") }}',
80
156
  },
81
157
  {
82
158
  displayName: 'Items per Page',
@@ -97,102 +173,35 @@ class SearchMessages {
97
173
  typeOptions: {
98
174
  minValue: 1,
99
175
  },
100
- description: 'Page number to retrieve (model can navigate)',
176
+ description: 'Page to retrieve (model can navigate: increase to see older messages)',
177
+ placeholder: '={{ $fromAI("Page_Number", "1", "number") }}',
101
178
  },
102
179
  ],
103
180
  };
104
181
  }
105
182
 
106
183
  async execute() {
107
- const items = this.getInputData ? this.getInputData() : [];
184
+ const items = typeof this.getInputData === 'function' ? this.getInputData() : [];
108
185
  const returnData = [];
186
+ const max = items.length > 0 ? items.length : 1;
109
187
 
110
- for (let itemIndex = 0; itemIndex < (items.length || 1); itemIndex++) {
188
+ for (let itemIndex = 0; itemIndex < max; itemIndex++) {
111
189
  try {
112
- const result = await this.executeSingle.call(this, itemIndex);
190
+ const result = await performSearch(this, itemIndex);
113
191
  returnData.push({
114
192
  json: result,
115
193
  pairedItem: { item: itemIndex },
116
194
  });
117
195
  } catch (err) {
118
- if (this.continueOnFail && this.continueOnFail()) {
119
- returnData.push({
120
- json: { error: err.message },
121
- pairedItem: { item: itemIndex },
122
- });
123
- } else {
124
- throw err;
125
- }
196
+ returnData.push({
197
+ json: { error: err.message },
198
+ pairedItem: { item: itemIndex },
199
+ });
126
200
  }
127
201
  }
128
202
 
129
203
  return [returnData];
130
204
  }
131
-
132
- async executeSingle(itemIndex) {
133
- const credentials = await this.getCredentials('evolutionApi');
134
- const serverUrl = credentials['server-url'];
135
- const apiKey = credentials.apikey;
136
-
137
- const instanceName = this.getNodeParameter('instanceName', itemIndex);
138
- const userConversationId = this.getNodeParameter('conversationId', itemIndex) || '';
139
- const keywords = this.getNodeParameter('keywords', itemIndex) || '';
140
- const dateFrom = this.getNodeParameter('dateFrom', itemIndex) || '';
141
- const dateTo = this.getNodeParameter('dateTo', itemIndex) || '';
142
- const pageSize = this.getNodeParameter('pageSize', itemIndex) || 10;
143
- const page = this.getNodeParameter('page', itemIndex) || 1;
144
-
145
- const skip = (page - 1) * pageSize;
146
-
147
- const whereClause = {};
148
- if (userConversationId) {
149
- whereClause['key.remote'] = userConversationId;
150
- }
151
- if (keywords) {
152
- whereClause['message.conversationMessage.text'] = { contains: keywords };
153
- }
154
- if (dateFrom || dateTo) {
155
- whereClause['timestamp'] = {};
156
- if (dateFrom) {
157
- whereClause['timestamp']['gte'] = new Date(dateFrom).getTime() / 1000;
158
- }
159
- if (dateTo) {
160
- whereClause['timestamp']['lte'] = new Date(dateTo).getTime() / 1000;
161
- }
162
- }
163
-
164
- const body = {
165
- where: whereClause,
166
- take: pageSize,
167
- skip: skip,
168
- orderBy: { timestamp: 'desc' },
169
- };
170
-
171
- const cleanUrl = serverUrl.replace(/\/$/, '');
172
- const response = await this.helpers.request({
173
- method: 'POST',
174
- uri: `${cleanUrl}/chat/findMessages/${instanceName}`,
175
- body,
176
- headers: {
177
- 'Content-Type': 'application/json',
178
- Accept: 'application/json',
179
- apikey: apiKey,
180
- },
181
- json: true,
182
- });
183
-
184
- const messages = response.messages || response;
185
- const total = messages.total || messages.length || 0;
186
- const totalPages = Math.ceil(total / pageSize);
187
-
188
- return {
189
- total,
190
- pages: totalPages,
191
- currentPage: page,
192
- pageSize,
193
- records: Array.isArray(messages.records) ? messages.records : messages,
194
- };
195
- }
196
205
  }
197
206
 
198
207
  exports.SearchMessages = SearchMessages;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-evolution-message-search",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Evolution API - Search Messages node for n8n. Search WhatsApp message history by keywords, dates, and conversation.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",