nothumanallowed 13.2.45 → 13.2.47
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 +35 -13
- package/src/constants.mjs +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.47",
|
|
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
|
@@ -2570,6 +2570,9 @@ export async function cmdUI(args) {
|
|
|
2570
2570
|
const extractSearchQuery = (t) => {
|
|
2571
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);
|
|
2572
2572
|
if (m) return m[1].trim();
|
|
2573
|
+
// If task contains a domain/URL, use it as the search anchor
|
|
2574
|
+
const domainMatch = t.match(/(?:https?:\/\/)?(?:www\.)?([a-z0-9-]+\.[a-z]{2,}(?:\.[a-z]{2,})?)/i);
|
|
2575
|
+
if (domainMatch) return domainMatch[0].replace(/^https?:\/\//,'');
|
|
2573
2576
|
const stripped = t.replace(/^[^:]+:\s*/,'').split(/[,\n]/)[0].slice(0,100).trim();
|
|
2574
2577
|
return stripped || t.slice(0,80).trim();
|
|
2575
2578
|
};
|
|
@@ -2709,24 +2712,35 @@ export async function cmdUI(args) {
|
|
|
2709
2712
|
} else if (agent === 'WebSearchAgent' || agent === 'ResearchAgent') {
|
|
2710
2713
|
sendToken('[Searching the web and reading pages...] ');
|
|
2711
2714
|
try {
|
|
2712
|
-
// Extract a concise search query from the step prompt
|
|
2713
|
-
// The planner should provide a short query, but if not, extract key terms
|
|
2715
|
+
// Extract a concise search query from the step prompt
|
|
2714
2716
|
let searchQuery = stepPrompt;
|
|
2715
|
-
// If the prompt is very long (> 120 chars), extract the core search terms
|
|
2716
2717
|
if (searchQuery.length > 120) {
|
|
2717
|
-
// Try to extract a meaningful short query
|
|
2718
2718
|
const keywordMatch = searchQuery.match(/(?:cerca|search|find|ricerca|notizie su|news about|latest on|aggiornamenti su)\s+(.{5,80}?)(?:\s+(?:e|and|per|for|poi|then)|$)/i);
|
|
2719
2719
|
if (keywordMatch) {
|
|
2720
2720
|
searchQuery = keywordMatch[1].trim();
|
|
2721
2721
|
} else {
|
|
2722
|
-
// Take first meaningful clause before comma/period
|
|
2723
2722
|
searchQuery = searchQuery.split(/[,\.\n]/)[0].slice(0, 100).trim();
|
|
2724
2723
|
}
|
|
2725
2724
|
}
|
|
2726
|
-
//
|
|
2725
|
+
// If step prompt / task contains a specific domain, fetch that page directly first
|
|
2726
|
+
const domainMatch = (stepPrompt + ' ' + task).match(/(?:https?:\/\/)?(?:www\.)?([a-z0-9-]+\.[a-z]{2,}(?:\/[^\s,]*)?)/i);
|
|
2727
|
+
if (domainMatch) {
|
|
2728
|
+
let targetUrl = domainMatch[0];
|
|
2729
|
+
if (!targetUrl.startsWith('http')) targetUrl = 'https://' + targetUrl;
|
|
2730
|
+
sendToken(`[Fetching ${targetUrl}...] `);
|
|
2731
|
+
try {
|
|
2732
|
+
const fetchResult = await withTimeout(executeTool('fetch_url', { url: targetUrl }, config), 20000);
|
|
2733
|
+
const fetchStr = typeof fetchResult === 'string' ? fetchResult : JSON.stringify(fetchResult);
|
|
2734
|
+
if (fetchStr && !fetchStr.startsWith('HTTP ') && !fetchStr.startsWith('Content blocked')) {
|
|
2735
|
+
toolData = `## Content from ${targetUrl}:\n${fetchStr.slice(0, 5000)}`;
|
|
2736
|
+
}
|
|
2737
|
+
} catch {}
|
|
2738
|
+
}
|
|
2739
|
+
// Deep web search for broader context
|
|
2727
2740
|
const searchResult = await withTimeout(executeTool('web_search', { query: searchQuery, deep: true }, config), 25000);
|
|
2728
|
-
|
|
2729
|
-
|
|
2741
|
+
const searchStr = typeof searchResult === 'string' ? searchResult : JSON.stringify(searchResult);
|
|
2742
|
+
toolData += (toolData ? '\n\n' : '') + `## Web search results for "${searchQuery}":\n${searchStr}`;
|
|
2743
|
+
} catch (e) { toolData = toolData || `Web search failed: ${e.message}`; }
|
|
2730
2744
|
|
|
2731
2745
|
} else if (agent === 'BrowserAgent') {
|
|
2732
2746
|
const urlMatch = stepPrompt.match(/https?:\/\/[^\s"']+/);
|
|
@@ -2911,21 +2925,29 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 6000)}\n` : ''}
|
|
|
2911
2925
|
const bodyStart = bodyHtml.search(/<body[^>]*>/i);
|
|
2912
2926
|
if (bodyStart >= 0) bodyHtml = bodyHtml.slice(bodyStart).replace(/<body[^>]*>/i, '').replace(/<\/body>[\s\S]*/i, '').trim();
|
|
2913
2927
|
}
|
|
2928
|
+
// Derive a short report title from the task (skip stop words, take first 5-6 meaningful words)
|
|
2929
|
+
const stopWords = new Set(['di','la','il','lo','le','gli','un','una','dei','del','della','per','che','con','su','in','e','a','da','è','come','analizza','analisi','ricerca','crea','genera','fai','fammi','dammi','the','of','for','and','a','an','in','with','on','about','analyze','analysis','research','create','generate','make','find','search']);
|
|
2930
|
+
const titleWords = task.replace(/[.,;:!?]/g,'').split(/\s+/).filter(w => w.length > 2 && !stopWords.has(w.toLowerCase())).slice(0, 6);
|
|
2931
|
+
const reportTitle = titleWords.length > 0 ? titleWords.map(w => w.charAt(0).toUpperCase()+w.slice(1)).join(' ') : 'Studio Report';
|
|
2914
2932
|
// Fallback: if LLM output is empty or has no HTML tags, build body from context using markdown→HTML conversion
|
|
2915
2933
|
if (!bodyHtml || !bodyHtml.includes('<')) {
|
|
2916
|
-
const reportTitle = task.slice(0, 80).replace(/</g,'<');
|
|
2917
2934
|
const sections = context.split(/\n#{1,3} |(?=\n\n)/).filter(s => s.trim()).slice(0, 12);
|
|
2918
|
-
bodyHtml = `<div class="header"><h1>${reportTitle}</h1><p>NHA Studio Report \u00b7 ${today}</p><div class="meta"><span>${today}</span></div></div>` +
|
|
2935
|
+
bodyHtml = `<div class="header"><h1>${reportTitle.replace(/</g,'<')}</h1><p>NHA Studio Report \u00b7 ${today}</p><div class="meta"><span>${today}</span></div></div>` +
|
|
2919
2936
|
sections.map(s => {
|
|
2920
2937
|
const lines = s.replace(/\*\*/g,'').replace(/\*/g,'').trim().split('\n').filter(Boolean);
|
|
2921
|
-
const
|
|
2938
|
+
const stitle = lines[0] || '';
|
|
2922
2939
|
const body = lines.slice(1).map(l => `<p>${l.replace(/</g,'<')}</p>`).join('');
|
|
2923
|
-
return `<div class="section"><div class="section-title">${
|
|
2940
|
+
return `<div class="section"><div class="section-title">${stitle.replace(/</g,'<')}</div>${body}</div>`;
|
|
2924
2941
|
}).join('') +
|
|
2925
2942
|
`<div class="footer">NHA Studio \u00b7 ${today}</div>`;
|
|
2943
|
+
} else {
|
|
2944
|
+
// Replace the h1 inside existing header div if the model included the full prompt as title
|
|
2945
|
+
bodyHtml = bodyHtml.replace(/(<div[^>]*class="header"[^>]*>[\s\S]*?<h1[^>]*>)([^<]{60,})(<\/h1>)/, (m, open, title, close) => {
|
|
2946
|
+
return open + reportTitle.replace(/</g,'<') + close;
|
|
2947
|
+
});
|
|
2926
2948
|
}
|
|
2927
2949
|
// Always wrap in the guaranteed NHA dark CSS template
|
|
2928
|
-
const finalHtml = wrapInNHATemplate(bodyHtml,
|
|
2950
|
+
const finalHtml = wrapInNHATemplate(bodyHtml, reportTitle);
|
|
2929
2951
|
sendToken('\n\n[Report generato]');
|
|
2930
2952
|
sendEvent({ canvas: finalHtml });
|
|
2931
2953
|
}
|
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.47';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|