nothumanallowed 13.2.47 → 13.2.50
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 +1 -1
- package/src/commands/ui.mjs +62 -12
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +130 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.50",
|
|
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": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
2851
|
-
${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context
|
|
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
|
|
2878
|
-
${context ? `## OUTPUT FROM PREVIOUS AGENTS:\n${context
|
|
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
|
-
//
|
|
2895
|
-
|
|
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:
|
|
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
|
-
//
|
|
2908
|
-
|
|
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
|
|
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.
|
|
8
|
+
export const VERSION = '13.2.50';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -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';
|
|
@@ -639,7 +644,16 @@ function onConversationSwitch(){
|
|
|
639
644
|
|
|
640
645
|
function openCanvasPanel(){
|
|
641
646
|
var cp = document.getElementById('canvasPanel');
|
|
642
|
-
if (cp)
|
|
647
|
+
if (!cp) return;
|
|
648
|
+
cp.classList.add('open');
|
|
649
|
+
// If no canvas data, show a tip in the frame area
|
|
650
|
+
if (!studioState.canvas) {
|
|
651
|
+
var cf = document.getElementById('canvasFrame');
|
|
652
|
+
if (cf) {
|
|
653
|
+
var tip = \x27<!DOCTYPE html><html><body style="background:#0a0a0a;color:#6b7280;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;text-align:center;padding:20px"><div><div style="font-size:32px;margin-bottom:16px">■</div><div style="font-size:13px;line-height:1.6">Nessun Canvas in questo workflow.<br>Aggiungi <strong style=\x22color:#4ade80\x22>html</strong>, <strong style=\x22color:#4ade80\x22>dashboard</strong> o <strong style=\x22color:#4ade80\x22>visual</strong> al prompt,<br>oppure usa un task con 2+ agenti specialisti.</div></div></body></html>\x27;
|
|
654
|
+
cf.srcdoc = tip;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
643
657
|
}
|
|
644
658
|
|
|
645
659
|
function reopenCanvas(){
|
|
@@ -697,8 +711,18 @@ function canvasCopyImage(){
|
|
|
697
711
|
}
|
|
698
712
|
function toggleCanvasSize(){
|
|
699
713
|
var p=document.getElementById('canvasPanel');if(!p)return;
|
|
700
|
-
if(p.
|
|
701
|
-
|
|
714
|
+
if(p.dataset.expanded==='1'){
|
|
715
|
+
p.dataset.expanded='';
|
|
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='';
|
|
720
|
+
} else {
|
|
721
|
+
p.dataset.expanded='1';
|
|
722
|
+
p.style.width='80vw';p.style.height='80vh';
|
|
723
|
+
p.style.top='10vh';p.style.left='50%';p.style.right='auto';
|
|
724
|
+
p.style.transform='translateX(-50%)';
|
|
725
|
+
}
|
|
702
726
|
}
|
|
703
727
|
// ---- MSG ACTIONS ----
|
|
704
728
|
function copyMsg(i){
|
|
@@ -3006,6 +3030,8 @@ function studioReset() {
|
|
|
3006
3030
|
studioState.running = false;
|
|
3007
3031
|
studioState.planned = false;
|
|
3008
3032
|
studioTokens = {in:0, out:0};
|
|
3033
|
+
var nudgeEl = document.getElementById(\x27studioParliamentNudge\x27);
|
|
3034
|
+
if (nudgeEl) nudgeEl.remove();
|
|
3009
3035
|
var ta = document.getElementById('studioTaskInput');
|
|
3010
3036
|
if (ta) ta.value = '';
|
|
3011
3037
|
var tb = document.getElementById('studioTokenBar');
|
|
@@ -3091,6 +3117,68 @@ function renderStudioLog() {
|
|
|
3091
3117
|
el.scrollTop = el.scrollHeight;
|
|
3092
3118
|
}
|
|
3093
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,'&').replace(/</g,'<').replace(/>/g,'>')
|
|
3130
|
+
.replace(/\*\*(.*?)\*\*/g,'<strong>$1</strong>')
|
|
3131
|
+
.replace(/\*(.*?)\*/g,'<em>$1</em>')
|
|
3132
|
+
.replace(/^#{3}\s+(.+)$/gm,'<h3>$1</h3>')
|
|
3133
|
+
.replace(/^#{2}\s+(.+)$/gm,'<h2>$1</h2>')
|
|
3134
|
+
.replace(/^#{1}\s+(.+)$/gm,'<h2>$1</h2>')
|
|
3135
|
+
.replace(/^-\s+(.+)$/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">■ 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 + ' · ' + 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 · nothumanallowed.com · ' + 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
|
+
|
|
3094
3182
|
function renderStudioResult() {
|
|
3095
3183
|
var el = document.getElementById('studioResult');
|
|
3096
3184
|
if (!el) return;
|
|
@@ -3100,10 +3188,23 @@ function renderStudioResult() {
|
|
|
3100
3188
|
var body = hasCanvas
|
|
3101
3189
|
? '<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap"><span style="color:var(--dim);font-size:13px">✓ ' + 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">▣ ' + t('canvas_open') + '</button></div>'
|
|
3102
3190
|
: '<div class="md-body">' + renderMd(studioState.result) + '</div>';
|
|
3103
|
-
|
|
3104
|
-
|
|
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">⤓ Download PDF</button>';
|
|
3192
|
+
el.innerHTML = '<div class="studio-result__title">✓ ' + t('workflow_complete') + '</div>' + body + dlBtn;
|
|
3193
|
+
// Update canvas button style: bright green when canvas exists, dimmed otherwise
|
|
3105
3194
|
var canvasBtn = document.getElementById('studioCanvasBtn');
|
|
3106
|
-
if (canvasBtn)
|
|
3195
|
+
if (canvasBtn) {
|
|
3196
|
+
if (hasCanvas) {
|
|
3197
|
+
canvasBtn.style.background = 'var(--greendim)';
|
|
3198
|
+
canvasBtn.style.borderColor = 'var(--green3)';
|
|
3199
|
+
canvasBtn.style.color = 'var(--green)';
|
|
3200
|
+
canvasBtn.title = t(\x27canvas_open\x27);
|
|
3201
|
+
} else {
|
|
3202
|
+
canvasBtn.style.background = \x27none\x27;
|
|
3203
|
+
canvasBtn.style.borderColor = \x27var(--border)\x27;
|
|
3204
|
+
canvasBtn.style.color = \x27var(--dim)\x27;
|
|
3205
|
+
canvasBtn.title = \x27Canvas non disponibile per questo workflow\x27;
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3107
3208
|
}
|
|
3108
3209
|
|
|
3109
3210
|
function studioSetNodeStatus(idx, status) {
|
|
@@ -3158,6 +3259,21 @@ async function runStudio() {
|
|
|
3158
3259
|
renderStudioNodes();
|
|
3159
3260
|
studioLog('Studio', '✓', 'Workflow planned: ' + planRes.steps.map(function(s){return s.label}).join(' -> '), 'system');
|
|
3160
3261
|
|
|
3262
|
+
// Parliament suggestion: show nudge if 3+ specialist steps and Parliament not already enabled
|
|
3263
|
+
var specialistAgents = planRes.steps.filter(function(s){ return !['WebSearchAgent','EmailAgent','CalendarAgent','GitHubAgent','SlackAgent','NotionAgent','CanvasAgent','HERALD'].includes(s.agent); });
|
|
3264
|
+
var parliamentChkEarly = document.getElementById(\x27studioParliamentMode\x27);
|
|
3265
|
+
if (specialistAgents.length >= 2 && parliamentChkEarly && !parliamentChkEarly.checked) {
|
|
3266
|
+
var nudge = document.getElementById(\x27studioParliamentNudge\x27);
|
|
3267
|
+
if (!nudge) {
|
|
3268
|
+
nudge = document.createElement(\x27div\x27);
|
|
3269
|
+
nudge.id = \x27studioParliamentNudge\x27;
|
|
3270
|
+
nudge.style.cssText = \x27margin:8px 0;padding:8px 12px;background:#1a1a2e;border:1px solid #6366f1;border-radius:8px;font-size:11px;color:#a5b4fc;display:flex;align-items:center;gap:10px\x27;
|
|
3271
|
+
nudge.innerHTML = \x27♖ <span><strong>Suggerimento:</strong> questo workflow ha \x27 + specialistAgents.length + \x27 agenti specialisti — attiva <strong>Parlamento</strong> per un confronto critico tra le loro analisi.</span><button onclick="document.getElementById(\\\x27studioParliamentMode\\\x27).checked=true;studioState.parliamentMode=true;this.parentNode.remove()" style="margin-left:auto;background:#6366f1;border:none;border-radius:6px;color:#fff;padding:4px 10px;cursor:pointer;font-size:10px;white-space:nowrap">Attiva ♖</button>\x27;
|
|
3272
|
+
var tokenBar = document.getElementById(\x27studioTokenBar\x27);
|
|
3273
|
+
if (tokenBar && tokenBar.parentNode) tokenBar.parentNode.insertBefore(nudge, tokenBar.parentNode.firstChild);
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
|
|
3161
3277
|
// Step 2: execute each step via SSE
|
|
3162
3278
|
var context = '';
|
|
3163
3279
|
for (var i = 0; i < studioState.nodes.length; i++) {
|
|
@@ -3195,11 +3311,17 @@ async function runStudio() {
|
|
|
3195
3311
|
}
|
|
3196
3312
|
|
|
3197
3313
|
// Parliament mode: Round 2 cross-reading deliberation
|
|
3314
|
+
// Read from both DOM and studioState (supports mid-run activation via nudge)
|
|
3198
3315
|
var parliamentChk = document.getElementById(\x27studioParliamentMode\x27);
|
|
3199
|
-
|
|
3316
|
+
var parliamentActive = studioState.parliamentMode || (parliamentChk && parliamentChk.checked);
|
|
3317
|
+
if (parliamentActive && studioState.nodes.length >= 1) {
|
|
3200
3318
|
var proposals = studioState.nodes
|
|
3201
3319
|
.filter(function(n) { return n.output && n.output !== \x27(no output)\x27 && n.agent !== \x27CanvasAgent\x27; })
|
|
3202
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
|
+
}
|
|
3203
3325
|
if (proposals.length >= 2) {
|
|
3204
3326
|
studioLog(\x27Parlamento\x27, \x27♖\x27, \x27Avvio deliberazione — Round 2 cross-reading tra agenti...\x27, \x27system\x27);
|
|
3205
3327
|
var deliberateBody = JSON.stringify({task: task, proposals: proposals, language: document.getElementById(\x27langSelect\x27) ? document.getElementById(\x27langSelect\x27).value : \x27it\x27});
|
|
@@ -3584,7 +3706,7 @@ function renderStudio(el) {
|
|
|
3584
3706
|
|
|
3585
3707
|
'<div style="display:flex;align-items:center;gap:8px;margin:8px 0">' +
|
|
3586
3708
|
'<div id="studioTokenBar" style="font-size:10px;color:var(--dim);font-family:var(--mono);flex:1"></div>' +
|
|
3587
|
-
'<button id="studioCanvasBtn" onclick="openCanvasPanel()" style="
|
|
3709
|
+
'<button id="studioCanvasBtn" onclick="openCanvasPanel()" title="' + t('canvas_open') + '" style="font-size:12px;padding:5px 14px;background:none;border:1px solid var(--border);border-radius:6px;color:var(--dim);cursor:pointer;font-weight:700;transition:all .2s">■ Canvas</button>' +
|
|
3588
3710
|
'</div>' +
|
|
3589
3711
|
'<div class="studio-canvas" id="studioNodes"></div>' +
|
|
3590
3712
|
'<div class="studio-log" id="studioLog" style="display:none"></div>' +
|