nothumanallowed 13.2.83 → 13.2.85

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.83",
3
+ "version": "13.2.85",
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": {
@@ -2998,10 +2998,19 @@ ${rawText.slice(0, 18000)}`;
2998
2998
  // Run all queries sequentially, accumulate results
2999
2999
  for (let qi = 0; qi < searchQueries.length; qi++) {
3000
3000
  const q = searchQueries[qi];
3001
+ sendToken(`[Searching: "${q.slice(0, 60)}"] `);
3001
3002
  try {
3002
- const searchResult = await withTimeout(executeTool('web_search', { query: q, deep: qi === 0 }, config), 25000);
3003
+ const searchResult = await withTimeout(executeTool('web_search', { query: q, deep: true }, config), 35000);
3003
3004
  const searchStr = typeof searchResult === 'string' ? searchResult : JSON.stringify(searchResult);
3004
- toolData += (toolData ? '\n\n' : '') + `## Web search: "${q}":\n${searchStr}`;
3005
+ // If no results, try without 'deep' (fallback to basic search)
3006
+ if (!searchStr || searchStr.length < 50 || /no results|not found/i.test(searchStr)) {
3007
+ sendToken('[Retrying basic search...] ');
3008
+ const retryResult = await withTimeout(executeTool('web_search', { query: q }, config), 25000);
3009
+ const retryStr = typeof retryResult === 'string' ? retryResult : JSON.stringify(retryResult);
3010
+ toolData += (toolData ? '\n\n' : '') + `## Web search: "${q}":\n${retryStr || 'No results found.'}`;
3011
+ } else {
3012
+ toolData += (toolData ? '\n\n' : '') + `## Web search: "${q}":\n${searchStr}`;
3013
+ }
3005
3014
  } catch (e) { toolData += (toolData ? '\n\n' : '') + `## Search "${q}" failed: ${e.message}`; }
3006
3015
  }
3007
3016
  } catch (e) { toolData = toolData || `Web search failed: ${e.message}`; }
@@ -3304,7 +3313,7 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS (use only what is RELEVANT to the wo
3304
3313
  if (stripped) sendToken(stripped);
3305
3314
  }
3306
3315
  },
3307
- { max_tokens: 4096 },
3316
+ { max_tokens: 8192 },
3308
3317
  ),
3309
3318
  llmTimeout
3310
3319
  );
@@ -3331,7 +3340,7 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS (use only what is RELEVANT to the wo
3331
3340
  callLLMStream(retryConfig, `You are ${agent}. Analyze the following data and complete the task. Be thorough and write in ${language}.\n\nDATA:\n${context}\n\nTASK: ${stepPrompt}`,
3332
3341
  'Write your complete analysis now.',
3333
3342
  (tok) => { retryOutput += tok; sendToken(tok); },
3334
- { max_tokens: 4096 },
3343
+ { max_tokens: 8192 },
3335
3344
  ),
3336
3345
  60000
3337
3346
  );
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.83';
8
+ export const VERSION = '13.2.85';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -27,6 +27,7 @@ const MAX_REDIRECTS = 5;
27
27
  const MAX_RESULTS = 8;
28
28
 
29
29
  const USER_AGENT = 'NHA-CLI/9.0 (NotHumanAllowed; +https://nothumanallowed.com)';
30
+ const BROWSER_UA = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0';
30
31
 
31
32
  // ── SSRF Protection ──────────────────────────────────────────────────────────
32
33
 
