nothumanallowed 13.2.74 → 13.2.75

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.74",
3
+ "version": "13.2.75",
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": {
@@ -2944,101 +2944,35 @@ Rules:
2944
2944
  } else if (agent === 'WebSearchAgent' || agent === 'ResearchAgent') {
2945
2945
  sendToken('[Searching the web and reading pages...] ');
2946
2946
  try {
2947
- // Extract a concise search query from the step prompt
2948
- let searchQuery = stepPrompt;
2949
-
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.
2947
+ // If there is document context from a previous step, ask the LLM to derive
2948
+ // the optimal search queries. This is generic and works for any document/task.
2949
+ let searchQueries = [stepPrompt.slice(0, 120)];
2952
2950
  if (context && context.length > 50) {
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}"] `);
2995
- }
2996
- }
2997
-
2998
- if (!context && searchQuery.length > 120) {
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);
3000
- if (keywordMatch) {
3001
- searchQuery = keywordMatch[1].trim();
3002
- } else {
3003
- searchQuery = searchQuery.split(/[,\.\n]/)[0].slice(0, 100).trim();
3004
- }
3005
- }
3006
- // If step prompt / task contains a specific domain, fetch that page directly first
3007
- const domainMatch = (stepPrompt + ' ' + task).match(/(?:https?:\/\/)?(?:www\.)?([a-z0-9-]+\.[a-z]{2,}(?:\/[^\s,]*)?)/i);
3008
- if (domainMatch) {
3009
- let targetUrl = domainMatch[0];
3010
- if (!targetUrl.startsWith('http')) targetUrl = 'https://' + targetUrl;
3011
- sendToken(`[Fetching ${targetUrl}...] `);
2951
+ sendToken('[Building search queries from document...] ');
3012
2952
  try {
3013
- const fetchResult = await withTimeout(executeTool('fetch_url', { url: targetUrl }, config), 20000);
3014
- const fetchStr = typeof fetchResult === 'string' ? fetchResult : JSON.stringify(fetchResult);
3015
- if (fetchStr && !fetchStr.startsWith('HTTP ') && !fetchStr.startsWith('Content blocked')) {
3016
- toolData = `## Content from ${targetUrl}:\n${fetchStr}`;
2953
+ const queryPlanSys = 'You are a search query generator. Given a document summary and a user task, output a JSON array of 1-3 concise web search queries (strings, max 80 chars each) that will find the best results. Output ONLY the JSON array, no explanation.';
2954
+ const queryPlanUser = `User task: "${task}"\n\nDocument content (summary):\n${context.slice(0, 3000)}\n\nGenerate search queries to fulfill the task. If the task asks for similar/alternative products, use technical specs as queries. If it asks where to buy, include vendor/distributor queries. Output: ["query1","query2",...]`;
2955
+ const planConfig2 = Object.assign({}, config, { thinking: 'off' });
2956
+ const queryRaw = await withTimeout(callLLM(planConfig2, queryPlanSys, queryPlanUser, { max_tokens: 200 }), 15000);
2957
+ const jsonMatch = queryRaw.match(/\[[\s\S]*?\]/);
2958
+ if (jsonMatch) {
2959
+ const parsed = JSON.parse(jsonMatch[0]);
2960
+ if (Array.isArray(parsed) && parsed.length > 0) {
2961
+ searchQueries = parsed.filter(q => typeof q === 'string' && q.length > 2).slice(0, 3);
2962
+ }
3017
2963
  }
3018
2964
  } catch {}
2965
+ sendToken(`[Queries: ${searchQueries.map(q => '"' + q + '"').join(', ')}] `);
3019
2966
  }
3020
- // Primary search
3021
- const searchResult = await withTimeout(executeTool('web_search', { query: searchQuery, deep: true }, config), 25000);
3022
- const searchStr = typeof searchResult === 'string' ? searchResult : JSON.stringify(searchResult);
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}"] `);
2967
+
2968
+ // Run all queries sequentially, accumulate results
2969
+ for (let qi = 0; qi < searchQueries.length; qi++) {
2970
+ const q = searchQueries[qi];
3037
2971
  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 {}
2972
+ const searchResult = await withTimeout(executeTool('web_search', { query: q, deep: qi === 0 }, config), 25000);
2973
+ const searchStr = typeof searchResult === 'string' ? searchResult : JSON.stringify(searchResult);
2974
+ toolData += (toolData ? '\n\n' : '') + `## Web search: "${q}":\n${searchStr}`;
2975
+ } catch (e) { toolData += (toolData ? '\n\n' : '') + `## Search "${q}" failed: ${e.message}`; }
3042
2976
  }
3043
2977
  } catch (e) { toolData = toolData || `Web search failed: ${e.message}`; }
3044
2978
 
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.74';
8
+ export const VERSION = '13.2.75';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11