nothumanallowed 13.2.12 → 13.2.14
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 +129 -66
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +146 -76
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.14",
|
|
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,89 @@ 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
|
-
|
|
2748
|
+
// Tool-data agents: fetch real live data and use buildSystemPrompt (tool calls allowed)
|
|
2749
|
+
const isLiveDataAgent = ['CalendarAgent','EmailAgent','GitHubAgent','NotionAgent','SlackAgent','DriveAgent','BrowserAgent','WebSearchAgent','ResearchAgent'].includes(agent);
|
|
2697
2750
|
|
|
2698
|
-
const canvasSystemPrompt = `You are an HTML report generator.
|
|
2699
|
-
|
|
2700
|
-
-
|
|
2701
|
-
- Do NOT
|
|
2702
|
-
-
|
|
2703
|
-
-
|
|
2704
|
-
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2751
|
+
const canvasSystemPrompt = `You are an HTML report generator. Output a single complete HTML document. No preamble, no explanation.
|
|
2752
|
+
RULES:
|
|
2753
|
+
- First character of your response must be < (start of <!DOCTYPE html>)
|
|
2754
|
+
- Do NOT use markdown code blocks, JSON, or any wrapper
|
|
2755
|
+
- Use clean design: white background, Inter/system-ui font, #6366f1 accent color
|
|
2756
|
+
- Structure: gradient header, then card sections with the content
|
|
2757
|
+
- Make it complete and self-contained`;
|
|
2758
|
+
|
|
2759
|
+
let sysPrompt, userMsg;
|
|
2760
|
+
|
|
2761
|
+
if (isCanvasAgent) {
|
|
2762
|
+
sysPrompt = canvasSystemPrompt;
|
|
2763
|
+
userMsg = `Generate a beautiful HTML dashboard report for this content. Start immediately with <!DOCTYPE html>:\n\n${context.slice(0, 8000)}`;
|
|
2764
|
+
} else if (isLiveDataAgent) {
|
|
2765
|
+
// These agents fetched real data — use buildSystemPrompt so they can call tools too
|
|
2766
|
+
const agentInstruction = `You are ${agent}, a specialist AI agent inside NHA Studio.\nYour task: ${stepPrompt}\n` +
|
|
2711
2767
|
(toolData ? `\n## DATA FROM TOOLS:\n${toolData.slice(0, 4000)}\n` : '') +
|
|
2712
2768
|
(context ? `\n## OUTPUT FROM PREVIOUS AGENTS:\n${context.slice(0, 3000)}\n` : '') +
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
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) ──────
|
|
2730
|
-
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
|
-
}
|
|
2769
|
+
'\nWrite your analysis in plain text. Do NOT output JSON, tool calls, or code blocks. Summarize the data clearly.';
|
|
2770
|
+
sysPrompt = buildSystemPrompt(agent, agentInstruction, config);
|
|
2771
|
+
userMsg = toolData
|
|
2772
|
+
? `Summarize the data above for: ${stepPrompt}`
|
|
2773
|
+
: context
|
|
2774
|
+
? `Based on the previous output, complete: ${stepPrompt}`
|
|
2775
|
+
: stepPrompt;
|
|
2742
2776
|
} else {
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2777
|
+
// All other agents (WriterAgent, DataAnalystAgent, specialist agents, etc.)
|
|
2778
|
+
// Use a focused prompt with NO TOOL_DEFINITIONS to prevent JSON/tool-call output
|
|
2779
|
+
const today = new Date().toISOString().split('T')[0];
|
|
2780
|
+
const language = config?.language || 'Italian';
|
|
2781
|
+
sysPrompt = `You are ${agent}, a specialist AI agent inside NHA Studio. Today is ${today}. Respond in ${language}.
|
|
2782
|
+
|
|
2783
|
+
CRITICAL RULES:
|
|
2784
|
+
- Do NOT output JSON, tool calls, function calls, or code blocks
|
|
2785
|
+
- Do NOT ask for more information — use only the data provided below
|
|
2786
|
+
- Write in plain prose, structured with headers and bullet points where appropriate
|
|
2787
|
+
- Be thorough and specific — this is for an executive briefing
|
|
2788
|
+
|
|
2789
|
+
${toolData ? `## LIVE DATA:\n${toolData.slice(0, 4000)}\n` : ''}
|
|
2790
|
+
${context ? `## CONTEXT FROM PREVIOUS AGENTS:\n${context.slice(0, 5000)}\n` : ''}`;
|
|
2791
|
+
userMsg = toolData
|
|
2792
|
+
? `Use the live data and context above to complete this task: ${stepPrompt}`
|
|
2793
|
+
: context
|
|
2794
|
+
? `Using the context from previous steps, complete this task: ${stepPrompt}`
|
|
2795
|
+
: stepPrompt;
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
// ── Stream LLM response ───────────────────────────────────────
|
|
2799
|
+
let fullOutput = '';
|
|
2800
|
+
sendToken(isCanvasAgent ? 'Generating visual report...' : '');
|
|
2801
|
+
try {
|
|
2802
|
+
await withTimeout(
|
|
2803
|
+
callLLMStream(config, sysPrompt, userMsg,
|
|
2804
|
+
(token) => { fullOutput += token; if (!isCanvasAgent) sendToken(token); },
|
|
2805
|
+
),
|
|
2806
|
+
isCanvasAgent ? 60000 : 35000
|
|
2746
2807
|
);
|
|
2808
|
+
} catch (e) {
|
|
2809
|
+
if (!isCanvasAgent) sendToken(`[Error: ${e.message}]`);
|
|
2747
2810
|
}
|
|
2748
2811
|
|
|
2749
2812
|
if (isCanvasAgent) {
|
|
2750
|
-
let html = fullOutput;
|
|
2813
|
+
let html = fullOutput.trim();
|
|
2814
|
+
// Strip thinking tags if not already filtered
|
|
2815
|
+
html = html.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
2751
2816
|
// Extract from markdown code block
|
|
2752
|
-
const mdMatch = html.match(/```html?\s*([\s\S]*?)```/);
|
|
2817
|
+
const mdMatch = html.match(/```html?\s*([\s\S]*?)```/i);
|
|
2753
2818
|
if (mdMatch) html = mdMatch[1].trim();
|
|
2754
|
-
//
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
} catch {}
|
|
2760
|
-
}
|
|
2819
|
+
// Find <!DOCTYPE or <html start if there's preamble text
|
|
2820
|
+
const doctypeIdx = html.indexOf('<!DOCTYPE');
|
|
2821
|
+
const htmlTagIdx = html.indexOf('<html');
|
|
2822
|
+
const startIdx = doctypeIdx >= 0 ? doctypeIdx : (htmlTagIdx >= 0 ? htmlTagIdx : -1);
|
|
2823
|
+
if (startIdx > 0) html = html.slice(startIdx);
|
|
2761
2824
|
// Fallback: build clean HTML from the context directly (no LLM needed)
|
|
2762
2825
|
if (!html.trim() || !html.includes('<')) {
|
|
2763
2826
|
// Try splitting on markdown headings first, then numbered items, then double newlines
|
|
2764
2827
|
let sections = context.split(/\n#{1,3} /).filter(s => s.trim());
|
|
2765
2828
|
if (sections.length <= 1) sections = context.split(/\n(?=\*\*\d+[\.\)])|(?=^\d+[\.\)])/).filter(s => s.trim());
|
|
2766
2829
|
if (sections.length <= 1) sections = context.split(/\n{2,}/).filter(s => s.trim());
|
|
2767
|
-
const reportTitle = (
|
|
2830
|
+
const reportTitle = (task.slice(0, 80) || 'NHA Studio Report').replace(/</g,'<').replace(/>/g,'>');
|
|
2768
2831
|
const cardsHtml = sections.map(s => {
|
|
2769
2832
|
const clean = s.replace(/\*\*/g, '').replace(/\*/g, '').trim();
|
|
2770
2833
|
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.14';
|
|
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
|
|
|
@@ -2705,7 +2748,8 @@ function renderStudioNodes() {
|
|
|
2705
2748
|
else if (n.status === 'done') cls += ' studio-node--done';
|
|
2706
2749
|
else if (n.status === 'error') cls += ' studio-node--error';
|
|
2707
2750
|
var statusLabel = {waiting:'◯ wait', running:'▶ running', done:'✓ done', error:'✕ error'}[n.status] || '';
|
|
2708
|
-
|
|
2751
|
+
var delay = (i * 120) + 'ms';
|
|
2752
|
+
html += '<div class="' + cls + '" style="animation-delay:' + delay + '">';
|
|
2709
2753
|
html += '<div class="studio-node__circle">' + n.icon + '</div>';
|
|
2710
2754
|
html += '<div class="studio-node__label">' + esc(n.label) + '</div>';
|
|
2711
2755
|
html += '<div class="studio-node__status studio-node__status--' + n.status + '">' + statusLabel + '</div>';
|
|
@@ -2715,7 +2759,8 @@ function renderStudioNodes() {
|
|
|
2715
2759
|
var arrowCls = 'studio-arrow';
|
|
2716
2760
|
if (n.status === 'done' && next.status === 'running') arrowCls += ' studio-arrow--active';
|
|
2717
2761
|
else if (n.status === 'done') arrowCls += ' studio-arrow--done';
|
|
2718
|
-
|
|
2762
|
+
var arrowDelay = (i * 120 + 60) + 'ms';
|
|
2763
|
+
html += '<div class="' + arrowCls + '" style="opacity:0;animation:stNodeIn .3s ease ' + arrowDelay + ' forwards">→</div>';
|
|
2719
2764
|
}
|
|
2720
2765
|
});
|
|
2721
2766
|
html += '</div>';
|
|
@@ -2773,9 +2818,12 @@ async function runStudio() {
|
|
|
2773
2818
|
renderStudioResult();
|
|
2774
2819
|
|
|
2775
2820
|
var btn = document.getElementById('studioRunBtn');
|
|
2776
|
-
if (btn) btn.disabled = true;
|
|
2821
|
+
if (btn) { btn.disabled = true; btn.textContent = 'Planning...'; }
|
|
2777
2822
|
|
|
2778
2823
|
studioLog('Studio', '⚙', 'Planning workflow for: "' + task + '"', 'system');
|
|
2824
|
+
// Show a temporary planning indicator in the nodes area
|
|
2825
|
+
var nodesEl = document.getElementById('studioNodes');
|
|
2826
|
+
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
2827
|
|
|
2780
2828
|
try {
|
|
2781
2829
|
// Step 1: plan the workflow
|
|
@@ -2815,9 +2863,8 @@ async function runStudio() {
|
|
|
2815
2863
|
var ct = document.getElementById('canvasTitle');
|
|
2816
2864
|
if (cf && cp) {
|
|
2817
2865
|
cf.srcdoc = stepResult.canvas;
|
|
2818
|
-
cp.
|
|
2866
|
+
cp.classList.add('open');
|
|
2819
2867
|
if (ct) ct.textContent = node.label + ' Report';
|
|
2820
|
-
canvasShowCanvas();
|
|
2821
2868
|
}
|
|
2822
2869
|
}
|
|
2823
2870
|
context = stepResult.output || stepResult.canvas || context;
|
|
@@ -2837,7 +2884,7 @@ async function runStudio() {
|
|
|
2837
2884
|
}
|
|
2838
2885
|
|
|
2839
2886
|
studioState.running = false;
|
|
2840
|
-
if (btn) btn.disabled = false;
|
|
2887
|
+
if (btn) { btn.disabled = false; btn.textContent = 'Run'; }
|
|
2841
2888
|
}
|
|
2842
2889
|
|
|
2843
2890
|
// ---- STUDIO SESSIONS ----
|
|
@@ -2982,8 +3029,9 @@ function runStudioStep(idx, node, task, context, stepDef) {
|
|
|
2982
3029
|
var cp2 = document.getElementById('canvasPanel');
|
|
2983
3030
|
if (cf2 && cp2) {
|
|
2984
3031
|
cf2.srcdoc = canvasHtml;
|
|
2985
|
-
cp2.
|
|
2986
|
-
|
|
3032
|
+
cp2.classList.add('open');
|
|
3033
|
+
var ct2 = document.getElementById('canvasTitle');
|
|
3034
|
+
if (ct2) ct2.textContent = 'Studio Report';
|
|
2987
3035
|
}
|
|
2988
3036
|
}
|
|
2989
3037
|
if (ev.usage) { studioAddTokens(ev.usage.input||0, ev.usage.output||0); }
|
|
@@ -3305,7 +3353,7 @@ async function runManualWorkflow() {
|
|
|
3305
3353
|
if (stepResult.canvas) {
|
|
3306
3354
|
var cf = document.getElementById('canvasFrame');
|
|
3307
3355
|
var cp = document.getElementById('canvasPanel');
|
|
3308
|
-
if (cf && cp) { cf.srcdoc = stepResult.canvas; cp.
|
|
3356
|
+
if (cf && cp) { cf.srcdoc = stepResult.canvas; cp.classList.add('open'); var ct3=document.getElementById('canvasTitle'); if(ct3) ct3.textContent='Studio Report'; }
|
|
3309
3357
|
}
|
|
3310
3358
|
context = stepResult.output || stepResult.canvas || context;
|
|
3311
3359
|
}
|
|
@@ -3562,7 +3610,8 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3562
3610
|
/* ---- MODAL ---- */
|
|
3563
3611
|
.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
3612
|
.modal-overlay--open{display:flex}
|
|
3565
|
-
.modal{background:var(--bg2);border:1px solid var(--border2);border-radius:8px;width:92%;max-width:
|
|
3613
|
+
.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}
|
|
3614
|
+
.modal--chat{height:80vh}
|
|
3566
3615
|
.modal__header{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border-bottom:1px solid var(--border)}
|
|
3567
3616
|
.modal__header h2{font-size:16px;color:var(--green)}
|
|
3568
3617
|
.modal__close{background:none;color:var(--dim);font-size:24px;padding:0 4px}
|
|
@@ -3570,6 +3619,18 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3570
3619
|
.modal__body textarea{width:100%;min-height:80px;margin-bottom:10px}
|
|
3571
3620
|
.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
3621
|
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border)}
|
|
3622
|
+
.modal--chat .modal__body{padding:0;display:flex;flex-direction:column;overflow:hidden}
|
|
3623
|
+
.agent-chat{display:flex;flex-direction:column;height:100%;min-height:0;padding:12px 16px;box-sizing:border-box}
|
|
3624
|
+
.agent-chat__messages{flex:1;overflow-y:auto;padding:4px 0 8px;min-height:0;display:flex;flex-direction:column;gap:8px}
|
|
3625
|
+
.agent-chat__bubble{max-width:88%;border-radius:8px;padding:8px 12px;font-size:13px;line-height:1.55;word-wrap:break-word}
|
|
3626
|
+
.agent-chat__bubble--user{align-self:flex-end;background:var(--green3);color:#e8ffe8}
|
|
3627
|
+
.agent-chat__bubble--agent{align-self:flex-start;background:var(--bg3);border:1px solid var(--border)}
|
|
3628
|
+
.agent-chat__footer{display:flex;flex-direction:column;gap:6px;padding-top:8px;border-top:1px solid var(--border)}
|
|
3629
|
+
.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}
|
|
3630
|
+
.agent-chat__drop:hover{border-color:var(--green)}
|
|
3631
|
+
.agent-chat__input-row{display:flex;gap:6px;align-items:flex-end}
|
|
3632
|
+
.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}
|
|
3633
|
+
.agent-chat__input:focus{border-color:var(--green)}
|
|
3573
3634
|
.btn{padding:8px 16px;border-radius:var(--r);font-size:12px;font-weight:600}
|
|
3574
3635
|
.btn--primary{background:var(--green3);color:var(--bg)}
|
|
3575
3636
|
.btn--secondary{background:var(--bg3);color:var(--dim);border:1px solid var(--border)}
|
|
@@ -3577,6 +3638,11 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3577
3638
|
/* ---- SPINNER ---- */
|
|
3578
3639
|
.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
3640
|
@keyframes spin{to{transform:rotate(360deg)}}
|
|
3641
|
+
.thinking-dots{display:inline-flex;gap:4px;align-items:center;padding:2px 0}
|
|
3642
|
+
.thinking-dots span{width:6px;height:6px;border-radius:50%;background:var(--dim);animation:tdot 1.2s ease-in-out infinite}
|
|
3643
|
+
.thinking-dots span:nth-child(2){animation-delay:.2s}
|
|
3644
|
+
.thinking-dots span:nth-child(3){animation-delay:.4s}
|
|
3645
|
+
@keyframes tdot{0%,80%,100%{opacity:.2;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}
|
|
3580
3646
|
|
|
3581
3647
|
/* ---- TOASTS (real-time notifications) ---- */
|
|
3582
3648
|
.toast-container{position:fixed;top:16px;right:16px;z-index:500;display:flex;flex-direction:column;gap:8px;pointer-events:none}
|
|
@@ -3614,7 +3680,8 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3614
3680
|
.studio-canvas__empty{display:flex;align-items:center;justify-content:center;height:180px;color:var(--dim);font-size:11px;flex-direction:column;gap:8px}
|
|
3615
3681
|
.studio-canvas__empty-icon{font-size:32px;opacity:.3}
|
|
3616
3682
|
.studio-nodes{display:flex;align-items:center;gap:0;padding:28px 24px;overflow-x:auto;min-height:130px;background:var(--bg2);border-radius:10px;border:1px solid var(--border);margin-bottom:16px}
|
|
3617
|
-
.studio-node{position:relative;display:flex;flex-direction:column;align-items:center;gap:7px;min-width:106px;max-width:126px}
|
|
3683
|
+
.studio-node{position:relative;display:flex;flex-direction:column;align-items:center;gap:7px;min-width:106px;max-width:126px;opacity:0;animation:stNodeIn .35s ease forwards}
|
|
3684
|
+
@keyframes stNodeIn{from{opacity:0;transform:translateY(10px) scale(.92)}to{opacity:1;transform:translateY(0) scale(1)}}
|
|
3618
3685
|
.studio-node__circle{width:56px;height:56px;border-radius:14px;border:1.5px solid var(--border2);background:var(--bg3);display:flex;align-items:center;justify-content:center;font-size:22px;transition:all .35s;flex-shrink:0}
|
|
3619
3686
|
.studio-node--active .studio-node__circle{border-color:var(--green3);box-shadow:0 0 0 4px rgba(99,102,241,.15);background:var(--greendim);animation:stRing 1.4s ease-out infinite}
|
|
3620
3687
|
.studio-node--done .studio-node__circle{border-color:#22c55e;background:rgba(34,197,94,.08);box-shadow:0 0 0 3px rgba(34,197,94,.12)}
|
|
@@ -3778,23 +3845,26 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
3778
3845
|
</div>
|
|
3779
3846
|
|
|
3780
3847
|
<div class="modal-overlay" id="agentModal">
|
|
3781
|
-
<div class="modal">
|
|
3848
|
+
<div class="modal modal--chat">
|
|
3782
3849
|
<div class="modal__header">
|
|
3783
3850
|
<div><h2 id="modalName">Agent</h2><div id="modalAgentDesc" style="font-size:10px;color:var(--dim);margin-top:2px"></div></div>
|
|
3784
3851
|
<button class="modal__close" onclick="closeModal()">×</button>
|
|
3785
3852
|
</div>
|
|
3786
3853
|
<div class="modal__body">
|
|
3787
|
-
<
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3854
|
+
<div class="agent-chat">
|
|
3855
|
+
<div class="agent-chat__messages" id="agentMessages"></div>
|
|
3856
|
+
<div class="agent-chat__footer">
|
|
3857
|
+
<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)">
|
|
3858
|
+
Drop a file or click to attach
|
|
3859
|
+
<input type="file" id="agentFileInput" style="display:none" onchange="handleFileSelect(this)">
|
|
3860
|
+
</div>
|
|
3861
|
+
<div id="agentFileInfo" style="display:none;font-size:10px;color:var(--cyan)"></div>
|
|
3862
|
+
<div class="agent-chat__input-row">
|
|
3863
|
+
<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>
|
|
3864
|
+
<button class="btn btn--primary" id="agentAskBtn" onclick="askAgent()" style="height:36px;padding:0 14px">Send</button>
|
|
3865
|
+
</div>
|
|
3866
|
+
</div>
|
|
3791
3867
|
</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
3868
|
</div>
|
|
3799
3869
|
</div>
|
|
3800
3870
|
</div>
|