nothumanallowed 13.2.48 → 13.2.51

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.48",
3
+ "version": "13.2.51",
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": {
@@ -2732,7 +2732,7 @@ export async function cmdUI(args) {
2732
2732
  const fetchResult = await withTimeout(executeTool('fetch_url', { url: targetUrl }, config), 20000);
2733
2733
  const fetchStr = typeof fetchResult === 'string' ? fetchResult : JSON.stringify(fetchResult);
2734
2734
  if (fetchStr && !fetchStr.startsWith('HTTP ') && !fetchStr.startsWith('Content blocked')) {
2735
- toolData = `## Content from ${targetUrl}:\n${fetchStr.slice(0, 5000)}`;
2735
+ toolData = `## Content from ${targetUrl}:\n${fetchStr}`;
2736
2736
  }
2737
2737
  } catch {}
2738
2738
  }
@@ -2835,7 +2835,7 @@ RULES:
2835
2835
 
2836
2836
  if (isCanvasAgent) {
2837
2837
  sysPrompt = canvasSystemPrompt;
2838
- userMsg = `Create a professional dashboard report for this data. Output ONLY the inner HTML body content (starting with <div class="header">):\n\n${context.slice(0, 10000)}`;
2838
+ userMsg = `Create a professional dashboard report for this data. Output ONLY the inner HTML body content (starting with <div class="header">):\n\n${context}`;
2839
2839
  } else if (isLiveDataAgent) {
2840
2840
  // These agents fetched real data — use a focused prompt (no tool definitions to avoid JSON output)
2841
2841
  const agentInstruction = `You are ${agent}, a specialist AI agent inside NHA Studio. Today is ${today}. Respond entirely in ${language}.
@@ -2847,8 +2847,8 @@ CRITICAL: Do NOT invent, hallucinate, or add any data not present in the DATA se
2847
2847
  Do NOT output JSON, tool calls, or code blocks. Write in plain text with markdown headers.
2848
2848
  Always apply your analysis specifically to the subject mentioned in the WORKFLOW GOAL.
2849
2849
 
2850
- ${toolData ? `## DATA FROM TOOLS:\n${toolData.slice(0, 6000)}\n` : '## DATA: No data was retrieved by this agent.\n'}
2851
- ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 4000)}\n` : ''}
2850
+ ${toolData ? `## DATA FROM TOOLS:\n${toolData}\n` : '## DATA: No data was retrieved by this agent.\n'}
2851
+ ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context}\n` : ''}
2852
2852
 
2853
2853
  Your task: ${stepPrompt}`;
2854
2854
  sysPrompt = agentInstruction;
@@ -2874,8 +2874,8 @@ CRITICAL RULES:
2874
2874
  - Be thorough and specific — this is for an executive briefing based on REAL data only
2875
2875
  - Always keep the OVERALL WORKFLOW GOAL in mind — apply your analysis specifically to the subject mentioned
2876
2876
 
2877
- ${toolData ? `## LIVE DATA FROM TOOLS:\n${toolData.slice(0, 6000)}\n` : '## LIVE DATA: No tool data was fetched for this step.\n'}
2878
- ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 6000)}\n` : ''}`;
2877
+ ${toolData ? `## LIVE DATA FROM TOOLS:\n${toolData}\n` : '## LIVE DATA: No tool data was fetched for this step.\n'}
2878
+ ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context}\n` : ''}`;
2879
2879
  userMsg = hasRealData
2880
2880
  ? `Based ONLY on the real data above, complete this task specifically for the subject in the WORKFLOW GOAL: ${stepPrompt}`
2881
2881
  : `No real data is available for "${task}". State this clearly and explain what data would be needed to complete: ${stepPrompt}`;
