nothumanallowed 13.5.102 → 13.5.104

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.102",
3
+ "version": "13.5.104",
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": {
@@ -577,6 +577,28 @@ export async function cmdUI(args) {
577
577
  return;
578
578
  }
579
579
 
580
+ // GET /api/version/check — check npm registry for latest version
581
+ if (method === 'GET' && pathname === '/api/version/check') {
582
+ try {
583
+ const npmRes = await fetch('https://registry.npmjs.org/nothumanallowed/latest', {
584
+ signal: AbortSignal.timeout(5000),
585
+ headers: { 'Accept': 'application/json' },
586
+ });
587
+ if (!npmRes.ok) { sendJSON(res, 200, { current: VERSION, latest: VERSION, updateAvailable: false }); }
588
+ else {
589
+ const data = await npmRes.json();
590
+ const latest = data.version || VERSION;
591
+ const pa = VERSION.split('.').map(Number);
592
+ const pb = latest.split('.').map(Number);
593
+ let cmp = 0;
594
+ for (let i = 0; i < 3; i++) { if ((pa[i]||0) > (pb[i]||0)) { cmp = -1; break; } if ((pa[i]||0) < (pb[i]||0)) { cmp = 1; break; } }
595
+ sendJSON(res, 200, { current: VERSION, latest, updateAvailable: cmp > 0 });
596
+ }
597
+ } catch(_) { sendJSON(res, 200, { current: VERSION, latest: VERSION, updateAvailable: false }); }
598
+ logRequest(method, pathname, 200, Date.now() - start);
599
+ return;
600
+ }
601
+
580
602
  // GET /api/status
