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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "13.2.12",
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": {
@@ -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-4 steps. IMPORTANT RULES:
2549
- - Use WebSearchAgent ONLY as step 1 when real web data is needed — it fetches real search results
2550
- - Use WriterAgent, SummaryAgent, DataAnalystAgent for analysis/synthesis steps — they work on text, NO tool calls
2551
- - Use CanvasAgent as the LAST step ONLY when a visual HTML report is explicitly requested
2552
- - The "prompt" field must be a plain language instruction — NEVER include JSON, tool calls, or code
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
- Available agents: WebSearchAgent, ResearchAgent, EmailAgent, CalendarAgent, GitHubAgent, NotionAgent, SlackAgent, WriterAgent, SummaryAgent, DataAnalystAgent, SecurityAgent, DevOpsAgent, CanvasAgent
2556
-
2557
- Icon values must be actual emoji characters (e.g. the magnifying glass emoji, pencil emoji, chart emoji, paintbrush emoji) — never HTML entities.
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 artificial intelligence news today and return the top 5 results with title, source and description"},{"icon":"✍️","agent":"WriterAgent","label":"Select and analyze","prompt":"From the search results provided, select the 3 most important AI news items and write a detailed analysis of each"}]}`;
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
- const isPureAnalysis = ['WriterAgent','SummaryAgent','DataAnalystAgent','SecurityAgent','DevOpsAgent'].includes(agent);
2697
-
2698
- const canvasSystemPrompt = `You are an HTML report generator. Your ONLY job is to output a single complete HTML document.
2699
- CRITICAL RULES:
2700
- - Start your response with exactly: <!DOCTYPE html>
2701
- - Do NOT wrap output in JSON, markdown code blocks, or any other format
2702
- - Do NOT output {"action":...} or any JSON
2703
- - Output raw HTML only, starting with <!DOCTYPE html> on the very first line
2704
- - Use a modern, clean design: white background, Inter/system font, subtle shadows, no cyberpunk
2705
- - Structure: header with title + subtitle, then content cards/sections
2706
- - Make it visually rich with proper spacing, colors (#6366f1 accent), and typography`;
2707
-
2708
- const agentInstruction = isCanvasAgent
2709
- ? `${canvasSystemPrompt}\n\nContent to render as HTML report:\n${context.slice(0, 4000)}`
2710
- : `You are ${agent}, a specialist AI agent inside NHA Studio.\nYour task: ${stepPrompt}\n` +
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
- (isPureAnalysis
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
- const sysPrompt = isCanvasAgent
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
- if (isCanvasAgent) {
2732
- // CanvasAgent: non-streaming call — more reliable for large HTML output
2733
- sendToken('Generating visual report...');
2734
- try {
2735
- fullOutput = await withTimeout(
2736
- callLLM(config, sysPrompt, userMsg, { max_tokens: 3000 }),
2737
- 'CanvasAgent'
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
- // Extract from JSON {"html": "..."}
2755
- if (!html.includes('<!DOCTYPE') && html.includes('"html"')) {
2756
- try {
2757
- const jm = html.match(/"html"\s*:\s*"([\s\S]+?)(?<!\\)"/);
2758
- if (jm) html = JSON.parse('"' + jm[1] + '"');
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 = (userMsg.slice(0, 80) || 'NHA Studio Report').replace(/</g,'&lt;').replace(/>/g,'&gt;');
2827
+ const reportTitle = (task.slice(0, 80) || 'NHA Studio Report').replace(/</g,'&lt;').replace(/>/g,'&gt;');
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.12';
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
 
@@ -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('modalPrompt').style.display='none';
1194
- document.getElementById('fileDropZone').style.display='none';
1195
- document.getElementById('fileInfo').style.display='none';
1196
- document.getElementById('modalResponse').style.display='block';
1197
- document.getElementById('modalResponse').innerHTML=h;
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('modalPrompt').style.display='';
2176
- document.getElementById('modalResponse').style.display='none';
2177
- document.getElementById('modalResponse').textContent='';
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='Ask';}
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
- document.getElementById('fileInfo').style.display = 'block';
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 info = document.getElementById('fileInfo');
2402
- info.style.display = 'block';
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
- var resp=document.getElementById('modalResponse');
2415
- resp.style.display='block';
2416
- resp.innerHTML='<span style="color:var(--dim)">Thinking...</span>';
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 Ask button while streaming
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 accumulated='';
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
- // fallback if done event never arrived
2444
- if(accumulated && resp.textContent!==accumulated){
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 NLA=String.fromCharCode(10);
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: ')===0){
2456
- try{
2457
- var ev=JSON.parse(line.slice(6));
2458
- if(ev.token){accumulated+=ev.token;resp.textContent=accumulated+'\u258B';}
2459
- if(ev.done){
2460
- try{resp.innerHTML=renderMd(accumulated||'(empty response)');}catch(e){resp.textContent=accumulated||'(empty response)';}
2461
- if(askBtn){askBtn.disabled=false;askBtn.textContent='Ask';}
2462
- attachedFileContent=null;attachedFileName=null;
2463
- document.getElementById('fileInfo').style.display='none';
2464
- document.getElementById('fileDropZone').style.borderColor='var(--border2)';
2465
- document.getElementById('fileInput').value='';
2466
- }
2467
- if(ev.error){resp.innerHTML='<span style="color:var(--red)">Error: '+esc(ev.error)+'</span>';if(askBtn){askBtn.disabled=false;askBtn.textContent='Ask';}}
2468
- }catch(e){}
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'){resp.innerHTML='<span style="color:var(--red)">Stream error: '+esc(err.message)+'</span>';}
2477
- if(askBtn){askBtn.disabled=false;askBtn.textContent='Ask';}
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', '&#9881;', '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.style.display = 'flex';
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.style.display = 'flex';
2986
- canvasShowCanvas();
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.style.display='flex'; canvasShowCanvas(); }
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:540px;max-height:90vh;display:flex;flex-direction:column}
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()">&times;</button>
3785
3849
  </div>
3786
3850
  <div class="modal__body">
3787
- <textarea id="modalPrompt" placeholder="Ask this agent something... (Enter to send)" onkeydown="if(event.key==='Enter'&&!event.shiftKey){askAgent();event.preventDefault();}"></textarea>
3788
- <div id="fileDropZone" style="border:2px dashed var(--border2);border-radius:6px;padding:12px;text-align:center;color:var(--dim);font-size:11px;cursor:pointer;margin-bottom:10px;transition:border-color .2s" onclick="document.getElementById('fileInput').click()" ondragover="event.preventDefault();this.style.borderColor='var(--green)'" ondragleave="this.style.borderColor='var(--border2)'" ondrop="event.preventDefault();this.style.borderColor='var(--border2)';handleFileDrop(event)">
3789
- Drop a file here or click to attach
3790
- <input type="file" id="fileInput" style="display:none" onchange="handleFileSelect(this)">
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>