nothumanallowed 13.2.82 → 13.2.84

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.82",
3
+ "version": "13.2.84",
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}`; }
@@ -3358,16 +3367,117 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS (use only what is RELEVANT to the wo
3358
3367
  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']);
3359
3368
  const titleWords = task.replace(/[.,;:!?]/g,'').split(/\s+/).filter(w => w.length > 2 && !stopWords.has(w.toLowerCase())).slice(0, 6);
3360
3369
  const reportTitle = titleWords.length > 0 ? titleWords.map(w => w.charAt(0).toUpperCase()+w.slice(1)).join(' ') : 'Studio Report';
3361
- // Fallback: if LLM output is empty or has no HTML tags, build body from context using markdown→HTML conversion
3370
+ // Convert markdown to NHA-classed HTML handles the case where Liara/Qwen3
3371
+ // returns markdown instead of HTML despite instructions.
3372
+ const mdToNhaHtml = (md) => {
3373
+ const esc = s => s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
3374
+ // inline: bold, italic, inline-code, links
3375
+ const inl = s => s
3376
+ .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
3377
+ .replace(/\*([^*]+)\*/g, '<em>$1</em>')
3378
+ .replace(/`([^`]+)`/g, '<code style="background:#1c1c28;padding:1px 5px;border-radius:3px;font-size:12px">$1</code>')
3379
+ .replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g, '<a href="$2" target="_blank">$1</a>');
3380
+
3381
+ const lines = md.split('\n');
3382
+ let out = [];
3383
+ let i = 0;
3384
+ let currentSection = null; // accumulates section content
3385
+
3386
+ const flushSection = () => {
3387
+ if (currentSection) { out.push(currentSection + '</div>'); currentSection = null; }
3388
+ };
3389
+
3390
+ while (i < lines.length) {
3391
+ const l = lines[i];
3392
+ // H1 — treat as sub-header inside a new section
3393
+ if (/^# /.test(l)) {
3394
+ flushSection();
3395
+ const title = esc(l.replace(/^# /, '').replace(/\*\*/g,'').replace(/\*/g,''));
3396
+ currentSection = `<div class="section"><div class="section-title">${title}</div>`;
3397
+ i++; continue;
3398
+ }
3399
+ // H2 / H3 — new section
3400
+ if (/^#{2,3} /.test(l)) {
3401
+ flushSection();
3402
+ const title = esc(l.replace(/^#{2,3} /, '').replace(/\*\*/g,'').replace(/\*/g,''));
3403
+ currentSection = `<div class="section"><div class="section-title">${title}</div>`;
3404
+ i++; continue;
3405
+ }
3406
+ // H4 — sub-heading inside current section
3407
+ if (/^#### /.test(l)) {
3408
+ const h = esc(l.replace(/^#### /, '').replace(/\*\*/g,'').replace(/\*/g,''));
3409
+ const frag = `<h3>${h}</h3>`;
3410
+ if (currentSection) currentSection += frag; else out.push(frag);
3411
+ i++; continue;
3412
+ }
3413
+ // Horizontal rule — divider
3414
+ if (/^---+$/.test(l.trim())) {
3415
+ const frag = '<div class="divider"></div>';
3416
+ if (currentSection) currentSection += frag; else out.push(frag);
3417
+ i++; continue;
3418
+ }
3419
+ // Table row
3420
+ if (l.trim().startsWith('|') && l.includes('|', 1)) {
3421
+ // Collect all table lines
3422
+ const tableLines = [];
3423
+ while (i < lines.length && lines[i].trim().startsWith('|')) {
3424
+ if (!/^\|[\s:|-]+\|$/.test(lines[i].trim())) tableLines.push(lines[i]);
3425
+ i++;
3426
+ }
3427
+ if (tableLines.length > 0) {
3428
+ const isHeader = tableLines.length > 1;
3429
+ let tHtml = '<table style="width:100%;border-collapse:collapse;margin:10px 0;font-size:12px">';
3430
+ tableLines.forEach((tl, ti) => {
3431
+ const cells = tl.split('|').slice(1,-1).map(c => c.trim());
3432
+ const tag = (ti === 0 && isHeader) ? 'th' : 'td';
3433
+ const bg = ti === 0 && isHeader ? 'background:#1c1c28;color:#a5b4fc;font-weight:700' : (ti % 2 === 0 ? 'background:#15151f' : 'background:#1a1a28');
3434
+ tHtml += '<tr>' + cells.map(c => `<${tag} style="${bg};padding:6px 10px;border:1px solid #2a2a38;text-align:left">${inl(esc(c))}</${tag}>`).join('') + '</tr>';
3435
+ });
3436
+ tHtml += '</table>';
3437
+ if (currentSection) currentSection += tHtml; else out.push(tHtml);
3438
+ }
3439
+ continue;
3440
+ }
3441
+ // Unordered list block
3442
+ if (/^(\s*[-*+] )/.test(l)) {
3443
+ const items = [];
3444
+ while (i < lines.length && /^(\s*[-*+] )/.test(lines[i])) {
3445
+ items.push(inl(esc(lines[i].replace(/^\s*[-*+] /, ''))));
3446
+ i++;
3447
+ }
3448
+ const frag = '<ul>' + items.map(it => `<li>${it}</li>`).join('') + '</ul>';
3449
+ if (currentSection) currentSection += frag; else out.push(frag);
3450
+ continue;
3451
+ }
3452
+ // Ordered list block
3453
+ if (/^\d+\. /.test(l)) {
3454
+ const items = [];
3455
+ while (i < lines.length && /^\d+\. /.test(lines[i])) {
3456
+ items.push(inl(esc(lines[i].replace(/^\d+\. /, ''))));
3457
+ i++;
3458
+ }
3459
+ const frag = '<ol>' + items.map(it => `<li>${it}</li>`).join('') + '</ol>';
3460
+ if (currentSection) currentSection += frag; else out.push(frag);
3461
+ continue;
3462
+ }
3463
+ // Blank line — skip
3464
+ if (!l.trim()) { i++; continue; }
3465
+ // Regular paragraph
3466
+ const frag = `<p>${inl(esc(l))}</p>`;
3467
+ if (currentSection) currentSection += frag; else out.push(frag);
3468
+ i++;
3469
+ }
3470
+ flushSection();
3471
+ return out.join('');
3472
+ };
3473
+
3474
+ // If LLM output has no HTML tags → it's markdown → convert
3362
3475
  if (!bodyHtml || !bodyHtml.includes('<')) {
3363
- const sections = context.split(/\n#{1,3} |(?=\n\n)/).filter(s => s.trim()).slice(0, 12);
3476
+ const source = bodyHtml || context;
3477
+ const converted = mdToNhaHtml(source);
3478
+ const agentNames = (stepDef && Array.isArray(stepDef)) ? '' : '';
3364
3479
  bodyHtml = `<div class="header"><h1>${reportTitle.replace(/</g,'&lt;')}</h1><p>NHA Studio Report \u00b7 ${today}</p><div class="meta"><span>${today}</span></div></div>` +
3365
- sections.map(s => {
3366
- const lines = s.replace(/\*\*/g,'').replace(/\*/g,'').trim().split('\n').filter(Boolean);
3367
- const stitle = lines[0] || '';
3368
- const body = lines.slice(1).map(l => `<p>${l.replace(/</g,'&lt;')}</p>`).join('');
3369
- return `<div class="section"><div class="section-title">${stitle.replace(/</g,'&lt;')}</div>${body}</div>`;
3370
- }).join('') +
3480
+ converted +
3371
3481
  `<div class="footer">NHA Studio \u00b7 ${today}</div>`;
3372
3482
  } else {
3373
3483
  // Replace the h1 inside existing header div if the model included the full prompt as title
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.82';
8
+ export const VERSION = '13.2.84';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -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,7 +4065,7 @@ 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) {
@@ -4057,8 +4073,12 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
4057
4073
  if (tb) {
4058
4074
  if (isStatus) {
4059
4075
  tb.textContent = ev.token.replace(new RegExp(\x27[\\\\r\\\\n]+\x27,\x27g\x27), \x27 \x27);
4076
+ } else {
4077
+ // Live token counter — shows progress without raw content
4078
+ var chars = output.length;
4079
+ var toks = Math.ceil(chars / 4);
4080
+ 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
4081
  }
4061
- // LLM output: don\x27t show raw tokens — just keep the animated dots from CSS
4062
4082
  }
4063
4083
  }
4064
4084
  }