nothumanallowed 13.2.24 → 13.2.26
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 +25 -8
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +158 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.26",
|
|
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
|
@@ -2562,19 +2562,36 @@ Example output:
|
|
|
2562
2562
|
{"steps":[{"icon":"🔍","agent":"WebSearchAgent","label":"Cerca notizie","prompt":"Cerca le ultime notizie su intelligenza artificiale oggi"},{"icon":"📰","agent":"HERALD","label":"Analisi notizie","prompt":"Analizza le notizie trovate e crea un briefing esecutivo"},{"icon":"📊","agent":"CanvasAgent","label":"Dashboard HTML","prompt":"Crea una dashboard HTML visuale con i risultati"}]}`;
|
|
2563
2563
|
|
|
2564
2564
|
try {
|
|
2565
|
-
|
|
2565
|
+
// Force thinking OFF for planner — we need deterministic JSON, not reasoning chains
|
|
2566
|
+
const planConfig = Object.assign({}, config, { thinking: 'off' });
|
|
2567
|
+
const planRaw = await callLLM(planConfig, 'You are a JSON workflow planner. Output ONLY valid JSON. No thinking, no explanation, no markdown.', planPrompt, { max_tokens: 1500 });
|
|
2568
|
+
process.stderr.write('[STUDIO PLAN RAW] ' + planRaw.slice(0, 400) + '\n');
|
|
2566
2569
|
let steps;
|
|
2567
2570
|
try {
|
|
2568
|
-
// Strip <think>...</think> blocks
|
|
2569
|
-
let clean = planRaw
|
|
2570
|
-
|
|
2571
|
+
// Strip ALL <think>...</think> blocks (greedy — handles nested/multiple)
|
|
2572
|
+
let clean = planRaw;
|
|
2573
|
+
let prev = '';
|
|
2574
|
+
while (prev !== clean) { prev = clean; clean = clean.replace(/<think>[\s\S]*?<\/think>/g, ''); }
|
|
2575
|
+
clean = clean.trim();
|
|
2576
|
+
// Strip markdown fences
|
|
2577
|
+
clean = clean.replace(/^```[\w]*\r?\n?/,'').replace(/\r?\n?```$/,'').trim();
|
|
2578
|
+
// Extract first complete JSON object
|
|
2571
2579
|
const jsonMatch = clean.match(/\{[\s\S]*\}/);
|
|
2572
2580
|
const parsed = JSON.parse(jsonMatch ? jsonMatch[0] : clean);
|
|
2573
2581
|
steps = parsed.steps;
|
|
2574
|
-
} catch {
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2582
|
+
} catch (parseErr) {
|
|
2583
|
+
process.stderr.write('[STUDIO PLAN PARSE ERR] ' + parseErr.message + '\n');
|
|
2584
|
+
// Fallback: build a sensible default plan from the task keywords
|
|
2585
|
+
const hasEmail = /email|mail/i.test(task);
|
|
2586
|
+
const hasCalendar = /calendar|agenda|calendari/i.test(task);
|
|
2587
|
+
const hasSearch = /cerca|search|notizie|news/i.test(task);
|
|
2588
|
+
const hasCanvas = /html|dashboard|visua|report/i.test(task);
|
|
2589
|
+
steps = [];
|
|
2590
|
+
if (hasEmail) steps.push({icon:'📧',agent:'EmailAgent',label:'Controlla email',prompt:task});
|
|
2591
|
+
if (hasCalendar) steps.push({icon:'📅',agent:'CalendarAgent',label:'Rivedi calendario',prompt:task});
|
|
2592
|
+
if (hasSearch || steps.length === 0) steps.push({icon:'🔍',agent:'WebSearchAgent',label:'Ricerca web',prompt:task});
|
|
2593
|
+
steps.push({icon:'📰',agent:'HERALD',label:'Analisi e briefing',prompt:task});
|
|
2594
|
+
if (hasCanvas) steps.push({icon:'📊',agent:'CanvasAgent',label:'Dashboard HTML',prompt:task});
|
|
2578
2595
|
}
|
|
2579
2596
|
if (!Array.isArray(steps) || !steps.length) {
|
|
2580
2597
|
sendJSON(res, 500, { error: 'Empty workflow plan' });
|
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.26';
|
|
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
|
@@ -2275,8 +2275,8 @@ function renderSettings(el) {
|
|
|
2275
2275
|
['profile-notes', 'Notes', 'Anything else agents should know about you'],
|
|
2276
2276
|
]) +
|
|
2277
2277
|
'<div style="padding:12px 16px;margin-bottom:16px;background:var(--amberdim);border:1px solid var(--amber3);border-radius:8px"><span style="font-family:var(--term);color:var(--amber);font-size:13px;font-weight:700">NHA Free (Liara)</span><div style="font-size:11px;color:var(--dim);margin:4px 0 8px">Powered by Qwen3 32B. Free, no API key needed. Slower (5-15s).</div><button onclick="apiPost(\\x27/api/config\\x27,{key:\\x27provider\\x27,value:\\x27nha\\x27}).then(function(){location.reload()})" style="padding:6px 16px;background:var(--amber3);color:var(--bg);border:none;border-radius:6px;cursor:pointer;font-family:var(--mono);font-size:11px;font-weight:700">Use NHA Free</button></div>' +
|
|
2278
|
-
settingsSection('language', 'Language / Lingua', '
|
|
2279
|
-
['lang', 'Language', '
|
|
2278
|
+
settingsSection('language', 'Language / Lingua', 'Select the language used by all agents and Studio workflows.', [
|
|
2279
|
+
['lang', 'Language', ''],
|
|
2280
2280
|
]) +
|
|
2281
2281
|
settingsSection('llm', 'LLM Provider', 'Or use your own API key for faster, more capable responses.', [
|
|
2282
2282
|
['provider', 'Provider', 'nha (free) / anthropic / openai / gemini / deepseek / grok / mistral'],
|
|
@@ -2345,6 +2345,35 @@ function settingsSection(id, title, desc, fields) {
|
|
|
2345
2345
|
h += '<option value="' + providers[pi].value + '"' + sel + '>' + providers[pi].label + '</option>';
|
|
2346
2346
|
}
|
|
2347
2347
|
h += '</select>';
|
|
2348
|
+
} else if (key === 'lang') {
|
|
2349
|
+
var langs = [
|
|
2350
|
+
{value:'it',label:'🇮🇹 Italiano'},
|
|
2351
|
+
{value:'en',label:'🇬🇧 English'},
|
|
2352
|
+
{value:'es',label:'🇪🇸 Español'},
|
|
2353
|
+
{value:'fr',label:'🇫🇷 Français'},
|
|
2354
|
+
{value:'de',label:'🇩🇪 Deutsch'},
|
|
2355
|
+
{value:'pt',label:'🇵🇹 Português'},
|
|
2356
|
+
{value:'nl',label:'🇳🇱 Nederlands'},
|
|
2357
|
+
{value:'pl',label:'🇵🇱 Polski'},
|
|
2358
|
+
{value:'ru',label:'🇷🇺 Русский'},
|
|
2359
|
+
{value:'zh',label:'🇨🇳 中文'},
|
|
2360
|
+
{value:'ja',label:'🇯🇵 日本語'},
|
|
2361
|
+
{value:'ko',label:'🇰🇷 한국어'},
|
|
2362
|
+
{value:'ar',label:'🇸🇦 العربية'},
|
|
2363
|
+
{value:'hi',label:'🇮🇳 हिन्दी'},
|
|
2364
|
+
{value:'tr',label:'🇹🇷 Türkçe'},
|
|
2365
|
+
{value:'sv',label:'🇸🇪 Svenska'},
|
|
2366
|
+
{value:'da',label:'🇩🇰 Dansk'},
|
|
2367
|
+
{value:'fi',label:'🇫🇮 Suomi'},
|
|
2368
|
+
{value:'cs',label:'🇨🇿 Čeština'},
|
|
2369
|
+
];
|
|
2370
|
+
var curLang = currentVal || 'it';
|
|
2371
|
+
h += '<select style="width:100%;padding:8px 12px;font-size:13px;background:var(--bg);color:var(--fg);border:1px solid var(--border2);border-radius:var(--r)" data-config-key="lang" data-section="' + esc(id) + '">';
|
|
2372
|
+
for (var li=0;li<langs.length;li++) {
|
|
2373
|
+
var lsel = curLang === langs[li].value ? ' selected' : '';
|
|
2374
|
+
h += '<option value="' + langs[li].value + '"' + lsel + '>' + langs[li].label + '</option>';
|
|
2375
|
+
}
|
|
2376
|
+
h += '</select>';
|
|
2348
2377
|
} else if (key === 'thinking') {
|
|
2349
2378
|
// Dropdown for thinking toggle
|
|
2350
2379
|
h += '<select style="width:100%;padding:8px 12px;font-size:13px;background:var(--bg);color:var(--fg);border:1px solid var(--border2);border-radius:var(--r)" data-config-key="thinking" data-section="' + esc(id) + '">' +
|
|
@@ -2404,13 +2433,22 @@ function saveSettingsSection(sectionId) {
|
|
|
2404
2433
|
var allOk = results.every(function(r) { return r; });
|
|
2405
2434
|
if (statusEl) {
|
|
2406
2435
|
if (allOk) {
|
|
2407
|
-
|
|
2436
|
+
if (sectionId === 'language') {
|
|
2437
|
+
var langNames = {it:'Italiano',en:'English',es:'Español',fr:'Français',de:'Deutsch',pt:'Português',nl:'Nederlands',pl:'Polski',ru:'Русский',zh:'中文',ja:'日本語',ko:'한국어',ar:'العربية',hi:'हिन्दी',tr:'Türkçe',sv:'Svenska',da:'Dansk',fi:'Suomi',cs:'Čeština'};
|
|
2438
|
+
try {
|
|
2439
|
+
var cfg2 = JSON.parse(localStorage.getItem('nha_config_cache') || '{}');
|
|
2440
|
+
var ln = langNames[cfg2.lang] || cfg2.lang || 'Italian';
|
|
2441
|
+
statusEl.textContent = '✓ Language set to ' + ln + '. All agents and Studio will now respond in ' + ln + '.';
|
|
2442
|
+
} catch(e) { statusEl.textContent = '✓ Saved!'; }
|
|
2443
|
+
} else {
|
|
2444
|
+
statusEl.textContent = 'Saved!';
|
|
2445
|
+
}
|
|
2408
2446
|
statusEl.style.color = 'var(--green)';
|
|
2409
2447
|
} else {
|
|
2410
2448
|
statusEl.textContent = 'Some fields failed to save.';
|
|
2411
2449
|
statusEl.style.color = 'var(--red)';
|
|
2412
2450
|
}
|
|
2413
|
-
setTimeout(function() { statusEl.textContent = ''; },
|
|
2451
|
+
setTimeout(function() { statusEl.textContent = ''; }, 4000);
|
|
2414
2452
|
}
|
|
2415
2453
|
});
|
|
2416
2454
|
}
|
|
@@ -2711,6 +2749,104 @@ function stopVoiceInput() {
|
|
|
2711
2749
|
}
|
|
2712
2750
|
|
|
2713
2751
|
// ---- STUDIO ----
|
|
2752
|
+
// ── i18n — UI string translations ────────────────────────────────────────────
|
|
2753
|
+
var I18N = {
|
|
2754
|
+
en: {
|
|
2755
|
+
chat:'Chat', studio:'Studio', settings:'Settings', agents:'Agents',
|
|
2756
|
+
run:'▶ Run', stop:'⬛ Stop', reset:'New workflow',
|
|
2757
|
+
placeholder_chat:'Message NHA... (Enter to send)',
|
|
2758
|
+
placeholder_studio:'Describe what you want to accomplish... (Ctrl+Enter to run)',
|
|
2759
|
+
planning:'Planning...', workflow_complete:'Workflow complete.',
|
|
2760
|
+
workflow_stopped:'Workflow stopped by user.',
|
|
2761
|
+
canvas_open:'Open Canvas', canvas_generated:'HTML Dashboard generated in Canvas panel.',
|
|
2762
|
+
saved:'Saved!', lang_set:'Language set to',
|
|
2763
|
+
agents_respond:'All agents will respond in',
|
|
2764
|
+
examples:'Examples', recent_sessions:'Recent sessions',
|
|
2765
|
+
restore:'Restore', delete:'Delete',
|
|
2766
|
+
send:'Send', attach:'Attach',
|
|
2767
|
+
settings_save:'Save',
|
|
2768
|
+
no_output:'(no output)', done:'(done)',
|
|
2769
|
+
token_label:'Tokens',
|
|
2770
|
+
},
|
|
2771
|
+
it: {
|
|
2772
|
+
chat:'Chat', studio:'Studio', settings:'Impostazioni', agents:'Agenti',
|
|
2773
|
+
run:'▶ Avvia', stop:'⬛ Ferma', reset:'Nuovo workflow',
|
|
2774
|
+
placeholder_chat:'Scrivi a NHA... (Invio per inviare)',
|
|
2775
|
+
placeholder_studio:'Descrivi cosa vuoi fare... (Ctrl+Invio per avviare)',
|
|
2776
|
+
planning:'Pianificazione...', workflow_complete:'Workflow completato.',
|
|
2777
|
+
workflow_stopped:'Workflow fermato dall\'utente.',
|
|
2778
|
+
canvas_open:'Apri Canvas', canvas_generated:'Dashboard HTML generata nel pannello Canvas.',
|
|
2779
|
+
saved:'Salvato!', lang_set:'Lingua impostata su',
|
|
2780
|
+
agents_respond:'Tutti gli agenti risponderanno in',
|
|
2781
|
+
examples:'Esempi', recent_sessions:'Sessioni recenti',
|
|
2782
|
+
restore:'Ripristina', delete:'Elimina',
|
|
2783
|
+
send:'Invia', attach:'Allega',
|
|
2784
|
+
settings_save:'Salva',
|
|
2785
|
+
no_output:'(nessun output)', done:'(completato)',
|
|
2786
|
+
token_label:'Token',
|
|
2787
|
+
},
|
|
2788
|
+
es: {
|
|
2789
|
+
chat:'Chat', studio:'Studio', settings:'Configuración', agents:'Agentes',
|
|
2790
|
+
run:'▶ Ejecutar', stop:'⬛ Detener', reset:'Nuevo flujo',
|
|
2791
|
+
placeholder_chat:'Mensaje a NHA... (Enter para enviar)',
|
|
2792
|
+
placeholder_studio:'Describe lo que quieres hacer... (Ctrl+Enter para ejecutar)',
|
|
2793
|
+
planning:'Planificando...', workflow_complete:'Flujo completado.',
|
|
2794
|
+
workflow_stopped:'Flujo detenido por el usuario.',
|
|
2795
|
+
canvas_open:'Abrir Canvas', canvas_generated:'Panel HTML generado en Canvas.',
|
|
2796
|
+
saved:'¡Guardado!', lang_set:'Idioma establecido en',
|
|
2797
|
+
agents_respond:'Todos los agentes responderán en',
|
|
2798
|
+
examples:'Ejemplos', recent_sessions:'Sesiones recientes',
|
|
2799
|
+
restore:'Restaurar', delete:'Eliminar',
|
|
2800
|
+
send:'Enviar', attach:'Adjuntar',
|
|
2801
|
+
settings_save:'Guardar',
|
|
2802
|
+
no_output:'(sin salida)', done:'(hecho)',
|
|
2803
|
+
token_label:'Tokens',
|
|
2804
|
+
},
|
|
2805
|
+
fr: {
|
|
2806
|
+
chat:'Chat', studio:'Studio', settings:'Paramètres', agents:'Agents',
|
|
2807
|
+
run:'▶ Lancer', stop:'⬛ Arrêter', reset:'Nouveau flux',
|
|
2808
|
+
placeholder_chat:'Message à NHA... (Entrée pour envoyer)',
|
|
2809
|
+
placeholder_studio:'Décrivez ce que vous voulez faire... (Ctrl+Entrée pour lancer)',
|
|
2810
|
+
planning:'Planification...', workflow_complete:'Flux terminé.',
|
|
2811
|
+
workflow_stopped:'Flux arrêté par l\'utilisateur.',
|
|
2812
|
+
canvas_open:'Ouvrir Canvas', canvas_generated:'Tableau de bord HTML généré dans Canvas.',
|
|
2813
|
+
saved:'Sauvegardé!', lang_set:'Langue définie sur',
|
|
2814
|
+
agents_respond:'Tous les agents répondront en',
|
|
2815
|
+
examples:'Exemples', recent_sessions:'Sessions récentes',
|
|
2816
|
+
restore:'Restaurer', delete:'Supprimer',
|
|
2817
|
+
send:'Envoyer', attach:'Joindre',
|
|
2818
|
+
settings_save:'Sauvegarder',
|
|
2819
|
+
no_output:'(aucune sortie)', done:'(terminé)',
|
|
2820
|
+
token_label:'Tokens',
|
|
2821
|
+
},
|
|
2822
|
+
de: {
|
|
2823
|
+
chat:'Chat', studio:'Studio', settings:'Einstellungen', agents:'Agenten',
|
|
2824
|
+
run:'▶ Starten', stop:'⬛ Stopp', reset:'Neuer Workflow',
|
|
2825
|
+
placeholder_chat:'Nachricht an NHA... (Enter zum Senden)',
|
|
2826
|
+
placeholder_studio:'Beschreibe was du tun möchtest... (Strg+Enter zum Starten)',
|
|
2827
|
+
planning:'Planung...', workflow_complete:'Workflow abgeschlossen.',
|
|
2828
|
+
workflow_stopped:'Workflow vom Benutzer gestoppt.',
|
|
2829
|
+
canvas_open:'Canvas öffnen', canvas_generated:'HTML-Dashboard im Canvas-Panel generiert.',
|
|
2830
|
+
saved:'Gespeichert!', lang_set:'Sprache auf',
|
|
2831
|
+
agents_respond:'Alle Agenten antworten auf',
|
|
2832
|
+
examples:'Beispiele', recent_sessions:'Letzte Sitzungen',
|
|
2833
|
+
restore:'Wiederherstellen', delete:'Löschen',
|
|
2834
|
+
send:'Senden', attach:'Anhängen',
|
|
2835
|
+
settings_save:'Speichern',
|
|
2836
|
+
no_output:'(keine Ausgabe)', done:'(erledigt)',
|
|
2837
|
+
token_label:'Token',
|
|
2838
|
+
},
|
|
2839
|
+
};
|
|
2840
|
+
// Fallback to 'en' for unmapped languages
|
|
2841
|
+
function t(key) {
|
|
2842
|
+
try {
|
|
2843
|
+
var cfg = JSON.parse(localStorage.getItem('nha_config_cache') || '{}');
|
|
2844
|
+
var lang = (cfg.lang || 'it').slice(0,2);
|
|
2845
|
+
var map = I18N[lang] || I18N.en;
|
|
2846
|
+
return map[key] || I18N.en[key] || key;
|
|
2847
|
+
} catch(e) { return I18N.en[key] || key; }
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2714
2850
|
var studioState = {
|
|
2715
2851
|
task: '',
|
|
2716
2852
|
nodes: [], // [{icon,agent,label,status:'waiting'|'running'|'done'|'error'}]
|
|
@@ -2727,10 +2863,10 @@ function stopStudio() {
|
|
|
2727
2863
|
if (studioAbortController) { try { studioAbortController.abort(); } catch(e) {} studioAbortController = null; }
|
|
2728
2864
|
studioState.running = false;
|
|
2729
2865
|
var btn = document.getElementById('studioRunBtn');
|
|
2730
|
-
if (btn) { btn.disabled = false; btn.textContent = '
|
|
2866
|
+
if (btn) { btn.disabled = false; btn.textContent = t('run'); }
|
|
2731
2867
|
var stopBtn = document.getElementById('studioStopBtn');
|
|
2732
2868
|
if (stopBtn) stopBtn.style.display = 'none';
|
|
2733
|
-
studioLog('Studio', '⬛', '
|
|
2869
|
+
studioLog('Studio', '⬛', t('workflow_stopped'), 'system');
|
|
2734
2870
|
// Mark any still-running nodes as error
|
|
2735
2871
|
studioState.nodes.forEach(function(n) { if (n.status === 'running') n.status = 'error'; });
|
|
2736
2872
|
renderStudioNodes();
|
|
@@ -2837,7 +2973,7 @@ function renderStudioResult() {
|
|
|
2837
2973
|
el.style.display = 'block';
|
|
2838
2974
|
var isHtml = studioState.result.trimStart().startsWith('<');
|
|
2839
2975
|
var body = isHtml
|
|
2840
|
-
? '<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap"><span style="color:var(--dim);font-size:13px">✓
|
|
2976
|
+
? '<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>'
|
|
2841
2977
|
: '<div class="md-body">' + renderMd(studioState.result) + '</div>';
|
|
2842
2978
|
el.innerHTML = '<div class="studio-result__title">✓ Workflow completato</div>' + body;
|
|
2843
2979
|
}
|
|
@@ -2868,7 +3004,7 @@ async function runStudio() {
|
|
|
2868
3004
|
studioAbortController = new AbortController();
|
|
2869
3005
|
|
|
2870
3006
|
var btn = document.getElementById('studioRunBtn');
|
|
2871
|
-
if (btn) { btn.disabled = true; btn.textContent = '
|
|
3007
|
+
if (btn) { btn.disabled = true; btn.textContent = t('planning'); }
|
|
2872
3008
|
var stopBtn = document.getElementById('studioStopBtn');
|
|
2873
3009
|
if (stopBtn) stopBtn.style.display = '';
|
|
2874
3010
|
|
|
@@ -2931,7 +3067,7 @@ async function runStudio() {
|
|
|
2931
3067
|
// Final result is the last step's output
|
|
2932
3068
|
studioState.result = context;
|
|
2933
3069
|
renderStudioResult();
|
|
2934
|
-
studioLog('Studio', '🎉', '
|
|
3070
|
+
studioLog('Studio', '🎉', t('workflow_complete'), 'system');
|
|
2935
3071
|
|
|
2936
3072
|
// Save session to localStorage for reuse in Chat
|
|
2937
3073
|
saveStudioSession(task, studioState.nodes, studioState.log, context);
|
|
@@ -2977,7 +3113,7 @@ function renderStudioSessionsBar() {
|
|
|
2977
3113
|
var sessions = loadStudioSessions();
|
|
2978
3114
|
if (!sessions.length) { el.style.display = 'none'; return; }
|
|
2979
3115
|
el.style.display = 'block';
|
|
2980
|
-
el.innerHTML = '<div style="font-size:10px;color:var(--dim);margin-bottom:8px;text-transform:uppercase;letter-spacing:1px">
|
|
3116
|
+
el.innerHTML = '<div style="font-size:10px;color:var(--dim);margin-bottom:8px;text-transform:uppercase;letter-spacing:1px">' + t('recent_sessions') + '</div>' +
|
|
2981
3117
|
'<div style="max-height:220px;overflow-y:auto;padding-right:4px">' +
|
|
2982
3118
|
sessions.map(function(s,i) {
|
|
2983
3119
|
return '<div class="studio-session-item">' +
|
|
@@ -3042,8 +3178,13 @@ var studioTokens = {in: 0, out: 0};
|
|
|
3042
3178
|
function studioAddTokens(inp, out) {
|
|
3043
3179
|
studioTokens.in += (inp||0);
|
|
3044
3180
|
studioTokens.out += (out||0);
|
|
3181
|
+
studioUpdateTokenBar();
|
|
3182
|
+
}
|
|
3183
|
+
function studioUpdateTokenBar() {
|
|
3045
3184
|
var el = document.getElementById('studioTokenBar');
|
|
3046
|
-
if (el)
|
|
3185
|
+
if (!el) return;
|
|
3186
|
+
if (studioTokens.in === 0 && studioTokens.out === 0) { el.textContent = ''; return; }
|
|
3187
|
+
el.textContent = '⬆ ' + studioTokens.in.toLocaleString() + ' in ⬇ ' + studioTokens.out.toLocaleString() + ' out';
|
|
3047
3188
|
}
|
|
3048
3189
|
|
|
3049
3190
|
function runStudioStep(idx, node, task, context, stepDef, signal) {
|
|
@@ -3104,6 +3245,7 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
|
|
|
3104
3245
|
if (scb) scb.style.display = '';
|
|
3105
3246
|
}
|
|
3106
3247
|
if (ev.usage) { studioAddTokens(ev.usage.input||0, ev.usage.output||0); }
|
|
3248
|
+
else if (ev.token && !isStatus) { studioTokens.out += Math.ceil(ev.token.length/4); studioUpdateTokenBar(); }
|
|
3107
3249
|
if (ev.done) { resolve({output: output || '(no output)', canvas: canvasHtml}); return; }
|
|
3108
3250
|
if (ev.error) { resolve({error: ev.error}); return; }
|
|
3109
3251
|
} catch(e) {}
|
|
@@ -3218,15 +3360,15 @@ function renderStudio(el) {
|
|
|
3218
3360
|
// ── AUTO MODE ──
|
|
3219
3361
|
'<div id="studioAutoMode">' +
|
|
3220
3362
|
'<div style="margin-bottom:10px">' +
|
|
3221
|
-
'<div style="font-size:10px;color:var(--dim);margin-bottom:6px;text-transform:uppercase;letter-spacing:1px">
|
|
3363
|
+
'<div style="font-size:10px;color:var(--dim);margin-bottom:6px;text-transform:uppercase;letter-spacing:1px">' + t('examples') + '</div>' +
|
|
3222
3364
|
examplesHtml +
|
|
3223
3365
|
'</div>' +
|
|
3224
3366
|
'<div class="studio-input-row">' +
|
|
3225
|
-
'<textarea id="studioTaskInput" placeholder="
|
|
3367
|
+
'<textarea id="studioTaskInput" placeholder="' + t('placeholder_studio') + '" onkeydown="if(event.key===\\x27Enter\\x27&&(event.ctrlKey||event.metaKey)){runStudio();event.preventDefault()}">' + esc(studioState.task) + '</textarea>' +
|
|
3226
3368
|
'<div style="display:flex;gap:6px">' +
|
|
3227
|
-
'<button id="studioRunBtn" class="studio-run-btn" onclick="runStudio()" style="flex:1" ' + (studioState.running ? 'disabled' : '') + '
|
|
3228
|
-
'<button id="studioStopBtn" onclick="stopStudio()" title="
|
|
3229
|
-
'<button onclick="studioReset()" title="
|
|
3369
|
+
'<button id="studioRunBtn" class="studio-run-btn" onclick="runStudio()" style="flex:1" ' + (studioState.running ? 'disabled' : '') + '>' + t('run') + '</button>' +
|
|
3370
|
+
'<button id="studioStopBtn" onclick="stopStudio()" title="' + t('stop') + '" style="padding:8px 14px;background:#7f1d1d;border:1px solid #ef4444;border-radius:8px;color:#ef4444;cursor:pointer;font-size:13px;font-weight:700;white-space:nowrap;' + (studioState.running ? '' : 'display:none') + '">■ ' + t('stop') + '</button>' +
|
|
3371
|
+
'<button onclick="studioReset()" title="' + t('reset') + '" style="padding:8px 12px;background:none;border:1px solid var(--border);border-radius:8px;color:var(--dim);cursor:pointer;font-size:16px;line-height:1" ' + (studioState.running ? 'disabled' : '') + '>↻</button>' +
|
|
3230
3372
|
'</div>' +
|
|
3231
3373
|
'</div>' +
|
|
3232
3374
|
'</div>' +
|