@@ -2883,6 +2883,8 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 6000)}\n` : ''}
2883
2883
 
2884
2884
  // ── Stream LLM response ───────────────────────────────────────
2885
2885
  let fullOutput = '';
2886
+ let inThinkBlock = false;
2887
+ let thinkBuf = '';
2886
2888
  sendToken(isCanvasAgent ? 'Generating visual report...' : '');
2887
2889
  const llmTimeout = isCanvasAgent ? 120000 : 90000;
2888
2890
  try {
@@ -2891,12 +2893,39 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 6000)}\n` : ''}
2891
2893
  (token) => {
2892
2894
  fullOutput += token;
2893
2895
  if (!isCanvasAgent) {
2894
- // Strip JSON tool calls from synthesis agent output before sending to client
2895
- const stripped = token.replace(/\{[\s\S]*?"action"[\s\S]*?\}/g, '').trim();
2896
+ // Buffer and strip <think>...</think> blocks before sending to client
2897
+ thinkBuf += token;
2898
+ // Process thinkBuf: emit only content outside think tags
2899
+ let out = '';
2900
+ let buf = thinkBuf;
2901
+ while (buf.length > 0) {
2902
+ if (inThinkBlock) {
2903
+ const closeIdx = buf.indexOf('</think>');
2904
+ if (closeIdx >= 0) {
2905
+ buf = buf.slice(closeIdx + 8);
2906
+ inThinkBlock = false;
2907
+ } else {
2908
+ buf = '';
2909
+ }
2910
+ } else {
2911
+ const openIdx = buf.indexOf('<think>');
2912
+ if (openIdx >= 0) {
2913
+ out += buf.slice(0, openIdx);
2914
+ buf = buf.slice(openIdx + 7);
2915
+ inThinkBlock = true;
2916
+ } else {
2917
+ out += buf;
2918
+ buf = '';
2919
+ }
2920
+ }
2921
+ }
2922
+ thinkBuf = '';
2923
+ // Strip JSON tool calls from specialist agent output
2924
+ const stripped = out.replace(/\{[\s\S]*?"action"[\s\S]*?\}/g, '').trim();
2896
2925
  if (stripped) sendToken(stripped);
2897
2926
  }
2898
2927
  },
2899
- { max_tokens: isCanvasAgent ? 4096 : 2048 },
2928
+ { max_tokens: 4096 },
2900
2929
  ),
2901
2930
  llmTimeout
2902
2931
  );
@@ -2904,10 +2933,31 @@ ${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 6000)}\n` : ''}
2904
2933
  if (!isCanvasAgent) sendToken(`[Error: ${e.message}]`);
2905
2934
  }
2906
2935
 
2907
- // Fallback: if LLM returned empty and we have tool data, send that directly
2908
- if (!isCanvasAgent && !fullOutput.trim() && toolData) {
2936
+ // Strip think tags from fullOutput before emptiness check
2937
+ const fullOutputClean = fullOutput.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
2938
+
2939
+ // Fallback: if LLM returned empty and we have tool data, send it directly
2940
+ if (!isCanvasAgent && !fullOutputClean && toolData) {
2909
2941
  fullOutput = toolData;
2910
- sendToken(toolData.slice(0, 2000));
2942
+ sendToken(toolData);
2943
+ }
2944
+ // Fallback: if LLM returned empty and we have context (specialist agents like CASSANDRA),
2945
+ // retry once without thinking and with a simplified direct prompt
2946
+ else if (!isCanvasAgent && !fullOutputClean && context && !toolData) {
2947
+ sendToken('[Retrying analysis...]');
2948
+ let retryOutput = '';
2949
+ try {
2950
+ const retryConfig = Object.assign({}, config, { thinking: 'off' });
2951
+ await withTimeout(
2952
+ 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}`,
2953
+ 'Write your complete analysis now.',
2954
+ (tok) => { retryOutput += tok; sendToken(tok); },
2955
+ { max_tokens: 4096 },
2956
+ ),
2957
+ 60000
2958
+ );
2959
+ } catch {}
2960
+ if (retryOutput.trim()) fullOutput = retryOutput;
2911
2961
  }
2912
2962
 
