nothumanallowed 15.1.62 → 15.1.63
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": "15.1.
|
|
3
|
+
"version": "15.1.63",
|
|
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 = '15.1.
|
|
8
|
+
export const VERSION = '15.1.63';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { callAgent, callLLM } from './llm.mjs';
|
|
12
|
-
import { buildSystemPrompt, parseActions, executeTool, TOOL_DEFINITIONS, LIARA_TOOL_DEFINITIONS } from './tool-executor.mjs';
|
|
12
|
+
import { buildSystemPrompt, parseActions, executeTool, TOOL_DEFINITIONS, LIARA_TOOL_DEFINITIONS, DESTRUCTIVE_ACTIONS } from './tool-executor.mjs';
|
|
13
13
|
import https from 'https';
|
|
14
14
|
import http from 'http';
|
|
15
15
|
import { URL } from 'url';
|
|
@@ -1047,13 +1047,17 @@ class TelegramResponder {
|
|
|
1047
1047
|
this._lastDirectAuditChatId = chatId;
|
|
1048
1048
|
// Run the per-domain direct-action dispatcher. First match wins; falls
|
|
1049
1049
|
// through to LLM if no handler claims the message.
|
|
1050
|
+
// Fast-path specialised handlers (regex-driven, lower latency for the
|
|
1051
|
+
// common cases), then the universal dispatcher that covers ALL 50+
|
|
1052
|
+
// mutation tools via a single LLM-NLU+deterministic-execute pass.
|
|
1050
1053
|
const directFresh =
|
|
1051
1054
|
await this._tryDirectFreshCalendarAction(cleanText, this.config) ||
|
|
1052
1055
|
await this._tryDirectFreshEmailAction(cleanText, this.config) ||
|
|
1053
1056
|
await this._tryDirectFreshTaskAction(cleanText, this.config) ||
|
|
1054
1057
|
await this._tryDirectFreshNoteAction(cleanText, this.config) ||
|
|
1055
1058
|
await this._tryDirectFreshReminderAction(cleanText, this.config) ||
|
|
1056
|
-
await this._tryDirectFreshSlackAction(cleanText, this.config)
|
|
1059
|
+
await this._tryDirectFreshSlackAction(cleanText, this.config) ||
|
|
1060
|
+
await this._tryDirectFreshUniversalAction(cleanText, this.config);
|
|
1057
1061
|
if (directFresh) {
|
|
1058
1062
|
this.log(`[Telegram] ${fromUser}: direct-fresh ${directFresh.action} → ${directFresh.success ? 'OK' : 'FAIL'}`);
|
|
1059
1063
|
const personaName = this.config.responder?.telegram?.botName || this.config.responder?.botName || '';
|
|
@@ -1663,6 +1667,181 @@ class TelegramResponder {
|
|
|
1663
1667
|
try { return this._extractJsonObject(await callLLM(config, sys, userMessage, { temperature: 0, maxTokens: 300 })); } catch { return null; }
|
|
1664
1668
|
}
|
|
1665
1669
|
|
|
1670
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1671
|
+
// UNIVERSAL DIRECT-ACTION DISPATCHER
|
|
1672
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1673
|
+
// Covers ALL 22 mutation tools in `DESTRUCTIVE_ACTIONS` (gmail, imap,
|
|
1674
|
+
// calendar, contacts, tasks, slack, github, file, drive, notify).
|
|
1675
|
+
// The LLM is used ONLY to (a) decide if the message maps to a tool and
|
|
1676
|
+
// (b) extract the params as JSON. Tool execution is then deterministic
|
|
1677
|
+
// server-side. No tool block is parsed from natural language by the
|
|
1678
|
+
// model — the model can never "say done" without us actually doing it.
|
|
1679
|
+
async _tryDirectFreshUniversalAction(userMessage, config) {
|
|
1680
|
+
if (!userMessage || typeof userMessage !== 'string' || userMessage.length < 3) return null;
|
|
1681
|
+
|
|
1682
|
+
const todayIso = new Date().toISOString().slice(0, 10);
|
|
1683
|
+
const sys =
|
|
1684
|
+
`You are a tool-routing classifier. Given a user message in any language, decide whether it ` +
|
|
1685
|
+
`requests a state-changing action that maps to ONE of these tools, and extract the params.\n\n` +
|
|
1686
|
+
`ALLOWED TOOLS (you MUST pick one of these OR return null):\n` +
|
|
1687
|
+
// Calendar
|
|
1688
|
+
`- calendar_create(summary, start, end, description?) — start/end ISO "YYYY-MM-DDTHH:MM:00"\n` +
|
|
1689
|
+
`- calendar_move(eventId? OR title, newStart, newEnd?) — if no eventId, title is used to find it\n` +
|
|
1690
|
+
`- calendar_update(eventId? OR title, summary?, start?, end?, description?)\n` +
|
|
1691
|
+
`- calendar_delete(eventId? OR title, date?)\n` +
|
|
1692
|
+
// Email Gmail
|
|
1693
|
+
`- gmail_send(to, subject, body) — primary email account\n` +
|
|
1694
|
+
`- gmail_reply(messageId? OR threadHint, body)\n` +
|
|
1695
|
+
`- gmail_delete(messageId? OR query)\n` +
|
|
1696
|
+
`- gmail_mark_read(messageId, isRead?)\n` +
|
|
1697
|
+
`- gmail_mark_starred(messageId, starred?)\n` +
|
|
1698
|
+
`- gmail_archive(messageId)\n` +
|
|
1699
|
+
// Email IMAP
|
|
1700
|
+
`- imap_send(accountId?, to, subject, body) — custom IMAP account\n` +
|
|
1701
|
+
`- imap_reply(accountId?, messageId, body)\n` +
|
|
1702
|
+
`- imap_trash(messageId)\n` +
|
|
1703
|
+
`- imap_mark_read(messageId, isRead?)\n` +
|
|
1704
|
+
`- imap_draft(accountId?, to, subject, body)\n` +
|
|
1705
|
+
// Contacts
|
|
1706
|
+
`- contact_add(name, email?, phone?, company?, address?)\n` +
|
|
1707
|
+
`- contact_update(query, email?, phone?, company?, address?)\n` +
|
|
1708
|
+
`- contact_delete(query)\n` +
|
|
1709
|
+
// Tasks
|
|
1710
|
+
`- task_add(title, priority?, due?)\n` +
|
|
1711
|
+
`- task_done(title)\n` +
|
|
1712
|
+
`- task_delete(title)\n` +
|
|
1713
|
+
// Google Tasks
|
|
1714
|
+
`- gtask_add(title, notes?, due?)\n` +
|
|
1715
|
+
`- gtask_complete(title)\n` +
|
|
1716
|
+
// Notes
|
|
1717
|
+
`- note_add(title, content?)\n` +
|
|
1718
|
+
// Reminders
|
|
1719
|
+
`- notify_remind(message, when) — when = ISO datetime\n` +
|
|
1720
|
+
`- reminder_create(message, when)\n` +
|
|
1721
|
+
// Slack
|
|
1722
|
+
`- slack_send(channel, text, threadTs?) — channel "#name"\n` +
|
|
1723
|
+
`- slack_dm(user, text) — user = name, id, or email\n` +
|
|
1724
|
+
`- slack_react(channel, ts, emoji)\n` +
|
|
1725
|
+
`- slack_mark_read(channel, ts)\n` +
|
|
1726
|
+
// Notion
|
|
1727
|
+
`- notion_page(title, content) — create a new Notion page\n` +
|
|
1728
|
+
// GitHub
|
|
1729
|
+
`- github_create_issue(repo, title, body?, labels?) — repo "owner/name"\n` +
|
|
1730
|
+
// File system (local to user)
|
|
1731
|
+
`- file_write(path, content)\n` +
|
|
1732
|
+
`- file_move(from, to)\n` +
|
|
1733
|
+
`- file_delete(path)\n` +
|
|
1734
|
+
`- file_mkdir(path)\n` +
|
|
1735
|
+
// Google Drive
|
|
1736
|
+
`- drive_upload(name, content, mimeType?) — Google Drive\n` +
|
|
1737
|
+
`- drive_update(fileId, content)\n` +
|
|
1738
|
+
`- drive_delete(fileId? OR name)\n` +
|
|
1739
|
+
`- drive_move(fileId, newParentFolderId? OR newName?)\n` +
|
|
1740
|
+
`- drive_share(fileId, email, role?) — role = "reader"|"writer"|"commenter"\n` +
|
|
1741
|
+
// Birthdays
|
|
1742
|
+
`- birthday_add(name, date) — date "YYYY-MM-DD" or "MM-DD"\n` +
|
|
1743
|
+
`- birthday_delete(name)\n` +
|
|
1744
|
+
// Alexandria E2E
|
|
1745
|
+
`- alexandria_send(channel, message)\n` +
|
|
1746
|
+
// Cron
|
|
1747
|
+
`- cron_create(name, schedule, command) — schedule = cron expression\n` +
|
|
1748
|
+
`- cron_delete(name)\n\n` +
|
|
1749
|
+
`Today is ${todayIso}. Relative dates: "domani" = ${this._addDaysIso(todayIso, 1).slice(0, 10)}, ` +
|
|
1750
|
+
`"dopodomani" = ${this._addDaysIso(todayIso, 2).slice(0, 10)}, "lunedì/martedì/..." resolve to next occurrence.\n\n` +
|
|
1751
|
+
`OUTPUT FORMAT (strict JSON, no markdown, no prose, no fences):\n` +
|
|
1752
|
+
`{"tool": "tool_name" | null, "params": { ... }}\n\n` +
|
|
1753
|
+
`If the message is a READ/LIST/QUERY operation (e.g. "mostra…", "che ho oggi", "leggi email", "trova"), ` +
|
|
1754
|
+
`OR is conversational chat (greetings, questions, opinions) OR is ambiguous → return {"tool": null}.\n` +
|
|
1755
|
+
`If a required param is genuinely missing AND not inferable → return {"tool": null}.\n` +
|
|
1756
|
+
`Never invent emails, eventIds, or recipient addresses.`;
|
|
1757
|
+
|
|
1758
|
+
let raw;
|
|
1759
|
+
try {
|
|
1760
|
+
raw = await callLLM(config, sys, userMessage, { temperature: 0, maxTokens: 400 });
|
|
1761
|
+
} catch (e) {
|
|
1762
|
+
this.log(`[direct-universal] LLM call failed: ${e.message}`);
|
|
1763
|
+
return null;
|
|
1764
|
+
}
|
|
1765
|
+
const parsed = this._extractJsonObject(raw);
|
|
1766
|
+
if (!parsed || !parsed.tool || !DESTRUCTIVE_ACTIONS.has(parsed.tool)) return null;
|
|
1767
|
+
if (!parsed.params || typeof parsed.params !== 'object') return null;
|
|
1768
|
+
|
|
1769
|
+
// Per-tool param normalization (matches the executor's accepted shapes).
|
|
1770
|
+
const params = { ...parsed.params };
|
|
1771
|
+
if (parsed.tool === 'calendar_create' && !params.summary) params.summary = params.title || params.name || params.subject;
|
|
1772
|
+
if (parsed.tool === 'calendar_create' && params.start && !params.end) params.end = this._addMinutesIso(params.start, 60);
|
|
1773
|
+
|
|
1774
|
+
try {
|
|
1775
|
+
const result = await executeTool(parsed.tool, params, config);
|
|
1776
|
+
const resultStr = typeof result === 'string' ? result : JSON.stringify(result);
|
|
1777
|
+
const ok = !/error|failed|not\s+found|invalid|does\s+not\s+exist|placeholder/i.test(resultStr);
|
|
1778
|
+
|
|
1779
|
+
if (this._lastDirectAuditChatId) {
|
|
1780
|
+
this._recordAudit(this._lastDirectAuditChatId, {
|
|
1781
|
+
tool: parsed.tool,
|
|
1782
|
+
success: ok,
|
|
1783
|
+
summary: this._summarizeParamsForAudit(parsed.tool, params),
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
const message = ok
|
|
1787
|
+
? this._formatActionResultIT(parsed.tool, params, resultStr)
|
|
1788
|
+
: `Non sono riuscito a eseguire ${parsed.tool}: ${resultStr.slice(0, 240)}`;
|
|
1789
|
+
return { action: parsed.tool, success: ok, message };
|
|
1790
|
+
} catch (e) {
|
|
1791
|
+
return { action: parsed.tool, success: false, message: `Errore durante ${parsed.tool}: ${e.message}` };
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/** Natural-language Italian summary for the audit log entry. */
|
|
1796
|
+
_summarizeParamsForAudit(tool, params) {
|
|
1797
|
+
if (tool.startsWith('calendar_')) {
|
|
1798
|
+
const t = params.summary || params.title || '';
|
|
1799
|
+
const s = params.start ? this._formatDateIT(String(params.start).slice(0, 10)) + ` ${String(params.start).slice(11, 16)}` : '';
|
|
1800
|
+
return `"${t}"${s ? ` · ${s}` : ''}`;
|
|
1801
|
+
}
|
|
1802
|
+
if (tool === 'gmail_send' || tool === 'imap_send') return `→ ${params.to || '?'} · "${(params.subject || '').slice(0, 60)}"`;
|
|
1803
|
+
if (tool === 'gmail_reply' || tool === 'imap_reply') return `reply → ${params.to || params.messageId || '?'}`;
|
|
1804
|
+
if (tool === 'slack_send') return `→ ${params.channel || '?'} · "${(params.text || '').slice(0, 60)}"`;
|
|
1805
|
+
if (tool === 'notify_remind') return `"${params.message || ''}" @ ${params.when || '?'}`;
|
|
1806
|
+
if (tool === 'github_create_issue') return `${params.repo || '?'}: "${params.title || ''}"`;
|
|
1807
|
+
if (tool === 'file_write') return `${params.path || '?'} (${(params.content || '').length} chars)`;
|
|
1808
|
+
if (tool === 'drive_upload') return `${params.name || '?'} (${(params.content || '').length} chars)`;
|
|
1809
|
+
if (tool === 'task_done' || tool === 'task_delete' || tool === 'contact_delete') return `"${params.title || params.name || '?'}"`;
|
|
1810
|
+
return JSON.stringify(params).slice(0, 80);
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
/** Italian-language natural response for a successful action. */
|
|
1814
|
+
_formatActionResultIT(tool, params, result) {
|
|
1815
|
+
switch (tool) {
|
|
1816
|
+
case 'calendar_create': {
|
|
1817
|
+
const t = params.summary || params.title || 'evento';
|
|
1818
|
+
const when = params.start ? `${this._formatDateIT(String(params.start).slice(0, 10))} alle ${String(params.start).slice(11, 16)}` : '';
|
|
1819
|
+
return `Fatto. Ho creato l'appuntamento "${t}"${when ? ` il ${when}` : ''}.`;
|
|
1820
|
+
}
|
|
1821
|
+
case 'calendar_move': return `Fatto. Appuntamento spostato.`;
|
|
1822
|
+
case 'calendar_update': return `Fatto. Appuntamento aggiornato.`;
|
|
1823
|
+
case 'calendar_delete': return `Fatto. Appuntamento cancellato.`;
|
|
1824
|
+
case 'gmail_send':
|
|
1825
|
+
case 'imap_send': return `Fatto. Email inviata a ${params.to}.`;
|
|
1826
|
+
case 'gmail_reply':
|
|
1827
|
+
case 'imap_reply': return `Fatto. Risposta inviata.`;
|
|
1828
|
+
case 'gmail_delete': return `Fatto. Email eliminata.`;
|
|
1829
|
+
case 'imap_trash': return `Fatto. Email spostata nel cestino.`;
|
|
1830
|
+
case 'contact_delete': return `Fatto. Contatto "${params.name || ''}" cancellato.`;
|
|
1831
|
+
case 'task_done': return `Fatto. Task "${params.title || ''}" completato.`;
|
|
1832
|
+
case 'task_delete': return `Fatto. Task "${params.title || ''}" cancellato.`;
|
|
1833
|
+
case 'task_clear': return `Fatto. Task list pulita.`;
|
|
1834
|
+
case 'notify_remind': return `Promemoria impostato: "${params.message || ''}" per ${params.when || ''}.`;
|
|
1835
|
+
case 'slack_send': return `Fatto. Messaggio inviato a ${params.channel || ''}.`;
|
|
1836
|
+
case 'github_create_issue': return `Issue creata su ${params.repo}: "${params.title}".`;
|
|
1837
|
+
case 'file_write': return `Fatto. File ${params.path} scritto (${(params.content || '').length} caratteri).`;
|
|
1838
|
+
case 'drive_upload': return `Fatto. "${params.name}" caricato su Google Drive.`;
|
|
1839
|
+
case 'drive_update': return `Fatto. File Drive aggiornato.`;
|
|
1840
|
+
case 'drive_delete': return `Fatto. File Drive eliminato.`;
|
|
1841
|
+
default: return `Fatto. ${result.slice(0, 200)}`;
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1666
1845
|
// ── Direct fresh calendar action (no LLM) ─────────────────────────────────
|
|
1667
1846
|
// Detects DELETE / LIST_MONTH / LIST_WEEK / LIST_DAY / LIST_TODAY /
|
|
1668
1847
|
// LIST_TOMORROW intents from a fresh user message and runs the proper tool
|
|
@@ -63,30 +63,39 @@ function getTsxPath() {
|
|
|
63
63
|
|
|
64
64
|
/** Actions that mutate external state and require user confirmation. */
|
|
65
65
|
export const DESTRUCTIVE_ACTIONS = new Set([
|
|
66
|
-
|
|
67
|
-
'gmail_send_attach',
|
|
68
|
-
'
|
|
69
|
-
|
|
70
|
-
'imap_send',
|
|
71
|
-
'
|
|
72
|
-
|
|
73
|
-
'
|
|
74
|
-
|
|
75
|
-
'
|
|
76
|
-
|
|
77
|
-
'
|
|
78
|
-
'
|
|
79
|
-
|
|
80
|
-
'
|
|
81
|
-
|
|
82
|
-
'
|
|
83
|
-
|
|
84
|
-
'slack_send',
|
|
85
|
-
|
|
86
|
-
'
|
|
87
|
-
|
|
88
|
-
'
|
|
89
|
-
|
|
66
|
+
// Gmail
|
|
67
|
+
'gmail_send', 'gmail_send_attach', 'gmail_reply', 'gmail_delete',
|
|
68
|
+
'gmail_mark_read', 'gmail_mark_starred', 'gmail_archive', 'gmail_trash',
|
|
69
|
+
// IMAP (custom email accounts)
|
|
70
|
+
'imap_send', 'imap_reply', 'imap_bulk_send', 'imap_send_template',
|
|
71
|
+
'imap_trash', 'imap_mark_read', 'imap_mark_starred', 'imap_draft',
|
|
72
|
+
// Calendar
|
|
73
|
+
'calendar_create', 'calendar_move', 'calendar_update', 'calendar_delete',
|
|
74
|
+
// Contacts
|
|
75
|
+
'contact_add', 'contact_update', 'contact_delete',
|
|
76
|
+
// Tasks (local) + Google Tasks
|
|
77
|
+
'task_add', 'task_done', 'task_delete', 'task_clear',
|
|
78
|
+
'gtask_add', 'gtask_complete', 'gtask_delete',
|
|
79
|
+
// Notes
|
|
80
|
+
'note_add',
|
|
81
|
+
// Reminders / notifications
|
|
82
|
+
'notify_remind', 'reminder_create',
|
|
83
|
+
// Slack
|
|
84
|
+
'slack_send', 'slack_dm', 'slack_react', 'slack_mark_read',
|
|
85
|
+
// Notion
|
|
86
|
+
'notion_page', 'notion_update',
|
|
87
|
+
// GitHub
|
|
88
|
+
'github_create_issue', 'github_comment',
|
|
89
|
+
// File system (local)
|
|
90
|
+
'file_write', 'file_move', 'file_delete', 'file_mkdir',
|
|
91
|
+
// Google Drive
|
|
92
|
+
'drive_upload', 'drive_update', 'drive_delete', 'drive_move', 'drive_share',
|
|
93
|
+
// Birthdays
|
|
94
|
+
'birthday_add', 'birthday_update', 'birthday_delete',
|
|
95
|
+
// Alexandria messaging
|
|
96
|
+
'alexandria_send',
|
|
97
|
+
// Cron / scheduling
|
|
98
|
+
'cron_create', 'cron_delete',
|
|
90
99
|
]);
|
|
91
100
|
|
|
92
101
|
// ── Tool Definitions (for system prompt) ─────────────────────────────────────
|