nothumanallowed 13.5.190 → 13.5.192

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": "nothumanallowed",
3
- "version": "13.5.190",
3
+ "version": "13.5.192",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/constants.mjs CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
 
8
- export const VERSION = '13.5.190';
8
+ export const VERSION = '13.5.192';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -136,7 +136,7 @@ function routeMessage(text, useAutoRoute = true) {
136
136
 
137
137
  // ── Language detection from message text ─────────────────────────────────────
138
138
 
139
- const IT_WORDS = new Set(['il','lo','la','le','gli','un','una','che','di','da','in','con','su','per','tra','fra','non','ma','se','come','dove','quando','chi','cosa','ho','hai','ha','sono','sei','siamo','avere','essere','fare','dire','andare','mi','ti','ci','si','vi','li','le','gli','mio','tuo','suo','nostro','vostro','loro','questo','quello','questi','quelli','anche','già','ancora','sempre','mai','oggi','domani','ieri','adesso','ora','poi','dopo','prima','qui','qua','lì','là','più','meno','molto','poco','bene','male','sì','no','grazie','prego','ciao','buongiorno','buonasera','appuntamenti','calendario','riunione','meteo','temperatura','email','posta','notizie']);
139
+ const IT_WORDS = new Set(['il','lo','la','le','gli','un','una','che','di','da','in','con','su','per','tra','fra','non','ma','se','come','dove','quando','chi','cosa','ho','hai','ha','sono','sei','siamo','avere','essere','fare','dire','andare','mi','ti','ci','si','vi','li','le','gli','mio','tuo','suo','nostro','vostro','loro','questo','quello','questi','quelli','anche','già','ancora','sempre','mai','oggi','domani','ieri','adesso','ora','poi','dopo','prima','qui','qua','lì','là','più','meno','molto','poco','bene','male','sì','no','grazie','prego','ciao','buongiorno','buonasera','appuntamenti','appuntamento','calendario','riunione','meteo','temperatura','email','posta','notizie','del','dello','della','degli','delle','nel','nello','nella','negli','nelle','dal','dallo','dalla','dagli','dalle','sul','sullo','sulla','sugli','sulle','col','coi','quello','quella','quelli','quelle','cancella','cancellare','elimina','eliminare','crea','creare','sposta','spostare','aggiungi','aggiungere','modifica','modificare','ricerca','trovami','trovare','mostra','mostrami','dimmi','rispondimi','aiutami','puoi','voglio','vorrei','devo','posso','giorno','giorni','mese','mesi','anno','anni','settimana','settimane','ore','minuto','minuti','mattina','pomeriggio','sera','notte','veterinario','medico','dentista','dottore','riunioni','scadenza','scadenze']);
140
140
  const ES_WORDS = new Set(['el','la','los','las','un','una','que','de','en','con','por','para','pero','como','donde','cuando','quien','qué','tengo','tienes','tiene','somos','soy','eres','hacer','decir','ir','me','te','se','nos','este','ese','estos','esos','también','ya','todavía','siempre','nunca','hoy','mañana','ayer','aquí','allí','más','menos','muy','bien','mal','sí','no','gracias','hola','buenos']);
141
141
  const FR_WORDS = new Set(['le','la','les','un','une','des','que','de','en','avec','pour','par','mais','comme','où','quand','qui','je','tu','il','elle','nous','vous','ils','elles','avoir','être','faire','dire','aller','me','te','se','ce','cet','cette','ces','aussi','déjà','toujours','jamais','aujourd','demain','hier','ici','là','plus','moins','très','bien','mal','oui','non','merci','bonjour','bonsoir']);
142
142
  const DE_WORDS = new Set(['der','die','das','ein','eine','und','oder','aber','nicht','mit','für','von','zu','an','auf','ist','sind','hat','haben','sein','werden','ich','du','er','sie','es','wir','ihr','mich','dich','sich','uns','euch','diesem','diesen','dieser','dieses','auch','schon','noch','immer','nie','heute','morgen','gestern','hier','dort','mehr','weniger','sehr','gut','schlecht','ja','nein','danke','hallo']);
@@ -313,6 +313,9 @@ class TelegramResponder {
313
313
  this.maxConcurrent = 3;
314
314
  this._updateCheckTimer = null;
315
315
  this._lastNotifiedVersion = null;
316
+ // Per-chat sticky agent: remembers last agent used, plus last turn context
317
+ this._lastAgentByChatId = {}; // chatId → agentName
318
+ this._lastContextByChatId = {}; // chatId → { agent, userMsg, agentReply, ts }
316
319
  }
317
320
 
318
321
  get enabled() {
@@ -359,11 +362,10 @@ class TelegramResponder {
359
362
  if (chatIds.length === 0) return;
360
363
 
361
364
  const msg =
362
- `🆕 *NHA v${latest} disponibile!*\n\n` +
365
+ `🆕 NHA v${latest} disponibile!\n\n` +
363
366
  `Una nuova versione di NotHumanAllowed è stata pubblicata.\n\n` +
364
- `Aggiorna con:\n` +
365
- `\`npm install -g nothumanallowed@latest\`\n\n` +
366
- `Poi riavvia il bot con: \`nha responder restart\``;
367
+ `Aggiorna con:\nnpm install -g nothumanallowed@latest\n\n` +
368
+ `Poi riavvia il bot con: nha ops stop && nha ops start`;
367
369
 
368
370
  this.log(`[Telegram] Broadcasting update notification v${latest} to ${chatIds.length} users`);
369
371
 
@@ -372,7 +374,6 @@ class TelegramResponder {
372
374
  await this._telegramCall('sendMessage', {
373
375
  chat_id: parseInt(chatId, 10),
374
376
  text: msg,
375
- parse_mode: 'Markdown',
376
377
  });
377
378
  } catch {
378
379
  // User blocked bot or chat no longer exists — ignore
@@ -566,15 +567,37 @@ class TelegramResponder {
566
567
  if (isVoice) {
567
568
  await this._telegramCall('sendMessage', {
568
569
  chat_id: chatId,
569
- text: `🎤 _"${cleanText}"_`,
570
- parse_mode: 'Markdown',
570
+ text: `🎤 "${cleanText}"`,
571
571
  }).catch(() => {});
572
572
  }
573
573
 
574
574
  this.pendingRequests++;
575
575
  try {
576
- const agent = routeMessage(cleanText, this.autoRoute);
577
- this.log(`[Telegram] ${fromUser} (chat ${chatId}): routed to ${agent.toUpperCase()}${isVoice ? ' [voice]' : ''}`);
576
+ // Sticky agent: for short/ambiguous messages (< 6 words), reuse last agent for this chat
577
+ // This handles confirmation messages like "Sì", "Ok", "Fallo", "Confermo", etc.
578
+ const wordCount = cleanText.trim().split(/\s+/).length;
579
+ const isAmbiguous = wordCount <= 5;
580
+ const lastCtx = this._lastContextByChatId[chatId];
581
+ const stickyAge = lastCtx ? (Date.now() - lastCtx.ts) : Infinity;
582
+ const useStickyAgent = isAmbiguous && lastCtx && stickyAge < 5 * 60 * 1000; // sticky for 5 min
583
+
584
+ let agent;
585
+ let enrichedMessage = cleanText;
586
+ if (useStickyAgent) {
587
+ agent = lastCtx.agent;
588
+ // Inject previous turn context so agent understands what "Sì" refers to
589
+ const nl = '\n';
590
+ enrichedMessage =
591
+ '[Conversazione precedente]' + nl +
592
+ 'Utente: ' + lastCtx.userMsg + nl +
593
+ 'Tu (' + agent.toUpperCase() + '): ' + lastCtx.agentReply.slice(0, 400) + nl + nl +
594
+ '[Nuovo messaggio utente]' + nl +
595
+ cleanText;
596
+ this.log(`[Telegram] ${fromUser}: sticky agent ${agent.toUpperCase()} (ambiguous message, last ctx ${Math.round(stickyAge/1000)}s ago)`);
597
+ } else {
598
+ agent = routeMessage(cleanText, this.autoRoute);
599
+ this.log(`[Telegram] ${fromUser} (chat ${chatId}): routed to ${agent.toUpperCase()}${isVoice ? ' [voice]' : ''}`);
600
+ }
578
601
 
579
602
  // Broadcast event
580
603
  this.wsBroadcast({
@@ -587,18 +610,19 @@ class TelegramResponder {
587
610
  await this._telegramCall('sendChatAction', { chat_id: chatId, action: 'typing' });
588
611
 
589
612
  // Detect language from the message text — overrides system locale
590
- const detectedLang = detectLanguage(cleanText);
613
+ // For sticky context, use lang from previous turn if current message is ambiguous
614
+ const detectedLang = detectLanguage(cleanText) || (lastCtx ? detectLanguage(lastCtx.userMsg) : null);
591
615
 
592
616
  // Tool-capable agents use the full tool execution loop
593
617
  // Pure reasoning/analysis agents use the simple callAgent (no tools)
594
618
  const TOOL_AGENTS = new Set(['herald', 'hermes', 'edi', 'jarvis', 'flux', 'echo', 'mercury', 'pipe', 'navi', 'link', 'prometheus', 'tempest']);
595
619
  let response;
596
620
  if (TOOL_AGENTS.has(agent)) {
597
- response = await callAgentWithTools(this.config, agent, cleanText, detectedLang);
621
+ response = await callAgentWithTools(this.config, agent, enrichedMessage, detectedLang);
598
622
  } else {
599
623
  // For non-tool agents: inject language instruction into the message
600
624
  const langInstruction = detectedLang ? `[Respond in ${detectedLang}] ` : '';
601
- response = await callAgent(this.config, agent, langInstruction + cleanText);
625
+ response = await callAgent(this.config, agent, langInstruction + enrichedMessage);
602
626
  }
603
627
 
604
628
  // Truncate if too long for Telegram (4096 char limit)
@@ -606,11 +630,19 @@ class TelegramResponder {
606
630
  ? response.slice(0, 3950) + '\n\n... [truncated]'
607
631
  : response;
608
632
 
609
- // Send response as text (voice reply TTS requires separate TTS service)
633
+ // Save context for sticky agent continuity (next short message reuses this agent)
634
+ this._lastContextByChatId[chatId] = {
635
+ agent,
636
+ userMsg: cleanText,
637
+ agentReply: response,
638
+ ts: Date.now(),
639
+ };
640
+ this._lastAgentByChatId[chatId] = agent;
641
+
642
+ // Send response as plain text — no parse_mode to avoid Markdown entity parse errors
610
643
  await this._telegramCall('sendMessage', {
611
644
  chat_id: chatId,
612
645
  text: `[${agent.toUpperCase()}]\n\n${truncated}`,
613
- parse_mode: 'Markdown',
614
646
  });
615
647
 
616
648
  this.log(`[Telegram] Responded to ${fromUser} via ${agent.toUpperCase()} (${response.length} chars)`);