2913
2963
  if (isCanvasAgent) {
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.48';
8
+ export const VERSION = '13.2.51';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -104,6 +104,11 @@ function makeDraggable(el, handleSelector) {
104
104
  if (e.button !== 0) return;
105
105
  dragging = true;
106
106
  sx = e.clientX; sy = e.clientY;
107
+ // Clear transform first so getBoundingClientRect gives the real rendered position
108
+ el.style.transform = '';
109
+ if (el.dataset) el.dataset.expanded = '';
110
+ el.style.width = el.style.width || '';
111
+ el.style.height = el.style.height || '';
107
112
  var rect = el.getBoundingClientRect();
108
113
  // Switch from CSS right/top to explicit left/top
109
114
  el.style.right = 'auto';
@@ -708,7 +713,10 @@ function toggleCanvasSize(){
708
713
  var p=document.getElementById('canvasPanel');if(!p)return;
709
714
  if(p.dataset.expanded==='1'){
710
715
  p.dataset.expanded='';
711
- p.style.width='';p.style.height='';p.style.top='';p.style.right='';p.style.left='';p.style.transform='';
716
+ // Reset to CSS default: fixed position top-right
717
+ p.style.width='';p.style.height='';
718
+ p.style.top='60px';p.style.right='12px';
719
+ p.style.left='';p.style.transform='';
712
720
  } else {
713
721
  p.dataset.expanded='1';
714
722
  p.style.width='80vw';p.style.height='80vh';
@@ -3109,6 +3117,68 @@ function renderStudioLog() {
3109
3117
  el.scrollTop = el.scrollHeight;
3110
3118
  }
3111
3119
 
3120
+ function downloadStudioPDF() {
3121
+ var task = studioState.task || 'NHA Studio Report';
3122
+ var today = new Date().toLocaleDateString('it-IT', {day:'2-digit',month:'2-digit',year:'numeric'});
3123
+ var nodes = studioState.nodes || [];
3124
+
3125
+ // Build sections for each agent
3126
+ var sectionsHtml = nodes.map(function(n) {
3127
+ if (!n.output || n.output === '(no output)' || n.agent === 'CanvasAgent') return '';
3128
+ var mdHtml = (n.output || '')
3129
+ .replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
3130
+ .replace(/\*\*(.*?)\*\*/g,'<strong>$1</strong>')
3131
+ .replace(/\*(.*?)\*/g,'<em>$1</em>')
3132
+ .replace(new RegExp('^#{3}[ \\t]+(.+)$','gm'),'<h3>$1</h3>')
3133
+ .replace(new RegExp('^#{2}[ \\t]+(.+)$','gm'),'<h2>$1</h2>')
3134
+ .replace(new RegExp('^#{1}[ \\t]+(.+)$','gm'),'<h2>$1</h2>')
3135
+ .replace(new RegExp('^-[ \\t]+(.+)$','gm'),'<li>$1</li>')
3136
+ .replace(/(<li>[\s\S]*?<\/li>)/g,'<ul>$1</ul>')
3137
+ .replace(/\n{2,}/g,'</p><p>')
3138
+ .replace(/\n/g,'<br>');
3139
+ return '<div class="section"><div class="agent-label">' + (n.icon||'') + ' ' + esc(n.label||n.agent) + '</div><div class="section-body"><p>' + mdHtml + '</p></div></div>';
3140
+ }).join('');
3141
+
3142
+ // Include canvas if present (as an embedded iframe screenshot fallback note)
3143
+ var canvasNote = studioState.canvas ? '<div class="section canvas-note"><div class="agent-label">&#9632; Canvas Report</div><div class="section-body"><p><em>Il Canvas HTML è disponibile nell\x27interfaccia Studio. Apri il pannello Canvas e usa la funzione stampa del browser per includerlo.</em></p></div></div>' : '';
3144
+
3145
+ var html = '<!DOCTYPE html><html lang="it"><head><meta charset="UTF-8"><title>' + esc(task) + '</title><style>' +
3146
+ 'body{font-family:"Helvetica Neue",Arial,sans-serif;color:#111;background:#fff;margin:0;padding:0}' +
3147
+ '.cover{background:#0d0d0d;color:#fff;padding:60px 50px;page-break-after:always}' +
3148
+ '.cover h1{font-size:28px;font-weight:700;margin:0 0 12px;color:#00ff41}' +
3149
+ '.cover .meta{font-size:13px;color:#aaa;margin-top:8px}' +
3150
+ '.cover .task{font-size:15px;color:#e0e0e0;margin-top:20px;line-height:1.6;max-width:700px}' +
3151
+ '.cover .brand{font-size:11px;color:#555;margin-top:40px;letter-spacing:2px;text-transform:uppercase}' +
3152
+ '.toc{padding:40px 50px;border-bottom:1px solid #e0e0e0;page-break-after:always}' +
3153
+ '.toc h2{font-size:14px;text-transform:uppercase;letter-spacing:2px;color:#555;margin-bottom:16px}' +
3154
+ '.toc ol{margin:0;padding-left:20px;font-size:13px;line-height:2}' +
3155
+ '.section{padding:36px 50px;border-bottom:1px solid #f0f0f0;page-break-inside:avoid}' +
3156
+ '.section:last-child{border-bottom:none}' +
3157
+ '.agent-label{font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#888;font-weight:700;margin-bottom:14px}' +
3158
+ '.section-body{font-size:13px;line-height:1.8;color:#222}' +
3159
+ '.section-body h2{font-size:16px;font-weight:700;color:#111;margin:20px 0 8px}' +
3160
+ '.section-body h3{font-size:14px;font-weight:600;color:#333;margin:16px 0 6px}' +
3161
+ '.section-body ul{margin:8px 0;padding-left:20px}' +
3162
+ '.section-body li{margin-bottom:4px}' +
3163
+ '.section-body strong{font-weight:700}' +
3164
+ '.section-body p{margin:0 0 12px}' +
3165
+ '.canvas-note{background:#f9f9f9}' +
3166
+ '.footer-bar{padding:20px 50px;background:#f9f9f9;font-size:10px;color:#aaa;text-align:center;letter-spacing:1px}' +
3167
+ '@media print{body{-webkit-print-color-adjust:exact;print-color-adjust:exact}.cover{page-break-after:always}.toc{page-break-after:always}}' +
3168
+ '</style></head><body>' +
3169
+ '<div class="cover"><div class="brand">NotHumanAllowed — NHA Studio</div><h1>' + esc(task.length > 80 ? task.slice(0,80)+'...' : task) + '</h1><div class="meta">Generato il ' + today + ' &nbsp;·&nbsp; ' + nodes.filter(function(n){return n.agent!=='CanvasAgent'}).length + ' agenti</div><div class="task">' + esc(task) + '</div></div>' +
3170
+ '<div class="toc"><h2>Indice</h2><ol>' + nodes.filter(function(n){return n.output&&n.output!=='(no output)'&&n.agent!=='CanvasAgent'}).map(function(n){return '<li>' + esc(n.label||n.agent) + '</li>';}).join('') + '</ol></div>' +
3171
+ sectionsHtml + canvasNote +
3172
+ '<div class="footer-bar">NHA Studio &nbsp;·&nbsp; nothumanallowed.com &nbsp;·&nbsp; ' + today + '</div>' +
3173
+ '</body></html>';
3174
+
3175
+ var win = window.open('', '_blank');
3176
+ if (!win) { alert('Popup bloccato — abilita i popup per scaricare il PDF'); return; }
3177
+ win.document.write(html);
3178
+ win.document.close();
3179
+ win.onload = function() { setTimeout(function(){ win.print(); }, 300); };
3180
+ }
3181
+
3112
3182
  function renderStudioResult() {
3113
3183
  var el = document.getElementById('studioResult');
3114
3184
  if (!el) return;
@@ -3118,7 +3188,8 @@ function renderStudioResult() {
3118
3188
  var body = hasCanvas
3119
3189
  ? '<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap"><span style="color:var(--dim);font-size:13px">&#10003; ' + t('canvas_generated') + '</span><button onclick="openCanvasPanel()" style="padding:6px 14px;background:var(--greendim);border:1px solid var(--green3);border-radius:8px;color:var(--green);font-size:12px;cursor:pointer;font-weight:700">&#x25A3; ' + t('canvas_open') + '</button></div>'
3120
3190
  : '<div class="md-body">' + renderMd(studioState.result) + '</div>';
3121
- el.innerHTML = '<div class="studio-result__title">&#10003; ' + t('workflow_complete') + '</div>' + body;
3191
+ var dlBtn = '<button onclick="downloadStudioPDF()" title="Scarica il workflow come PDF" style="margin-top:10px;padding:6px 14px;background:none;border:1px solid var(--border);border-radius:8px;color:var(--dim);font-size:11px;cursor:pointer;font-family:var(--mono);letter-spacing:.5px">&#x2913; Download PDF</button>';
3192
+ el.innerHTML = '<div class="studio-result__title">&#10003; ' + t('workflow_complete') + '</div>' + body + dlBtn;
3122
3193
  // Update canvas button style: bright green when canvas exists, dimmed otherwise
3123
3194
  var canvasBtn = document.getElementById('studioCanvasBtn');
3124
3195
  if (canvasBtn) {
@@ -3240,11 +3311,17 @@ async function runStudio() {
3240
3311
  }
3241
3312
 
3242
3313
  // Parliament mode: Round 2 cross-reading deliberation
3314
+ // Read from both DOM and studioState (supports mid-run activation via nudge)
3243
3315
  var parliamentChk = document.getElementById(\x27studioParliamentMode\x27);
3244
- if (parliamentChk && parliamentChk.checked && studioState.nodes.length >= 2) {
3316
+ var parliamentActive = studioState.parliamentMode || (parliamentChk && parliamentChk.checked);
3317
+ if (parliamentActive && studioState.nodes.length >= 1) {
3245
3318
  var proposals = studioState.nodes
3246
3319
  .filter(function(n) { return n.output && n.output !== \x27(no output)\x27 && n.agent !== \x27CanvasAgent\x27; })
3247
3320
  .map(function(n) { return {agent: n.agent, label: n.label, output: n.output}; });
3321
+ // Need at least 2 proposals for cross-reading; if only 1, include the full context as a second proposal
3322
+ if (proposals.length === 1 && context) {
3323
+ proposals.push({agent: \x27Context\x27, label: \x27Contesto workflow\x27, output: context});
3324
+ }
3248
3325
  if (proposals.length >= 2) {
3249
3326
  studioLog(\x27Parlamento\x27, \x27&#x2656;\x27, \x27Avvio deliberazione — Round 2 cross-reading tra agenti...\x27, \x27system\x27);
3250
3327
  var deliberateBody = JSON.stringify({task: task, proposals: proposals, language: document.getElementById(\x27langSelect\x27) ? document.getElementById(\x27langSelect\x27).value : \x27it\x27});