@peopl-health/nexus 1.1.8 → 1.3.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/MIGRATION_GUIDE.md +71 -379
- package/README.md +80 -559
- package/lib/adapters/BaileysProvider.js +25 -1
- package/lib/adapters/TwilioProvider.js +107 -0
- package/lib/adapters/registry.js +29 -0
- package/lib/config/configLoader.js +38 -0
- package/lib/controllers/assistantController.js +3 -3
- package/lib/controllers/messageController.js +31 -1
- package/lib/core/NexusMessaging.js +151 -35
- package/lib/helpers/assistantHelper.js +6 -6
- package/lib/helpers/baileysHelper.js +3 -3
- package/lib/helpers/twilioHelper.js +3 -3
- package/lib/index.d.ts +1 -1
- package/lib/index.js +84 -9
- package/lib/interactive/index.js +86 -0
- package/lib/interactive/registry.js +31 -0
- package/lib/interactive/twilioMapper.js +60 -0
- package/lib/models/messageModel.js +8 -0
- package/lib/routes/index.js +3 -1
- package/lib/services/airtableService.js +4 -0
- package/lib/services/assistantService.js +16 -2
- package/lib/storage/NoopStorage.js +19 -0
- package/lib/storage/registry.js +31 -0
- package/lib/templates/predefinedTemplates.js +1 -3
- package/lib/utils/defaultLLMProvider.js +1 -1
- package/lib/utils/index.js +3 -5
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,611 +1,132 @@
|
|
|
1
|
-
# nexus
|
|
1
|
+
# @peopl-health/nexus
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A concise, configurable messaging and assistant toolkit for WhatsApp. It supports Twilio (production‑ready) and Baileys (limited), optional Mongo storage, OpenAI assistants, templates/flows via Twilio Content API, and an event/middleware model so apps can customize behavior.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
- **Multi-Provider Support**: Seamlessly switch between Twilio and Baileys
|
|
8
|
-
- **Configurable Architecture**: Adapter pattern for messaging providers
|
|
9
|
-
- **AI Assistant Integration**: Built-in support for OpenAI and custom LLM providers
|
|
10
|
-
- **MongoDB Storage**: Persistent message and thread storage
|
|
11
|
-
- **Template Messaging**: Support for WhatsApp Business templates
|
|
12
|
-
- **Scheduled Messages**: Queue and send messages at specific times
|
|
13
|
-
- **Flow Management**: Create conversational flows and approval processes
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
5
|
+
## Install
|
|
16
6
|
|
|
17
7
|
```bash
|
|
18
8
|
npm install @peopl-health/nexus
|
|
9
|
+
# Providers / AI
|
|
10
|
+
npm install twilio baileys openai
|
|
19
11
|
```
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Install the providers you need:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
# For Twilio WhatsApp
|
|
27
|
-
npm install twilio
|
|
28
|
-
|
|
29
|
-
# For Baileys (direct WhatsApp connection)
|
|
30
|
-
npm install baileys
|
|
13
|
+
## Quick Start (Twilio)
|
|
31
14
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
## Quick Start
|
|
37
|
-
|
|
38
|
-
### Basic Messaging (Twilio)
|
|
39
|
-
|
|
40
|
-
```javascript
|
|
41
|
-
const { Nexus } = require('nexus-messaging');
|
|
15
|
+
```js
|
|
16
|
+
const express = require('express');
|
|
17
|
+
const { Nexus, setupDefaultRoutes } = require('@peopl-health/nexus');
|
|
42
18
|
|
|
43
19
|
const nexus = new Nexus();
|
|
44
|
-
|
|
45
20
|
await nexus.initialize({
|
|
46
21
|
provider: 'twilio',
|
|
47
22
|
providerConfig: {
|
|
48
|
-
accountSid: process.env.
|
|
49
|
-
authToken: process.env.
|
|
50
|
-
phoneNumber:
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// Send a message
|
|
55
|
-
await nexus.sendMessage({
|
|
56
|
-
to: '+1234567890',
|
|
57
|
-
message: 'Hello from Nexus!'
|
|
58
|
-
});
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### With AI Assistant
|
|
62
|
-
|
|
63
|
-
```javascript
|
|
64
|
-
const { Nexus, BaseAssistant } = require('@peopl/nexus');
|
|
65
|
-
|
|
66
|
-
const nexus = new Nexus();
|
|
67
|
-
|
|
68
|
-
await nexus.initialize({
|
|
69
|
-
provider: 'twilio',
|
|
70
|
-
providerConfig: { /* twilio config */ },
|
|
71
|
-
llm: 'openai',
|
|
72
|
-
llmConfig: {
|
|
73
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
74
|
-
}
|
|
23
|
+
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
24
|
+
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
25
|
+
phoneNumber: process.env.TWILIO_PHONE_NUMBER
|
|
26
|
+
},
|
|
27
|
+
storage: 'mongo', // or 'noop', or your custom adapter/instance
|
|
28
|
+
storageConfig: { mongoUri: process.env.MONGODB_URI }
|
|
75
29
|
});
|
|
76
30
|
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return await assistant.processMessage(messageData);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
31
|
+
// Built‑in routes (assistant, conversation, media, message, template)
|
|
32
|
+
const app = express();
|
|
33
|
+
app.use(express.json());
|
|
34
|
+
setupDefaultRoutes(app);
|
|
84
35
|
|
|
85
|
-
//
|
|
36
|
+
// Incoming webhooks
|
|
86
37
|
app.post('/webhook', async (req, res) => {
|
|
87
38
|
await nexus.processMessage(req.body);
|
|
88
39
|
res.sendStatus(200);
|
|
89
40
|
});
|
|
90
41
|
```
|
|
91
42
|
|
|
92
|
-
##
|
|
93
|
-
|
|
94
|
-
### Option 1: NPM Package (Recommended)
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
npm install nexus-messaging twilio openai
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Option 2: Git Dependency
|
|
101
|
-
|
|
102
|
-
```json
|
|
103
|
-
{
|
|
104
|
-
"dependencies": {
|
|
105
|
-
"@peopl/nexus": "git+https://github.com/peopl-health/nexus.git"
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Option 3: Local Development
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
# Clone and link locally
|
|
114
|
-
git clone https://github.com/peopl-health/nexus.git
|
|
115
|
-
cd nexus
|
|
116
|
-
npm link
|
|
117
|
-
|
|
118
|
-
# In your project
|
|
119
|
-
npm link @peopl/nexus
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## Configuration Options
|
|
43
|
+
## Templates & Approvals (Twilio)
|
|
123
44
|
|
|
124
|
-
|
|
45
|
+
Nexus auto‑injects the active Twilio provider into the template controllers during `initialize`. Default routes under `/api/template` work immediately:
|
|
46
|
+
- `GET /api/template` list templates
|
|
47
|
+
- `GET /api/template/:id` get one
|
|
48
|
+
- `POST /api/template/text` create text template
|
|
49
|
+
- `POST /api/template/approval` submit for approval
|
|
50
|
+
- `GET /api/template/status/:sid` check status
|
|
51
|
+
- `DELETE /api/template/:id` delete
|
|
125
52
|
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
#### Baileys (Direct WhatsApp)
|
|
139
|
-
```javascript
|
|
140
|
-
{
|
|
141
|
-
provider: 'baileys',
|
|
142
|
-
providerConfig: {
|
|
143
|
-
printQRInTerminal: true,
|
|
144
|
-
// Additional Baileys options
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Storage Options
|
|
150
|
-
|
|
151
|
-
```javascript
|
|
152
|
-
{
|
|
153
|
-
storage: 'mongo', // Default
|
|
154
|
-
storageConfig: {
|
|
155
|
-
uri: process.env.MONGODB_URI || 'mongodb://localhost:27017/nexus'
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Or disable storage
|
|
160
|
-
{ storage: false }
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### LLM Integration
|
|
164
|
-
|
|
165
|
-
```javascript
|
|
166
|
-
{
|
|
167
|
-
llm: 'openai',
|
|
168
|
-
llmConfig: {
|
|
169
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
170
|
-
model: 'gpt-4',
|
|
171
|
-
temperature: 0.7
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
## Advanced Usage
|
|
177
|
-
|
|
178
|
-
### Custom Assistant
|
|
179
|
-
|
|
180
|
-
```javascript
|
|
181
|
-
const { BaseAssistant } = require('@peopl/nexus/utils');
|
|
182
|
-
|
|
183
|
-
class CustomerServiceAssistant extends BaseAssistant {
|
|
184
|
-
async processMessage(messageData) {
|
|
185
|
-
// Custom business logic
|
|
186
|
-
if (messageData.message.includes('order')) {
|
|
187
|
-
return await this.handleOrderInquiry(messageData);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return await super.processMessage(messageData);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async handleOrderInquiry(messageData) {
|
|
194
|
-
// Custom order handling logic
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Template Messages
|
|
200
|
-
|
|
201
|
-
```javascript
|
|
202
|
-
await nexus.sendMessage({
|
|
203
|
-
to: '+1234567890',
|
|
204
|
-
contentSid: 'HX1234567890abcdef', // Twilio template SID
|
|
205
|
-
variables: {
|
|
206
|
-
'1': 'John',
|
|
207
|
-
'2': 'Tomorrow at 3 PM'
|
|
208
|
-
}
|
|
53
|
+
Programmatic use:
|
|
54
|
+
```js
|
|
55
|
+
const provider = nexus.getMessaging().getProvider();
|
|
56
|
+
const content = await provider.createTemplate({
|
|
57
|
+
friendly_name: 'hello_' + Date.now(),
|
|
58
|
+
language: 'es',
|
|
59
|
+
variables: { '1': 'Nombre' },
|
|
60
|
+
types: { 'twilio/text': { body: 'Hola {{1}}' } }
|
|
209
61
|
});
|
|
62
|
+
await provider.submitForApproval(content.sid, 'hello', 'UTILITY');
|
|
63
|
+
const status = await provider.checkApprovalStatus(content.sid);
|
|
210
64
|
```
|
|
211
65
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
```javascript
|
|
215
|
-
await nexus.sendScheduledMessage({
|
|
216
|
-
to: '+1234567890',
|
|
217
|
-
message: 'Reminder: Your appointment is tomorrow',
|
|
218
|
-
sendAt: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours from now
|
|
219
|
-
});
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
## Routes for Consumer Servers
|
|
223
|
-
|
|
224
|
-
The library exports pre-built route definitions that consumer servers can use with minimal code:
|
|
225
|
-
|
|
226
|
-
### Option 1: Setup All Default Routes (Minimal Code)
|
|
66
|
+
## Interactive & Flows
|
|
227
67
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const {
|
|
231
|
-
|
|
232
|
-
const app = express();
|
|
233
|
-
|
|
234
|
-
// Setup all default routes with built-in controllers (one line!)
|
|
235
|
-
setupDefaultRoutes(app);
|
|
236
|
-
|
|
237
|
-
// Add your custom routes
|
|
238
|
-
app.get('/api/custom', myCustomController);
|
|
239
|
-
app.post('/api/special', mySpecialController);
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Option 2: Individual Route Control
|
|
243
|
-
|
|
244
|
-
```javascript
|
|
245
|
-
const express = require('express');
|
|
246
|
-
const { routes, createRouter } = require('@peopl-health/nexus');
|
|
68
|
+
Provider‑agnostic APIs with Twilio mapping (Baileys: not supported):
|
|
69
|
+
```js
|
|
70
|
+
const { registerFlow, sendInteractive, registerInteractiveHandler, attachInteractiveRouter } = require('@peopl-health/nexus');
|
|
247
71
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
app.use('/api/assistant', createRouter(routes.assistantRoutes, myControllers));
|
|
252
|
-
app.use('/api/message', createRouter(routes.messageRoutes, myControllers));
|
|
253
|
-
app.use('/api/template', createRouter(routes.templateRoutes, myControllers));
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### Available Default Route Groups
|
|
257
|
-
|
|
258
|
-
The `setupDefaultRoutes()` function sets up these 5 route groups:
|
|
259
|
-
|
|
260
|
-
#### **Assistant Routes** (`/api/assistant`)
|
|
261
|
-
- `POST /active` - Set active assistant
|
|
262
|
-
- `POST /add-instruction` - Add instruction to assistant
|
|
263
|
-
- `POST /add-msg` - Add message to assistant
|
|
264
|
-
- `POST /create` - Create new assistant
|
|
265
|
-
- `POST /get-info` - Get assistant information
|
|
266
|
-
- `GET /list` - List all assistants
|
|
267
|
-
- `POST /switch` - Switch between assistants
|
|
268
|
-
- `POST /stop` - Stop assistant
|
|
269
|
-
|
|
270
|
-
#### **Conversation Routes** (`/api/conversation`)
|
|
271
|
-
- `GET /` - Get conversations
|
|
272
|
-
- `GET /search` - Search conversations
|
|
273
|
-
- `GET /by-name` - Get conversations by name
|
|
274
|
-
- `GET /:phoneNumber` - Get conversation messages
|
|
275
|
-
- `GET /:phoneNumber/new` - Get new messages
|
|
276
|
-
- `POST /reply` - Send conversation reply
|
|
277
|
-
- `POST /send-template` - Send template to new number
|
|
278
|
-
- `POST /:phoneNumber/read` - Mark messages as read
|
|
279
|
-
|
|
280
|
-
#### **Media Routes** (`/api/media`)
|
|
281
|
-
- `GET /:key(*)` - Get media file
|
|
282
|
-
- `POST /upload` - Upload media file
|
|
283
|
-
|
|
284
|
-
#### **Message Routes** (`/api/message`)
|
|
285
|
-
- `POST /send` - Send single message
|
|
286
|
-
- `POST /send-bulk` - Send bulk messages
|
|
287
|
-
- `POST /send-bulk-airtable` - Send bulk messages from Airtable
|
|
288
|
-
|
|
289
|
-
#### **Template Routes** (`/api/template`)
|
|
290
|
-
- `POST /text` - Create text template
|
|
291
|
-
- `GET /` - List templates
|
|
292
|
-
- `GET /predefined` - Get predefined templates
|
|
293
|
-
- `GET /:id` - Get specific template
|
|
294
|
-
- `GET /complete/:sid` - Get complete template
|
|
295
|
-
- `POST /flow` - Create flow template
|
|
296
|
-
- `DELETE /flow/:sid` - Delete flow template
|
|
297
|
-
- `POST /approval` - Submit template for approval
|
|
298
|
-
- `GET /status/:sid` - Check approval status
|
|
299
|
-
- `DELETE /:id` - Delete template
|
|
300
|
-
|
|
301
|
-
## API Reference
|
|
302
|
-
|
|
303
|
-
### Nexus Class
|
|
304
|
-
|
|
305
|
-
#### `initialize(options)` → `Promise<void>`
|
|
306
|
-
Initialize with providers and configuration.
|
|
307
|
-
|
|
308
|
-
**Parameters:**
|
|
309
|
-
- `provider` (string): 'twilio' or 'baileys'
|
|
310
|
-
- `providerConfig` (object): Provider-specific configuration
|
|
311
|
-
- `storage` (string|false): 'mongo' or false to disable
|
|
312
|
-
- `storageConfig` (object): Storage configuration
|
|
313
|
-
- `llm` (string): 'openai' for AI features
|
|
314
|
-
- `llmConfig` (object): LLM configuration
|
|
315
|
-
|
|
316
|
-
#### `sendMessage(messageData)` → `Promise<Object>`
|
|
317
|
-
Send a message through the configured provider.
|
|
318
|
-
|
|
319
|
-
**Parameters:**
|
|
320
|
-
- `to` (string): Recipient phone number
|
|
321
|
-
- `message` (string): Message text
|
|
322
|
-
- `fileUrl` (string, optional): File URL for media
|
|
323
|
-
- `contentSid` (string, optional): Template content SID
|
|
324
|
-
- `variables` (object, optional): Template variables
|
|
325
|
-
|
|
326
|
-
#### `processMessage(rawMessage)` → `Promise<void>`
|
|
327
|
-
Process incoming webhook/event message.
|
|
328
|
-
|
|
329
|
-
#### `setHandlers(handlers)` → `void`
|
|
330
|
-
Set message and status handlers.
|
|
331
|
-
|
|
332
|
-
#### `isConnected()` → `boolean`
|
|
333
|
-
Check provider connection status.
|
|
334
|
-
|
|
335
|
-
#### `disconnect()` → `Promise<void>`
|
|
336
|
-
Clean shutdown of all services.
|
|
337
|
-
|
|
338
|
-
## Examples
|
|
339
|
-
|
|
340
|
-
Complete examples in `/examples`:
|
|
341
|
-
|
|
342
|
-
- **`basic-usage.js`** - Pure messaging without AI
|
|
343
|
-
- **`consumer-server.js`** - Full Express server with AI assistant
|
|
344
|
-
- **`assistants/ExampleAssistant.js`** - Custom assistant implementation
|
|
345
|
-
|
|
346
|
-
## Publishing to NPM
|
|
347
|
-
|
|
348
|
-
```bash
|
|
349
|
-
# Login to npm
|
|
350
|
-
npm login
|
|
351
|
-
|
|
352
|
-
# Publish (first time)
|
|
353
|
-
npm publish
|
|
354
|
-
|
|
355
|
-
# Update version and publish
|
|
356
|
-
npm version patch # or minor/major
|
|
357
|
-
npm publish
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
## Environment Variables
|
|
361
|
-
|
|
362
|
-
```bash
|
|
363
|
-
# Twilio
|
|
364
|
-
TWILIO_SID=your_account_sid
|
|
365
|
-
TWILIO_TOKEN=your_auth_token
|
|
366
|
-
TWILIO_PHONE=whatsapp:+1234567890
|
|
367
|
-
|
|
368
|
-
# MongoDB
|
|
369
|
-
MONGODB_URI=mongodb://localhost:27017/nexus
|
|
370
|
-
|
|
371
|
-
# OpenAI
|
|
372
|
-
OPENAI_API_KEY=your_openai_key
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
## Customization
|
|
376
|
-
|
|
377
|
-
Define custom handlers for different message types:
|
|
378
|
-
|
|
379
|
-
```javascript
|
|
380
|
-
nexus.setHandlers({
|
|
381
|
-
onMessage: async (messageData, nexus) => {
|
|
382
|
-
// Handle regular text messages
|
|
383
|
-
},
|
|
384
|
-
|
|
385
|
-
onInteractive: async (messageData, nexus) => {
|
|
386
|
-
// Handle button clicks, list selections, flow responses
|
|
387
|
-
const { type, payload } = messageData.interactive;
|
|
388
|
-
|
|
389
|
-
if (type === 'button') {
|
|
390
|
-
console.log('Button clicked:', payload);
|
|
391
|
-
}
|
|
392
|
-
},
|
|
393
|
-
|
|
394
|
-
onMedia: async (messageData, nexus) => {
|
|
395
|
-
// Handle image, document, audio messages
|
|
396
|
-
const { url, contentType } = messageData.media;
|
|
397
|
-
},
|
|
398
|
-
|
|
399
|
-
onCommand: async (messageData, nexus) => {
|
|
400
|
-
// Handle commands like /help, /start
|
|
401
|
-
const { command, args } = messageData.command;
|
|
402
|
-
},
|
|
403
|
-
|
|
404
|
-
onKeyword: async (messageData, nexus) => {
|
|
405
|
-
// Handle keyword triggers
|
|
406
|
-
console.log('Keyword matched:', messageData.keyword);
|
|
407
|
-
},
|
|
408
|
-
|
|
409
|
-
onFlow: async (messageData, nexus) => {
|
|
410
|
-
// Handle flow triggers
|
|
411
|
-
console.log('Flow triggered:', messageData.flow);
|
|
412
|
-
}
|
|
72
|
+
registerFlow('greeting_qr', {
|
|
73
|
+
type: 'quick-reply', language: 'es', body: 'Hola {{1}}', variables: { '1': 'Nombre' },
|
|
74
|
+
buttons: [{ text: 'Sí' }, { text: 'No' }]
|
|
413
75
|
});
|
|
414
|
-
|
|
76
|
+
await sendInteractive(nexus, { to: '+521555...', id: 'greeting_qr' });
|
|
415
77
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
Customize how messages are parsed:
|
|
419
|
-
|
|
420
|
-
```javascript
|
|
421
|
-
await nexus.initialize({
|
|
422
|
-
// ... other config
|
|
423
|
-
parserConfig: {
|
|
424
|
-
commandPrefixes: ['/', '!', '#'],
|
|
425
|
-
keywords: [
|
|
426
|
-
'help',
|
|
427
|
-
'support',
|
|
428
|
-
{ pattern: 'urgent.*issue', flags: 'i' }
|
|
429
|
-
],
|
|
430
|
-
flowTriggers: [
|
|
431
|
-
'start onboarding',
|
|
432
|
-
'begin survey'
|
|
433
|
-
]
|
|
434
|
-
}
|
|
78
|
+
registerInteractiveHandler({ type: 'button', id: /sí|si/i }, async (msg, messaging) => {
|
|
79
|
+
await messaging.sendMessage({ to: msg.from, message: '¡Confirmado!' });
|
|
435
80
|
});
|
|
81
|
+
attachInteractiveRouter(nexus);
|
|
436
82
|
```
|
|
437
83
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
```javascript
|
|
441
|
-
const { OpenAI } = require('openai');
|
|
442
|
-
|
|
443
|
-
const openai = new OpenAI({
|
|
444
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
await nexus.initialize({
|
|
448
|
-
// ... other config
|
|
449
|
-
assistant: {
|
|
450
|
-
llmClient: openai,
|
|
451
|
-
assistants: {
|
|
452
|
-
'SUPPORT_ASSISTANT': 'asst_abc123',
|
|
453
|
-
'SALES_ASSISTANT': 'asst_def456'
|
|
454
|
-
},
|
|
455
|
-
handlers: {
|
|
456
|
-
onRequiresAction: async (result, threadData) => {
|
|
457
|
-
// Handle function calls
|
|
458
|
-
const toolCalls = result.run.required_action.submit_tool_outputs.tool_calls;
|
|
459
|
-
const toolOutputs = [];
|
|
460
|
-
|
|
461
|
-
for (const toolCall of toolCalls) {
|
|
462
|
-
if (toolCall.function.name === 'get_weather') {
|
|
463
|
-
const output = await getWeather(JSON.parse(toolCall.function.arguments));
|
|
464
|
-
toolOutputs.push({
|
|
465
|
-
tool_call_id: toolCall.id,
|
|
466
|
-
output: JSON.stringify(output)
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return await nexus.getAssistantManager().submitToolOutputs(
|
|
472
|
-
threadData.threadId,
|
|
473
|
-
result.run.id,
|
|
474
|
-
toolOutputs
|
|
475
|
-
);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
});
|
|
84
|
+
## Storage (Adapters)
|
|
480
85
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
86
|
+
- Built‑in: `mongo` (default), `noop`.
|
|
87
|
+
- Register your adapter or pass an instance directly.
|
|
88
|
+
```js
|
|
89
|
+
const { registerStorage } = require('@peopl-health/nexus/lib/storage/registry');
|
|
90
|
+
registerStorage('src', MyStorageClass);
|
|
91
|
+
await nexus.initialize({ storage: 'src', storageConfig: { /* ... */ } });
|
|
92
|
+
// OR
|
|
93
|
+
await nexus.initialize({ storage: new MyStorageClass(/* ... */) });
|
|
486
94
|
```
|
|
487
95
|
|
|
488
|
-
##
|
|
489
|
-
|
|
490
|
-
### Nexus Class
|
|
491
|
-
|
|
492
|
-
#### `initialize(options)`
|
|
493
|
-
Initialize Nexus with providers and configuration.
|
|
96
|
+
## Middleware & Events
|
|
494
97
|
|
|
495
|
-
|
|
496
|
-
|
|
98
|
+
Add middleware per type or global; subscribe to events.
|
|
99
|
+
```js
|
|
100
|
+
const bus = nexus.getMessaging().getEventBus();
|
|
101
|
+
bus.on('message:received', (m) => console.log('rx', m.id));
|
|
497
102
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
message: 'Hello World!',
|
|
502
|
-
fileUrl: 'https://example.com/image.jpg', // optional
|
|
503
|
-
fileType: 'image', // optional
|
|
504
|
-
contentSid: 'template_sid', // optional for templates
|
|
505
|
-
variables: { '1': 'John', '2': 'Doe' } // optional for templates
|
|
103
|
+
nexus.getMessaging().use('message', async (msg, nx, next) => {
|
|
104
|
+
// sanitize/annotate
|
|
105
|
+
return next();
|
|
506
106
|
});
|
|
507
107
|
```
|
|
508
108
|
|
|
509
|
-
|
|
510
|
-
Schedule a message for future delivery.
|
|
511
|
-
|
|
512
|
-
```javascript
|
|
513
|
-
await nexus.sendScheduledMessage({
|
|
514
|
-
to: '+1234567890',
|
|
515
|
-
message: 'Reminder: Your appointment is tomorrow',
|
|
516
|
-
sendTime: '2024-01-15T10:00:00Z',
|
|
517
|
-
timeZone: 'America/Mexico_City'
|
|
518
|
-
});
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
#### `processMessage(rawMessage)`
|
|
522
|
-
Process incoming message from webhook.
|
|
523
|
-
|
|
524
|
-
### Individual Components
|
|
525
|
-
|
|
526
|
-
You can also use individual components for more control:
|
|
527
|
-
|
|
528
|
-
```javascript
|
|
529
|
-
const { TwilioProvider, MongoStorage, MessageParser } = require('@peopl/nexus');
|
|
530
|
-
|
|
531
|
-
// Use components individually
|
|
532
|
-
const provider = new TwilioProvider(config);
|
|
533
|
-
await provider.initialize();
|
|
534
|
-
|
|
535
|
-
const storage = new MongoStorage(config);
|
|
536
|
-
await storage.connect();
|
|
537
|
-
|
|
538
|
-
const parser = new MessageParser(config);
|
|
539
|
-
const parsedMessage = parser.parseMessage(rawMessage);
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
## Examples
|
|
543
|
-
|
|
544
|
-
### Basic Echo Bot
|
|
545
|
-
```javascript
|
|
546
|
-
const { Nexus } = require('nexus-messaging');
|
|
547
|
-
|
|
548
|
-
const nexus = new Nexus();
|
|
109
|
+
## Assistants (Optional)
|
|
549
110
|
|
|
111
|
+
Register assistant classes and (optionally) a custom resolver. OpenAI is supported via `llm: 'openai'`.
|
|
112
|
+
```js
|
|
550
113
|
await nexus.initialize({
|
|
551
114
|
provider: 'twilio',
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
onMessage: async (messageData, nexus) => {
|
|
557
|
-
await nexus.sendMessage({
|
|
558
|
-
to: messageData.from,
|
|
559
|
-
message: `Echo: ${messageData.message}`
|
|
560
|
-
});
|
|
115
|
+
llm: 'openai', llmConfig: { apiKey: process.env.OPENAI_API_KEY },
|
|
116
|
+
assistants: {
|
|
117
|
+
registry: { SUPPORT: SupportAssistantClass, SALES: SalesAssistantClass },
|
|
118
|
+
getAssistantById: (id, thread) => null // optional override
|
|
561
119
|
}
|
|
562
120
|
});
|
|
563
121
|
```
|
|
564
122
|
|
|
565
|
-
|
|
566
|
-
```javascript
|
|
567
|
-
nexus.setHandlers({
|
|
568
|
-
onCommand: async (messageData, nexus) => {
|
|
569
|
-
const { command, args } = messageData.command;
|
|
570
|
-
|
|
571
|
-
switch (command) {
|
|
572
|
-
case 'help':
|
|
573
|
-
await nexus.sendMessage({
|
|
574
|
-
to: messageData.from,
|
|
575
|
-
message: 'Available commands: /help, /status, /info'
|
|
576
|
-
});
|
|
577
|
-
break;
|
|
578
|
-
|
|
579
|
-
case 'status':
|
|
580
|
-
await nexus.sendMessage({
|
|
581
|
-
to: messageData.from,
|
|
582
|
-
message: `System status: ${nexus.isConnected() ? 'Online' : 'Offline'}`
|
|
583
|
-
});
|
|
584
|
-
break;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
});
|
|
588
|
-
```
|
|
123
|
+
## Routes (Importable)
|
|
589
124
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
onInteractive: async (messageData, nexus) => {
|
|
594
|
-
const { type, payload } = messageData.interactive;
|
|
595
|
-
|
|
596
|
-
if (type === 'button' && payload === 'get_support') {
|
|
597
|
-
await nexus.sendMessage({
|
|
598
|
-
to: messageData.from,
|
|
599
|
-
message: 'Connecting you to support...'
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
// Create assistant thread for support
|
|
603
|
-
await nexus.createAssistantThread(messageData.from, 'SUPPORT_ASSISTANT');
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
});
|
|
607
|
-
```
|
|
125
|
+
Use `setupDefaultRoutes(app)` to mount everything, or pick from `routes` + `createRouter()` to mount subsets.
|
|
126
|
+
|
|
127
|
+
## Examples
|
|
608
128
|
|
|
609
|
-
|
|
129
|
+
See:
|
|
130
|
+
- examples/basic-usage.js
|
|
131
|
+
- examples/assistants/
|
|
610
132
|
|
|
611
|
-
MIT
|