nothumanallowed 14.1.5 → 14.1.6

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": "14.1.5",
3
+ "version": "14.1.6",
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/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 = '14.1.5';
8
+ export const VERSION = '14.1.6';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -399,6 +399,57 @@ export function register(router) {
399
399
  }
400
400
  });
401
401
 
402
+ // POST /api/chat — non-streaming, for attachments (PDF, image, text file)
403
+ router.post('/api/chat', async (req, res) => {
404
+ try {
405
+ const body = await parseBody(req);
406
+ if (!body.message) return sendError(res, 400, 'message required');
407
+ const config = loadConfig();
408
+ const chatSystemPrompt = await getChatSystemPrompt();
409
+ let enrichedPrompt = chatSystemPrompt;
410
+ try { const ic = await getImapAccountsContext(); if (ic) enrichedPrompt += ic; } catch {}
411
+ const LANG_MAP = { it:'Italian', en:'English', es:'Spanish', fr:'French', de:'German', pt:'Portuguese', nl:'Dutch', pl:'Polish', ru:'Russian', zh:'Chinese', ja:'Japanese', ko:'Korean', ar:'Arabic', hi:'Hindi', tr:'Turkish', sv:'Swedish', da:'Danish', fi:'Finnish', cs:'Czech' };
412
+ const userLang = LANG_MAP[(config?.language || config?.lang || 'en').slice(0,2)] || 'English';
413
+ enrichedPrompt += `\n\nIMPORTANT: Always respond in ${userLang}.`;
414
+
415
+ let response;
416
+
417
+ if (body.pdfBase64) {
418
+ const userMsg = body.message || 'Analyze this PDF document and describe its content.';
419
+ const provider = config?.llm?.provider || 'nha';
420
+ if (provider === 'nha') {
421
+ // Liara Vision non supporta PDF — estrai testo grezzo dal base64 come fallback
422
+ const buf = Buffer.from(body.pdfBase64, 'base64');
423
+ const rawText = buf.toString('latin1').replace(/[^\x20-\x7E\n\r\t]/g, ' ').replace(/\s{4,}/g, '\n').slice(0, 20000);
424
+ const fileCtx = `\n\n--- PDF: ${body.pdfName || 'document.pdf'} (testo estratto) ---\n${rawText}\n--- END PDF ---`;
425
+ response = await callLLM(config, enrichedPrompt + fileCtx, userMsg);
426
+ } else {
427
+ // Anthropic/OpenAI/Gemini — vision nativa per PDF
428
+ response = await callLLMVision(config, enrichedPrompt, userMsg, {
429
+ base64: body.pdfBase64,
430
+ mediaType: 'application/pdf',
431
+ fileName: body.pdfName || 'document.pdf',
432
+ });
433
+ }
434
+ } else if (body.imageBase64) {
435
+ // Image — vision call
436
+ const userMsg = body.message || 'Describe what you see in this image.';
437
+ response = await callLLMVision(config, enrichedPrompt, userMsg, {
438
+ base64: body.imageBase64,
439
+ mediaType: body.imageMimeType || 'image/png',
440
+ });
441
+ } else if (body.fileContent) {
442
+ // Text file — inject content into prompt
443
+ const fileCtx = `\n\n--- FILE: ${body.fileName || 'file'} ---\n${String(body.fileContent).slice(0, 40000)}\n--- END FILE ---`;
444
+ response = await callLLM(config, enrichedPrompt + fileCtx, body.message);
445
+ } else {
446
+ response = await callLLM(config, enrichedPrompt, body.message);
447
+ }
448
+
449
+ sendJSON(res, 200, { response });
450
+ } catch (e) { sendError(res, 500, e.message); }
451
+ });
452
+
402
453
  // POST /api/ask — single-turn non-streaming chat
403
454
  router.post('/api/ask', async (req, res) => {
404
455
  try {