nothumanallowed 15.1.35 → 15.1.36
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": "15.1.
|
|
3
|
+
"version": "15.1.36",
|
|
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 = '15.1.
|
|
8
|
+
export const VERSION = '15.1.36';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -530,6 +530,38 @@ class TelegramResponder {
|
|
|
530
530
|
saveTelegramContext(this._lastContextByChatId);
|
|
531
531
|
}
|
|
532
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Route a fresh message to the best agent.
|
|
535
|
+
*
|
|
536
|
+
* Tier 1 — keyword table (fast, no LLM cost). Falls through to CONDUCTOR
|
|
537
|
+
* when nothing matches.
|
|
538
|
+
*
|
|
539
|
+
* Tier 2 — if Tier 1 returned the fallback CONDUCTOR AND the user has an
|
|
540
|
+
* LLM key configured, ask the LLM to pick the right agent given the
|
|
541
|
+
* conversation history. This rescues paraphrased queries like
|
|
542
|
+
* "mostrami quanto vale ora il metallo prezioso giallo" (no keyword match)
|
|
543
|
+
* which v13 used to route correctly because of a similar LLM router.
|
|
544
|
+
*/
|
|
545
|
+
async _routeFreshMessage(text, lastCtx) {
|
|
546
|
+
const keywordAgent = routeMessage(text, this.autoRoute);
|
|
547
|
+
if (keywordAgent !== 'conductor') return keywordAgent;
|
|
548
|
+
// Tier 2 fallback
|
|
549
|
+
const hasKey = !!(this.config.llm?.apiKey || this.config.llm?.openaiKey || this.config.llm?.geminiKey || this.config.llm?.deepseekKey || (this.config.llm?.provider === 'nha'));
|
|
550
|
+
if (!hasKey) return keywordAgent;
|
|
551
|
+
try {
|
|
552
|
+
const AGENTS = ['herald', 'mercury', 'athena', 'oracle', 'forge', 'scheherazade', 'saber', 'sauron', 'conductor'];
|
|
553
|
+
const tail = (lastCtx?.conversationLog || []).slice(-6)
|
|
554
|
+
.map(t => `${t.role === 'user' ? 'User' : 'Bot'}: ${String(t.content).slice(0, 200)}`)
|
|
555
|
+
.join('\n');
|
|
556
|
+
const sys = 'You are a routing classifier. Reply with EXACTLY one lowercase agent name from this list and nothing else: ' + AGENTS.join(', ') + '. herald=calendar/email/weather/news, mercury=finance/markets/crypto, athena=audit/compliance, oracle=data/analytics, forge=code/architecture, scheherazade=writing/content, saber=security, sauron=monitoring, conductor=anything else.';
|
|
557
|
+
const usr = `Recent conversation (most recent last):\n${tail || '(none)'}\n\nUser message: "${text}"\n\nWhich agent? Reply with ONLY the lowercase agent name.`;
|
|
558
|
+
const ans = await callLLM(this.config, sys, usr, { max_tokens: 16 });
|
|
559
|
+
const picked = String(ans || '').trim().toLowerCase().split(/\s+/)[0];
|
|
560
|
+
if (AGENTS.includes(picked)) return picked;
|
|
561
|
+
} catch { /* LLM unavailable, keep keyword fallback */ }
|
|
562
|
+
return keywordAgent;
|
|
563
|
+
}
|
|
564
|
+
|
|
533
565
|
get enabled() {
|
|
534
566
|
return !!this.token;
|
|
535
567
|
}
|
|
@@ -802,10 +834,25 @@ class TelegramResponder {
|
|
|
802
834
|
let enrichedMessage = cleanText;
|
|
803
835
|
let preHistory = null;
|
|
804
836
|
|
|
837
|
+
// ── Always inject multi-turn rolling history (15.1.36) ─────────────
|
|
838
|
+
// Even when the new message isn't a "continuation" of the very last
|
|
839
|
+
// turn, the user may still be referring to something earlier in the
|
|
840
|
+
// conversation ("come ti avevo detto ieri", "ricorda che..."). Pass
|
|
841
|
+
// the full conversation log to the agent as preHistory.
|
|
842
|
+
const rollingLog = (lastCtx && Array.isArray(lastCtx.conversationLog) && lastCtx.conversationLog.length > 0)
|
|
843
|
+
? lastCtx.conversationLog
|
|
844
|
+
.filter(t => t && (t.role === 'user' || t.role === 'assistant') && typeof t.content === 'string')
|
|
845
|
+
.map(t => ({ role: t.role, content: t.content }))
|
|
846
|
+
: null;
|
|
847
|
+
|
|
805
848
|
if (isContinuation && !lastWasCompleted) {
|
|
806
849
|
// Continue with same agent and inject full history for context
|
|
807
850
|
agent = lastCtx.agent;
|
|
808
|
-
if
|
|
851
|
+
// Prefer the rolling multi-turn log if available; fall back to the
|
|
852
|
+
// legacy single-turn `history` for older saved contexts.
|
|
853
|
+
if (rollingLog && rollingLog.length > 0) {
|
|
854
|
+
preHistory = rollingLog;
|
|
855
|
+
} else if (lastCtx.history && lastCtx.history.length > 0) {
|
|
809
856
|
preHistory = lastCtx.history;
|
|
810
857
|
}
|
|
811
858
|
|
|
@@ -870,9 +917,13 @@ class TelegramResponder {
|
|
|
870
917
|
|
|
871
918
|
this.log(`[Telegram] ${fromUser}: continuation → ${agent.toUpperCase()} (ctx ${Math.round(stickyAge/1000)}s ago, history=${preHistory ? preHistory.length : 0})`);
|
|
872
919
|
} else {
|
|
873
|
-
// Fresh request — route normally
|
|
874
|
-
|
|
875
|
-
|
|
920
|
+
// Fresh request — route normally, but STILL pass the rolling log so
|
|
921
|
+
// the model has the conversation context even when the new message
|
|
922
|
+
// is on a fresh topic (e.g. user starts a new task but the previous
|
|
923
|
+
// session is still relevant for memory: names, preferences, etc.).
|
|
924
|
+
agent = await this._routeFreshMessage(cleanText, lastCtx);
|
|
925
|
+
if (rollingLog && rollingLog.length > 0) preHistory = rollingLog;
|
|
926
|
+
this.log(`[Telegram] ${fromUser}: new request → ${agent.toUpperCase()}${isVoice ? ' [voice]' : ''}${lastWasCompleted ? ' [prev completed]' : ''} (rolling history=${preHistory ? preHistory.length : 0})`);
|
|
876
927
|
}
|
|
877
928
|
|
|
878
929
|
// Broadcast event
|
|
@@ -906,12 +957,25 @@ class TelegramResponder {
|
|
|
906
957
|
? responseText.slice(0, 3950) + '\n\n... [truncated]'
|
|
907
958
|
: responseText;
|
|
908
959
|
|
|
909
|
-
//
|
|
960
|
+
// ── Multi-turn rolling memory (15.1.36) ────────────────────────────
|
|
961
|
+
// v13 worked well partially because every chat retained a real
|
|
962
|
+
// conversation history. The v14 refactor reduced this to 1 turn —
|
|
963
|
+
// hence "Telegram doesn't understand me anymore". We now keep the
|
|
964
|
+
// last MAX_CONVERSATION_TURNS turns per chat, persisted to disk.
|
|
965
|
+
const MAX_CONVERSATION_TURNS = 20; // user+assistant pairs
|
|
966
|
+
const prevLog = (lastCtx && Array.isArray(lastCtx.conversationLog)) ? lastCtx.conversationLog : [];
|
|
967
|
+
const conversationLog = [
|
|
968
|
+
...prevLog,
|
|
969
|
+
{ role: 'user', content: cleanText, ts: Date.now() },
|
|
970
|
+
{ role: 'assistant', content: responseText, ts: Date.now() },
|
|
971
|
+
].slice(-MAX_CONVERSATION_TURNS * 2);
|
|
972
|
+
|
|
910
973
|
this._lastContextByChatId[chatId] = {
|
|
911
974
|
agent,
|
|
912
975
|
userMsg: cleanText,
|
|
913
976
|
agentReply: responseText,
|
|
914
|
-
history: isCompletedAction(responseText) ? null : responseHistory, //
|
|
977
|
+
history: isCompletedAction(responseText) ? null : responseHistory, // single-turn (legacy)
|
|
978
|
+
conversationLog, // multi-turn (new)
|
|
915
979
|
ts: Date.now(),
|
|
916
980
|
};
|
|
917
981
|
this._lastAgentByChatId[chatId] = agent;
|