nothumanallowed 13.5.185 → 13.5.189
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.
|
|
3
|
+
"version": "13.5.189",
|
|
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 = '13.5.
|
|
8
|
+
export const VERSION = '13.5.189';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -134,6 +134,44 @@ function routeMessage(text, useAutoRoute = true) {
|
|
|
134
134
|
return bestAgent;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
// ── Language detection from message text ─────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
const IT_WORDS = new Set(['il','lo','la','le','gli','un','una','che','di','da','in','con','su','per','tra','fra','non','ma','se','come','dove','quando','chi','cosa','ho','hai','ha','sono','sei','siamo','avere','essere','fare','dire','andare','mi','ti','ci','si','vi','li','le','gli','mio','tuo','suo','nostro','vostro','loro','questo','quello','questi','quelli','anche','già','ancora','sempre','mai','oggi','domani','ieri','adesso','ora','poi','dopo','prima','qui','qua','lì','là','più','meno','molto','poco','bene','male','sì','no','grazie','prego','ciao','buongiorno','buonasera','appuntamenti','calendario','riunione','meteo','temperatura','email','posta','notizie']);
|
|
140
|
+
const ES_WORDS = new Set(['el','la','los','las','un','una','que','de','en','con','por','para','pero','como','donde','cuando','quien','qué','tengo','tienes','tiene','somos','soy','eres','hacer','decir','ir','me','te','se','nos','este','ese','estos','esos','también','ya','todavía','siempre','nunca','hoy','mañana','ayer','aquí','allí','más','menos','muy','bien','mal','sí','no','gracias','hola','buenos']);
|
|
141
|
+
const FR_WORDS = new Set(['le','la','les','un','une','des','que','de','en','avec','pour','par','mais','comme','où','quand','qui','je','tu','il','elle','nous','vous','ils','elles','avoir','être','faire','dire','aller','me','te','se','ce','cet','cette','ces','aussi','déjà','toujours','jamais','aujourd','demain','hier','ici','là','plus','moins','très','bien','mal','oui','non','merci','bonjour','bonsoir']);
|
|
142
|
+
const DE_WORDS = new Set(['der','die','das','ein','eine','und','oder','aber','nicht','mit','für','von','zu','an','auf','ist','sind','hat','haben','sein','werden','ich','du','er','sie','es','wir','ihr','mich','dich','sich','uns','euch','diesem','diesen','dieser','dieses','auch','schon','noch','immer','nie','heute','morgen','gestern','hier','dort','mehr','weniger','sehr','gut','schlecht','ja','nein','danke','hallo']);
|
|
143
|
+
const PT_WORDS = new Set(['o','a','os','as','um','uma','que','de','em','com','por','para','mas','como','onde','quando','quem','eu','tu','ele','ela','nós','vós','eles','elas','ter','ser','fazer','dizer','ir','me','te','se','nos','este','esse','isso','aquele','também','já','ainda','sempre','nunca','hoje','amanhã','ontem','aqui','lá','mais','menos','muito','bem','mal','sim','não','obrigado','olá']);
|
|
144
|
+
|
|
145
|
+
function detectLanguage(text) {
|
|
146
|
+
if (!text || text.length < 6) return null;
|
|
147
|
+
const words = text.toLowerCase().replace(/[^a-zàáâãäèéêëìíîïòóôõöùúûüýñçàèìòù\s]/g, ' ').split(/\s+/).filter(w => w.length > 1);
|
|
148
|
+
if (words.length < 2) return null;
|
|
149
|
+
|
|
150
|
+
let it = 0, es = 0, fr = 0, de = 0, pt = 0, en = 0;
|
|
151
|
+
for (const w of words) {
|
|
152
|
+
if (IT_WORDS.has(w)) it++;
|
|
153
|
+
if (ES_WORDS.has(w)) es++;
|
|
154
|
+
if (FR_WORDS.has(w)) fr++;
|
|
155
|
+
if (DE_WORDS.has(w)) de++;
|
|
156
|
+
if (PT_WORDS.has(w)) pt++;
|
|
157
|
+
// Basic English common words
|
|
158
|
+
if (['the','a','an','is','are','was','were','have','has','do','does','i','you','he','she','we','they','and','or','but','not','with','for','from','to','in','on','at','this','that','these','those','can','will','would','could','should','what','where','when','who','how'].includes(w)) en++;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const max = Math.max(it, es, fr, de, pt, en);
|
|
162
|
+
if (max === 0) return null;
|
|
163
|
+
const threshold = Math.max(2, words.length * 0.15); // at least 15% of words or 2
|
|
164
|
+
if (max < threshold) return null;
|
|
165
|
+
|
|
166
|
+
if (it === max) return 'Italian';
|
|
167
|
+
if (es === max) return 'Spanish';
|
|
168
|
+
if (fr === max) return 'French';
|
|
169
|
+
if (de === max) return 'German';
|
|
170
|
+
if (pt === max) return 'Portuguese';
|
|
171
|
+
if (en === max) return 'English';
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
|
|
137
175
|
// ── Tool-aware agent call (LLM + tool execution loop) ────────────────────────
|
|
138
176
|
|
|
139
177
|
/**
|
|
@@ -141,12 +179,13 @@ function routeMessage(text, useAutoRoute = true) {
|
|
|
141
179
|
* Like chat.mjs but headless — no confirmation prompts, all tools auto-executed.
|
|
142
180
|
* Returns a human-readable summary of what was done.
|
|
143
181
|
*/
|
|
144
|
-
async function callAgentWithTools(config, agentName, userMessage) {
|
|
182
|
+
async function callAgentWithTools(config, agentName, userMessage, languageOverride) {
|
|
145
183
|
const today = new Date().toISOString().split('T')[0];
|
|
146
184
|
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
147
185
|
const locale = Intl.DateTimeFormat().resolvedOptions().locale || 'en';
|
|
148
186
|
const LANG_MAP = { en: 'English', it: 'Italian', es: 'Spanish', fr: 'French', de: 'German', pt: 'Portuguese', nl: 'Dutch', pl: 'Polish', ru: 'Russian', ja: 'Japanese', ko: 'Korean', zh: 'Chinese', ar: 'Arabic', hi: 'Hindi', tr: 'Turkish' };
|
|
149
|
-
|
|
187
|
+
// Priority: explicit override (from message text detection) → config setting → system locale
|
|
188
|
+
const language = languageOverride || config?.profile?.language || config?.language || LANG_MAP[locale.split('-')[0]] || 'English';
|
|
150
189
|
|
|
151
190
|
const systemPrompt = TOOL_DEFINITIONS
|
|
152
191
|
.replace('{{TODAY}}', today)
|
|
@@ -547,11 +586,20 @@ class TelegramResponder {
|
|
|
547
586
|
// Send typing indicator
|
|
548
587
|
await this._telegramCall('sendChatAction', { chat_id: chatId, action: 'typing' });
|
|
549
588
|
|
|
589
|
+
// Detect language from the message text — overrides system locale
|
|
590
|
+
const detectedLang = detectLanguage(cleanText);
|
|
591
|
+
|
|
550
592
|
// Tool-capable agents use the full tool execution loop
|
|
551
593
|
// Pure reasoning/analysis agents use the simple callAgent (no tools)
|
|
552
594
|
const TOOL_AGENTS = new Set(['herald', 'hermes', 'edi', 'jarvis', 'flux', 'echo', 'mercury', 'pipe', 'navi', 'link', 'prometheus', 'tempest']);
|
|
553
|
-
|
|
554
|
-
|
|
595
|
+
let response;
|
|
596
|
+
if (TOOL_AGENTS.has(agent)) {
|
|
597
|
+
response = await callAgentWithTools(this.config, agent, cleanText, detectedLang);
|
|
598
|
+
} else {
|
|
599
|
+
// For non-tool agents: inject language instruction into the message
|
|
600
|
+
const langInstruction = detectedLang ? `[Respond in ${detectedLang}] ` : '';
|
|
601
|
+
response = await callAgent(this.config, agent, langInstruction + cleanText);
|
|
602
|
+
}
|
|
555
603
|
|
|
556
604
|
// Truncate if too long for Telegram (4096 char limit)
|
|
557
605
|
const truncated = response.length > 4000
|
|
@@ -160,18 +160,21 @@ TOOLS:
|
|
|
160
160
|
15. calendar_move(eventId: string, newStart: string, newEnd: string)
|
|
161
161
|
Reschedule an event. ALWAYS confirm before moving.
|
|
162
162
|
|
|
163
|
-
16.
|
|
164
|
-
|
|
163
|
+
16. calendar_date(date: string)
|
|
164
|
+
List all events for a specific date (YYYY-MM-DD). Use this when the user asks about a specific day (e.g. "May 13", "next Tuesday"). ALWAYS prefer this over calendar_week when a specific date is mentioned.
|
|
165
|
+
|
|
166
|
+
17. calendar_find(query: string, daysAhead?: number)
|
|
167
|
+
Search for a calendar event by name/keyword in the next N days (default 30). Returns matching events with their IDs.
|
|
165
168
|
ALWAYS use this FIRST when the user wants to modify an event — you need the eventId.
|
|
166
169
|
|
|
167
|
-
|
|
170
|
+
18. calendar_update(eventId: string, summary?: string, location?: string, description?: string, start?: string, end?: string)
|
|
168
171
|
Update ANY field of an existing calendar event: title, location, description, start time, end time.
|
|
169
172
|
You MUST call calendar_find first to get the eventId. Only include fields that need to change. ALWAYS confirm before updating.
|
|
170
173
|
|
|
171
|
-
|
|
174
|
+
19. schedule_meeting(clientName: string, subject: string, location: string, durationMinutes: number, dateFrom: string, dateTo: string, workdayStart?: number, workdayEnd?: number)
|
|
172
175
|
Find optimal meeting slots considering existing calendar events, locations, and estimated travel time between appointments. Returns ranked slots with travel info. dateFrom and dateTo are YYYY-MM-DD.
|
|
173
176
|
|
|
174
|
-
|
|
177
|
+
20. schedule_draft_email(clientName: string, subject: string, location: string, durationMinutes: number, dateFrom: string, dateTo: string)
|
|
175
178
|
Same as schedule_meeting, but also generates a professional email proposing the top 3 slots to the client. Returns both the slots and a ready-to-send email draft.
|
|
176
179
|
|
|
177
180
|
--- TASKS ---
|
|
@@ -597,7 +600,7 @@ Never output a JSON block as a suggestion — every block executes immediately.
|
|
|
597
600
|
AVAILABLE TOOLS:
|
|
598
601
|
gmail_list · gmail_read · gmail_send · gmail_draft · gmail_reply · gmail_mark_read · gmail_mark_unread · gmail_archive · gmail_delete · gmail_send_attach
|
|
599
602
|
imap_accounts · imap_list · imap_read · imap_send · imap_sync · imap_labels · imap_mark_read · imap_reply · imap_thread · imap_search · imap_mark_starred · imap_trash · imap_draft · imap_send_template · imap_bulk_send
|
|
600
|
-
calendar_today · calendar_tomorrow · calendar_upcoming · calendar_week · calendar_create · calendar_move · calendar_find · calendar_update · schedule_meeting · schedule_draft_email
|
|
603
|
+
calendar_today · calendar_tomorrow · calendar_date · calendar_upcoming · calendar_week · calendar_create · calendar_move · calendar_find · calendar_update · schedule_meeting · schedule_draft_email
|
|
601
604
|
task_list · task_add · task_done · task_move · task_delete · task_clear · task_edit
|
|
602
605
|
contact_search · contact_add · contact_update · contact_delete
|
|
603
606
|
gtask_list · gtask_add · gtask_complete
|
|
@@ -1199,6 +1202,14 @@ export async function executeTool(action, params, config) {
|
|
|
1199
1202
|
return formatEvents(events);
|
|
1200
1203
|
}
|
|
1201
1204
|
|
|
1205
|
+
case 'calendar_date': {
|
|
1206
|
+
const dateStr = params.date;
|
|
1207
|
+
if (!dateStr || !/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return 'Invalid date format. Use YYYY-MM-DD.';
|
|
1208
|
+
const events = await getEventsForDate(config, dateStr);
|
|
1209
|
+
if (events.length === 0) return `No events scheduled for ${dateStr}.`;
|
|
1210
|
+
return formatEvents(events);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1202
1213
|
case 'calendar_upcoming': {
|
|
1203
1214
|
const hours = params.hours || 2;
|
|
1204
1215
|
const events = await getUpcomingEvents(config, hours);
|
|
@@ -1255,7 +1266,7 @@ export async function executeTool(action, params, config) {
|
|
|
1255
1266
|
|
|
1256
1267
|
case 'calendar_find': {
|
|
1257
1268
|
const query = (params.query || '').toLowerCase();
|
|
1258
|
-
const daysAhead = params.daysAhead ||
|
|
1269
|
+
const daysAhead = params.daysAhead || 30;
|
|
1259
1270
|
const from = new Date();
|
|
1260
1271
|
const to = new Date(from.getTime() + daysAhead * 86400000);
|
|
1261
1272
|
const events = await listEvents(config, 'primary', from, to);
|