nothumanallowed 13.2.12 → 13.2.13
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 +124 -64
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +140 -73
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.13",
|
|
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
|
@@ -2545,19 +2545,71 @@ export async function cmdUI(args) {
|
|
|
2545
2545
|
|
|
2546
2546
|
const planPrompt = `You are a workflow planner for NHA Studio. The user wants to accomplish this task: "${task}"
|
|
2547
2547
|
|
|
2548
|
-
Design a sequential workflow of 2-
|
|
2549
|
-
- Use WebSearchAgent
|
|
2550
|
-
- Use
|
|
2551
|
-
- Use CanvasAgent as the LAST step ONLY when a visual HTML report is
|
|
2552
|
-
- The "prompt" field must be a plain language instruction —
|
|
2548
|
+
Design a sequential workflow of 2-5 steps. RULES:
|
|
2549
|
+
- Use tool-agents (WebSearchAgent, EmailAgent, CalendarAgent, GitHubAgent, NotionAgent, SlackAgent) FIRST when real live data is needed
|
|
2550
|
+
- Use specialist agents (SABER, ATLAS, JARVIS, etc.) for deep domain analysis — they have rich expert system prompts
|
|
2551
|
+
- Use CanvasAgent as the LAST step ONLY when a visual HTML report is requested
|
|
2552
|
+
- The "prompt" field must be a plain language instruction — never JSON or code
|
|
2553
2553
|
- Each agent receives the previous step's output as context automatically
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2554
|
+
- Pick the most relevant agents for the task — don't use all of them
|
|
2555
|
+
|
|
2556
|
+
TOOL AGENTS (fetch real live data):
|
|
2557
|
+
- WebSearchAgent: search the web for current information
|
|
2558
|
+
- EmailAgent: read user's real unread emails
|
|
2559
|
+
- CalendarAgent: read user's real calendar events for today
|
|
2560
|
+
- GitHubAgent: read user's GitHub notifications and issues
|
|
2561
|
+
- NotionAgent: search user's Notion workspace
|
|
2562
|
+
- SlackAgent: read user's Slack messages
|
|
2563
|
+
- WriterAgent: write, summarize, synthesize text (no live data)
|
|
2564
|
+
- SummaryAgent: condense and summarize content
|
|
2565
|
+
- DataAnalystAgent: analyze data, find patterns, generate insights
|
|
2566
|
+
- SecurityAgent: security audit, threat analysis
|
|
2567
|
+
- DevOpsAgent: infrastructure, deployment, CI/CD analysis
|
|
2568
|
+
- CanvasAgent: generate a beautiful HTML visual dashboard (LAST step only)
|
|
2569
|
+
|
|
2570
|
+
SPECIALIST AGENTS (deep domain experts with rich system prompts):
|
|
2571
|
+
- SABER: security audits, OWASP, penetration testing, vulnerability analysis
|
|
2572
|
+
- ATLAS: infrastructure-as-code, Terraform, Kubernetes, cloud architecture
|
|
2573
|
+
- JARVIS: full-stack architecture, API design, system design, ADRs
|
|
2574
|
+
- VERITAS: fact-checking, evidence verification, claim validation
|
|
2575
|
+
- CASSANDRA: risk analysis, failure modes, worst-case scenarios
|
|
2576
|
+
- MERCURY: financial analysis, ROI, unit economics, market modeling
|
|
2577
|
+
- HERALD: news analysis, trend detection, executive briefings
|
|
2578
|
+
- ATHENA: tech evaluation, framework comparison, benchmarks
|
|
2579
|
+
- ORACLE: business intelligence, KPIs, OKRs, dashboards
|
|
2580
|
+
- NAVI: data exploration, statistical analysis, pattern detection
|
|
2581
|
+
- MUSE: creative brainstorming, ideation, naming, taglines
|
|
2582
|
+
- QUILL: short-form content, summaries, press releases
|
|
2583
|
+
- SCHEHERAZADE: long-form technical writing, documentation, tutorials
|
|
2584
|
+
- ECHO: content adaptation, cross-platform distribution
|
|
2585
|
+
- POLYGLOT: translation, localization, multilingual content
|
|
2586
|
+
- FORGE: CI/CD pipelines, GitHub Actions, Docker builds
|
|
2587
|
+
- FLUX: deployment strategies, blue/green, canary releases
|
|
2588
|
+
- SHOGUN: Kubernetes, Helm, container orchestration
|
|
2589
|
+
- PIPE: data pipelines, Airflow, dbt, ETL
|
|
2590
|
+
- MACRO: bulk operations, data migration, batch processing
|
|
2591
|
+
- SHELL: shell scripting, CLI tools, automation scripts
|
|
2592
|
+
- CONDUCTOR: workflow orchestration, task decomposition
|
|
2593
|
+
- CRON: scheduling, cron jobs, time-based automation
|
|
2594
|
+
- HERMES: webhooks, event-driven architecture, integrations
|
|
2595
|
+
- BABEL: API design, microservices, OpenAPI specs
|
|
2596
|
+
- CARTOGRAPHER: data mapping, schema inference, knowledge graphs
|
|
2597
|
+
- LOGOS: logical analysis, argument mapping, decision theory
|
|
2598
|
+
- EDI: A/B testing, statistical modeling, hypothesis testing
|
|
2599
|
+
- EPICURE: nutrition, recipes, meal planning
|
|
2600
|
+
- MURASAKI: creative writing, storytelling, narrative craft
|
|
2601
|
+
- LINK: community management, reputation systems
|
|
2602
|
+
- GLITCH: chaos engineering, resilience testing
|
|
2603
|
+
- TEMPEST: performance engineering, load testing
|
|
2604
|
+
- SAURON: observability, monitoring, alerting
|
|
2605
|
+
- PROMETHEUS: capability routing, task decomposition
|
|
2606
|
+
- ADE: agent design, system prompt engineering
|
|
2607
|
+
- ZERO: vulnerability scanning, dependency audit, secret detection
|
|
2608
|
+
|
|
2609
|
+
Icon values must be actual emoji characters — never HTML entities.
|
|
2558
2610
|
|
|
2559
2611
|
Respond with ONLY valid JSON, no markdown:
|
|
2560
|
-
{"steps":[{"icon":"🔍","agent":"WebSearchAgent","label":"Search AI news","prompt":"Search for the latest
|
|
2612
|
+
{"steps":[{"icon":"🔍","agent":"WebSearchAgent","label":"Search AI news","prompt":"Search for the latest AI agent news"},{"icon":"🧠","agent":"ATHENA","label":"Tech analysis","prompt":"Analyze the search results and compare the key technologies mentioned"}]}`;
|
|
2561
2613
|
|
|
2562
2614
|
try {
|
|
2563
2615
|
const planRaw = await callLLM(config, 'You are a JSON workflow planner. Respond only with valid JSON.', planPrompt, { max_tokens: 800 });
|
|
@@ -2693,78 +2745,86 @@ Respond with ONLY valid JSON, no markdown:
|
|
|
2693
2745
|
|
|
2694
2746
|
// ── Build system prompt with real tool data ───────────────────
|
|
2695
2747
|
const isCanvasAgent = agent === 'CanvasAgent';
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
const
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
-
|
|
2704
|
-
-
|
|
2705
|
-
-
|
|
2706
|
-
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2748
|
+
// Synthesis agents: do NOT wrap with TOOL_DEFINITIONS — use focused prompts only
|
|
2749
|
+
const isSynthesisAgent = ['WriterAgent','SummaryAgent','DataAnalystAgent','SecurityAgent','DevOpsAgent'].includes(agent);
|
|
2750
|
+
const isToolOutputAgent = ['CalendarAgent','EmailAgent','GitHubAgent','NotionAgent','SlackAgent'].includes(agent);
|
|
2751
|
+
const isPureAnalysis = isSynthesisAgent || isToolOutputAgent;
|
|
2752
|
+
|
|
2753
|
+
const canvasSystemPrompt = `You are an HTML report generator. Output a single complete HTML document. No preamble, no explanation.
|
|
2754
|
+
RULES:
|
|
2755
|
+
- First character of your response must be < (start of <!DOCTYPE html>)
|
|
2756
|
+
- Do NOT use markdown code blocks, JSON, or any wrapper
|
|
2757
|
+
- Use clean design: white background, Inter/system-ui font, #6366f1 accent color
|
|
2758
|
+
- Structure: gradient header, then card sections with the content
|
|
2759
|
+
- Make it complete and self-contained`;
|
|
2760
|
+
|
|
2761
|
+
let sysPrompt, userMsg;
|
|
2762
|
+
|
|
2763
|
+
if (isCanvasAgent) {
|
|
2764
|
+
sysPrompt = canvasSystemPrompt;
|
|
2765
|
+
userMsg = `Generate a beautiful HTML dashboard report for this content. Start immediately with <!DOCTYPE html>:\n\n${context.slice(0, 8000)}`;
|
|
2766
|
+
} else if (isSynthesisAgent) {
|
|
2767
|
+
// Focused system prompt — no TOOL_DEFINITIONS bloat
|
|
2768
|
+
const today = new Date().toISOString().split('T')[0];
|
|
2769
|
+
const language = config?.language || 'Italian';
|
|
2770
|
+
sysPrompt = `You are ${agent}, a specialist AI agent inside NHA Studio. Today is ${today}. Respond in ${language}.
|
|
2771
|
+
Task: ${stepPrompt}
|
|
2772
|
+
${toolData ? `\n## LIVE DATA:\n${toolData.slice(0, 4000)}\n` : ''}
|
|
2773
|
+
${context ? `\n## CONTEXT FROM PREVIOUS STEPS:\n${context.slice(0, 5000)}\n` : ''}
|
|
2774
|
+
Write your full response in plain prose. Do NOT output JSON, tool calls, or code blocks unless explicitly asked. Use the context and data above — do not ask for more information.`;
|
|
2775
|
+
userMsg = toolData
|
|
2776
|
+
? `Use the live data and context above to complete: ${stepPrompt}`
|
|
2777
|
+
: context
|
|
2778
|
+
? `Based on the context above, complete: ${stepPrompt}`
|
|
2779
|
+
: stepPrompt;
|
|
2780
|
+
} else {
|
|
2781
|
+
const agentInstruction = `You are ${agent}, a specialist AI agent inside NHA Studio.\nYour task: ${stepPrompt}\n` +
|
|
2711
2782
|
(toolData ? `\n## DATA FROM TOOLS:\n${toolData.slice(0, 4000)}\n` : '') +
|
|
2712
2783
|
(context ? `\n## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 3000)}\n` : '') +
|
|
2713
|
-
(
|
|
2784
|
+
(isToolOutputAgent
|
|
2714
2785
|
? '\nWrite your analysis in plain text. Do NOT output JSON, tool calls, or code blocks. Use the context above.'
|
|
2715
2786
|
: '\nOutput your result directly. No preamble.');
|
|
2787
|
+
sysPrompt = buildSystemPrompt(agent, agentInstruction, config);
|
|
2788
|
+
userMsg = toolData
|
|
2789
|
+
? `Use the data above to complete: ${stepPrompt}`
|
|
2790
|
+
: context
|
|
2791
|
+
? `Based on the previous output, complete: ${stepPrompt}`
|
|
2792
|
+
: stepPrompt;
|
|
2793
|
+
}
|
|
2716
2794
|
|
|
2717
|
-
|
|
2718
|
-
? canvasSystemPrompt
|
|
2719
|
-
: buildSystemPrompt(agent, agentInstruction, config);
|
|
2720
|
-
|
|
2721
|
-
const userMsg = isCanvasAgent
|
|
2722
|
-
? `Create a beautiful HTML report for this content:\n\n${context.slice(0, 4000)}`
|
|
2723
|
-
: toolData
|
|
2724
|
-
? `Use the data above to complete: ${stepPrompt}`
|
|
2725
|
-
: context
|
|
2726
|
-
? `Based on the previous output, complete: ${stepPrompt}`
|
|
2727
|
-
: stepPrompt;
|
|
2728
|
-
|
|
2729
|
-
// ── Stream LLM response (or non-stream for CanvasAgent) ──────
|
|
2795
|
+
// ── Stream LLM response ───────────────────────────────────────
|
|
2730
2796
|
let fullOutput = '';
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
);
|
|
2739
|
-
} catch (e) {
|
|
2740
|
-
fullOutput = '';
|
|
2741
|
-
}
|
|
2742
|
-
} else {
|
|
2743
|
-
await callLLMStream(config, sysPrompt, userMsg,
|
|
2744
|
-
(token) => { fullOutput += token; sendToken(token); },
|
|
2745
|
-
{ max_tokens: 2500 }
|
|
2797
|
+
sendToken(isCanvasAgent ? 'Generating visual report...' : '');
|
|
2798
|
+
try {
|
|
2799
|
+
await withTimeout(
|
|
2800
|
+
callLLMStream(config, sysPrompt, userMsg,
|
|
2801
|
+
(token) => { fullOutput += token; if (!isCanvasAgent) sendToken(token); },
|
|
2802
|
+
),
|
|
2803
|
+
isCanvasAgent ? 60000 : 35000
|
|
2746
2804
|
);
|
|
2805
|
+
} catch (e) {
|
|
2806
|
+
if (!isCanvasAgent) sendToken(`[Error: ${e.message}]`);
|
|
2747
2807
|
}
|
|
2748
2808
|
|
|
2749
2809
|
if (isCanvasAgent) {
|
|
2750
|
-
let html = fullOutput;
|
|
2810
|
+
let html = fullOutput.trim();
|
|
2811
|
+
// Strip thinking tags if not already filtered
|
|
2812
|
+
html = html.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
2751
2813
|
// Extract from markdown code block
|
|
2752
|
-
const mdMatch = html.match(/```html?\s*([\s\S]*?)```/);
|
|
2814
|
+
const mdMatch = html.match(/```html?\s*([\s\S]*?)```/i);
|
|
2753
2815
|
if (mdMatch) html = mdMatch[1].trim();
|
|
2754
|
-
//
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
} catch {}
|
|
2760
|
-
}
|
|
2816
|
+
// Find <!DOCTYPE or <html start if there's preamble text
|
|
2817
|
+
const doctypeIdx = html.indexOf('<!DOCTYPE');
|
|
2818
|
+
const htmlTagIdx = html.indexOf('<html');
|
|
2819
|
+
const startIdx = doctypeIdx >= 0 ? doctypeIdx : (htmlTagIdx >= 0 ? htmlTagIdx : -1);
|
|
2820
|
+
if (startIdx > 0) html = html.slice(startIdx);
|
|
2761
2821
|
// Fallback: build clean HTML from the context directly (no LLM needed)
|
|
2762
2822
|
if (!html.trim() || !html.includes('<')) {
|
|
2763
2823
|
// Try splitting on markdown headings first, then numbered items, then double newlines
|
|
2764
2824
|
let sections = context.split(/\n#{1,3} /).filter(s => s.trim());
|
|
2765
2825
|
if (sections.length <= 1) sections = context.split(/\n(?=\*\*\d+[\.\)])|(?=^\d+[\.\)])/).filter(s => s.trim());
|
|
2766
2826
|
if (sections.length <= 1) sections = context.split(/\n{2,}/).filter(s => s.trim());
|
|
2767
|
-
const reportTitle = (
|
|
2827
|
+
const reportTitle = (task.slice(0, 80) || 'NHA Studio Report').replace(/</g,'<').replace(/>/g,'>');
|
|
2768
2828
|
const cardsHtml = sections.map(s => {
|
|
2769
2829
|
const clean = s.replace(/\*\*/g, '').replace(/\*/g, '').trim();
|
|
2770
2830
|
const lines = clean.split('\n').filter(Boolean);
|
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.13';
|
|
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
|
@@ -190,6 +190,7 @@ function deleteConv(id){return fetch(API+'/api/conversations/'+id,{method:'DELET
|
|
|
190
190
|
function clearChatHistory(){createNewConv()}
|
|
191
191
|
var agentsList = [];
|
|
192
192
|
var selectedAgent = null;
|
|
193
|
+
var agentChatHistory = []; // [{role:'user'|'agent', text:'...'}]
|
|
193
194
|
|
|
194
195
|
// ---- NAV ----
|
|
195
196
|
function switchView(v) {
|
|
@@ -1188,16 +1189,18 @@ function openDayDetail(dateStr){
|
|
|
1188
1189
|
});
|
|
1189
1190
|
}
|
|
1190
1191
|
|
|
1191
|
-
// Use the agent modal for day detail
|
|
1192
|
+
// Use the agent modal for day detail (read-only mode)
|
|
1193
|
+
selectedAgent=null;
|
|
1194
|
+
agentChatHistory=[];
|
|
1192
1195
|
document.getElementById('modalName').textContent=dayLabel;
|
|
1193
|
-
document.getElementById('
|
|
1194
|
-
|
|
1195
|
-
document.getElementById('
|
|
1196
|
-
|
|
1197
|
-
|
|
1196
|
+
document.getElementById('modalAgentDesc').textContent='';
|
|
1197
|
+
// Show the day events in the messages area
|
|
1198
|
+
var msgEl=document.getElementById('agentMessages');
|
|
1199
|
+
if(msgEl){msgEl.innerHTML='<div class="agent-chat__bubble agent-chat__bubble--agent md-body" style="width:100%;max-width:100%;box-sizing:border-box">'+h+'</div>';}
|
|
1200
|
+
// Hide input footer in read-only mode
|
|
1201
|
+
var footer=document.querySelector('.agent-chat__footer');
|
|
1202
|
+
if(footer)footer.style.display='none';
|
|
1198
1203
|
document.getElementById('agentModal').classList.add('modal-overlay--open');
|
|
1199
|
-
var sendBtn=document.getElementById('agentModal').querySelector('.btn--primary');
|
|
1200
|
-
if(sendBtn)sendBtn.style.display='none';
|
|
1201
1204
|
}
|
|
1202
1205
|
|
|
1203
1206
|
// ---- GITHUB ----
|
|
@@ -2162,8 +2165,39 @@ function confirmDeleteAgent(name){
|
|
|
2162
2165
|
});
|
|
2163
2166
|
}
|
|
2164
2167
|
|
|
2168
|
+
function renderAgentMessages(){
|
|
2169
|
+
var el=document.getElementById('agentMessages');
|
|
2170
|
+
if(!el)return;
|
|
2171
|
+
if(agentChatHistory.length===0){
|
|
2172
|
+
var icon=AGENT_ICONS[selectedAgent]||'\uD83E\uDD16';
|
|
2173
|
+
var desc=AGENT_DESCRIPTIONS[selectedAgent]||'';
|
|
2174
|
+
el.innerHTML='<div style="text-align:center;padding:24px 8px;color:var(--dim);font-size:12px">'+
|
|
2175
|
+
'<div style="font-size:28px;margin-bottom:6px">'+icon+'</div>'+
|
|
2176
|
+
'<div style="color:var(--fg);font-weight:600;margin-bottom:4px">'+esc(selectedAgent.toUpperCase())+'</div>'+
|
|
2177
|
+
(desc?'<div>'+esc(desc)+'</div>':'')+
|
|
2178
|
+
'</div>';
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
el.innerHTML=agentChatHistory.map(function(m){
|
|
2182
|
+
var cls='agent-chat__bubble agent-chat__bubble--'+(m.role==='user'?'user':'agent');
|
|
2183
|
+
var content;
|
|
2184
|
+
if(m.role==='user'){
|
|
2185
|
+
content=esc(m.text);
|
|
2186
|
+
} else if(m.waiting||(m.streaming&&!m.text)){
|
|
2187
|
+
content='<span class="thinking-dots"><span></span><span></span><span></span></span>';
|
|
2188
|
+
} else if(m.streaming){
|
|
2189
|
+
content=esc(m.text)+'\u258B';
|
|
2190
|
+
} else {
|
|
2191
|
+
content=renderMd(m.text);
|
|
2192
|
+
}
|
|
2193
|
+
return '<div class="'+cls+' '+(m.role==='agent'?'md-body':'')+'">'+content+'</div>';
|
|
2194
|
+
}).join('');
|
|
2195
|
+
el.scrollTop=el.scrollHeight;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2165
2198
|
function openAgent(name,display){
|
|
2166
2199
|
selectedAgent=name;
|
|
2200
|
+
agentChatHistory=[];
|
|
2167
2201
|
attachedFileContent=null;attachedFileName=null;
|
|
2168
2202
|
var icon=AGENT_ICONS[name.toLowerCase()]||'\u{1F916}';
|
|
2169
2203
|
var desc=AGENT_DESCRIPTIONS[name.toLowerCase()]||'';
|
|
@@ -2172,17 +2206,17 @@ function openAgent(name,display){
|
|
|
2172
2206
|
var subEl=document.getElementById('modalAgentDesc');
|
|
2173
2207
|
if(subEl){subEl.textContent=desc;}
|
|
2174
2208
|
document.getElementById('modalPrompt').value='';
|
|
2175
|
-
document.getElementById('
|
|
2176
|
-
document.getElementById('
|
|
2177
|
-
document.getElementById('
|
|
2178
|
-
document.getElementById('modalResponse').innerHTML='';
|
|
2179
|
-
document.getElementById('fileInfo').style.display='none';
|
|
2180
|
-
document.getElementById('fileDropZone').style.display='';
|
|
2181
|
-
document.getElementById('fileDropZone').style.borderColor='var(--border2)';
|
|
2182
|
-
document.getElementById('fileInput').value='';
|
|
2209
|
+
document.getElementById('agentFileInfo').style.display='none';
|
|
2210
|
+
document.getElementById('agentFileInput').value='';
|
|
2211
|
+
document.getElementById('agentFileDropZone').style.borderColor='';
|
|
2183
2212
|
var askBtn=document.getElementById('agentAskBtn');
|
|
2184
|
-
if(askBtn){askBtn.disabled=false;askBtn.textContent='
|
|
2213
|
+
if(askBtn){askBtn.disabled=false;askBtn.textContent='Send';}
|
|
2214
|
+
// Ensure footer is visible (may be hidden from calendar day-detail view)
|
|
2215
|
+
var footer=document.querySelector('.agent-chat__footer');
|
|
2216
|
+
if(footer)footer.style.display='';
|
|
2217
|
+
renderAgentMessages();
|
|
2185
2218
|
document.getElementById('agentModal').classList.add('modal-overlay--open');
|
|
2219
|
+
setTimeout(function(){var i=document.getElementById('modalPrompt');if(i)i.focus();},100);
|
|
2186
2220
|
}
|
|
2187
2221
|
function closeModal(){
|
|
2188
2222
|
document.getElementById('agentModal').classList.remove('modal-overlay--open');
|
|
@@ -2388,21 +2422,20 @@ function handleFileSelect(input) {
|
|
|
2388
2422
|
if (file) readFile(file);
|
|
2389
2423
|
}
|
|
2390
2424
|
function readFile(file) {
|
|
2425
|
+
var infoId = document.getElementById('agentFileInfo') ? 'agentFileInfo' : 'fileInfo';
|
|
2426
|
+
var dropId = document.getElementById('agentFileDropZone') ? 'agentFileDropZone' : 'fileDropZone';
|
|
2427
|
+
var infoEl = document.getElementById(infoId);
|
|
2428
|
+
var dropEl = document.getElementById(dropId);
|
|
2391
2429
|
if (file.size > 500000) {
|
|
2392
|
-
|
|
2393
|
-
document.getElementById('fileInfo').textContent = 'File too large (max 500KB)';
|
|
2394
|
-
document.getElementById('fileInfo').style.color = 'var(--red)';
|
|
2430
|
+
if(infoEl){infoEl.style.display='block';infoEl.style.color='var(--red)';infoEl.textContent='File too large (max 500KB)';}
|
|
2395
2431
|
return;
|
|
2396
2432
|
}
|
|
2397
2433
|
var reader = new FileReader();
|
|
2398
2434
|
reader.onload = function(e) {
|
|
2399
2435
|
attachedFileContent = e.target.result;
|
|
2400
2436
|
attachedFileName = file.name;
|
|
2401
|
-
var
|
|
2402
|
-
|
|
2403
|
-
info.style.color = 'var(--cyan)';
|
|
2404
|
-
info.textContent = 'Attached: ' + file.name + ' (' + (file.size / 1024).toFixed(1) + ' KB)';
|
|
2405
|
-
document.getElementById('fileDropZone').style.borderColor = 'var(--green)';
|
|
2437
|
+
if(infoEl){infoEl.style.display='block';infoEl.style.color='var(--cyan)';infoEl.textContent='Attached: '+file.name+' ('+(file.size/1024).toFixed(1)+' KB)';}
|
|
2438
|
+
if(dropEl){dropEl.style.borderColor='var(--green)';}
|
|
2406
2439
|
};
|
|
2407
2440
|
reader.readAsText(file);
|
|
2408
2441
|
}
|
|
@@ -2411,9 +2444,13 @@ var agentAbortController = null;
|
|
|
2411
2444
|
|
|
2412
2445
|
function askAgent(){
|
|
2413
2446
|
var p=document.getElementById('modalPrompt').value.trim();if(!p||!selectedAgent)return;
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2447
|
+
|
|
2448
|
+
// Add user message to history
|
|
2449
|
+
agentChatHistory.push({role:'user',text:p});
|
|
2450
|
+
// Add waiting placeholder — shows dots until first token arrives
|
|
2451
|
+
agentChatHistory.push({role:'agent',text:'',waiting:true});
|
|
2452
|
+
renderAgentMessages();
|
|
2453
|
+
document.getElementById('modalPrompt').value='';
|
|
2417
2454
|
|
|
2418
2455
|
// Abort any previous stream
|
|
2419
2456
|
if(agentAbortController){try{agentAbortController.abort();}catch(e){}}
|
|
@@ -2422,11 +2459,16 @@ function askAgent(){
|
|
|
2422
2459
|
var payload={agent:selectedAgent,prompt:p};
|
|
2423
2460
|
if(attachedFileContent){payload.fileContent=attachedFileContent;payload.fileName=attachedFileName;}
|
|
2424
2461
|
|
|
2425
|
-
// Disable
|
|
2462
|
+
// Disable Send button while streaming
|
|
2426
2463
|
var askBtn=document.getElementById('agentAskBtn');
|
|
2427
2464
|
if(askBtn){askBtn.disabled=true;askBtn.textContent='...';}
|
|
2428
2465
|
|
|
2429
|
-
var
|
|
2466
|
+
var agentMsgIdx=agentChatHistory.length-1; // index of the streaming placeholder
|
|
2467
|
+
|
|
2468
|
+
function updateStreamingBubble(text,done){
|
|
2469
|
+
agentChatHistory[agentMsgIdx]={role:'agent',text:text,waiting:false,streaming:!done};
|
|
2470
|
+
renderAgentMessages();
|
|
2471
|
+
}
|
|
2430
2472
|
|
|
2431
2473
|
fetch(API+'/api/ask/stream',{
|
|
2432
2474
|
method:'POST',
|
|
@@ -2437,44 +2479,45 @@ function askAgent(){
|
|
|
2437
2479
|
var reader=response.body.getReader();
|
|
2438
2480
|
var decoder=new TextDecoder();
|
|
2439
2481
|
var buf='';
|
|
2482
|
+
var accumulated='';
|
|
2440
2483
|
function pump(){
|
|
2441
2484
|
return reader.read().then(function(result){
|
|
2442
2485
|
if(result.done){
|
|
2443
|
-
|
|
2444
|
-
if(
|
|
2445
|
-
try{resp.innerHTML=renderMd(accumulated);}catch(e){resp.textContent=accumulated;}
|
|
2446
|
-
}
|
|
2447
|
-
if(askBtn){askBtn.disabled=false;askBtn.textContent='Ask';}
|
|
2486
|
+
updateStreamingBubble(accumulated||'(empty response)',true);
|
|
2487
|
+
if(askBtn){askBtn.disabled=false;askBtn.textContent='Send';}
|
|
2448
2488
|
return;
|
|
2449
2489
|
}
|
|
2450
2490
|
buf+=decoder.decode(result.value,{stream:true});
|
|
2451
|
-
var
|
|
2452
|
-
var lines=buf.split(NLA);
|
|
2491
|
+
var lines=buf.split(String.fromCharCode(10));
|
|
2453
2492
|
buf=lines.pop();
|
|
2454
2493
|
lines.forEach(function(line){
|
|
2455
|
-
if(line.indexOf('data: ')
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2494
|
+
if(line.indexOf('data: ')!==0)return;
|
|
2495
|
+
try{
|
|
2496
|
+
var ev=JSON.parse(line.slice(6));
|
|
2497
|
+
if(ev.token){accumulated+=ev.token;updateStreamingBubble(accumulated,false);}
|
|
2498
|
+
if(ev.done){
|
|
2499
|
+
updateStreamingBubble(accumulated||'(empty response)',true);
|
|
2500
|
+
if(askBtn){askBtn.disabled=false;askBtn.textContent='Send';}
|
|
2501
|
+
attachedFileContent=null;attachedFileName=null;
|
|
2502
|
+
document.getElementById('agentFileInfo').style.display='none';
|
|
2503
|
+
document.getElementById('agentFileInput').value='';
|
|
2504
|
+
document.getElementById('agentFileDropZone').style.borderColor='';
|
|
2505
|
+
}
|
|
2506
|
+
if(ev.error){
|
|
2507
|
+
updateStreamingBubble('\u26a0\ufe0f Error: '+ev.error,true);
|
|
2508
|
+
if(askBtn){askBtn.disabled=false;askBtn.textContent='Send';}
|
|
2509
|
+
}
|
|
2510
|
+
}catch(e){}
|
|
2470
2511
|
});
|
|
2471
2512
|
return pump();
|
|
2472
2513
|
});
|
|
2473
2514
|
}
|
|
2474
2515
|
return pump();
|
|
2475
2516
|
}).catch(function(err){
|
|
2476
|
-
if(err.name!=='AbortError'){
|
|
2477
|
-
|
|
2517
|
+
if(err.name!=='AbortError'){
|
|
2518
|
+
updateStreamingBubble('\u26a0\ufe0f Stream error: '+err.message,true);
|
|
2519
|
+
}
|
|
2520
|
+
if(askBtn){askBtn.disabled=false;askBtn.textContent='Send';}
|
|
2478
2521
|
});
|
|
2479
2522
|
}
|
|
2480
2523
|
|
|
@@ -2773,9 +2816,12 @@ async function runStudio() {
|
|
|
2773
2816
|
renderStudioResult();
|
|
2774
2817
|
|
|
2775
2818
|
var btn = document.getElementById('studioRunBtn');
|
|
2776
|
-
if (btn) btn.disabled = true;
|
|
2819
|
+
if (btn) { btn.disabled = true; btn.textContent = 'Planning...'; }
|
|
2777
2820
|
|
|
2778
2821
|
studioLog('Studio', '⚙', 'Planning workflow for: "' + task + '"', 'system');
|
|
2822
|
+
// Show a temporary planning indicator in the nodes area
|
|
2823
|
+
var nodesEl = document.getElementById('studioNodes');
|
|
2824
|
+
if (nodesEl) nodesEl.innerHTML = '<div style="text-align:center;padding:20px;color:var(--dim);font-size:12px;font-family:var(--font)"><span class="thinking-dots"><span></span><span></span><span></span></span><div style="margin-top:8px">Designing workflow...</div></div>';
|
|
2779
2825
|
|
|
2780
2826
|
try {
|
|
2781
2827
|
// Step 1: plan the workflow
|
|
@@ -2815,9 +2861,8 @@ async function runStudio() {
|
|
|
2815
2861
|
var ct = document.getElementById('canvasTitle');
|
|
2816
2862
|
if (cf && cp) {
|
|
2817
2863
|
cf.srcdoc = stepResult.canvas;
|
|
2818
|
-
cp.
|
|
2864
|
+
cp.classList.add('open');
|
|
2819
2865
|
if (ct) ct.textContent = node.label + ' Report';
|
|
2820
|
-
canvasShowCanvas();
|
|
2821
2866
|
}
|
|
2822
2867
|
}
|
|
2823
2868
|
context = stepResult.output || stepResult.canvas || context;
|
|
@@ -2837,7 +2882,7 @@ async function runStudio() {
|
|
|
2837
2882
|
}
|
|
2838
2883
|
|
|
2839
2884
|
studioState.running = false;
|
|
2840
|
-
if (btn) btn.disabled = false;
|
|
2885
|
+
if (btn) { btn.disabled = false; btn.textContent = 'Run'; }
|
|
2841
2886
|
}
|
|
2842
2887
|
|
|
2843
2888
|
// ---- STUDIO SESSIONS ----
|
|
@@ -2982,8 +3027,9 @@ function runStudioStep(idx, node, task, context, stepDef) {
|
|
|
2982
3027
|
var cp2 = document.getElementById('canvasPanel');
|
|
2983
3028
|
if (cf2 && cp2) {
|
|
2984
3029
|
cf2.srcdoc = canvasHtml;
|
|
2985
|
-
cp2.
|
|
2986
|
-
|
|
3030
|
+
cp2.classList.add('open');
|
|
3031
|
+
var ct2 = document.getElementById('canvasTitle');
|
|
3032
|
+
if (ct2) ct2.textContent = 'Studio Report';
|
|
2987
3033
|
}
|
|
2988
3034
|
}
|
|
2989
3035
|
if (ev.usage) { studioAddTokens(ev.usage.input||0, ev.usage.output||0); }
|
|
@@ -3305,7 +3351,7 @@ async function runManualWorkflow() {
|
|
|
3305
3351
|
if (stepResult.canvas) {
|
|
3306
3352
|
var cf = document.getElementById('canvasFrame');
|
|
3307
3353
|
var cp = document.getElementById('canvasPanel');
|
|
3308
|
-
if (cf && cp) { cf.srcdoc = stepResult.canvas; cp.
|
|
3354
|
+
if (cf && cp) { cf.srcdoc = stepResult.canvas; cp.classList.add('open'); var ct3=document.getElementById('canvasTitle'); if(ct3) ct3.textContent='Studio Report'; }
|
|
3309
3355
|
}
|
|
3310
3356
|
context = stepResult.output || stepResult.canvas || context;
|
|
3311
3357
|
}
|
|
@@ -3562,7 +3608,8 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3562
3608
|
/* ---- MODAL ---- */
|
|
3563
3609
|
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:300;align-items:center;justify-content:center}
|
|
3564
3610
|
.modal-overlay--open{display:flex}
|
|
3565
|
-
.modal{background:var(--bg2);border:1px solid var(--border2);border-radius:8px;width:92%;max-width:
|
|
3611
|
+
.modal{background:var(--bg2);border:1px solid var(--border2);border-radius:8px;width:92%;max-width:560px;max-height:90vh;display:flex;flex-direction:column}
|
|
3612
|
+
.modal--chat{height:80vh}
|
|
3566
3613
|
.modal__header{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border-bottom:1px solid var(--border)}
|
|
3567
3614
|
.modal__header h2{font-size:16px;color:var(--green)}
|
|
3568
3615
|
.modal__close{background:none;color:var(--dim);font-size:24px;padding:0 4px}
|
|
@@ -3570,6 +3617,18 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3570
3617
|
.modal__body textarea{width:100%;min-height:80px;margin-bottom:10px}
|
|
3571
3618
|
.modal__response{background:var(--bg3);border:1px solid var(--border);border-radius:var(--r);padding:12px;word-wrap:break-word;max-height:400px;overflow-y:auto;font-size:13px}
|
|
3572
3619
|
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border)}
|
|
3620
|
+
.modal--chat .modal__body{padding:0;display:flex;flex-direction:column;overflow:hidden}
|
|
3621
|
+
.agent-chat{display:flex;flex-direction:column;height:100%;min-height:0;padding:12px 16px;box-sizing:border-box}
|
|
3622
|
+
.agent-chat__messages{flex:1;overflow-y:auto;padding:4px 0 8px;min-height:0;display:flex;flex-direction:column;gap:8px}
|
|
3623
|
+
.agent-chat__bubble{max-width:88%;border-radius:8px;padding:8px 12px;font-size:13px;line-height:1.55;word-wrap:break-word}
|
|
3624
|
+
.agent-chat__bubble--user{align-self:flex-end;background:var(--green3);color:#e8ffe8}
|
|
3625
|
+
.agent-chat__bubble--agent{align-self:flex-start;background:var(--bg3);border:1px solid var(--border)}
|
|
3626
|
+
.agent-chat__footer{display:flex;flex-direction:column;gap:6px;padding-top:8px;border-top:1px solid var(--border)}
|
|
3627
|
+
.agent-chat__drop{border:2px dashed var(--border2);border-radius:6px;padding:8px;text-align:center;color:var(--dim);font-size:11px;cursor:pointer;transition:border-color .2s}
|
|
3628
|
+
.agent-chat__drop:hover{border-color:var(--green)}
|
|
3629
|
+
.agent-chat__input-row{display:flex;gap:6px;align-items:flex-end}
|
|
3630
|
+
.agent-chat__input{flex:1;background:var(--bg2);border:1px solid var(--border);border-radius:var(--r);padding:8px 10px;color:var(--fg);font-size:13px;font-family:var(--font);resize:none;min-height:36px;max-height:120px;overflow-y:auto;outline:none}
|
|
3631
|
+
.agent-chat__input:focus{border-color:var(--green)}
|
|
3573
3632
|
.btn{padding:8px 16px;border-radius:var(--r);font-size:12px;font-weight:600}
|
|
3574
3633
|
.btn--primary{background:var(--green3);color:var(--bg)}
|
|
3575
3634
|
.btn--secondary{background:var(--bg3);color:var(--dim);border:1px solid var(--border)}
|
|
@@ -3577,6 +3636,11 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3577
3636
|
/* ---- SPINNER ---- */
|
|
3578
3637
|
.spinner{width:24px;height:24px;border:2px solid var(--border);border-top-color:var(--green);border-radius:50%;animation:spin .6s linear infinite;margin:0 auto 12px}
|
|
3579
3638
|
@keyframes spin{to{transform:rotate(360deg)}}
|
|
3639
|
+
.thinking-dots{display:inline-flex;gap:4px;align-items:center;padding:2px 0}
|
|
3640
|
+
.thinking-dots span{width:6px;height:6px;border-radius:50%;background:var(--dim);animation:tdot 1.2s ease-in-out infinite}
|
|
3641
|
+
.thinking-dots span:nth-child(2){animation-delay:.2s}
|
|
3642
|
+
.thinking-dots span:nth-child(3){animation-delay:.4s}
|
|
3643
|
+
@keyframes tdot{0%,80%,100%{opacity:.2;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}
|
|
3580
3644
|
|
|
3581
3645
|
/* ---- TOASTS (real-time notifications) ---- */
|
|
3582
3646
|
.toast-container{position:fixed;top:16px;right:16px;z-index:500;display:flex;flex-direction:column;gap:8px;pointer-events:none}
|
|
@@ -3778,23 +3842,26 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3778
3842
|
</div>
|
|
3779
3843
|
|
|
3780
3844
|
<div class="modal-overlay" id="agentModal">
|
|
3781
|
-
<div class="modal">
|
|
3845
|
+
<div class="modal modal--chat">
|
|
3782
3846
|
<div class="modal__header">
|
|
3783
3847
|
<div><h2 id="modalName">Agent</h2><div id="modalAgentDesc" style="font-size:10px;color:var(--dim);margin-top:2px"></div></div>
|
|
3784
3848
|
<button class="modal__close" onclick="closeModal()">×</button>
|
|
3785
3849
|
</div>
|
|
3786
3850
|
<div class="modal__body">
|
|
3787
|
-
<
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3851
|
+
<div class="agent-chat">
|
|
3852
|
+
<div class="agent-chat__messages" id="agentMessages"></div>
|
|
3853
|
+
<div class="agent-chat__footer">
|
|
3854
|
+
<div class="agent-chat__drop" id="agentFileDropZone" onclick="document.getElementById('agentFileInput').click()" ondragover="event.preventDefault();this.style.borderColor='var(--green)'" ondragleave="this.style.borderColor=''" ondrop="event.preventDefault();this.style.borderColor='';handleFileDrop(event)">
|
|
3855
|
+
Drop a file or click to attach
|
|
3856
|
+
<input type="file" id="agentFileInput" style="display:none" onchange="handleFileSelect(this)">
|
|
3857
|
+
</div>
|
|
3858
|
+
<div id="agentFileInfo" style="display:none;font-size:10px;color:var(--cyan)"></div>
|
|
3859
|
+
<div class="agent-chat__input-row">
|
|
3860
|
+
<textarea class="agent-chat__input" id="modalPrompt" rows="1" placeholder="Ask this agent... (Enter to send)" onkeydown="if(event.key==='Enter'&&!event.shiftKey){askAgent();event.preventDefault();}"></textarea>
|
|
3861
|
+
<button class="btn btn--primary" id="agentAskBtn" onclick="askAgent()" style="height:36px;padding:0 14px">Send</button>
|
|
3862
|
+
</div>
|
|
3863
|
+
</div>
|
|
3791
3864
|
</div>
|
|
3792
|
-
<div id="fileInfo" style="display:none;font-size:10px;color:var(--cyan);margin-bottom:8px"></div>
|
|
3793
|
-
<div class="modal__response md-body" id="modalResponse" style="display:none"></div>
|
|
3794
|
-
</div>
|
|
3795
|
-
<div class="modal__footer">
|
|
3796
|
-
<button class="btn btn--secondary" onclick="closeModal()">Close</button>
|
|
3797
|
-
<button class="btn btn--primary" id="agentAskBtn" onclick="askAgent()">Ask</button>
|
|
3798
3865
|
</div>
|
|
3799
3866
|
</div>
|
|
3800
3867
|
</div>
|