fluxy-bot 0.16.2 → 0.16.3
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/package.json
CHANGED
|
@@ -371,18 +371,38 @@ export class ChannelManager {
|
|
|
371
371
|
// Show "typing..." while the agent processes
|
|
372
372
|
this.startTyping(msg.channel, msg.rawSender);
|
|
373
373
|
|
|
374
|
+
// Track text chunks for WhatsApp — send intermediate chunks when agent pauses for tool use
|
|
375
|
+
let waChunkBuf = '';
|
|
376
|
+
|
|
374
377
|
startFluxyAgentQuery(
|
|
375
378
|
convId,
|
|
376
379
|
channelContext + msg.text,
|
|
377
380
|
model,
|
|
378
381
|
(type, eventData) => {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
382
|
+
// Accumulate text tokens
|
|
383
|
+
if (type === 'bot:token' && eventData.token) {
|
|
384
|
+
waChunkBuf += eventData.token;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Agent paused to use a tool — send accumulated text as an intermediate WhatsApp message
|
|
388
|
+
if (type === 'bot:tool' && waChunkBuf.trim()) {
|
|
389
|
+
this.sendMessage(msg.channel, msg.rawSender, waChunkBuf.trim()).catch((err) => {
|
|
390
|
+
log.warn(`[channels] Failed to send WhatsApp chunk: ${err.message}`);
|
|
383
391
|
});
|
|
392
|
+
waChunkBuf = '';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (type === 'bot:response' && eventData.content) {
|
|
396
|
+
// Send remaining text after the last tool use (or the full response if no tools were used)
|
|
397
|
+
const remaining = waChunkBuf.trim();
|
|
398
|
+
if (remaining) {
|
|
399
|
+
this.sendMessage(msg.channel, msg.rawSender, remaining).catch((err) => {
|
|
400
|
+
log.warn(`[channels] Failed to send WhatsApp reply: ${err.message}`);
|
|
401
|
+
});
|
|
402
|
+
waChunkBuf = '';
|
|
403
|
+
}
|
|
384
404
|
|
|
385
|
-
// Save to DB
|
|
405
|
+
// Save full response to DB
|
|
386
406
|
workerApi(`/api/conversations/${convId}/messages`, 'POST', {
|
|
387
407
|
role: 'assistant',
|
|
388
408
|
content: eventData.content,
|
|
@@ -479,21 +499,42 @@ export class ChannelManager {
|
|
|
479
499
|
enrichedScript += `\n\n---\n# Customer History (${msg.sender})\n\n${customerMemory}`;
|
|
480
500
|
}
|
|
481
501
|
|
|
502
|
+
// Track text chunks for WhatsApp — send intermediate chunks when agent pauses for tool use
|
|
503
|
+
let waChunkBuf = '';
|
|
504
|
+
|
|
482
505
|
startFluxyAgentQuery(
|
|
483
506
|
convId,
|
|
484
507
|
channelContext + msg.text,
|
|
485
508
|
model,
|
|
486
509
|
(type, eventData) => {
|
|
510
|
+
// Accumulate text tokens
|
|
511
|
+
if (type === 'bot:token' && eventData.token) {
|
|
512
|
+
waChunkBuf += eventData.token;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Agent paused to use a tool — send accumulated text as an intermediate WhatsApp message
|
|
516
|
+
if (type === 'bot:tool' && waChunkBuf.trim()) {
|
|
517
|
+
this.sendMessage(msg.channel, msg.rawSender, waChunkBuf.trim()).catch((err) => {
|
|
518
|
+
log.warn(`[channels] Failed to send WhatsApp chunk: ${err.message}`);
|
|
519
|
+
});
|
|
520
|
+
waChunkBuf = '';
|
|
521
|
+
}
|
|
522
|
+
|
|
487
523
|
if (type === 'bot:response' && eventData.content) {
|
|
488
|
-
// Add
|
|
524
|
+
// Add full response to the conversation buffer
|
|
489
525
|
buffer!.push({ role: 'assistant', content: eventData.content });
|
|
490
526
|
if (buffer!.length > MAX_BUFFER_MESSAGES) {
|
|
491
527
|
buffer!.splice(0, buffer!.length - MAX_BUFFER_MESSAGES);
|
|
492
528
|
}
|
|
493
529
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
530
|
+
// Send remaining text after the last tool use (or full response if no tools were used)
|
|
531
|
+
const remaining = waChunkBuf.trim();
|
|
532
|
+
if (remaining) {
|
|
533
|
+
this.sendMessage(msg.channel, msg.rawSender, remaining).catch((err) => {
|
|
534
|
+
log.warn(`[channels] Failed to send customer reply: ${err.message}`);
|
|
535
|
+
});
|
|
536
|
+
waChunkBuf = '';
|
|
537
|
+
}
|
|
497
538
|
}
|
|
498
539
|
|
|
499
540
|
if (type === 'bot:done') {
|
package/supervisor/index.ts
CHANGED
|
@@ -1048,6 +1048,11 @@ ${!connected ? '<script>setTimeout(()=>location.reload(),4000)</script>' : ''}
|
|
|
1048
1048
|
}
|
|
1049
1049
|
} catch {}
|
|
1050
1050
|
|
|
1051
|
+
// Mirror chat responses to WhatsApp self-chat (if connected)
|
|
1052
|
+
const waStatus = channelManager.getStatus('whatsapp');
|
|
1053
|
+
const waMirrorJid = waStatus?.connected ? waStatus.info?.phoneNumber : null;
|
|
1054
|
+
let waChunkBuf = '';
|
|
1055
|
+
|
|
1051
1056
|
// Start agent query
|
|
1052
1057
|
agentQueryActive = true;
|
|
1053
1058
|
currentStreamConvId = convId;
|
|
@@ -1056,6 +1061,13 @@ ${!connected ? '<script>setTimeout(()=>location.reload(),4000)</script>' : ''}
|
|
|
1056
1061
|
// Track stream buffer for reconnecting clients
|
|
1057
1062
|
if (type === 'bot:token' && eventData.token) {
|
|
1058
1063
|
currentStreamBuffer += eventData.token;
|
|
1064
|
+
if (waMirrorJid) waChunkBuf += eventData.token;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// WhatsApp mirror: send intermediate chunk when agent pauses for tool use
|
|
1068
|
+
if (type === 'bot:tool' && waMirrorJid && waChunkBuf.trim()) {
|
|
1069
|
+
channelManager.sendMessage('whatsapp', `${waMirrorJid}@s.whatsapp.net`, waChunkBuf.trim()).catch(() => {});
|
|
1070
|
+
waChunkBuf = '';
|
|
1059
1071
|
}
|
|
1060
1072
|
|
|
1061
1073
|
// Intercept bot:done — Vite HMR handles file changes automatically
|
|
@@ -1082,6 +1094,13 @@ ${!connected ? '<script>setTimeout(()=>location.reload(),4000)</script>' : ''}
|
|
|
1082
1094
|
// Save assistant response to DB + clear stream state
|
|
1083
1095
|
if (type === 'bot:response') {
|
|
1084
1096
|
currentStreamBuffer = '';
|
|
1097
|
+
|
|
1098
|
+
// WhatsApp mirror: send remaining chunk
|
|
1099
|
+
if (waMirrorJid && waChunkBuf.trim()) {
|
|
1100
|
+
channelManager.sendMessage('whatsapp', `${waMirrorJid}@s.whatsapp.net`, waChunkBuf.trim()).catch(() => {});
|
|
1101
|
+
waChunkBuf = '';
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1085
1104
|
(async () => {
|
|
1086
1105
|
try {
|
|
1087
1106
|
await workerApi(`/api/conversations/${convId}/messages`, 'POST', {
|
|
@@ -231,6 +231,62 @@ Your installed skills and their SKILL.md contents are injected below in your con
|
|
|
231
231
|
- `skills/{name}/SCRIPT.md` — business logic for customer interactions. Belongs to the skill.
|
|
232
232
|
- `whatsapp/{phone}.md` — customer conversation logs. Your memory of each customer.
|
|
233
233
|
|
|
234
|
+
## Marketplace — Getting New Skills
|
|
235
|
+
|
|
236
|
+
The Fluxy Marketplace at `https://fluxy.bot/marketplace` is where you get new skills. You can browse the full catalog at:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
https://fluxy.bot/api/marketplace.md
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Read that file for the current list of available skills, prices, and download instructions.
|
|
243
|
+
|
|
244
|
+
### Free skills — direct download
|
|
245
|
+
|
|
246
|
+
Free skills can be downloaded without any code or payment:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
curl -sL https://fluxy.bot/api/marketplace/download/free/<skill-id> -o /tmp/<skill-id>.tar.gz
|
|
250
|
+
echo "<sha256> /tmp/<skill-id>.tar.gz" | shasum -a 256 -c
|
|
251
|
+
tar xzf /tmp/<skill-id>.tar.gz -C workspace/skills/
|
|
252
|
+
rm /tmp/<skill-id>.tar.gz
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The SHA-256 hash is listed in the marketplace catalog. **If verification fails, do NOT extract.** Delete the file and tell your human.
|
|
256
|
+
|
|
257
|
+
### Paid skills — redeem codes
|
|
258
|
+
|
|
259
|
+
Your human buys paid skills from the web marketplace and gives you a redeem code (format: `XXXX-XXXX-XXXX-XXXX`). To redeem:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
curl -s -X POST https://fluxy.bot/api/marketplace/redeem \
|
|
263
|
+
-H "Content-Type: application/json" \
|
|
264
|
+
-d '{"code": "THE-CODE-HERE"}'
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
The response contains a list of skills with temporary download URLs and SHA-256 hashes:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"skills": [
|
|
272
|
+
{ "name": "skill-id", "version": "1.0.0", "url": "https://...", "sha256": "..." }
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
For each skill: download, verify SHA-256, extract to `workspace/skills/`, clean up. Download links expire after 1 hour — redeem the code again if you need fresh links.
|
|
278
|
+
|
|
279
|
+
### After installing a skill
|
|
280
|
+
|
|
281
|
+
1. Read the skill's `SKILL.md` for setup instructions
|
|
282
|
+
2. Follow the setup steps (ask your human for API keys, configure channels, etc.)
|
|
283
|
+
3. Check `skill.json` → `depends` — make sure all dependencies are installed
|
|
284
|
+
4. If the skill has a `SCRIPT.md`, it's a customer-facing skill — configure the channel to use it
|
|
285
|
+
|
|
286
|
+
### Product catalog (JSON)
|
|
287
|
+
|
|
288
|
+
For a machine-readable catalog: `GET https://fluxy.bot/api/marketplace/products`
|
|
289
|
+
|
|
234
290
|
---
|
|
235
291
|
|
|
236
292
|
## Channels (WhatsApp, Telegram, etc.)
|