nothumanallowed 13.2.40 → 13.2.42
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 +1 -1
- package/src/commands/ui.mjs +42 -31
- package/src/constants.mjs +1 -1
- package/src/services/llm.mjs +33 -14
- package/src/services/web-ui.mjs +9 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.42",
|
|
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/commands/ui.mjs
CHANGED
|
@@ -2546,25 +2546,30 @@ export async function cmdUI(args) {
|
|
|
2546
2546
|
const plannerLang = (() => { const LANG_MAP2 = {en:'English',it:'Italian',es:'Spanish',fr:'French',de:'German',pt:'Portuguese',zh:'Chinese',ja:'Japanese',ar:'Arabic',hi:'Hindi',ru:'Russian',nl:'Dutch',pl:'Polish',tr:'Turkish',ko:'Korean'}; const lc = (config?.language||'it').slice(0,2); return LANG_MAP2[lc]||'Italian'; })();
|
|
2547
2547
|
|
|
2548
2548
|
// ── Fast keyword-based planning (no LLM call needed for common patterns) ──────
|
|
2549
|
-
// Detect task intent from keywords — avoids sending the full task through SENTINEL
|
|
2550
2549
|
const taskLow = task.toLowerCase();
|
|
2551
|
-
const hasEmail
|
|
2552
|
-
const hasCalendar
|
|
2553
|
-
const hasSearch
|
|
2554
|
-
const hasCanvas
|
|
2555
|
-
const hasGitHub
|
|
2556
|
-
const hasSlack
|
|
2557
|
-
const hasNotion
|
|
2558
|
-
const hasBriefing
|
|
2559
|
-
const hasFinance
|
|
2560
|
-
const hasSecurity
|
|
2550
|
+
const hasEmail = /email|mail|inbox|posta/i.test(taskLow);
|
|
2551
|
+
const hasCalendar = /calendar|agenda|calendari|eventi|schedule/i.test(taskLow);
|
|
2552
|
+
const hasSearch = /cerca|search|notizie|news|ultime|latest|web|internet|tendenz|trend/i.test(taskLow);
|
|
2553
|
+
const hasCanvas = /html|dashboard|visua|report|grafico|chart/i.test(taskLow);
|
|
2554
|
+
const hasGitHub = /github|git|issue|pr|pull request/i.test(taskLow);
|
|
2555
|
+
const hasSlack = /slack|channel|messag/i.test(taskLow);
|
|
2556
|
+
const hasNotion = /notion|note|page/i.test(taskLow);
|
|
2557
|
+
const hasBriefing = /briefing|analisi|analizza|summary|sommario|riassunto|riepiloga|valutazione|valuta/i.test(taskLow);
|
|
2558
|
+
const hasFinance = /finance|mercato|market|stock|trading|finanz|investiment|cripto/i.test(taskLow);
|
|
2559
|
+
const hasSecurity = /security|sicurezza|vulnerabilit|audit|pentest|rischi|dipendenz/i.test(taskLow);
|
|
2560
|
+
const hasStrategy = /strateg|competitiv|posizionament|raccomandaz|competitive|positioning/i.test(taskLow);
|
|
2561
|
+
const hasReputation = /reputazion|reputation|online|brand|review|recension/i.test(taskLow);
|
|
2562
|
+
const hasCode = /codice|code|refactor|debug|bug|sviluppo|software|npm|package/i.test(taskLow);
|
|
2563
|
+
const hasWriting = /scrivi|write|articolo|article|blog|testo|text|documento|document/i.test(taskLow);
|
|
2564
|
+
const hasData = /dati|data|dataset|csv|json|analizza i dati|pattern|statistich/i.test(taskLow);
|
|
2565
|
+
const hasTranslate = /traduci|translate|traduzione|translation/i.test(taskLow);
|
|
2566
|
+
|
|
2567
|
+
const it = plannerLang === 'Italian';
|
|
2561
2568
|
|
|
2562
2569
|
// Extract a clean short search query from the task (to avoid SENTINEL flagging long task strings)
|
|
2563
2570
|
const extractSearchQuery = (t) => {
|
|
2564
|
-
|
|
2565
|
-
const m = t.match(/(?:cerca|search|find|ricerca|notizie su|news about|latest on|aggiornamenti su|ultime su)\s+(.{5,80}?)(?:\s+(?:e |and |per |for |poi |then )|[,\n]|$)/i);
|
|
2571
|
+
const m = t.match(/(?:cerca|search|find|ricerca|notizie su|news about|latest on|aggiornamenti su|ultime su|tendenz|trend)\s+(.{5,80}?)(?:\s+(?:e |and |per |for |poi |then )|[,\n]|$)/i);
|
|
2566
2572
|
if (m) return m[1].trim();
|
|
2567
|
-
// Strip leading instruction prefix (everything before the first colon)
|
|
2568
2573
|
const stripped = t.replace(/^[^:]+:\s*/,'').split(/[,\n]/)[0].slice(0,100).trim();
|
|
2569
2574
|
return stripped || t.slice(0,80).trim();
|
|
2570
2575
|
};
|
|
@@ -2573,29 +2578,35 @@ export async function cmdUI(args) {
|
|
|
2573
2578
|
// Build plan directly from keywords — reliable, fast, no SENTINEL risk
|
|
2574
2579
|
const buildKeywordPlan = () => {
|
|
2575
2580
|
const steps = [];
|
|
2576
|
-
if (hasEmail)
|
|
2577
|
-
if (hasCalendar) steps.push({icon:'\u{1F4C5}',agent:'CalendarAgent',label:
|
|
2578
|
-
if (hasGitHub)
|
|
2579
|
-
if (hasSlack)
|
|
2580
|
-
if (hasNotion)
|
|
2581
|
-
if (hasSearch || (!hasEmail && !hasCalendar && !hasGitHub && !hasSlack)) {
|
|
2582
|
-
steps.push({icon:'\u{1F50D}',agent:'WebSearchAgent',label:
|
|
2581
|
+
if (hasEmail) steps.push({icon:'\u{1F4E7}',agent:'EmailAgent', label:it?'Controlla email':'Check emails', prompt:'Read the latest unread emails and identify urgent items, deadlines, and required actions'});
|
|
2582
|
+
if (hasCalendar) steps.push({icon:'\u{1F4C5}',agent:'CalendarAgent', label:it?'Rivedi calendario':'Review calendar', prompt:'Check today\'s events and identify any scheduling conflicts or important meetings'});
|
|
2583
|
+
if (hasGitHub) steps.push({icon:'\u{1F4BB}',agent:'GitHubAgent', label:'GitHub', prompt:'Read open issues and pull requests, identify what needs attention'});
|
|
2584
|
+
if (hasSlack) steps.push({icon:'\u{1F4AC}',agent:'SlackAgent', label:'Slack', prompt:'Check recent Slack messages and identify important conversations'});
|
|
2585
|
+
if (hasNotion) steps.push({icon:'\u{1F4DD}',agent:'NotionAgent', label:'Notion', prompt:'Search Notion for relevant pages and notes'});
|
|
2586
|
+
if (hasSearch || hasReputation || (!hasEmail && !hasCalendar && !hasGitHub && !hasSlack)) {
|
|
2587
|
+
steps.push({icon:'\u{1F50D}',agent:'WebSearchAgent',label:it?'Ricerca web':'Web search',prompt:searchQuery});
|
|
2583
2588
|
}
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2589
|
+
// Specialist agents — can stack multiple
|
|
2590
|
+
if (hasSecurity) steps.push({icon:'\u{1F6E1}',agent:'cassandra', label:it?'CASSANDRA \u2014 Rischi sicurezza':'CASSANDRA \u2014 Security risks', prompt:'Analyze the collected data and identify security risks, vulnerabilities and concrete recommendations'});
|
|
2591
|
+
if (hasFinance) steps.push({icon:'\u{1F4B0}',agent:'mercury', label:it?'MERCURY \u2014 Analisi mercato':'MERCURY \u2014 Market analysis', prompt:'Analyze the financial data and market trends from the collected information'});
|
|
2592
|
+
if (hasStrategy) steps.push({icon:'\u{265F}', agent:'athena', label:it?'ATHENA \u2014 Strategia':'ATHENA \u2014 Strategy', prompt:'Based on the collected data, produce strategic analysis with competitive positioning and concrete recommendations'});
|
|
2593
|
+
if (hasReputation) steps.push({icon:'\u{1F52D}',agent:'oracle', label:it?'ORACLE \u2014 Reputazione':'ORACLE \u2014 Reputation', prompt:'Analyze the online reputation data, sentiment and brand positioning from the collected information'});
|
|
2594
|
+
if (hasCode) steps.push({icon:'\u{1F527}',agent:'forge', label:it?'FORGE \u2014 Analisi codice':'FORGE \u2014 Code analysis', prompt:'Analyze the code, dependencies and technical issues identified in the data'});
|
|
2595
|
+
if (hasWriting) steps.push({icon:'\u{1F58A}',agent:'quill', label:it?'QUILL \u2014 Redazione':'QUILL \u2014 Writing', prompt:'Write a polished, professional document based on all the collected information'});
|
|
2596
|
+
if (hasData) steps.push({icon:'\u{1F4CA}',agent:'DataAnalystAgent',label:it?'Analisi dati':'Data analysis', prompt:'Analyze the data and extract key patterns, trends and insights'});
|
|
2597
|
+
if (hasTranslate) steps.push({icon:'\u{1F310}',agent:'polyglot', label:it?'POLYGLOT \u2014 Traduzione':'POLYGLOT \u2014 Translation', prompt:'Translate the content as requested, maintaining meaning and style'});
|
|
2598
|
+
// If no specialist added but we have data, add HERALD for synthesis
|
|
2599
|
+
const hasSpecialist = hasSecurity || hasFinance || hasStrategy || hasReputation || hasCode || hasWriting || hasData || hasTranslate;
|
|
2600
|
+
if (!hasSpecialist && (hasBriefing || steps.length > 0)) {
|
|
2601
|
+
steps.push({icon:'\u{1F4F0}',agent:'HERALD',label:it?'HERALD \u2014 Briefing esecutivo':'HERALD \u2014 Executive briefing',prompt:'Based on ALL the data collected by the previous steps, write a complete executive briefing with priorities, findings, and strategic recommendations. Do NOT invent data — only use what was provided.'});
|
|
2590
2602
|
}
|
|
2591
|
-
if (hasCanvas) steps.push({icon:'\u{1F4CA}',agent:'CanvasAgent',label:
|
|
2603
|
+
if (hasCanvas) steps.push({icon:'\u{1F4CA}',agent:'CanvasAgent',label:it?'Dashboard HTML':'HTML Dashboard',prompt:'Create a professional HTML dashboard report with the briefing data'});
|
|
2592
2604
|
return steps;
|
|
2593
2605
|
};
|
|
2594
2606
|
|
|
2595
|
-
// Use keyword plan directly
|
|
2596
|
-
// Only fall back to LLM planning for genuinely ambiguous tasks
|
|
2607
|
+
// Use keyword plan directly — only fall back to LLM for genuinely ambiguous tasks
|
|
2597
2608
|
const keywordSteps = buildKeywordPlan();
|
|
2598
|
-
const taskIsComplex = !hasEmail && !hasCalendar && !hasSearch && !hasGitHub && !hasSlack && !hasBriefing && keywordSteps.length <= 1;
|
|
2609
|
+
const taskIsComplex = !hasEmail && !hasCalendar && !hasSearch && !hasGitHub && !hasSlack && !hasBriefing && !hasStrategy && !hasReputation && !hasCode && !hasWriting && !hasData && keywordSteps.length <= 1;
|
|
2599
2610
|
|
|
2600
2611
|
try {
|
|
2601
2612
|
let steps;
|
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.2.
|
|
8
|
+
export const VERSION = '13.2.42';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/services/llm.mjs
CHANGED
|
@@ -521,7 +521,7 @@ export async function callLLMStream(config, systemPrompt, userMessage, onToken,
|
|
|
521
521
|
{ role: 'system', content: sanitize(systemPrompt) },
|
|
522
522
|
{ role: 'user', content: sanitize(userMessage) },
|
|
523
523
|
],
|
|
524
|
-
stream:
|
|
524
|
+
stream: false,
|
|
525
525
|
chat_template_kwargs: { enable_thinking: thinkingEnabled },
|
|
526
526
|
};
|
|
527
527
|
const nhaRes = await fetch('https://nothumanallowed.com/api/v1/liara/chat', {
|
|
@@ -533,10 +533,13 @@ export async function callLLMStream(config, systemPrompt, userMessage, onToken,
|
|
|
533
533
|
const err = await nhaRes.text();
|
|
534
534
|
throw new Error(`NHA Free ${nhaRes.status}: ${err}`);
|
|
535
535
|
}
|
|
536
|
-
//
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
536
|
+
// Non-streaming: vLLM returns complete text — no BPE subword splitting issues
|
|
537
|
+
const nhaJson = await nhaRes.json();
|
|
538
|
+
let fullNhaText = nhaJson.choices?.[0]?.message?.content || '';
|
|
539
|
+
// Strip <think>...</think> blocks
|
|
540
|
+
fullNhaText = fullNhaText.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
541
|
+
if (onToken) onToken(fullNhaText);
|
|
542
|
+
return fullNhaText;
|
|
540
543
|
}
|
|
541
544
|
|
|
542
545
|
const format = provider === 'anthropic' ? 'anthropic' : 'openai';
|
|
@@ -647,6 +650,8 @@ function parseSSEText(text, format, onToken) {
|
|
|
647
650
|
let fullText = '';
|
|
648
651
|
let thinkBuf = '';
|
|
649
652
|
let inThink = false;
|
|
653
|
+
let isHtmlOutput = false;
|
|
654
|
+
let chunkCount = 0;
|
|
650
655
|
|
|
651
656
|
for (const line of text.split('\n')) {
|
|
652
657
|
if (!line.startsWith('data: ')) continue;
|
|
@@ -680,10 +685,18 @@ function parseSSEText(text, format, onToken) {
|
|
|
680
685
|
}
|
|
681
686
|
}
|
|
682
687
|
if (out) {
|
|
683
|
-
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
|
|
688
|
+
chunkCount++;
|
|
689
|
+
if (chunkCount <= 3) process.stderr.write(`[QWEN3 CHUNK ${chunkCount}] len=${out.length} repr=${JSON.stringify(out.slice(0,60))}\n`);
|
|
690
|
+
// Detect HTML output on first meaningful token
|
|
691
|
+
if (!isHtmlOutput && (out.includes('<div') || out.includes('<!DOCTYPE') || out.includes('<html'))) {
|
|
692
|
+
isHtmlOutput = true;
|
|
693
|
+
}
|
|
694
|
+
if (!isHtmlOutput) {
|
|
695
|
+
out = fixQwen3Markdown(out);
|
|
696
|
+
const insideTag = fullText.lastIndexOf('<') > fullText.lastIndexOf('>');
|
|
697
|
+
if (fullText && out && !insideTag && !/[\s\n]$/.test(fullText) && !/^[\s\n.,;:!?)\]}'">]/.test(out)) {
|
|
698
|
+
out = ' ' + out;
|
|
699
|
+
}
|
|
687
700
|
}
|
|
688
701
|
fullText += out;
|
|
689
702
|
if (onToken) onToken(out);
|
|
@@ -691,7 +704,7 @@ function parseSSEText(text, format, onToken) {
|
|
|
691
704
|
}
|
|
692
705
|
} catch {}
|
|
693
706
|
}
|
|
694
|
-
|
|
707
|
+
process.stderr.write(`[QWEN3 TOTAL CHUNKS] ${chunkCount}, fullText len=${fullText.length}\n`);
|
|
695
708
|
return fullText;
|
|
696
709
|
}
|
|
697
710
|
|
|
@@ -703,6 +716,7 @@ async function streamSSEWithCallback(res, format, onToken) {
|
|
|
703
716
|
let fullText = '';
|
|
704
717
|
let thinkBuf = ''; // accumulates <think>...</think> content to suppress
|
|
705
718
|
let inThink = false;
|
|
719
|
+
let isHtmlOutput = false;
|
|
706
720
|
|
|
707
721
|
while (true) {
|
|
708
722
|
const { done, value } = await reader.read();
|
|
@@ -748,10 +762,15 @@ async function streamSSEWithCallback(res, format, onToken) {
|
|
|
748
762
|
}
|
|
749
763
|
}
|
|
750
764
|
if (out) {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
765
|
+
if (!isHtmlOutput && (out.includes('<div') || out.includes('<!DOCTYPE') || out.includes('<html'))) {
|
|
766
|
+
isHtmlOutput = true;
|
|
767
|
+
}
|
|
768
|
+
if (!isHtmlOutput) {
|
|
769
|
+
out = fixQwen3Markdown(out);
|
|
770
|
+
const insideTag2 = fullText.lastIndexOf('<') > fullText.lastIndexOf('>');
|
|
771
|
+
if (fullText && out && !insideTag2 && !/[\s\n]$/.test(fullText) && !/^[\s\n.,;:!?)\]}'">]/.test(out)) {
|
|
772
|
+
out = ' ' + out;
|
|
773
|
+
}
|
|
755
774
|
}
|
|
756
775
|
fullText += out;
|
|
757
776
|
if (onToken) onToken(out);
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -2852,6 +2852,7 @@ var studioState = {
|
|
|
2852
2852
|
nodes: [], // [{icon,agent,label,status:'waiting'|'running'|'done'|'error'}]
|
|
2853
2853
|
log: [], // [{agent,icon,text,time,type:'agent'|'system'|'error'}]
|
|
2854
2854
|
result: '',
|
|
2855
|
+
canvas: null, // HTML canvas content if generated
|
|
2855
2856
|
running: false,
|
|
2856
2857
|
planned: false
|
|
2857
2858
|
};
|
|
@@ -2971,14 +2972,14 @@ function renderStudioResult() {
|
|
|
2971
2972
|
if (!el) return;
|
|
2972
2973
|
if (!studioState.result) { el.style.display = 'none'; return; }
|
|
2973
2974
|
el.style.display = 'block';
|
|
2974
|
-
var
|
|
2975
|
-
var body =
|
|
2975
|
+
var hasCanvas = !!(studioState.canvas);
|
|
2976
|
+
var body = hasCanvas
|
|
2976
2977
|
? '<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap"><span style="color:var(--dim);font-size:13px">✓ ' + t('canvas_generated') + '</span><button onclick="openCanvasPanel()" style="padding:6px 14px;background:var(--greendim);border:1px solid var(--green3);border-radius:8px;color:var(--green);font-size:12px;cursor:pointer;font-weight:700">▣ ' + t('canvas_open') + '</button></div>'
|
|
2977
2978
|
: '<div class="md-body">' + renderMd(studioState.result) + '</div>';
|
|
2978
2979
|
el.innerHTML = '<div class="studio-result__title">✓ ' + t('workflow_complete') + '</div>' + body;
|
|
2979
|
-
// Show
|
|
2980
|
+
// Show canvas button in toolbar whenever canvas data exists
|
|
2980
2981
|
var canvasBtn = document.getElementById('studioCanvasBtn');
|
|
2981
|
-
if (canvasBtn) canvasBtn.style.display =
|
|
2982
|
+
if (canvasBtn) canvasBtn.style.display = hasCanvas ? '' : 'none';
|
|
2982
2983
|
}
|
|
2983
2984
|
|
|
2984
2985
|
function studioSetNodeStatus(idx, status) {
|
|
@@ -2998,6 +2999,7 @@ async function runStudio() {
|
|
|
2998
2999
|
studioState.nodes = [];
|
|
2999
3000
|
studioState.log = [];
|
|
3000
3001
|
studioState.result = '';
|
|
3002
|
+
studioState.canvas = null;
|
|
3001
3003
|
studioState.running = true;
|
|
3002
3004
|
studioState.planned = false;
|
|
3003
3005
|
renderStudioNodes();
|
|
@@ -3233,6 +3235,7 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
|
|
|
3233
3235
|
}
|
|
3234
3236
|
if (ev.canvas) {
|
|
3235
3237
|
canvasHtml = ev.canvas;
|
|
3238
|
+
studioState.canvas = ev.canvas;
|
|
3236
3239
|
// Render canvas immediately when received — don't wait for step resolution
|
|
3237
3240
|
var cf2 = document.getElementById('canvasFrame');
|
|
3238
3241
|
var cp2 = document.getElementById('canvasPanel');
|
|
@@ -3240,10 +3243,10 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
|
|
|
3240
3243
|
cf2.srcdoc = canvasHtml;
|
|
3241
3244
|
cp2.classList.add('open');
|
|
3242
3245
|
var ct2 = document.getElementById('canvasTitle');
|
|
3243
|
-
if (ct2) ct2.textContent =
|
|
3246
|
+
if (ct2) ct2.textContent = \x27Studio Report\x27;
|
|
3244
3247
|
}
|
|
3245
3248
|
var scb = document.getElementById('studioCanvasBtn');
|
|
3246
|
-
if (scb) scb.style.display =
|
|
3249
|
+
if (scb) scb.style.display = \x27\x27;
|
|
3247
3250
|
}
|
|
3248
3251
|
if (ev.usage) { studioAddTokens(ev.usage.input||0, ev.usage.output||0); }
|
|
3249
3252
|
else if (ev.token && !isStatus) { studioTokens.out += Math.ceil(ev.token.length/4); studioUpdateTokenBar(); }
|