nothumanallowed 13.2.73 → 13.2.74

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.2.73",
3
+ "version": "13.2.74",
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": {
@@ -2947,22 +2947,55 @@ Rules:
2947
2947
  // Extract a concise search query from the step prompt
2948
2948
  let searchQuery = stepPrompt;
2949
2949
 
2950
- // If context contains extracted PDF data, extract the best search query from it:
2951
- // product codes, model numbers, part numbers etc. are better search terms than the task text.
2950
+ // If context contains extracted PDF/document data, build a smart search query.
2951
+ // Detect whether the task asks for "similar" products vs. exact product lookup.
2952
2952
  if (context && context.length > 50) {
2953
- // Look for product codes: alphanumeric codes, e.g. 321k63, VFD-001, 4WE6D6X
2954
- const codeMatch = context.match(/\b([A-Z0-9]{2,}[-\/]?[A-Z0-9]{2,}(?:[-\/][A-Z0-9]+)*)\b/g);
2955
- const productCodes = codeMatch ? [...new Set(codeMatch)].slice(0, 3) : [];
2956
- // Also grab manufacturer name if present
2957
- const mfrMatch = context.match(/(?:Marca|Marchio|Manufacturer|Brand|Produttore|Costruttore)[:\s]+([A-Za-z0-9 &]{2,40})/i);
2958
- const mfr = mfrMatch ? mfrMatch[1].trim() : '';
2959
- if (productCodes.length > 0) {
2960
- searchQuery = (mfr ? mfr + ' ' : '') + productCodes.join(' ') + ' buy acquista distributore';
2961
- sendToken(`[Search query from document: "${searchQuery}"] `);
2953
+ const taskLow2 = task.toLowerCase();
2954
+ const wantsSimilar = /simil|equivalen|alternativ|sostitut|find similar|alternative|replacement/i.test(taskLow2 + ' ' + stepPrompt);
2955
+
2956
+ // Extract manufacturer name from structured context
2957
+ const mfrMatch = context.match(/(?:Marca|Marchio|Manufacturer|Brand|Produttore|Costruttore|Parker|Bosch|Rexroth|SMC|Festo|Burkert|Norgren|Sirai|Asco)[:\s]*([A-Za-z0-9 &]{2,40})/i);
2958
+ const mfr = mfrMatch ? mfrMatch[1].trim().split(/\s+/).slice(0,2).join(' ') : '';
2959
+
2960
+ // Extract model/part code: 3-8 char alphanumeric, NOT common words/units
2961
+ const IGNORE = new Set(['NBR','FKM','RUBY','BSP','PDF','URL','HTTP','THE','AND','FOR','MIN','MAX','BAR','VAC','KV','AC','DC','CE','UK','EU','ISO','DIN']);
2962
+ const codeRx = /\b([A-Z][A-Z0-9]{2,7}(?:[-\/][A-Z0-9]{1,6})*)\b/g;
2963
+ const allCodes = [];
2964
+ let cm;
2965
+ while ((cm = codeRx.exec(context)) !== null) {
2966
+ const c = cm[1];
2967
+ if (!IGNORE.has(c) && c.length >= 4 && /\d/.test(c)) allCodes.push(c);
2968
+ }
2969
+ const productCode = [...new Set(allCodes)][0] || '';
2970
+
2971
+ // Extract key technical specs for similarity search
2972
+ const pressMatch = context.match(/(?:pressione|pressure|MOPD)[^\d]*(\d+)\s*bar/i);
2973
+ const pressure = pressMatch ? pressMatch[1] + ' bar' : '';
2974
+ const portMatch = context.match(/(?:porta|port|attacco|fitting)[^\d]*(\d+\/\d+[''"]?)/i);
2975
+ const port = portMatch ? portMatch[1] : '';
2976
+ const typeMatch = context.match(/(?:valvola|valve|solenoid)[^,\n]{0,30}?(2\/2|3\/2|pilot.operated|normally.closed|normally.open)/i);
2977
+ const valveType = typeMatch ? typeMatch[1] : '';
2978
+
2979
+ if (wantsSimilar) {
2980
+ // Task wants equivalent/similar product — search by specs, not by exact code
2981
+ const specParts = [
2982
+ valveType || 'solenoid valve',
2983
+ pressure,
2984
+ port,
2985
+ 'hydraulic oil',
2986
+ 'acquista distributore Italy'
2987
+ ].filter(Boolean);
2988
+ searchQuery = specParts.join(' ');
2989
+ if (mfr && mfr.toLowerCase() !== productCode.toLowerCase()) searchQuery = mfr + ' ' + searchQuery;
2990
+ sendToken(`[Search query (similar product): "${searchQuery}"] `);
2991
+ } else if (productCode) {
2992
+ // Task wants the exact product — search by code + manufacturer
2993
+ searchQuery = (mfr ? mfr + ' ' : '') + productCode + ' acquista distributore';
2994
+ sendToken(`[Search query (exact product): "${searchQuery}"] `);
2962
2995
  }
2963
2996
  }
2964
2997
 
2965
- if (searchQuery.length > 120 && !context) {
2998
+ if (!context && searchQuery.length > 120) {
2966
2999
  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);
2967
3000
  if (keywordMatch) {
2968
3001
  searchQuery = keywordMatch[1].trim();
@@ -2984,10 +3017,29 @@ Rules:
2984
3017
  }
2985
3018
  } catch {}
2986
3019
  }
2987
- // Deep web search for broader context
3020
+ // Primary search
2988
3021
  const searchResult = await withTimeout(executeTool('web_search', { query: searchQuery, deep: true }, config), 25000);
2989
3022
  const searchStr = typeof searchResult === 'string' ? searchResult : JSON.stringify(searchResult);
2990
3023
  toolData += (toolData ? '\n\n' : '') + `## Web search results for "${searchQuery}":\n${searchStr}`;
3024
+
3025
+ // Secondary search: if task mentions "similar" or "where to buy", run a second query for vendors
3026
+ const taskLow3 = task.toLowerCase();
3027
+ if (/simil|equivalen|alternativ|sostitut|rivendit|distributore|vend|acquist|compra|dove\s+trovare|where\s+to\s+buy/i.test(taskLow3) && context && context.length > 50) {
3028
+ // Build vendor search query from manufacturer + product type
3029
+ const mfrVendor = context.match(/(?:Parker|Bosch|Rexroth|SMC|Festo|Burkert|Norgren|Sirai|Asco)\s+[A-Za-z]*/i);
3030
+ const mfrName = mfrVendor ? mfrVendor[0].trim() : '';
3031
+ const typeVendor = context.match(/(?:valvola|valve|solenoid|elettrovalvola)[^,\n]{0,30}?(2\/2|pilot.operated|normally.closed)/i);
3032
+ const typeStr = typeVendor ? typeVendor[1] : 'solenoid valve';
3033
+ const pressVendor = context.match(/(\d+)\s*bar/i);
3034
+ const pressStr = pressVendor ? pressVendor[1] + ' bar' : '';
3035
+ const vendorQuery = [mfrName, typeStr, pressStr, 'rivenditore distributore acquisto'].filter(Boolean).join(' ');
3036
+ sendToken(`[Search query (vendor/similar): "${vendorQuery}"] `);
3037
+ try {
3038
+ const vendorResult = await withTimeout(executeTool('web_search', { query: vendorQuery, deep: true }, config), 20000);
3039
+ const vendorStr = typeof vendorResult === 'string' ? vendorResult : JSON.stringify(vendorResult);
3040
+ toolData += `\n\n## Vendor search results for "${vendorQuery}":\n${vendorStr}`;
3041
+ } catch {}
3042
+ }
2991
3043
  } catch (e) { toolData = toolData || `Web search failed: ${e.message}`; }
2992
3044
 
2993
3045
  } 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.2.73';
8
+ export const VERSION = '13.2.74';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -3367,7 +3367,11 @@ function renderStudioLog() {
3367
3367
  el.scrollTop = el.scrollHeight;
3368
3368
  }
3369
3369
 
3370
+ var _downloadPdfLast = 0;
3370
3371
  function downloadStudioPDF() {
3372
+ var now = Date.now();
3373
+ if (now - _downloadPdfLast < 3000) return; // debounce: max 1 download every 3s
3374
+ _downloadPdfLast = now;
3371
3375
  var task = studioState.task || 'NHA Studio Report';
3372
3376
  var today = new Date().toLocaleDateString('it-IT', {day:'2-digit',month:'2-digit',year:'numeric'});
3373
3377
  var nodes = studioState.nodes || [];