nothumanallowed 9.8.2 → 9.8.4
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 +40 -7
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +73 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "9.8.
|
|
3
|
+
"version": "9.8.4",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents, 53 tools. Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, GitHub, Notion, Slack, voice chat, 28 languages. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -1095,14 +1095,35 @@ export async function cmdUI(args) {
|
|
|
1095
1095
|
fullResponse = `\n\n${fullResponse}`;
|
|
1096
1096
|
}
|
|
1097
1097
|
} else if (toolResults.length > 0) {
|
|
1098
|
-
//
|
|
1098
|
+
// Extract canvas/screenshot markers from tool results BEFORE second LLM call
|
|
1099
|
+
// These markers must be preserved in the final response for the UI to render
|
|
1100
|
+
let preservedMarkers = '';
|
|
1099
1101
|
const toolContext = toolResults.map(t => {
|
|
1100
|
-
let clean = t.result
|
|
1101
|
-
|
|
1102
|
+
let clean = t.result;
|
|
1103
|
+
// Extract and preserve canvas markers
|
|
1104
|
+
const canvasMatch = clean.match(/\[CANVAS_RENDER\][\s\S]*?\[\/CANVAS_RENDER\]/);
|
|
1105
|
+
if (canvasMatch) {
|
|
1106
|
+
preservedMarkers += canvasMatch[0] + '\n';
|
|
1107
|
+
clean = clean.replace(/\[CANVAS_RENDER\][\s\S]*?\[\/CANVAS_RENDER\]/, '').trim();
|
|
1108
|
+
}
|
|
1109
|
+
if (clean.includes('[CANVAS_CLEAR]')) {
|
|
1110
|
+
preservedMarkers += '[CANVAS_CLEAR]Canvas cleared.[/CANVAS_CLEAR]\n';
|
|
1111
|
+
clean = clean.replace(/\[CANVAS_CLEAR\][\s\S]*?\[\/CANVAS_CLEAR\]/, '').trim();
|
|
1112
|
+
}
|
|
1113
|
+
// Extract screenshot file markers
|
|
1114
|
+
const ssMatch = clean.match(/\[SCREENSHOT_FILE\].*?\[\/SCREENSHOT_FILE\]/);
|
|
1115
|
+
if (ssMatch) {
|
|
1116
|
+
preservedMarkers += ssMatch[0] + '\n';
|
|
1117
|
+
clean = clean.replace(/\[SCREENSHOT_FILE\].*?\[\/SCREENSHOT_FILE\]/, '').trim();
|
|
1118
|
+
}
|
|
1119
|
+
clean = clean.replace(/\[Screenshot[^\]]*\]/g, '').replace(/!\[.*?\]\(data:image[^)]+\)/g, '').slice(0, 3000);
|
|
1120
|
+
return `[${t.action} result]: ${clean.trim() || 'Done.'}`;
|
|
1102
1121
|
}).join('\n\n');
|
|
1103
1122
|
const followUp = `The user asked: "${body.message}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond conversationally based ONLY on the REAL data above. Do NOT output any JSON blocks, base64, or image markdown — just natural text.`;
|
|
1104
1123
|
try {
|
|
1105
1124
|
fullResponse = await callLLM(config, enrichedSystemPrompt, followUp);
|
|
1125
|
+
// Prepend preserved markers so the UI can render canvas/screenshots
|
|
1126
|
+
if (preservedMarkers) fullResponse = preservedMarkers + fullResponse;
|
|
1106
1127
|
} catch {
|
|
1107
1128
|
fullResponse = toolResults.map(t => `${t.action}: ${t.result}`).join('\n\n');
|
|
1108
1129
|
}
|
|
@@ -1437,23 +1458,35 @@ export async function cmdUI(args) {
|
|
|
1437
1458
|
// If tools were executed, make a second LLM call with results
|
|
1438
1459
|
let finalResponse = fullResponse;
|
|
1439
1460
|
if (toolResults.length > 0) {
|
|
1461
|
+
// Extract canvas/screenshot markers BEFORE sending to LLM
|
|
1462
|
+
let preservedMarkers = '';
|
|
1440
1463
|
const toolContext = toolResults.map(t => {
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1464
|
+
let clean = t.result;
|
|
1465
|
+
const canvasMatch = clean.match(/\[CANVAS_RENDER\][\s\S]*?\[\/CANVAS_RENDER\]/);
|
|
1466
|
+
if (canvasMatch) { preservedMarkers += canvasMatch[0] + '\n'; clean = clean.replace(/\[CANVAS_RENDER\][\s\S]*?\[\/CANVAS_RENDER\]/, '').trim(); }
|
|
1467
|
+
if (clean.includes('[CANVAS_CLEAR]')) { preservedMarkers += '[CANVAS_CLEAR]Canvas cleared.[/CANVAS_CLEAR]\n'; clean = clean.replace(/\[CANVAS_CLEAR\][\s\S]*?\[\/CANVAS_CLEAR\]/, '').trim(); }
|
|
1468
|
+
clean = clean.replace(/\[Screenshot[^\]]*\]/g, '').replace(/!\[.*?\]\(data:image[^)]+\)/g, '').slice(0, 3000);
|
|
1469
|
+
return `[${t.action} result]: ${clean.trim() || 'Done.'}`;
|
|
1444
1470
|
}).join('\n\n');
|
|
1471
|
+
|
|
1472
|
+
// If we have canvas content, send it to client immediately via SSE
|
|
1473
|
+
if (preservedMarkers.includes('[CANVAS_RENDER]')) {
|
|
1474
|
+
sendSSE('canvas', { markers: preservedMarkers });
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1445
1477
|
const followUp = `The user asked: "${msg}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond to the user conversationally based ONLY on the REAL data above. Present the results clearly. Do NOT output any JSON blocks, any base64 data, or any image markdown — just natural text. If a screenshot was taken, just mention "Screenshot captured" without embedding it.`;
|
|
1446
1478
|
sendSSE('tool_synthesis', {});
|
|
1447
1479
|
try {
|
|
1448
1480
|
finalResponse = await callLLMStream(config, enrichedPrompt, followUp, (chunk) => {
|
|
1449
1481
|
sendSSE('token', { content: chunk });
|
|
1450
1482
|
});
|
|
1451
|
-
// Strip any JSON blocks and base64 the LLM might have emitted
|
|
1452
1483
|
finalResponse = finalResponse
|
|
1453
1484
|
.replace(/```json[\s\S]*?```/g, '')
|
|
1454
1485
|
.replace(/!\[.*?\]\(data:image\/[^)]+\)/g, '')
|
|
1455
1486
|
.replace(/data:image\/[a-z]+;base64,[A-Za-z0-9+/=]{100,}/g, '[image]')
|
|
1456
1487
|
.trim();
|
|
1488
|
+
// Prepend preserved markers for persistence
|
|
1489
|
+
if (preservedMarkers) finalResponse = preservedMarkers + finalResponse;
|
|
1457
1490
|
} catch {
|
|
1458
1491
|
finalResponse = toolResults.map(t => `${t.action}: ${t.result}`).join('\n\n');
|
|
1459
1492
|
}
|
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 = '9.8.
|
|
8
|
+
export const VERSION = '9.8.4';
|
|
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
|
@@ -94,7 +94,18 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
94
94
|
.msg{margin-bottom:12px}
|
|
95
95
|
.msg--user .msg__bubble{background:var(--bg3);border:1px solid var(--border2);border-radius:8px 8px 2px 8px;padding:10px 14px;max-width:85%;margin-left:auto;color:var(--bright)}
|
|
96
96
|
.msg--assistant .msg__bubble{background:var(--greendim);border:1px solid var(--green3);border-radius:8px 8px 8px 2px;padding:10px 14px;max-width:85%;color:var(--text);white-space:pre-wrap;word-wrap:break-word}
|
|
97
|
+
.msg--assistant .msg__bubble img{max-width:100%;border-radius:8px;margin:8px 0;border:1px solid rgba(0,255,65,0.2)}
|
|
97
98
|
.msg__label{font-size:10px;color:var(--dim);margin-bottom:2px}
|
|
99
|
+
.msg__actions{display:flex;gap:6px;margin-top:4px;opacity:0.15;transition:opacity 0.2s}
|
|
100
|
+
.msg:hover .msg__actions{opacity:1}
|
|
101
|
+
.msg__actions button{background:none;border:none;color:var(--dim);cursor:pointer;font-size:10px;font-family:var(--mono);padding:2px 4px}
|
|
102
|
+
.msg__actions button:hover{color:var(--green)}
|
|
103
|
+
#canvasPanel{position:fixed;top:60px;right:12px;width:480px;max-height:calc(100vh - 80px);background:#0d0d0d;border:1px solid var(--green);border-radius:12px;z-index:1000;overflow:hidden;display:none;flex-direction:column;box-shadow:0 0 30px rgba(0,255,65,0.1)}
|
|
104
|
+
#canvasPanel.open{display:flex}
|
|
105
|
+
#canvasPanel .cvs-header{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-bottom:1px solid var(--green);background:rgba(0,255,65,0.05)}
|
|
106
|
+
#canvasPanel .cvs-header span{font-family:var(--mono);color:var(--green);font-size:12px}
|
|
107
|
+
#canvasPanel .cvs-header button{background:none;border:none;color:var(--dim);cursor:pointer;font-size:14px;margin-left:8px}
|
|
108
|
+
#canvasPanel iframe{flex:1;border:none;background:#fff;min-height:350px;width:100%}
|
|
98
109
|
.msg--thinking{color:var(--dim);font-style:italic}
|
|
99
110
|
.tool-indicator{display:inline-block;padding:2px 8px;margin:2px 0;border-radius:4px;font-size:11px;background:var(--bg3);border:1px solid var(--border)}
|
|
100
111
|
.tool-indicator--browser{border-color:#9c27b0;color:#ce93d8}
|
|
@@ -433,17 +444,32 @@ function renderMessages(){
|
|
|
433
444
|
el.innerHTML='<div class="chat__empty"><div class="chat__empty-title">NHA Chat</div><div>Personal Operations Assistant — Streaming + Web Search + Browser</div><div class="chat__empty-hint">Try: Show my unread emails / Search the web for React 19 / Open google.com and take a screenshot</div></div>';
|
|
434
445
|
return;
|
|
435
446
|
}
|
|
436
|
-
var h='';chatHistory.forEach(function(m){
|
|
447
|
+
var h='';chatHistory.forEach(function(m,mi){
|
|
437
448
|
var raw=m.content||'';
|
|
438
|
-
|
|
449
|
+
var isA=m.role==='assistant';
|
|
450
|
+
// Strip any raw base64 data that leaked into content
|
|
439
451
|
raw=raw.replace(/data:image\\/[a-z]+;base64,[A-Za-z0-9+\\/=]{200,}/g,'[image]');
|
|
440
452
|
raw=raw.replace(/[A-Za-z0-9+\\/=]{500,}/g,'');
|
|
453
|
+
// Handle canvas markers (assistant only)
|
|
454
|
+
if(isA){
|
|
455
|
+
var cm=raw.match(/\\[CANVAS_RENDER\\]([\\s\\S]*?)\\[\\/CANVAS_RENDER\\]/);
|
|
456
|
+
if(cm){try{var cd=JSON.parse(cm[1]);showCanvas(cd.html,cd.title);}catch(e){} raw=raw.replace(/\\[CANVAS_RENDER\\][\\s\\S]*?\\[\\/CANVAS_RENDER\\]/,'').trim();}
|
|
457
|
+
if(raw.indexOf('[CANVAS_CLEAR]')!==-1){closeCanvas();raw=raw.replace(/\\[CANVAS_CLEAR\\][\\s\\S]*?\\[\\/CANVAS_CLEAR\\]/,'').trim();}
|
|
458
|
+
// Handle screenshot file markers
|
|
459
|
+
var sm=raw.match(/\\[SCREENSHOT_FILE\\](.*?)\\[\\/SCREENSHOT_FILE\\]/);
|
|
460
|
+
if(sm){var fn=sm[1].split('/').pop();raw=raw.replace(/\\[SCREENSHOT_FILE\\].*?\\[\\/SCREENSHOT_FILE\\]/,'');raw='\\n'+raw;}
|
|
461
|
+
}
|
|
441
462
|
var imgs=[];var idx=0;
|
|
442
|
-
// Match both /api/screenshots/ URLs and data:image (short ones only, for inline display)
|
|
443
463
|
var safe=raw.replace(/!\\[([^\\]]*)\\]\\((\\/api\\/screenshots\\/[a-zA-Z0-9._-]+)\\)/g,function(_,alt,src){var ph='__IMG'+idx+'__';imgs.push({ph:ph,alt:alt,src:src});idx++;return ph;});
|
|
444
464
|
var content=esc(safe);
|
|
445
465
|
for(var i=0;i<imgs.length;i++){content=content.replace(imgs[i].ph,'<img class="screenshot-preview" alt="'+esc(imgs[i].alt)+'" src="'+imgs[i].src+'">');}
|
|
446
|
-
|
|
466
|
+
// Action buttons
|
|
467
|
+
var acts='<div class="msg__actions">';
|
|
468
|
+
acts+='<button onclick="copyMsg('+mi+')">Copy</button>';
|
|
469
|
+
if(isA){acts+='<button onclick="retryMsg('+mi+')">Retry</button>';}
|
|
470
|
+
else{acts+='<button onclick="editMsg('+mi+')">Edit</button>';}
|
|
471
|
+
acts+='</div>';
|
|
472
|
+
h+='<div class="msg msg--'+esc(m.role)+'"><div class="msg__label">'+esc(m.role==='user'?'You':'NHA')+'</div><div class="msg__bubble">'+content+'</div>'+acts+'</div>';
|
|
447
473
|
});
|
|
448
474
|
el.innerHTML=h;el.scrollTop=el.scrollHeight;
|
|
449
475
|
}
|
|
@@ -496,6 +522,42 @@ function clearChatAttach(){
|
|
|
496
522
|
document.getElementById('chatImageInput').value='';
|
|
497
523
|
}
|
|
498
524
|
|
|
525
|
+
// ---- CANVAS ----
|
|
526
|
+
function showCanvas(html,title){
|
|
527
|
+
var p=document.getElementById('canvasPanel');
|
|
528
|
+
var t=document.getElementById('canvasTitle');
|
|
529
|
+
var f=document.getElementById('canvasFrame');
|
|
530
|
+
if(!p||!f)return;
|
|
531
|
+
if(t)t.textContent=title||'Canvas';
|
|
532
|
+
p.classList.add('open');
|
|
533
|
+
var doc=f.contentDocument||f.contentWindow.document;
|
|
534
|
+
doc.open();doc.write(html);doc.close();
|
|
535
|
+
}
|
|
536
|
+
function closeCanvas(){var p=document.getElementById('canvasPanel');if(p)p.classList.remove('open');}
|
|
537
|
+
function toggleCanvasSize(){
|
|
538
|
+
var p=document.getElementById('canvasPanel');if(!p)return;
|
|
539
|
+
if(p.style.width==='80vw'){p.style.width='';p.style.height='';p.style.top='';p.style.right='';}
|
|
540
|
+
else{p.style.width='80vw';p.style.height='80vh';p.style.top='10vh';p.style.right='10vw';}
|
|
541
|
+
}
|
|
542
|
+
// ---- MSG ACTIONS ----
|
|
543
|
+
function copyMsg(i){
|
|
544
|
+
var m=chatHistory[i];if(!m)return;
|
|
545
|
+
var t=(m.content||'').replace(/\\[CANVAS_RENDER\\][\\s\\S]*?\\[\\/CANVAS_RENDER\\]/g,'').replace(/\\[SCREENSHOT_FILE\\].*?\\[\\/SCREENSHOT_FILE\\]/g,'').trim();
|
|
546
|
+
navigator.clipboard.writeText(t).catch(function(){});
|
|
547
|
+
}
|
|
548
|
+
function retryMsg(i){
|
|
549
|
+
if(i<1||chatHistory[i].role!=='assistant')return;
|
|
550
|
+
var userMsg=chatHistory[i-1];if(!userMsg||userMsg.role!=='user')return;
|
|
551
|
+
chatHistory.splice(i,1);saveChatToStorage();renderMessages();
|
|
552
|
+
var inp=document.getElementById('chatInput');if(inp){inp.value=userMsg.content;}
|
|
553
|
+
sendChat();
|
|
554
|
+
}
|
|
555
|
+
function editMsg(i){
|
|
556
|
+
if(chatHistory[i].role!=='user')return;
|
|
557
|
+
var inp=document.getElementById('chatInput');if(!inp)return;
|
|
558
|
+
inp.value=chatHistory[i].content;inp.focus();
|
|
559
|
+
chatHistory.splice(i);saveChatToStorage();renderMessages();
|
|
560
|
+
}
|
|
499
561
|
function sendChat(){
|
|
500
562
|
var inp=document.getElementById('chatInput');if(!inp)return;
|
|
501
563
|
var msg=inp.value.trim();
|
|
@@ -590,6 +652,12 @@ function sendChat(){
|
|
|
590
652
|
updateBrowserFrame(data.base64,data.format||'jpeg');
|
|
591
653
|
if(data.url)updateBrowserStatus(data.url);
|
|
592
654
|
}
|
|
655
|
+
if(currentEvent==='canvas'&&data.markers){
|
|
656
|
+
// Canvas content arrived — render it immediately
|
|
657
|
+
var cm=data.markers.match(/\\[CANVAS_RENDER\\]([\\s\\S]*?)\\[\\/CANVAS_RENDER\\]/);
|
|
658
|
+
if(cm){try{var cd=JSON.parse(cm[1]);showCanvas(cd.html,cd.title);}catch(e){}}
|
|
659
|
+
if(data.markers.indexOf('[CANVAS_CLEAR]')!==-1)closeCanvas();
|
|
660
|
+
}
|
|
593
661
|
if(currentEvent==='tool_synthesis'){chatHistory[streamIdx].content='';renderMessages();}
|
|
594
662
|
if(currentEvent==='done'){endStreaming();if(data.content)chatHistory[streamIdx].content=data.content;var ssf=data.screenshotFiles||[];for(var fi=0;fi<ssf.length;fi++){chatHistory[streamIdx].content+='\\n\\n';}renderMessages();loadConvList();if(ssf.length>0)setTimeout(closeBrowserViewer,5000);}
|
|
595
663
|
if(currentEvent==='error'){endStreaming();chatHistory[streamIdx].content='Error: '+(data.message||'Unknown');renderMessages();}
|
|
@@ -1956,6 +2024,7 @@ init();
|
|
|
1956
2024
|
</div>
|
|
1957
2025
|
</div>
|
|
1958
2026
|
|
|
2027
|
+
<div id="canvasPanel"><div class="cvs-header"><span id="canvasTitle">Canvas</span><div><button onclick="toggleCanvasSize()" title="Resize">⤢</button><button onclick="closeCanvas()" title="Close">×</button></div></div><iframe id="canvasFrame" sandbox="allow-scripts allow-same-origin"></iframe></div>
|
|
1959
2028
|
<script>${JS}</script>
|
|
1960
2029
|
</body>
|
|
1961
2030
|
</html>`;
|