nothumanallowed 9.3.5 → 9.3.7
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 +18 -4
- package/src/constants.mjs +1 -1
- package/src/services/tool-executor.mjs +29 -2
- package/src/services/web-ui.mjs +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "9.3.
|
|
3
|
+
"version": "9.3.7",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents + 58 tools + browser automation + web search. Streaming chat, headless Chrome CDP, multi-conversation, export. Gmail, Calendar, Drive, GitHub, Notion, Slack. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -987,7 +987,7 @@ export async function cmdUI(args) {
|
|
|
987
987
|
let fullResponse;
|
|
988
988
|
if (toolResults.length > 0) {
|
|
989
989
|
// Second LLM call with real tool results — forces the LLM to use actual data
|
|
990
|
-
const toolContext = toolResults.map(t => `[${t.action} result]: ${t.result}`).join('\n\n');
|
|
990
|
+
const toolContext = toolResults.map(t => `[${t.action} result]: ${t.result.slice(0, 3000)}`).join('\n\n');
|
|
991
991
|
const followUp = `The user asked: "${body.message}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond to the user based ONLY on the REAL data above. Do NOT invent or fabricate any information. Present the actual results clearly.`;
|
|
992
992
|
try {
|
|
993
993
|
fullResponse = await callLLM(config, enrichedSystemPrompt, followUp);
|
|
@@ -1189,8 +1189,22 @@ export async function cmdUI(args) {
|
|
|
1189
1189
|
}
|
|
1190
1190
|
|
|
1191
1191
|
const result = await executeTool(action, params, config);
|
|
1192
|
-
|
|
1193
|
-
|
|
1192
|
+
const resultStr = typeof result === 'object' ? JSON.stringify(result) : String(result);
|
|
1193
|
+
toolResults.push({ action, result: resultStr });
|
|
1194
|
+
sendSSE('tool', { action, status: 'done', result: typeof resultStr === 'string' ? resultStr.slice(0, 500) : '' });
|
|
1195
|
+
|
|
1196
|
+
// If the tool produced a screenshot (web_search with screenshot=true), send it via SSE
|
|
1197
|
+
if (resultStr.includes('[Screenshot of results captured')) {
|
|
1198
|
+
try {
|
|
1199
|
+
const be = await import('../services/browser-engine.mjs');
|
|
1200
|
+
if (be.isBrowserRunning()) {
|
|
1201
|
+
const ssResult = await be.browserScreenshot({ fullPage: true, format: 'png' });
|
|
1202
|
+
if (!ssResult.error) {
|
|
1203
|
+
sendSSE('screenshot', { base64: ssResult.base64, format: 'png' });
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
} catch { /* screenshot send failed */ }
|
|
1207
|
+
}
|
|
1194
1208
|
} catch (e) {
|
|
1195
1209
|
toolResults.push({ action, result: `Error: ${e.message}` });
|
|
1196
1210
|
sendSSE('tool', { action, status: 'error', error: e.message });
|
|
@@ -1200,7 +1214,7 @@ export async function cmdUI(args) {
|
|
|
1200
1214
|
// If tools were executed, make a second LLM call with results
|
|
1201
1215
|
let finalResponse = fullResponse;
|
|
1202
1216
|
if (toolResults.length > 0) {
|
|
1203
|
-
const toolContext = toolResults.map(t => `[${t.action} result]: ${t.result}`).join('\n\n');
|
|
1217
|
+
const toolContext = toolResults.map(t => `[${t.action} result]: ${t.result.slice(0, 3000)}`).join('\n\n');
|
|
1204
1218
|
const followUp = `The user asked: "${msg}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond to the user based ONLY on the REAL data above. Present the actual results clearly.`;
|
|
1205
1219
|
sendSSE('tool_synthesis', {});
|
|
1206
1220
|
try {
|
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.3.
|
|
8
|
+
export const VERSION = '9.3.7';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -267,9 +267,10 @@ TOOLS:
|
|
|
267
267
|
|
|
268
268
|
--- WEB SEARCH & FETCH ---
|
|
269
269
|
|
|
270
|
-
47. web_search(query: string, deep?: boolean)
|
|
270
|
+
47. web_search(query: string, deep?: boolean, screenshot?: boolean)
|
|
271
271
|
Search the web using DuckDuckGo. Returns titles, URLs, and snippets.
|
|
272
272
|
Set deep=true to also fetch and extract the top 3 pages' full content (slower but more detailed).
|
|
273
|
+
Set screenshot=true to also render the search results as a visual page and capture a screenshot (useful when the user asks to "see" results or wants a screenshot of search results).
|
|
273
274
|
ALWAYS use this for ANY web search request ("search for X", "find X", "look up X", "cerca X").
|
|
274
275
|
Do NOT open Google/Bing in the browser for searches — use this tool instead. It's faster and never gets blocked.
|
|
275
276
|
|
|
@@ -1288,10 +1289,36 @@ export async function executeTool(action, params, config) {
|
|
|
1288
1289
|
if (result.error) return `Search error: ${result.message}`;
|
|
1289
1290
|
if (result.results.length === 0) return `No results found for "${query}".`;
|
|
1290
1291
|
|
|
1291
|
-
|
|
1292
|
+
const textResult = `Web search: "${query}" — ${result.resultCount} results\n\n` +
|
|
1292
1293
|
result.results.map((r, i) =>
|
|
1293
1294
|
`${i + 1}. ${r.title}\n ${r.url}\n ${r.snippet}`
|
|
1294
1295
|
).join('\n\n');
|
|
1296
|
+
|
|
1297
|
+
// If screenshot requested, render results as HTML in browser and capture
|
|
1298
|
+
if (params.screenshot) {
|
|
1299
|
+
try {
|
|
1300
|
+
const be = await import('./browser-engine.mjs');
|
|
1301
|
+
// Ensure browser is running (open about:blank if needed)
|
|
1302
|
+
if (!be.isBrowserRunning()) {
|
|
1303
|
+
await be.browserOpen('https://example.com', { waitForLoad: true });
|
|
1304
|
+
}
|
|
1305
|
+
// Build search results HTML
|
|
1306
|
+
const esc = (s) => (s || '').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
1307
|
+
const htmlItems = result.results.map((r, i) =>
|
|
1308
|
+
`<div style="margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid #3c4043"><div style="font-size:18px;color:#8ab4f8;margin-bottom:4px;font-weight:600">${i + 1}. ${esc(r.title)}</div><div style="font-size:13px;color:#bdc1c6;margin-bottom:6px">${esc(r.url)}</div><div style="font-size:14px;color:#969ba1;line-height:1.5">${esc(r.snippet)}</div></div>`
|
|
1309
|
+
).join('');
|
|
1310
|
+
const fullHtml = `<html><head><style>body{background:#202124;color:#e8eaed;font-family:Arial,Helvetica,sans-serif;padding:24px 40px;max-width:800px;margin:0 auto}h1{font-size:22px;color:#8ab4f8;margin-bottom:24px;border-bottom:2px solid #3c4043;padding-bottom:12px}</style></head><body><h1>Search results: "${esc(query)}"</h1>${htmlItems}<div style="color:#5f6368;font-size:12px;margin-top:16px">Powered by NHA web_search — ${result.resultCount} results via DuckDuckGo</div></body></html>`;
|
|
1311
|
+
// Render by injecting HTML into current page via JS
|
|
1312
|
+
await be.browserEval(`document.open();document.write(${JSON.stringify(fullHtml)});document.close();`);
|
|
1313
|
+
await new Promise(r => setTimeout(r, 300));
|
|
1314
|
+
const ss = await be.browserScreenshot({ fullPage: true });
|
|
1315
|
+
if (!ss.error) {
|
|
1316
|
+
return textResult + `\n\n[Screenshot of results captured (${Math.round(ss.size / 1024)}KB)]`;
|
|
1317
|
+
}
|
|
1318
|
+
} catch { /* screenshot failed, return text only */ }
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
return textResult;
|
|
1295
1322
|
}
|
|
1296
1323
|
|
|
1297
1324
|
case 'fetch_url': {
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -483,7 +483,8 @@ function sendChat(){
|
|
|
483
483
|
chatHistory.push({role:'assistant',content:''});
|
|
484
484
|
renderMessages();
|
|
485
485
|
var streamIdx=chatHistory.length-1;
|
|
486
|
-
var
|
|
486
|
+
var cleanHistory=chatHistory.slice(0,-1).map(function(m){return{role:m.role,content:(m.content||'').replace(/!\\[Screenshot\\]\\(data:image\\/[^)]+\\)/g,'[Screenshot was shown]').slice(0,4000)};});
|
|
487
|
+
var payload={message:msg,history:cleanHistory,conversationId:activeConvId};
|
|
487
488
|
|
|
488
489
|
fetch(API+'/api/chat/stream',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(function(response){
|
|
489
490
|
if(!response.ok||!response.body){chatHistory[streamIdx].content='Error: connection failed';chatStreaming=false;renderMessages();return;}
|