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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.16.2",
3
+ "version": "0.16.3",
4
4
  "releaseNotes": [
5
5
  "1. react router implemented",
6
6
  "2. new workspace design",
@@ -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
- if (type === 'bot:response' && eventData.content) {
380
- // Send agent's response back via WhatsApp
381
- this.sendMessage(msg.channel, msg.rawSender, eventData.content).catch((err) => {
382
- log.warn(`[channels] Failed to send WhatsApp reply: ${err.message}`);
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 assistant response to the buffer
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
- this.sendMessage(msg.channel, msg.rawSender, eventData.content).catch((err) => {
495
- log.warn(`[channels] Failed to send customer reply: ${err.message}`);
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') {
@@ -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.)