581
603
  if (method === 'GET' && pathname === '/api/status') {
582
604
  sendJSON(res, 200, {
@@ -1389,7 +1411,7 @@ export async function cmdUI(args) {
1389
1411
  // NHA Free tier — Liara Vision (zero API key)
1390
1412
  const r = await fetch('https://nothumanallowed.com/api/v1/liara/vision', {
1391
1413
  method: 'POST',
1392
- headers: { 'Content-Type': 'application/json' },
1414
+ headers: { 'Content-Type': 'application/json', 'x-nha-client': 'studio' },
1393
1415
  body: JSON.stringify({ image_base64: body.imageBase64, prompt: imagePrompt }),
1394
1416
  });
1395
1417
  if (!r.ok) throw new Error(`Liara Vision ${r.status}`);
@@ -1477,7 +1499,7 @@ export async function cmdUI(args) {
1477
1499
  // Fallback: send first page as image to vision model
1478
1500
  const r = await fetch('https://nothumanallowed.com/api/v1/liara/vision', {
1479
1501
  method: 'POST',
1480
- headers: { 'Content-Type': 'application/json' },
1502
+ headers: { 'Content-Type': 'application/json', 'x-nha-client': 'studio' },
1481
1503
  body: JSON.stringify({ image_base64: body.pdfBase64, prompt: pdfPrompt }),
1482
1504
  });
1483
1505
  if (r.ok) {
@@ -1491,7 +1513,7 @@ export async function cmdUI(args) {
1491
1513
  const truncatedText = pdfText.slice(0, 12000);
1492
1514
  const r = await fetch('https://nothumanallowed.com/api/v1/liara/chat', {
1493
1515
  method: 'POST',
1494
- headers: { 'Content-Type': 'application/json' },
1516
+ headers: { 'Content-Type': 'application/json', 'x-nha-client': 'studio' },
1495
1517
  body: JSON.stringify({
1496
1518
  model: 'nha-v1',
1497
1519
  messages: [
@@ -3123,6 +3145,29 @@ ${rawText.slice(0, 18000)}`;
3123
3145
  }
3124
3146
  } catch (e) { toolData += (toolData ? '\n\n' : '') + `## Search "${q}" failed: ${e.message}`; }
3125
3147
  }
3148
+
3149
+ // After all searches: extract URLs from results and fetch booking/info portals directly
3150
+ // This is critical for travel/restaurant/accommodation tasks where portals have internal search
3151
+ const isBookingTask = /(ristorante|restaurant|b&b|hotel|albergo|prenotaz|booking|vacanz|romantico|sushi|menu|disponib|soggiorno|weekend|cena|dinner|accommodation)/i.test(task + ' ' + stepPrompt);
3152
+ if (isBookingTask && toolData.length > 100) {
3153
+ // Extract URLs found in search results
3154
+ const foundUrls = [...new Set((toolData.match(/https?:\/\/[^\s"'\n<>)]+/g) || []))];
3155
+ // Prioritize booking/info portals
3156
+ const portalDomains = ['thefork', 'theforkmanger', 'booking.com', 'tripadvisor', 'yelp', 'zomato', 'airbnb', 'agriturismo', 'expedia', 'hotel', 'b-b.it', 'bed-and-breakfast', 'locanda', 'osteria', 'ristorante', 'viaggi'];
3157
+ const portalUrls = foundUrls.filter(u => portalDomains.some(d => u.toLowerCase().includes(d))).slice(0, 3);
3158
+ if (portalUrls.length > 0) {
3159
+ sendToken(`[Reading ${portalUrls.length} portal page(s)...] `);
3160
+ for (const pu of portalUrls) {
3161
+ try {
3162
+ const pfetch = await withTimeout(executeTool('fetch_url', { url: pu }, config), 20000);
3163
+ const pfetchStr = typeof pfetch === 'string' ? pfetch : JSON.stringify(pfetch);
3164
+ if (pfetchStr && pfetchStr.length > 200) {
3165
+ toolData += '\n\n## Portal page: ' + pu + '\n' + pfetchStr.slice(0, 5000);
3166
+ }
3167
+ } catch {}
3168
+ }
3169
+ }
3170
+ }
3126
3171
  } catch (e) { toolData = toolData || `Web search failed: ${e.message}`; }
3127
3172
 
3128
3173
  } else if (agent === 'BrowserAgent') {
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.62';
8
+ export const VERSION = '13.5.104';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -288,6 +288,7 @@ export async function callNHA(apiKey, model, systemPrompt, userMessage, stream =
288
288
  method: 'POST',
289
289
  headers: {
290
290
  'Content-Type': 'application/json',
291
+ 'x-nha-client': 'cli',
291
292
  },
292
293
  body: JSON.stringify(body),
293
294
  });
@@ -369,7 +370,7 @@ export async function callLLMVision(config, systemPrompt, userMessage, media) {
369
370
  if (!base64) throw new Error('media.base64 required for vision');
370
371
  const res = await fetch('https://nothumanallowed.com/api/v1/liara/vision', {
371
372
  method: 'POST',
372
- headers: { 'Content-Type': 'application/json' },
373
+ headers: { 'Content-Type': 'application/json', 'x-nha-client': 'cli' },
373
374
  body: JSON.stringify({ image_base64: base64, prompt: userMessage || 'Describe this image in detail.' }),
374
375
  });
375
376
  if (!res.ok) {
@@ -547,7 +548,7 @@ export async function callLLMStream(config, systemPrompt, userMessage, onToken,
547
548
  };
548
549
  const nhaRes = await fetch('https://nothumanallowed.com/api/v1/liara/chat', {
549
550
  method: 'POST',
550
- headers: { 'Content-Type': 'application/json' },
551
+ headers: { 'Content-Type': 'application/json', 'x-nha-client': 'cli' },
551
552
  body: JSON.stringify(nhaBody),
552
553
  });
553
554
  if (!nhaRes.ok) {
@@ -1469,7 +1469,7 @@ export async function executeTool(action, params, config) {
1469
1469
  for (const dr of result.deepResults) {
1470
1470
  lines.push(`--- ${dr.title} ---`);
1471
1471
  lines.push(`URL: ${dr.url}`);
1472
- lines.push(dr.content.slice(0, 2000));
1472
+ lines.push(dr.content.slice(0, 4000));
1473
1473
  lines.push('');
1474
1474
  }
1475
1475
 
@@ -3395,7 +3395,9 @@ function renderSidebar() {
3395
3395
  \x27<a href="https://nothumanallowed.com/docs/agents" target="_blank" class="nav-item" style="text-decoration:none"><span class="nav-item__icon">&#129302;</span> \x27+t(\x27nav_agents_guide\x27)+\x27</a>\x27+
3396
3396
  \x27<a href="https://nothumanallowed.com/docs/mobile" target="_blank" class="nav-item" style="text-decoration:none"><span class="nav-item__icon">&#128241;</span> \x27+t(\x27nav_mobile\x27)+\x27</a>\x27+
3397
3397
  \x27</div>\x27+
3398
- \x27<div style="padding:12px 16px;margin-top:auto;border-top:1px solid var(--border);font-size:10px;color:var(--dim)">nothumanallowed.com<span style="margin-left:6px;opacity:.5">v${VERSION}</span></div>\x27;
3398
+ \x27<div style="padding:12px 16px;margin-top:auto;border-top:1px solid var(--border);font-size:10px;color:var(--dim)">nothumanallowed.com<span style="margin-left:6px;opacity:.5">v${VERSION}</span>\x27+
3399
+ (_updateInfo&&_updateInfo.updateAvailable?\x27<span style="margin-left:8px;background:#f59e0b;color:#000;border-radius:4px;padding:1px 6px;font-weight:700;cursor:pointer" title="Run: npm i -g nothumanallowed to update to v\x27+(_updateInfo.latest||\x27\x27)+\x27">&#8593; Update v\x27+(_updateInfo.latest||\x27\x27)+\x27</span>\x27:\x27\x27)+
3400
+ \x27</div>\x27;
3399
3401
  }
3400
3402
 
3401
3403
  var studioState = {
@@ -6508,6 +6510,13 @@ function init(){
6508
6510
  setTimeout(function(){
6509
6511
  fetch(\x27https://nothumanallowed.com/api/v1/telemetry/ping\x27,{method:\x27POST\x27,headers:{\x27Content-Type\x27:\x27application/json\x27},body:JSON.stringify({platform:\x27web-ui\x27,version:\x27${VERSION}\x27})}).catch(function(){});
6510
6512
  },3000);
6513
+ // Version update check — once at boot, non-blocking
6514
+ setTimeout(function(){
6515
+ fetch(API+\x27/api/version/check\x27).then(function(r){return r.json();}).then(function(d){
6516
+ _updateInfo=d;
6517
+ if(d.updateAvailable){renderSidebar();}
6518
+ }).catch(function(){});
6519
+ },5000);
6511
6520
  }
6512
6521
  init();
6513
6522
 
@@ -6548,6 +6557,7 @@ var _wcPlanPending = null; // null | { plan: string, message: string } — pla
6548
6557
  var _wcDiffQueue = []; // [{file, before, after}] diffs from last agent run
6549
6558
  var _wcGrepOpen = false; // grep panel visible
6550
6559
  var _wcGrepQuery = '';
6560
+ var _updateInfo = null; // {current, latest, updateAvailable} — fetched once at boot
6551
6561
  var _wcGrepResults = [];
6552
6562
  var _wcOverlayMinimized = false; // overlay minimized by user click
6553
6563
  var _wcOverlayTimer = null; // inactivity timer to restore overlay