nothumanallowed 13.5.103 → 13.5.105

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": "13.5.103",
3
+ "version": "13.5.105",
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": {
@@ -2731,6 +2731,7 @@ export async function cmdUI(args) {
2731
2731
  const hasWriting = /scrivi|write|articolo|article|blog|testo|text|documento|document/i.test(taskLow);
2732
2732
  const hasData = /dati|data|dataset|csv|json|analizza i dati|pattern|statistich/i.test(taskLow);
2733
2733
  const hasTranslate = /traduci|translate|traduzione|translation/i.test(taskLow);
2734
+ const hasTravel = /ristorante|restaurant|b&b|hotel|albergo|agriturismo|locanda|osteria|prenotaz|vacanz|romantico|sushi|giapponese|cinese|pizza|cena|dinner|pranzo|lunch|soggiorno|weekend|pernottament|posto\s+dove\s+mangiare|posto\s+dove\s+dormire|dove\s+mangiare|dove\s+dormire|posto\s+romantico|gita|escursione/i.test(taskLow);
2734
2735
 
2735
2736
  const it = plannerLang === 'Italian';
2736
2737
 
@@ -2754,6 +2755,7 @@ export async function cmdUI(args) {
2754
2755
  const pdfName = body.pdfName || 'documento allegato';
2755
2756
  steps.push({icon:'\u{1F4C4}',agent:'DocumentReaderAgent',label:it?'Leggi documento':'Read document',reason:it?'Allegato PDF rilevato \u2014 estraggo dati tecnici prima di ogni altra operazione':'PDF attachment detected \u2014 extracting technical data first',prompt:`Extract all technical specifications, model numbers, part codes, product names, manufacturer, dimensions, ratings, and any other key data from the attached document "${pdfName}". List every technical detail precisely.`});
2756
2757
  }
2758
+ if (hasTravel) steps.push({icon:'\u{1F374}',agent:'TravelAgent', label:it?'Ricerca ristoranti & hotel':'Search restaurants & hotels', reason:it?'Task di viaggio/prenotazione: cerco disponibilità reale su TheFork, Booking, TripAdvisor con browser automation':'Travel/booking task: searching real availability on TheFork, Booking, TripAdvisor with browser automation', prompt:task});
2757
2759
  if (hasEmail) steps.push({icon:'\u{1F4E7}',agent:'EmailAgent', label:it?'Controlla email':'Check emails', reason:it?'Parola chiave email/mail/posta rilevata nel task':'Keyword email/mail detected in task', prompt:'Read the latest unread emails and identify urgent items, deadlines, and required actions'});
2758
2760
  if (hasCalendar) steps.push({icon:'\u{1F4C5}',agent:'CalendarAgent', label:it?'Rivedi calendario':'Review calendar', reason:it?'Parola chiave calendario/agenda/eventi rilevata nel task':'Keyword calendar/agenda/events detected in task', prompt:'Check today\'s events and identify any scheduling conflicts or important meetings'});
2759
2761
  if (hasGitHub) steps.push({icon:'\u{1F4BB}',agent:'GitHubAgent', label:'GitHub', reason:it?'Parola chiave GitHub/git/issue/PR rilevata nel task':'Keyword GitHub/git/issue/PR detected in task', prompt:'Read open issues and pull requests, identify what needs attention'});
@@ -2761,7 +2763,7 @@ export async function cmdUI(args) {
2761
2763
  if (hasNotion) steps.push({icon:'\u{1F4DD}',agent:'NotionAgent', label:'Notion', reason:it?'Parola chiave Notion/note rilevata nel task':'Keyword Notion/note detected in task', prompt:'Search Notion for relevant pages and notes'});
2762
2764
  // When PDF is present: always search web (to find where to buy, similar products etc.)
2763
2765
  // The search query will be refined at runtime using the extracted PDF specs as context
2764
- if (hasPdf || hasSearch || hasReputation || (!hasEmail && !hasCalendar && !hasGitHub && !hasSlack)) {
2766
+ if (!hasTravel && (hasPdf || hasSearch || hasReputation || (!hasEmail && !hasCalendar && !hasGitHub && !hasSlack))) {
2765
2767
  const searchPrompt = hasPdf
2766
2768
  ? (it ? 'Usando le specifiche tecniche estratte dal documento (codice prodotto, modello, costruttore, caratteristiche), cerca online dove acquistare il prodotto o articoli equivalenti. Usa i codici esatti dal documento come query di ricerca.' : 'Using the technical specifications extracted from the document (product code, model, manufacturer, specs), search online for where to buy this product or equivalent alternatives. Use exact codes from the document as search queries.')
2767
2769
  : searchQuery;
@@ -2851,7 +2853,7 @@ Review the plan above. You may:
2851
2853
  - ADJUST the "prompt" field of any step to better match the task
2852
2854
  - KEEP steps that are correct as-is
2853
2855
 
2854
- Available agents: WebSearchAgent, DocumentReaderAgent, EmailAgent, CalendarAgent, GitHubAgent, SlackAgent, NotionAgent, HERALD, ORACLE, ATHENA, CASSANDRA, MERCURY, QUILL, DataAnalystAgent, polyglot, CanvasAgent (last, only if visual output needed).
2856
+ Available agents: TravelAgent (restaurants/hotels/bookings with real browser automation on TheFork/Booking/TripAdvisor), WebSearchAgent, DocumentReaderAgent, EmailAgent, CalendarAgent, GitHubAgent, SlackAgent, NotionAgent, HERALD, ORACLE, ATHENA, CASSANDRA, MERCURY, QUILL, DataAnalystAgent, polyglot, CanvasAgent (last, only if visual output needed).
2855
2857
 
2856
2858
  Output ONLY:
2857
2859
  {"steps":[{"icon":"EMOJI","agent":"AGENT_NAME","label":"LABEL","reason":"WHY THIS AGENT","prompt":"INSTRUCTION"}]}
@@ -2869,7 +2871,7 @@ Language for labels: ${plannerLang}.
2869
2871
 
2870
2872
  Build a workflow plan for this task.
2871
2873
 
2872
- Available agents: WebSearchAgent, DocumentReaderAgent, EmailAgent, CalendarAgent, GitHubAgent, SlackAgent, NotionAgent, HERALD, ORACLE, ATHENA, CASSANDRA, MERCURY, QUILL, DataAnalystAgent, polyglot, CanvasAgent.
2874
+ Available agents: TravelAgent (restaurants/hotels/bookings with real browser automation on TheFork/Booking/TripAdvisor), WebSearchAgent, DocumentReaderAgent, EmailAgent, CalendarAgent, GitHubAgent, SlackAgent, NotionAgent, HERALD, ORACLE, ATHENA, CASSANDRA, MERCURY, QUILL, DataAnalystAgent, polyglot, CanvasAgent.
2873
2875
 
2874
2876
  Output ONLY:
2875
2877
  {"steps":[{"icon":"EMOJI","agent":"AGENT_NAME","label":"LABEL","reason":"WHY THIS AGENT","prompt":"INSTRUCTION"}]}
@@ -3145,8 +3147,155 @@ ${rawText.slice(0, 18000)}`;
3145
3147
  }
3146
3148
  } catch (e) { toolData += (toolData ? '\n\n' : '') + `## Search "${q}" failed: ${e.message}`; }
3147
3149
  }
3150
+
3151
+ // After all searches: extract URLs from results and fetch booking/info portals directly
3152
+ // This is critical for travel/restaurant/accommodation tasks where portals have internal search
3153
+ const isBookingTask = /(ristorante|restaurant|b&b|hotel|albergo|prenotaz|booking|vacanz|romantico|sushi|menu|disponib|soggiorno|weekend|cena|dinner|accommodation)/i.test(task + ' ' + stepPrompt);
3154
+ if (isBookingTask && toolData.length > 100) {
3155
+ // Extract URLs found in search results
3156
+ const foundUrls = [...new Set((toolData.match(/https?:\/\/[^\s"'\n<>)]+/g) || []))];
3157
+ // Prioritize booking/info portals
3158
+ const portalDomains = ['thefork', 'theforkmanger', 'booking.com', 'tripadvisor', 'yelp', 'zomato', 'airbnb', 'agriturismo', 'expedia', 'hotel', 'b-b.it', 'bed-and-breakfast', 'locanda', 'osteria', 'ristorante', 'viaggi'];
3159
+ const portalUrls = foundUrls.filter(u => portalDomains.some(d => u.toLowerCase().includes(d))).slice(0, 3);
3160
+ if (portalUrls.length > 0) {
3161
+ sendToken(`[Reading ${portalUrls.length} portal page(s)...] `);
3162
+ for (const pu of portalUrls) {
3163
+ try {
3164
+ const pfetch = await withTimeout(executeTool('fetch_url', { url: pu }, config), 20000);
3165
+ const pfetchStr = typeof pfetch === 'string' ? pfetch : JSON.stringify(pfetch);
3166
+ if (pfetchStr && pfetchStr.length > 200) {
3167
+ toolData += '\n\n## Portal page: ' + pu + '\n' + pfetchStr.slice(0, 5000);
3168
+ }
3169
+ } catch {}
3170
+ }
3171
+ }
3172
+ }
3148
3173
  } catch (e) { toolData = toolData || `Web search failed: ${e.message}`; }
3149
3174
 
3175
+ } else if (agent === 'TravelAgent') {
3176
+ sendToken('[TravelAgent: analyzing your request...] ');
3177
+ try {
3178
+ const be = await import('../services/browser-engine.mjs');
3179
+ const travelTask = stepPrompt || task;
3180
+
3181
+ // ── Extract parameters from task ──
3182
+ // Date: "16 maggio", "16/05", "16-05-2026", "sabato 16", etc.
3183
+ const dateMatch = travelTask.match(/(\d{1,2})\s+(gennaio|febbraio|marzo|aprile|maggio|giugno|luglio|agosto|settembre|ottobre|novembre|dicembre)/i)
3184
+ || travelTask.match(/(\d{1,2})[\/\-](\d{1,2})(?:[\/\-](\d{4}))?/)
3185
+ || travelTask.match(/(monday|tuesday|wednesday|thursday|friday|saturday|sunday|luned|marted|mercoled|gioved|venerd|sabato|domenica)\s+\w+/i);
3186
+ const monthNames = {gennaio:1,febbraio:2,marzo:3,aprile:4,maggio:5,giugno:6,luglio:7,agosto:8,settembre:9,ottobre:10,novembre:11,dicembre:12};
3187
+ let targetDate = null;
3188
+ let targetDateStr = null;
3189
+ if (dateMatch && dateMatch[2] && isNaN(Number(dateMatch[2]))) {
3190
+ const day = parseInt(dateMatch[1]);
3191
+ const month = monthNames[(dateMatch[2] || '').toLowerCase()];
3192
+ if (day && month) {
3193
+ const year = new Date().getFullYear();
3194
+ targetDate = new Date(year, month - 1, day);
3195
+ targetDateStr = String(day).padStart(2, '0') + '/' + String(month).padStart(2, '0') + '/' + year;
3196
+ }
3197
+ }
3198
+
3199
+ // City/location: "a Bologna", "a Roma", "near Milan", "vicino a Firenze"
3200
+ const cityMatch = travelTask.match(/\b(?:a|in|near|vicino\s+a|at)\s+([A-Z][a-zA-Z\s]{2,20}?)(?:\s*[,\.!?]|\s+(?:il|la|per|con|un|una|mi|mia|del|della)|$)/);
3201
+ const city = cityMatch ? cityMatch[1].trim() : null;
3202
+
3203
+ // Cuisine/restaurant type
3204
+ const cuisineMatch = travelTask.match(/\b(sushi|pizza|giapponese|japanese|italiano|italian|cinese|chinese|indiano|indian|steakhouse|bistrot|trattoria|osteria)\b/i);
3205
+ const cuisine = cuisineMatch ? cuisineMatch[1].toLowerCase() : null;
3206
+
3207
+ // Accommodation type
3208
+ const hasAccommodation = /b&b|bed\s*&?\s*breakfast|hotel|albergo|agriturismo|locanda|ostello|hostel|airbnb/i.test(travelTask);
3209
+ const hasRestaurant = /ristorante|restaurant|sushi|cena|dinner|pranzo|lunch|mangiare|eat/i.test(travelTask);
3210
+
3211
+ const summaryParts = [];
3212
+ if (city) summaryParts.push('location: ' + city);
3213
+ if (targetDateStr) summaryParts.push('date: ' + targetDateStr);
3214
+ if (cuisine) summaryParts.push('cuisine: ' + cuisine);
3215
+ if (hasAccommodation) summaryParts.push('accommodation: yes');
3216
+ if (hasRestaurant) summaryParts.push('restaurant: yes');
3217
+ sendToken('[Extracted — ' + (summaryParts.join(', ') || 'general search') + '] ');
3218
+
3219
+ // ── Build search URLs for portals ──
3220
+ const portalResults = [];
3221
+ const cityQ = city ? encodeURIComponent(city) : '';
3222
+ const cuisineQ = cuisine ? encodeURIComponent(cuisine) : '';
3223
+ const dateQ = targetDateStr || '';
3224
+
3225
+ // TheFork: restaurant search
3226
+ if (hasRestaurant) {
3227
+ const theforkQuery = [cuisine, city].filter(Boolean).join(' ');
3228
+ const theforkUrl = 'https://www.thefork.it/ristoranti/' + (city ? encodeURIComponent(city.toLowerCase()) : 'italia') + (cuisine ? '?q=' + cuisineQ : '');
3229
+ sendToken('[Searching TheFork...] ');
3230
+ try {
3231
+ if (!be.isBrowserRunning()) await be.browserOpen(theforkUrl, { waitForLoad: true });
3232
+ else await be.browserNavigate(theforkUrl, { waitForLoad: true });
3233
+ await new Promise(r => setTimeout(r, 2500));
3234
+ const theforkContent = await be.browserExtract({ selector: 'body', format: 'text' });
3235
+ if (theforkContent && !theforkContent.error && theforkContent.text && theforkContent.text.length > 200) {
3236
+ portalResults.push('## TheFork — ' + theforkUrl + '\n' + theforkContent.text.slice(0, 5000));
3237
+ } else {
3238
+ const fetchFork = await withTimeout(executeTool('fetch_url', { url: theforkUrl }, config), 20000);
3239
+ if (fetchFork && fetchFork.length > 200) portalResults.push('## TheFork — ' + theforkUrl + '\n' + fetchFork.slice(0, 5000));
3240
+ }
3241
+ } catch (e) {
3242
+ try {
3243
+ const fetchFork = await withTimeout(executeTool('fetch_url', { url: theforkUrl }, config), 20000);
3244
+ if (fetchFork && fetchFork.length > 200) portalResults.push('## TheFork — ' + theforkUrl + '\n' + fetchFork.slice(0, 5000));
3245
+ } catch {}
3246
+ }
3247
+ }
3248
+
3249
+ // Booking.com: B&B / hotel search
3250
+ if (hasAccommodation) {
3251
+ const checkin = targetDate ? targetDate.toISOString().slice(0, 10) : '';
3252
+ const checkout = targetDate ? new Date(targetDate.getTime() + 86400000).toISOString().slice(0, 10) : '';
3253
+ const bookingUrl = 'https://www.booking.com/search.html?ss=' + (cityQ || 'Italy') + (checkin ? '&checkin=' + checkin + '&checkout=' + checkout : '') + '&group_adults=2&no_rooms=1&b_h4u_keep_filters=&from_sf=1';
3254
+ sendToken('[Searching Booking.com...] ');
3255
+ try {
3256
+ if (!be.isBrowserRunning()) await be.browserOpen(bookingUrl, { waitForLoad: true });
3257
+ else await be.browserNavigate(bookingUrl, { waitForLoad: true });
3258
+ await new Promise(r => setTimeout(r, 3000));
3259
+ const bookingContent = await be.browserExtract({ selector: 'body', format: 'text' });
3260
+ if (bookingContent && !bookingContent.error && bookingContent.text && bookingContent.text.length > 200) {
3261
+ portalResults.push('## Booking.com — ' + bookingUrl + '\n' + bookingContent.text.slice(0, 5000));
3262
+ } else {
3263
+ const fetchBook = await withTimeout(executeTool('fetch_url', { url: bookingUrl }, config), 20000);
3264
+ if (fetchBook && fetchBook.length > 200) portalResults.push('## Booking.com — ' + bookingUrl + '\n' + fetchBook.slice(0, 5000));
3265
+ }
3266
+ } catch (e) {
3267
+ try {
3268
+ const fetchBook = await withTimeout(executeTool('fetch_url', { url: bookingUrl }, config), 20000);
3269
+ if (fetchBook && fetchBook.length > 200) portalResults.push('## Booking.com — ' + bookingUrl + '\n' + fetchBook.slice(0, 5000));
3270
+ } catch {}
3271
+ }
3272
+ }
3273
+
3274
+ // TripAdvisor: restaurants
3275
+ if (hasRestaurant && city) {
3276
+ const taUrl = 'https://www.tripadvisor.it/Search?q=' + [cuisineQ, cityQ].filter(Boolean).join('+') + '&searchSessionId=&sid=&blockRedirect=true';
3277
+ sendToken('[Searching TripAdvisor...] ');
3278
+ try {
3279
+ const fetchTa = await withTimeout(executeTool('fetch_url', { url: taUrl }, config), 20000);
3280
+ if (fetchTa && fetchTa.length > 200) portalResults.push('## TripAdvisor — ' + taUrl + '\n' + fetchTa.slice(0, 5000));
3281
+ } catch {}
3282
+ }
3283
+
3284
+ // Also do a DuckDuckGo search for the full task to capture any other results
3285
+ sendToken('[Web search backup...] ');
3286
+ try {
3287
+ const generalQuery = [cuisine, 'ristorante', city, targetDateStr ? 'prenotazione' : '', hasAccommodation ? 'b&b romantico' : ''].filter(Boolean).join(' ');
3288
+ const searchResult = await withTimeout(executeTool('web_search', { query: generalQuery, deep: true }, config), 30000);
3289
+ if (searchResult && searchResult.length > 100) {
3290
+ portalResults.push('## Web search: "' + generalQuery + '"\n' + (typeof searchResult === 'string' ? searchResult : JSON.stringify(searchResult)));
3291
+ }
3292
+ } catch {}
3293
+
3294
+ toolData = portalResults.length > 0
3295
+ ? portalResults.join('\n\n')
3296
+ : 'No results found on travel portals. Try specifying city, date, and type of place.';
3297
+ } catch (e) { toolData = toolData || 'TravelAgent failed: ' + e.message; }
3298
+
3150
3299
  } else if (agent === 'BrowserAgent') {
3151
3300
  // Collect all URLs from stepPrompt + task, plus infer subpaths mentioned (e.g. /about, /docs)
3152
3301
  const allUrlMatches = [...new Set((stepPrompt + ' ' + task).match(/https?:\/\/[^\s"'<>)]+/g) || [])];
@@ -3355,7 +3504,7 @@ ${rawText.slice(0, 18000)}`;
3355
3504
  const today = new Date().toISOString().split('T')[0];
3356
3505
  const isCanvasAgent = agent === 'CanvasAgent';
3357
3506
  // Tool-data agents: fetch real live data and use buildSystemPrompt (tool calls allowed)
3358
- const isLiveDataAgent = ['CalendarAgent','EmailAgent','GitHubAgent','NotionAgent','SlackAgent','DriveAgent','BrowserAgent','WebSearchAgent','ResearchAgent','FileReaderAgent','CodeExecutorAgent'].includes(agent);
3507
+ const isLiveDataAgent = ['CalendarAgent','EmailAgent','GitHubAgent','NotionAgent','SlackAgent','DriveAgent','BrowserAgent','WebSearchAgent','ResearchAgent','FileReaderAgent','CodeExecutorAgent','TravelAgent'].includes(agent);
3359
3508
 
3360
3509
  // ── Canvas HTML template — built server-side, guaranteed CSS ─────
3361
3510
  // The LLM outputs ONLY the <body> inner HTML (no <html>, no <style>)
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.5.102';
8
+ export const VERSION = '13.5.105';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -1469,7 +1469,7 @@ export async function executeTool(action, params, config) {
1469
1469
  for (const dr of result.deepResults) {
1470
1470
  lines.push(`--- ${dr.title} ---`);
1471
1471
  lines.push(`URL: ${dr.url}`);
1472
- lines.push(dr.content.slice(0, 2000));
1472
+ lines.push(dr.content.slice(0, 4000));
1473
1473
  lines.push('');
1474
1474
  }
1475
1475
 
@@ -6144,6 +6144,7 @@ function renderStudio(el) {
6144
6144
 
6145
6145
  // Agent catalog
6146
6146
  var STUDIO_AGENTS = [
6147
+ {icon:'&#127860;',name:'TravelAgent',desc:'Restaurants, hotels & bookings (browser automation)'},
6147
6148
  {icon:'&#128269;',name:'WebSearchAgent',desc:'Search the web'},
6148
6149
  {icon:'&#127760;',name:'BrowserAgent',desc:'Navigate & screenshot pages'},
6149
6150
  {icon:'&#128140;',name:'EmailAgent',desc:'Read & summarize emails'},