nothumanallowed 9.4.2 → 9.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "9.4.2",
3
+ "version": "9.4.4",
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": {
@@ -1027,8 +1027,11 @@ export async function cmdUI(args) {
1027
1027
  let fullResponse;
1028
1028
  if (toolResults.length > 0) {
1029
1029
  // Second LLM call with real tool results — forces the LLM to use actual data
1030
- const toolContext = toolResults.map(t => `[${t.action} result]: ${t.result.slice(0, 3000)}`).join('\n\n');
1031
- 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 — just natural text.`;
1030
+ const toolContext = toolResults.map(t => {
1031
+ let clean = t.result.replace(/\[Screenshot[^\]]*\]/g, '').replace(/!\[.*?\]\(data:image[^)]+\)/g, '').slice(0, 3000);
1032
+ return `[${t.action} result]: ${clean.trim()}`;
1033
+ }).join('\n\n');
1034
+ 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.`;
1032
1035
  try {
1033
1036
  fullResponse = await callLLM(config, enrichedSystemPrompt, followUp);
1034
1037
  } catch {
@@ -1295,7 +1298,6 @@ export async function cmdUI(args) {
1295
1298
  // If the tool produced a screenshot (web_search with screenshot=true), send it via SSE
1296
1299
  if (resultStr.includes('[Screenshot of results captured')) {
1297
1300
  try {
1298
- // Extract filename from result (tool-executor already saved it)
1299
1301
  const fileMatch = resultStr.match(/file:(ss-\d+\.jpg)/);
1300
1302
  if (fileMatch) {
1301
1303
  const ssFilename = fileMatch[1];
@@ -1303,6 +1305,8 @@ export async function cmdUI(args) {
1303
1305
  if (fs.existsSync(ssPath)) {
1304
1306
  const ssBase64 = fs.readFileSync(ssPath).toString('base64');
1305
1307
  sendSSE('screenshot', { base64: ssBase64, format: 'jpeg', filename: ssFilename });
1308
+ // Also send as browser_frame for the viewer
1309
+ sendSSE('browser_frame', { base64: ssBase64, format: 'jpeg', url: 'Search results' });
1306
1310
  if (!res._screenshotFiles) res._screenshotFiles = [];
1307
1311
  res._screenshotFiles.push(ssFilename);
1308
1312
  }
@@ -1318,15 +1322,23 @@ export async function cmdUI(args) {
1318
1322
  // If tools were executed, make a second LLM call with results
1319
1323
  let finalResponse = fullResponse;
1320
1324
  if (toolResults.length > 0) {
1321
- const toolContext = toolResults.map(t => `[${t.action} result]: ${t.result.slice(0, 3000)}`).join('\n\n');
1322
- 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 — just natural text.`;
1325
+ const toolContext = toolResults.map(t => {
1326
+ // Strip screenshot file references and base64 from tool results the screenshot was already sent to the UI
1327
+ let clean = t.result.replace(/\[Screenshot[^\]]*\]/g, '').replace(/!\[.*?\]\(data:image[^)]+\)/g, '').slice(0, 3000);
1328
+ return `[${t.action} result]: ${clean.trim()}`;
1329
+ }).join('\n\n');
1330
+ 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.`;
1323
1331
  sendSSE('tool_synthesis', {});
1324
1332
  try {
1325
1333
  finalResponse = await callLLMStream(config, enrichedPrompt, followUp, (chunk) => {
1326
1334
  sendSSE('token', { content: chunk });
1327
1335
  });
1328
- // Strip any JSON blocks the LLM might have emitted anyway
1329
- finalResponse = finalResponse.replace(/```json[\s\S]*?```/g, '').trim();
1336
+ // Strip any JSON blocks and base64 the LLM might have emitted
1337
+ finalResponse = finalResponse
1338
+ .replace(/```json[\s\S]*?```/g, '')
1339
+ .replace(/!\[.*?\]\(data:image\/[^)]+\)/g, '')
1340
+ .replace(/data:image\/[a-z]+;base64,[A-Za-z0-9+/=]{100,}/g, '[image]')
1341
+ .trim();
1330
1342
  } catch {
1331
1343
  finalResponse = toolResults.map(t => `${t.action}: ${t.result}`).join('\n\n');
1332
1344
  }
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.4.2';
8
+ export const VERSION = '9.4.4';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -564,8 +564,8 @@ function sendChat(){
564
564
  var label=toolLabels[data.action]||data.action;
565
565
  var indicator=data.status==='executing'?'\\u23f3 '+label+'...':'\\u2705 '+label;
566
566
  if(data.status==='error')indicator='\\u274c '+label+' failed';
567
- // Show browser viewer for browser actions
568
- var isBrowserAction=data.action&&data.action.startsWith('browser_');
567
+ // Show browser viewer for browser and web_search actions
568
+ var isBrowserAction=data.action&&(data.action.startsWith('browser_')||data.action==='web_search');
569
569
  if(isBrowserAction&&data.status==='executing'){showBrowserViewer(label,'Executing...');}
570
570
  if(isBrowserAction&&data.status==='done'){updateBrowserStatus('\\u2705 '+label);}
571
571
  if(isBrowserAction&&data.status==='error'){updateBrowserStatus('\\u274c '+label);}