nothumanallowed 13.3.0 → 13.3.2
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 +135 -40
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +5 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.3.
|
|
3
|
+
"version": "13.3.2",
|
|
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
|
@@ -2730,79 +2730,174 @@ export async function cmdUI(args) {
|
|
|
2730
2730
|
// PDF attachment: always read document first to extract specs/data before any web search
|
|
2731
2731
|
if (hasPdf) {
|
|
2732
2732
|
const pdfName = body.pdfName || 'documento allegato';
|
|
2733
|
-
steps.push({icon:'\u{1F4C4}',agent:'DocumentReaderAgent',label:it?'Leggi documento':'Read document',prompt:`Extract all technical specifications, model numbers, part codes, product names, manufacturer, dimensions, ratings, and any other key data from the attached document "${pdfName}". List every technical detail precisely.`});
|
|
2733
|
+
steps.push({icon:'\u{1F4C4}',agent:'DocumentReaderAgent',label:it?'Leggi documento':'Read document',reason:it?'Allegato PDF rilevato \u2014 estraggo dati tecnici prima di ogni altra operazione':'PDF attachment detected \u2014 extracting technical data first',prompt:`Extract all technical specifications, model numbers, part codes, product names, manufacturer, dimensions, ratings, and any other key data from the attached document "${pdfName}". List every technical detail precisely.`});
|
|
2734
2734
|
}
|
|
2735
|
-
if (hasEmail) steps.push({icon:'\u{1F4E7}',agent:'EmailAgent', label:it?'Controlla email':'Check emails', prompt:'Read the latest unread emails and identify urgent items, deadlines, and required actions'});
|
|
2736
|
-
if (hasCalendar) steps.push({icon:'\u{1F4C5}',agent:'CalendarAgent', label:it?'Rivedi calendario':'Review calendar', prompt:'Check today\'s events and identify any scheduling conflicts or important meetings'});
|
|
2737
|
-
if (hasGitHub) steps.push({icon:'\u{1F4BB}',agent:'GitHubAgent', label:'GitHub',
|
|
2738
|
-
if (hasSlack) steps.push({icon:'\u{1F4AC}',agent:'SlackAgent', label:'Slack',
|
|
2739
|
-
if (hasNotion) steps.push({icon:'\u{1F4DD}',agent:'NotionAgent', label:'Notion',
|
|
2735
|
+
if (hasEmail) steps.push({icon:'\u{1F4E7}',agent:'EmailAgent', label:it?'Controlla email':'Check emails', reason:it?'Parola chiave email/mail/posta rilevata nel task':'Keyword email/mail detected in task', prompt:'Read the latest unread emails and identify urgent items, deadlines, and required actions'});
|
|
2736
|
+
if (hasCalendar) steps.push({icon:'\u{1F4C5}',agent:'CalendarAgent', label:it?'Rivedi calendario':'Review calendar', reason:it?'Parola chiave calendario/agenda/eventi rilevata nel task':'Keyword calendar/agenda/events detected in task', prompt:'Check today\'s events and identify any scheduling conflicts or important meetings'});
|
|
2737
|
+
if (hasGitHub) steps.push({icon:'\u{1F4BB}',agent:'GitHubAgent', label:'GitHub', reason:it?'Parola chiave GitHub/git/issue/PR rilevata nel task':'Keyword GitHub/git/issue/PR detected in task', prompt:'Read open issues and pull requests, identify what needs attention'});
|
|
2738
|
+
if (hasSlack) steps.push({icon:'\u{1F4AC}',agent:'SlackAgent', label:'Slack', reason:it?'Parola chiave Slack/canale/messaggio rilevata nel task':'Keyword Slack/channel/message detected in task', prompt:'Check recent Slack messages and identify important conversations'});
|
|
2739
|
+
if (hasNotion) steps.push({icon:'\u{1F4DD}',agent:'NotionAgent', label:'Notion', reason:it?'Parola chiave Notion/note rilevata nel task':'Keyword Notion/note detected in task', prompt:'Search Notion for relevant pages and notes'});
|
|
2740
2740
|
// When PDF is present: always search web (to find where to buy, similar products etc.)
|
|
2741
2741
|
// The search query will be refined at runtime using the extracted PDF specs as context
|
|
2742
2742
|
if (hasPdf || hasSearch || hasReputation || (!hasEmail && !hasCalendar && !hasGitHub && !hasSlack)) {
|
|
2743
2743
|
const searchPrompt = hasPdf
|
|
2744
2744
|
? (it ? 'Usando le specifiche tecniche estratte dal documento (codice prodotto, modello, costruttore, caratteristiche), cerca online dove acquistare il prodotto o articoli equivalenti. Usa i codici esatti dal documento come query di ricerca.' : 'Using the technical specifications extracted from the document (product code, model, manufacturer, specs), search online for where to buy this product or equivalent alternatives. Use exact codes from the document as search queries.')
|
|
2745
2745
|
: searchQuery;
|
|
2746
|
-
|
|
2746
|
+
const searchReason = hasPdf ? (it?'Complemento PDF: cerco informazioni online con i dati estratti':'PDF complement: searching online with extracted specs') : hasReputation ? (it?'Parola chiave reputazione/brand: raccolgo dati web':'Reputation/brand keyword: collecting web data') : hasSearch ? (it?'Parola chiave cerca/search/notizie rilevata':'Keyword search/news detected') : (it?'Nessuna fonte dati specifica \u2014 web come fonte primaria':'No specific data source \u2014 web as primary source');
|
|
2747
|
+
steps.push({icon:'\u{1F50D}',agent:'WebSearchAgent',label:it?'Ricerca web':'Web search',reason:searchReason,prompt:searchPrompt});
|
|
2747
2748
|
}
|
|
2748
2749
|
// Specialist agents — can stack multiple
|
|
2749
|
-
if (hasSecurity) steps.push({icon:'\u{1F6E1}',agent:'cassandra', label:it?'CASSANDRA \u2014 Rischi sicurezza':'CASSANDRA \u2014 Security risks', prompt:'Analyze the collected data and identify security risks, vulnerabilities and concrete recommendations'});
|
|
2750
|
-
if (hasFinance) steps.push({icon:'\u{1F4B0}',agent:'mercury', label:it?'MERCURY \u2014 Analisi mercato':'MERCURY \u2014 Market analysis', prompt:'Analyze the financial data and market trends from the collected information'});
|
|
2751
|
-
if (hasStrategy) steps.push({icon:'\u{265F}', agent:'athena', label:it?'ATHENA \u2014 Strategia':'ATHENA \u2014 Strategy', prompt:'Based on the collected data, produce strategic analysis with competitive positioning and concrete recommendations'});
|
|
2752
|
-
if (hasReputation) steps.push({icon:'\u{1F52D}',agent:'oracle', label:it?'ORACLE \u2014 Reputazione':'ORACLE \u2014 Reputation', prompt:'Analyze the online reputation data, sentiment and brand positioning from the collected information'});
|
|
2753
|
-
if (hasCode) steps.push({icon:'\u{1F527}',agent:'forge', label:it?'FORGE \u2014 Analisi codice':'FORGE \u2014 Code analysis', prompt:'Analyze the code, dependencies and technical issues identified in the data'});
|
|
2754
|
-
if (hasWriting) steps.push({icon:'\u{1F58A}',agent:'quill', label:it?'QUILL \u2014 Redazione':'QUILL \u2014 Writing', prompt:'Write a polished, professional document based on all the collected information'});
|
|
2755
|
-
if (hasData) steps.push({icon:'\u{1F4CA}',agent:'DataAnalystAgent',label:it?'Analisi dati':'Data analysis', prompt:'Analyze the data and extract key patterns, trends and insights'});
|
|
2756
|
-
if (hasTranslate) steps.push({icon:'\u{1F310}',agent:'polyglot', label:it?'POLYGLOT \u2014 Traduzione':'POLYGLOT \u2014 Translation', prompt:'Translate the content as requested, maintaining meaning and style'});
|
|
2750
|
+
if (hasSecurity) steps.push({icon:'\u{1F6E1}',agent:'cassandra', label:it?'CASSANDRA \u2014 Rischi sicurezza':'CASSANDRA \u2014 Security risks', reason:it?'Parola chiave sicurezza/vulnerabilit\u00e0/audit rilevata':'Keyword security/vulnerability/audit detected', prompt:'Analyze the collected data and identify security risks, vulnerabilities and concrete recommendations'});
|
|
2751
|
+
if (hasFinance) steps.push({icon:'\u{1F4B0}',agent:'mercury', label:it?'MERCURY \u2014 Analisi mercato':'MERCURY \u2014 Market analysis', reason:it?'Parola chiave finanza/mercato/investimento rilevata':'Keyword finance/market/investment detected', prompt:'Analyze the financial data and market trends from the collected information'});
|
|
2752
|
+
if (hasStrategy) steps.push({icon:'\u{265F}', agent:'athena', label:it?'ATHENA \u2014 Strategia':'ATHENA \u2014 Strategy', reason:it?'Parola chiave strategia/competitivo/posizionamento rilevata':'Keyword strategy/competitive/positioning detected',prompt:'Based on the collected data, produce strategic analysis with competitive positioning and concrete recommendations'});
|
|
2753
|
+
if (hasReputation) steps.push({icon:'\u{1F52D}',agent:'oracle', label:it?'ORACLE \u2014 Reputazione':'ORACLE \u2014 Reputation', reason:it?'Parola chiave reputazione/brand/recensioni rilevata':'Keyword reputation/brand/reviews detected', prompt:'Analyze the online reputation data, sentiment and brand positioning from the collected information'});
|
|
2754
|
+
if (hasCode) steps.push({icon:'\u{1F527}',agent:'forge', label:it?'FORGE \u2014 Analisi codice':'FORGE \u2014 Code analysis', reason:it?'Parola chiave codice/refactor/bug/npm rilevata':'Keyword code/refactor/bug/npm detected', prompt:'Analyze the code, dependencies and technical issues identified in the data'});
|
|
2755
|
+
if (hasWriting) steps.push({icon:'\u{1F58A}',agent:'quill', label:it?'QUILL \u2014 Redazione':'QUILL \u2014 Writing', reason:it?'Parola chiave scrivi/articolo/documento rilevata':'Keyword write/article/document detected', prompt:'Write a polished, professional document based on all the collected information'});
|
|
2756
|
+
if (hasData) steps.push({icon:'\u{1F4CA}',agent:'DataAnalystAgent',label:it?'Analisi dati':'Data analysis', reason:it?'Parola chiave dati/dataset/statistiche rilevata':'Keyword data/dataset/statistics detected', prompt:'Analyze the data and extract key patterns, trends and insights'});
|
|
2757
|
+
if (hasTranslate) steps.push({icon:'\u{1F310}',agent:'polyglot', label:it?'POLYGLOT \u2014 Traduzione':'POLYGLOT \u2014 Translation', reason:it?'Parola chiave traduci/traduzione rilevata':'Keyword translate/translation detected', prompt:'Translate the content as requested, maintaining meaning and style'});
|
|
2757
2758
|
// If no specialist added but we have data, add HERALD for synthesis
|
|
2758
2759
|
const hasSpecialist = hasSecurity || hasFinance || hasStrategy || hasReputation || hasCode || hasWriting || hasData || hasTranslate;
|
|
2759
2760
|
if (!hasSpecialist && (hasBriefing || steps.length > 0)) {
|
|
2760
|
-
steps.push({icon:'\u{1F4F0}',agent:'HERALD',label:it?'HERALD \u2014 Briefing esecutivo':'HERALD \u2014 Executive briefing',prompt:'Based on ALL the data collected by the previous steps, write a complete executive briefing with priorities, findings, and strategic recommendations. Do NOT invent data — only use what was provided.'});
|
|
2761
|
+
steps.push({icon:'\u{1F4F0}',agent:'HERALD',label:it?'HERALD \u2014 Briefing esecutivo':'HERALD \u2014 Executive briefing',reason:it?'Nessun agente specialista \u2014 HERALD sintetizza tutti i dati raccolti':'No specialist agent \u2014 HERALD synthesizes all collected data',prompt:'Based on ALL the data collected by the previous steps, write a complete executive briefing with priorities, findings, and strategic recommendations. Do NOT invent data — only use what was provided.'});
|
|
2761
2762
|
}
|
|
2762
2763
|
// Add CanvasAgent: always when explicitly requested OR when 2+ specialist agents ran (complex analysis deserves a visual report)
|
|
2763
2764
|
const specialistCount = [hasSecurity,hasFinance,hasStrategy,hasReputation,hasCode,hasWriting,hasData].filter(Boolean).length;
|
|
2764
2765
|
if (hasCanvas || specialistCount >= 2 || (hasSpecialist && hasBriefing)) {
|
|
2765
|
-
|
|
2766
|
+
const canvasReason = hasCanvas ? (it?'Parola chiave html/dashboard/report visuale rilevata':'Keyword html/dashboard/visual report detected') : (it?specialistCount+' agenti specialisti \u2014 analisi complessa merita una dashboard':specialistCount+' specialist agents \u2014 complex analysis needs a visual dashboard');
|
|
2767
|
+
steps.push({icon:'\u{1F4CA}',agent:'CanvasAgent',label:it?'Dashboard HTML':'HTML Dashboard',reason:canvasReason,prompt:'Create a professional HTML dashboard report summarizing all findings from the previous agents'});
|
|
2766
2768
|
}
|
|
2767
2769
|
return steps;
|
|
2768
2770
|
};
|
|
2769
2771
|
|
|
2770
|
-
//
|
|
2772
|
+
// ── Hybrid planning: keyword baseline + LLM refinement ──────────────────
|
|
2773
|
+
//
|
|
2774
|
+
// Strategy (3 tiers):
|
|
2775
|
+
//
|
|
2776
|
+
// TIER 1 — Keyword baseline (always runs, <1ms, zero LLM):
|
|
2777
|
+
// Builds a solid plan from regex matches on the task. Reliable for all
|
|
2778
|
+
// known patterns. Already contains `reason` for each step.
|
|
2779
|
+
//
|
|
2780
|
+
// TIER 2 — LLM refinement (runs when baseline ≥ 1 step OR task is non-trivial):
|
|
2781
|
+
// Receives the task + the keyword plan as context. Can ADD missing steps,
|
|
2782
|
+
// REMOVE wrong ones, REORDER, and ADJUST prompts. Does NOT build from scratch.
|
|
2783
|
+
// Falls back to keyword plan on any parse/timeout error.
|
|
2784
|
+
//
|
|
2785
|
+
// TIER 3 — LLM-only fallback (runs when keyword baseline is empty):
|
|
2786
|
+
// Task had zero keyword matches → pure LLM planning with full task text.
|
|
2787
|
+
// Same fallback: on error, returns a single WebSearchAgent step.
|
|
2788
|
+
//
|
|
2789
|
+
// Why this is safe now: SENTINEL's /api/studio/ is an intent-aware route.
|
|
2790
|
+
// Prompt injection detection is disabled for this path — the body IS the task.
|
|
2791
|
+
// Encoding attacks, rate limits, and toxicity checks remain fully active.
|
|
2792
|
+
|
|
2771
2793
|
const keywordSteps = buildKeywordPlan();
|
|
2772
|
-
const
|
|
2794
|
+
const hasKeywordPlan = keywordSteps.length > 0;
|
|
2795
|
+
|
|
2796
|
+
// Sanitize task for LLM: strip HTML tags and control chars (defensive, not SENTINEL).
|
|
2797
|
+
const sanitizedTask = task.replace(/<[^>]*>/g, ' ').replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, '').trim();
|
|
2798
|
+
|
|
2799
|
+
// Build a compact JSON representation of the keyword plan for the LLM to refine.
|
|
2800
|
+
const keywordPlanJson = hasKeywordPlan
|
|
2801
|
+
? JSON.stringify(keywordSteps.map(s => ({ agent: s.agent, label: s.label, reason: s.reason || '' })))
|
|
2802
|
+
: '[]';
|
|
2803
|
+
|
|
2804
|
+
const planConfig = Object.assign({}, config, { thinking: 'off' });
|
|
2773
2805
|
|
|
2774
2806
|
try {
|
|
2775
|
-
let steps;
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
steps = keywordSteps;
|
|
2780
|
-
} else {
|
|
2781
|
-
// Task is ambiguous — use LLM planner with sanitized short description
|
|
2782
|
-
const shortTask = task.slice(0, 200).replace(/[`'"]/g, ' ');
|
|
2783
|
-
const plannerLangStr = plannerLang;
|
|
2784
|
-
const planPrompt = `Workflow planner. Goal: ${shortTask}\nLanguage: ${plannerLangStr}.\nOutput ONLY JSON:\n{"steps":[{"icon":"EMOJI","agent":"AGENT_NAME","label":"LABEL","prompt":"INSTRUCTION"}]}\nAgents: WebSearchAgent, EmailAgent, CalendarAgent, HERALD, ORACLE, ATHENA, CASSANDRA, MERCURY, QUILL, CanvasAgent (last, only if visual needed). 2-5 steps.`;
|
|
2785
|
-
const planConfig = Object.assign({}, config, { thinking: 'off' });
|
|
2786
|
-
const planRaw = await callLLM(planConfig, 'Output ONLY valid JSON. No explanation.', planPrompt, { max_tokens: 800 });
|
|
2787
|
-
process.stderr.write('[STUDIO PLAN LLM RAW] ' + planRaw.slice(0, 400) + '\n');
|
|
2807
|
+
let steps = keywordSteps;
|
|
2808
|
+
|
|
2809
|
+
// TIER 2 / 3: always attempt LLM if we have a working LLM config
|
|
2810
|
+
if (config && (config.provider || config.apiKey || config.baseUrl)) {
|
|
2788
2811
|
try {
|
|
2812
|
+
let planPrompt;
|
|
2813
|
+
let planSys;
|
|
2814
|
+
|
|
2815
|
+
if (hasKeywordPlan) {
|
|
2816
|
+
// TIER 2: refine the keyword plan
|
|
2817
|
+
planSys = `You are a workflow planner for NHA Studio. Output ONLY valid JSON — no explanation, no markdown.`;
|
|
2818
|
+
planPrompt = `Task: ${sanitizedTask}
|
|
2819
|
+
|
|
2820
|
+
Keyword-detected plan (JSON):
|
|
2821
|
+
${keywordPlanJson}
|
|
2822
|
+
|
|
2823
|
+
Language for labels: ${plannerLang}.
|
|
2824
|
+
|
|
2825
|
+
Review the plan above. You may:
|
|
2826
|
+
- ADD steps that are clearly needed but missing
|
|
2827
|
+
- REMOVE steps that are wrong for this task
|
|
2828
|
+
- REORDER steps to fix logical sequence (e.g. Notion before email)
|
|
2829
|
+
- ADJUST the "prompt" field of any step to better match the task
|
|
2830
|
+
- KEEP steps that are correct as-is
|
|
2831
|
+
|
|
2832
|
+
Available agents: WebSearchAgent, DocumentReaderAgent, EmailAgent, CalendarAgent, GitHubAgent, SlackAgent, NotionAgent, HERALD, ORACLE, ATHENA, CASSANDRA, MERCURY, QUILL, DataAnalystAgent, polyglot, CanvasAgent (last, only if visual output needed).
|
|
2833
|
+
|
|
2834
|
+
Output ONLY:
|
|
2835
|
+
{"steps":[{"icon":"EMOJI","agent":"AGENT_NAME","label":"LABEL","reason":"WHY THIS AGENT","prompt":"INSTRUCTION"}]}
|
|
2836
|
+
|
|
2837
|
+
Rules:
|
|
2838
|
+
- 2 to 6 steps maximum
|
|
2839
|
+
- CanvasAgent only as the final step and only for complex multi-agent analyses
|
|
2840
|
+
- Keep existing reasons where step is unchanged, write a new reason when you add/change a step`;
|
|
2841
|
+
} else {
|
|
2842
|
+
// TIER 3: pure LLM planning — zero keyword matches
|
|
2843
|
+
planSys = `You are a workflow planner for NHA Studio. Output ONLY valid JSON — no explanation, no markdown.`;
|
|
2844
|
+
planPrompt = `Task: ${sanitizedTask}
|
|
2845
|
+
|
|
2846
|
+
Language for labels: ${plannerLang}.
|
|
2847
|
+
|
|
2848
|
+
Build a workflow plan for this task.
|
|
2849
|
+
|
|
2850
|
+
Available agents: WebSearchAgent, DocumentReaderAgent, EmailAgent, CalendarAgent, GitHubAgent, SlackAgent, NotionAgent, HERALD, ORACLE, ATHENA, CASSANDRA, MERCURY, QUILL, DataAnalystAgent, polyglot, CanvasAgent.
|
|
2851
|
+
|
|
2852
|
+
Output ONLY:
|
|
2853
|
+
{"steps":[{"icon":"EMOJI","agent":"AGENT_NAME","label":"LABEL","reason":"WHY THIS AGENT","prompt":"INSTRUCTION"}]}
|
|
2854
|
+
|
|
2855
|
+
Rules:
|
|
2856
|
+
- 2 to 5 steps
|
|
2857
|
+
- HERALD = executive synthesis when no other specialist fits
|
|
2858
|
+
- CanvasAgent only as the final step for complex multi-agent workflows
|
|
2859
|
+
- reason = one sentence explaining why this agent was chosen`;
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
const planRaw = await callLLM(planConfig, planSys, planPrompt, { max_tokens: 900 });
|
|
2863
|
+
process.stderr.write('[STUDIO PLAN LLM RAW] mode=' + (hasKeywordPlan ? 'refine' : 'pure') + ' len=' + planRaw.length + '\n');
|
|
2864
|
+
|
|
2865
|
+
// Parse LLM output — strip <think> blocks (Qwen3), markdown fences, extract JSON
|
|
2789
2866
|
let clean = planRaw;
|
|
2790
2867
|
let prev = '';
|
|
2791
2868
|
while (prev !== clean) { prev = clean; clean = clean.replace(/<think>[\s\S]*?<\/think>/g, ''); }
|
|
2792
|
-
clean = clean.trim().replace(/^```[\w]*\r?\n?/,'').replace(/\r?\n?```$/,'').trim();
|
|
2869
|
+
clean = clean.trim().replace(/^```[\w]*\r?\n?/, '').replace(/\r?\n?```$/, '').trim();
|
|
2793
2870
|
const jsonMatch = clean.match(/\{[\s\S]*\}/);
|
|
2794
2871
|
const parsed = JSON.parse(jsonMatch ? jsonMatch[0] : clean);
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2872
|
+
|
|
2873
|
+
if (Array.isArray(parsed.steps) && parsed.steps.length > 0) {
|
|
2874
|
+
// Merge: LLM steps override keyword steps. Preserve `reason` from keyword where LLM kept same agent.
|
|
2875
|
+
const keywordReasonMap = {};
|
|
2876
|
+
keywordSteps.forEach(s => { keywordReasonMap[s.agent] = s.reason || ''; });
|
|
2877
|
+
steps = parsed.steps.map(s => ({
|
|
2878
|
+
icon: s.icon || '\u{1F916}',
|
|
2879
|
+
agent: s.agent,
|
|
2880
|
+
label: s.label,
|
|
2881
|
+
reason: s.reason || keywordReasonMap[s.agent] || '',
|
|
2882
|
+
prompt: s.prompt,
|
|
2883
|
+
}));
|
|
2884
|
+
process.stderr.write('[STUDIO PLAN LLM OK] steps=' + steps.length + '\n');
|
|
2885
|
+
} else {
|
|
2886
|
+
process.stderr.write('[STUDIO PLAN LLM EMPTY] falling back to keyword plan\n');
|
|
2887
|
+
}
|
|
2888
|
+
} catch (llmErr) {
|
|
2889
|
+
process.stderr.write('[STUDIO PLAN LLM ERR] ' + llmErr.message + ' — using keyword plan\n');
|
|
2890
|
+
// steps already = keywordSteps, no action needed
|
|
2799
2891
|
}
|
|
2892
|
+
} else {
|
|
2893
|
+
process.stderr.write('[STUDIO PLAN KEYWORD ONLY] no LLM config, steps=' + keywordSteps.length + '\n');
|
|
2800
2894
|
}
|
|
2895
|
+
|
|
2896
|
+
// Final safety net: if everything failed and we have nothing, single web search step
|
|
2801
2897
|
if (!Array.isArray(steps) || !steps.length) {
|
|
2802
|
-
|
|
2803
|
-
logRequest(method, pathname, 500, Date.now() - start);
|
|
2804
|
-
return;
|
|
2898
|
+
steps = [{ icon: '\u{1F50D}', agent: 'WebSearchAgent', label: plannerLang === 'Italian' ? 'Ricerca web' : 'Web search', reason: plannerLang === 'Italian' ? 'Fallback: nessun piano costruito' : 'Fallback: no plan built', prompt: sanitizedTask }];
|
|
2805
2899
|
}
|
|
2900
|
+
|
|
2806
2901
|
sendJSON(res, 200, { steps });
|
|
2807
2902
|
logRequest(method, pathname, 200, Date.now() - start);
|
|
2808
2903
|
} catch (e) {
|
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.3.
|
|
8
|
+
export const VERSION = '13.3.2';
|
|
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
|
@@ -3409,6 +3409,9 @@ function renderStudioNodes() {
|
|
|
3409
3409
|
html += '<div class="' + cls + '" data-agent-label="' + esc(n.label || n.agent) + '" style="' + style + ';cursor:pointer" onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))" title="Vai al log di ' + esc(n.label || n.agent) + '">';
|
|
3410
3410
|
html += '<div class="studio-node__circle">' + n.icon + '</div>';
|
|
3411
3411
|
html += '<div class="studio-node__label">' + esc(n.label) + '</div>';
|
|
3412
|
+
if (n.reason) {
|
|
3413
|
+
html += '<div class="studio-node__reason" onclick="event.stopPropagation();this.classList.toggle(String.fromCharCode(111,112,101,110))" title="' + esc(n.reason) + '">ℹ<span class="studio-node__reason-tip">' + esc(n.reason) + '</span></div>';
|
|
3414
|
+
}
|
|
3412
3415
|
html += '<div class="studio-node__status studio-node__status--' + n.status + '">' + statusLabel + '</div>';
|
|
3413
3416
|
if (n.status === 'running') {
|
|
3414
3417
|
html += '<div class="studio-node__progress"><span></span><span></span><span></span></div>';
|
|
@@ -3944,7 +3947,7 @@ async function runStudio() {
|
|
|
3944
3947
|
}
|
|
3945
3948
|
|
|
3946
3949
|
studioState.nodes = planRes.steps.map(function(s) {
|
|
3947
|
-
return {icon: s.icon, agent: s.agent, label: s.label, status: 'waiting'};
|
|
3950
|
+
return {icon: s.icon, agent: s.agent, label: s.label, reason: s.reason || '', status: 'waiting'};
|
|
3948
3951
|
});
|
|
3949
3952
|
renderStudioNodes();
|
|
3950
3953
|
studioLog('Studio', '✓', 'Workflow planned: ' + planRes.steps.map(function(s){return s.label}).join(' -> '), 'system');
|
|
@@ -5125,7 +5128,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
5125
5128
|
.studio-node__label{font-size:10px;color:var(--dim);text-align:center;line-height:1.3;max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}
|
|
5126
5129
|
.studio-node--active .studio-node__label{color:var(--green);font-weight:700}
|
|
5127
5130
|
.studio-node--done .studio-node__label{color:#22c55e;font-weight:600}
|
|
5128
|
-
.studio-node__status{font-size:8px;padding:2px 8px;border-radius:20px;font-weight:700;text-transform:uppercase;letter-spacing:.6px}
|
|
5131
|
+
.studio-node__reason{position:relative;font-size:11px;color:var(--dim);cursor:pointer;line-height:1;padding:2px 3px;border-radius:4px;transition:color .15s}.studio-node__reason:hover{color:var(--green)}.studio-node__reason-tip{display:none;position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);background:#1a1a2e;border:1px solid #6366f1;border-radius:6px;padding:6px 9px;font-size:10px;color:#c7d2fe;white-space:normal;width:180px;line-height:1.4;z-index:999;pointer-events:none;text-transform:none;font-weight:400;letter-spacing:0;text-align:left;box-shadow:0 4px 20px rgba(0,0,0,.5)}.studio-node__reason.open .studio-node__reason-tip{display:block}.studio-node__status{font-size:8px;padding:2px 8px;border-radius:20px;font-weight:700;text-transform:uppercase;letter-spacing:.6px}
|
|
5129
5132
|
.studio-node__status--waiting{background:rgba(156,163,175,.1);color:var(--dim)}
|
|
5130
5133
|
.studio-node__status--running{background:rgba(99,102,241,.15);color:var(--green);animation:stPulse .9s ease-in-out infinite}
|
|
5131
5134
|
.studio-node__status--done{background:rgba(34,197,94,.12);color:#22c55e}
|