@@ -291,9 +292,13 @@ export async function webSearch(query, maxResults = MAX_RESULTS) {
291
292
  try {
292
293
  const res = await fetch(searchUrl, {
293
294
  headers: {
294
- 'User-Agent': USER_AGENT,
295
- 'Accept': 'text/html',
296
- 'Accept-Language': 'en-US,en;q=0.9',
295
+ 'User-Agent': BROWSER_UA,
296
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
297
+ 'Accept-Language': 'en-US,en;q=0.5',
298
+ 'Accept-Encoding': 'identity',
299
+ 'DNT': '1',
300
+ 'Connection': 'keep-alive',
301
+ 'Upgrade-Insecure-Requests': '1',
297
302
  },
298
303
  signal: controller.signal,
299
304
  });
@@ -325,58 +330,55 @@ export async function webSearch(query, maxResults = MAX_RESULTS) {
325
330
  /**
326
331
  * Parse DuckDuckGo HTML results page.
327
332
  * Extracts title, URL, and snippet from result items.
333
+ *
334
+ * DDG HTML structure (current):
335
+ * <div class="result results_links results_links_deep web-result ">
336
+ * <h2 class="result__title">
337
+ * <a class="result__a" href="//duckduckgo.com/l/?uddg=ENCODED_URL&...">Title</a>
338
+ * </h2>
339
+ * <a class="result__snippet" href="...">Snippet text</a>
340
+ * </div>
328
341
  */
329
342
  function parseDuckDuckGoResults(html, maxResults) {
330
343
  const results = [];
331
344
 
332
- // DuckDuckGo HTML wraps results in <div class="result..."> with
333
- // <a class="result__a" href="...">title</a> and
334
- // <a class="result__snippet">snippet</a>
335
- const resultBlocks = html.split(/class="result\s/);
345
+ // Split on individual result divs. Each web result starts with this class sequence.
346
+ const resultBlocks = html.split('class="result results_links');
336
347
 
337
348
  for (let i = 1; i < resultBlocks.length && results.length < maxResults; i++) {
338
349
  const block = resultBlocks[i];
339
350
 
340
- // Extract URL DuckDuckGo uses redirect URLs, extract the actual destination
351
+ // Extract URL from uddg= parameter in the result__a href
341
352
  let url = '';
342
- const urlMatch = block.match(/class="result__a"\s+href="([^"]+)"/);
343
- if (urlMatch) {
344
- url = urlMatch[1];
345
- // DuckDuckGo wraps URLs: //duckduckgo.com/l/?uddg=ENCODED_URL&...
346
- if (url.includes('uddg=')) {
347
- const uddgMatch = url.match(/uddg=([^&]+)/);
348
- if (uddgMatch) {
349
- try {
350
- url = decodeURIComponent(uddgMatch[1]);
351
- } catch {
352
- url = uddgMatch[1];
353
- }
354
- }
353
+ const uddgMatch = block.match(/uddg=([^&"]+)/);
354
+ if (uddgMatch) {
355
+ try {
356
+ url = decodeURIComponent(uddgMatch[1]);
357
+ } catch {
358
+ url = uddgMatch[1];
355
359
  }
356
- // Handle protocol-relative URLs
357
- if (url.startsWith('//')) url = 'https:' + url;
358
360
  }
361
+ if (!url) continue;
359
362
 
360
- // Extract title
363
+ // Extract title from result__a anchor text
361
364
  let title = '';
362
365
  const titleMatch = block.match(/class="result__a"[^>]*>([\s\S]*?)<\/a>/);
363
366
  if (titleMatch) {
364
367
  title = htmlToText(titleMatch[1]).trim();
365
368
  }
369
+ if (!title) continue;
366
370
 
367
- // Extract snippet
371
+ // Extract snippet from result__snippet anchor
368
372
  let snippet = '';
369
373
  const snippetMatch = block.match(/class="result__snippet"[^>]*>([\s\S]*?)<\/a>/);
370
- if (!snippetMatch) {
374
+ if (snippetMatch) {
375
+ snippet = htmlToText(snippetMatch[1]).trim();
376
+ } else {
371
377
  const altSnippet = block.match(/class="result__snippet"[^>]*>([\s\S]*?)<\//);
372
378
  if (altSnippet) snippet = htmlToText(altSnippet[1]).trim();
373
- } else {
374
- snippet = htmlToText(snippetMatch[1]).trim();
375
379
  }
376
380
 
377
- if (url && title) {
378
- results.push({ title, url, snippet: snippet.slice(0, 300) });
379
- }
381
+ results.push({ title, url, snippet: snippet.slice(0, 300) });
380
382
  }
381
383
 
382
384
  return results;
@@ -3796,7 +3796,15 @@ async function runStudio() {
3796
3796
  if (ct) ct.textContent = node.label + ' Report';
3797
3797
  }
3798
3798
  }
3799
- context = realOutput || stepResult.canvas || context;
3799
+ // Accumulate context: append each step's output so specialist agents see ALL previous data
3800
+ var NL = String.fromCharCode(10);
3801
+ if (realOutput) {
3802
+ context = context
3803
+ ? context + NL + NL + '---' + NL + '## ' + node.label + ':' + NL + realOutput
3804
+ : '## ' + node.label + ':' + NL + realOutput;
3805
+ } else if (stepResult.canvas) {
3806
+ context = context || '[Canvas generated]';
3807
+ }
3800
3808
  }
3801
3809
 
3802
3810
  // Parliament mode: Round 2 cross-reading deliberation
@@ -3993,8 +4001,14 @@ function studioAddTokens(inp, out) {
3993
4001
  function studioUpdateTokenBar() {
3994
4002
  var el = document.getElementById('studioTokenBar');
3995
4003
  if (!el) return;
3996
- if (studioTokens.in === 0 && studioTokens.out === 0) { el.textContent = ''; return; }
3997
- el.textContent = '⬆ ' + studioTokens.in.toLocaleString() + ' in ⬇ ' + studioTokens.out.toLocaleString() + ' out';
4004
+ if (studioTokens.in === 0 && studioTokens.out === 0) { el.innerHTML = ''; return; }
4005
+ var total = studioTokens.in + studioTokens.out;
4006
+ el.innerHTML = '<span style="color:var(--green);font-weight:700">\u2B06 ' + studioTokens.in.toLocaleString() + '</span>' +
4007
+ '<span style="color:var(--dim)"> in &nbsp;</span>' +
4008
+ '<span style="color:#a5b4fc;font-weight:700">\u2B07 ' + studioTokens.out.toLocaleString() + '</span>' +
4009
+ '<span style="color:var(--dim)"> out &nbsp;\u2022&nbsp; </span>' +
4010
+ '<span style="color:var(--bright);font-weight:700">' + total.toLocaleString() + '</span>' +
4011
+ '<span style="color:var(--dim)"> tot</span>';
3998
4012
  }
3999
4013
 
4000
4014
  function runStudioStep(idx, node, task, context, stepDef, signal) {
@@ -4003,7 +4017,9 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
4003
4017
  var canvasHtml = null;
4004
4018
  // Inject attachment into first step only — pass PDF/image as dedicated fields,
4005
4019
  // NOT as raw base64 in context (would cause 100k+ token overflow for any real PDF).
4006
- var bodyObj = {stepIdx: idx, agent: node.agent, task: task, context: context, stepDef: stepDef};
4020
+ // Cap accumulated context to ~40KB to avoid token overflow keep the most recent content
4021
+ var cappedContext = context && context.length > 40000 ? context.slice(-40000) : context;
4022
+ var bodyObj = {stepIdx: idx, agent: node.agent, task: task, context: cappedContext, stepDef: stepDef};
4007
4023
  if (idx === 0 && studioState.attachmentContext) {
4008
4024
  var ac = studioState.attachmentContext;
4009
4025
  var isPdfAttach = ac.indexOf('[ATTACHED PDF:') === 0;
@@ -4049,16 +4065,28 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
4049
4065
  if (ev.token) {
4050
4066
  var isStatus = ev.token.charAt(0) === \x27[\x27 && ev.token.indexOf(\x27]\x27) > 0 && ev.token.length < 80;
4051
4067
  if (!isStatus) { output += ev.token; }
4052
- // Update live log: show status tokens as text, LLM output as animated dots
4068
+ // Update live log
4053
4069
  var entries = document.querySelectorAll(\x27.studio-log-entry\x27);
4054
4070
  var last = entries[entries.length - 1];
4055
4071
  if (last) {
4056
4072
  var tb = last.querySelector(\x27.studio-log-entry__text\x27);
4057
4073
  if (tb) {
4058
4074
  if (isStatus) {
4059
- tb.textContent = ev.token.replace(new RegExp(\x27[\\\\r\\\\n]+\x27,\x27g\x27), \x27 \x27);
4075
+ var st = ev.token.replace(new RegExp(\x27[\\\\r\\\\n]+\x27,\x27g\x27), \x27 \x27);
4076
+ // Render [Searching: "query"] as a styled search chip
4077
+ var srchM = st.match(/^\\[Searching:\\s*"([^"]+)"\\]\\s*$/);
4078
+ if (srchM) {
4079
+ var qEsc = srchM[1].replace(/&/g,\x27&amp;\x27).replace(/</g,\x27&lt;\x27).replace(/>/g,\x27&gt;\x27);
4080
+ tb.innerHTML = \x27<span style="display:inline-flex;align-items:center;gap:6px;background:#1c1c28;border:1px solid #6366f133;border-radius:20px;padding:3px 10px 3px 8px;font-size:11px;font-family:var(--mono)"><span style="color:#6366f1">&#128269;</span><span style="color:var(--dim)">Cercando</span><strong style="color:#a5b4fc">\x27 + qEsc + \x27</strong><span style="color:#6366f1;animation:pulse 1s infinite">&#183;&#183;&#183;</span></span>\x27;
4081
+ } else {
4082
+ tb.textContent = st;
4083
+ }
4084
+ } else {
4085
+ // Live token counter — shows progress without raw content
4086
+ var chars = output.length;
4087
+ var toks = Math.ceil(chars / 4);
4088
+ tb.innerHTML = \x27<span style="color:var(--green);font-family:var(--mono);font-size:10px">&#9679; Generating\u2026 \x27 + toks + \x27 token</span>\x27;
4060
4089
  }
4061
- // LLM output: don\x27t show raw tokens — just keep the animated dots from CSS
4062
4090
  }
4063
4091
  }
4064
4092
  }