nothumanallowed 11.2.1 → 11.4.0
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 +1 -1
- package/src/bootstrap.mjs +7 -3
- package/src/commands/ui.mjs +4 -2
- package/src/constants.mjs +1 -1
- package/src/services/llm.mjs +51 -1
- package/src/services/web-ui.mjs +4 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.4.0",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents, 53 tools. Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, GitHub, Notion, Slack, voice chat, 28 languages. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/bootstrap.mjs
CHANGED
|
@@ -102,10 +102,14 @@ export async function bootstrap() {
|
|
|
102
102
|
ok('NHA is ready!\n');
|
|
103
103
|
|
|
104
104
|
if (!config.llm.apiKey) {
|
|
105
|
-
console.log(` ${'\x1b[1;33m'}Next step:${'\x1b[0m'}
|
|
105
|
+
console.log(` ${'\x1b[1;33m'}Next step:${'\x1b[0m'} Choose your LLM provider:\n`);
|
|
106
|
+
console.log(` ${'\x1b[1;32m'}Option 1 — NHA Free (no API key needed):${'\x1b[0m'}`);
|
|
107
|
+
console.log(` nha config set provider nha`);
|
|
108
|
+
console.log(` ${'\x1b[2m'}Powered by Liara (Qwen3 32B). Free, slower (5-15s). No key required.${'\x1b[0m'}\n`);
|
|
109
|
+
console.log(` ${'\x1b[1;36m'}Option 2 — Your own API key (faster, more capable):${'\x1b[0m'}`);
|
|
106
110
|
console.log(` nha config set provider anthropic`);
|
|
107
|
-
console.log(` nha config set key sk-ant-api03-YOUR_KEY_HERE
|
|
108
|
-
console.log(`
|
|
111
|
+
console.log(` nha config set key sk-ant-api03-YOUR_KEY_HERE`);
|
|
112
|
+
console.log(` ${'\x1b[2m'}Supported: anthropic, openai, gemini, deepseek, grok, mistral, cohere${'\x1b[0m'}\n`);
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
return true;
|
package/src/commands/ui.mjs
CHANGED
|
@@ -1088,7 +1088,9 @@ export async function cmdUI(args) {
|
|
|
1088
1088
|
}
|
|
1089
1089
|
|
|
1090
1090
|
if (!config.llm.apiKey) {
|
|
1091
|
-
|
|
1091
|
+
if (config.llm.provider !== 'nha') {
|
|
1092
|
+
sendJSON(res, 200, { response: 'No API key configured. Run: nha config set key YOUR_KEY\nOr use NHA Free (no key needed): nha config set provider nha', error: 'no_api_key' });
|
|
1093
|
+
}
|
|
1092
1094
|
logRequest(method, pathname, 200, Date.now() - start);
|
|
1093
1095
|
return;
|
|
1094
1096
|
}
|
|
@@ -1496,7 +1498,7 @@ export async function cmdUI(args) {
|
|
|
1496
1498
|
if (method === 'POST' && pathname === '/api/chat/stream') {
|
|
1497
1499
|
const body = await parseBody(req);
|
|
1498
1500
|
if (!body.message) { sendJSON(res, 400, { error: 'message required' }); logRequest(method, pathname, 400, Date.now() - start); return; }
|
|
1499
|
-
if (!config.llm.apiKey) { sendJSON(res, 200, { error: 'no_api_key' }); logRequest(method, pathname, 200, Date.now() - start); return; }
|
|
1501
|
+
if (!config.llm.apiKey && config.llm.provider !== 'nha') { sendJSON(res, 200, { error: 'no_api_key' }); logRequest(method, pathname, 200, Date.now() - start); return; }
|
|
1500
1502
|
|
|
1501
1503
|
const msg = body.message.trim();
|
|
1502
1504
|
const convId = body.conversationId;
|
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 = '11.
|
|
8
|
+
export const VERSION = '11.4.0';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/services/llm.mjs
CHANGED
|
@@ -232,7 +232,49 @@ export async function streamSSE(res, format) {
|
|
|
232
232
|
|
|
233
233
|
// ── Router ─────────────────────────────────────────────────────────────────
|
|
234
234
|
|
|
235
|
+
/**
|
|
236
|
+
* NHA Free (Liara) — free LLM tier, no API key required.
|
|
237
|
+
* Connects to the NHA-hosted Qwen3 + LoRA on Hetzner GPU.
|
|
238
|
+
* OpenAI-compatible format. Slower than paid providers (5-15 seconds).
|
|
239
|
+
*/
|
|
240
|
+
/**
|
|
241
|
+
* NHA Free (Liara) — free LLM tier, no API key required.
|
|
242
|
+
* Connects to the NHA-hosted Qwen3 32B on Hetzner GPU.
|
|
243
|
+
* OpenAI-compatible format. Slower than paid providers (5-15 seconds).
|
|
244
|
+
* Supports thinking mode (Qwen3 native reasoning).
|
|
245
|
+
*/
|
|
246
|
+
export async function callNHA(apiKey, model, systemPrompt, userMessage, stream = false) {
|
|
247
|
+
const body = {
|
|
248
|
+
model: model || '/opt/models/qwen3-32b',
|
|
249
|
+
max_tokens: 4096,
|
|
250
|
+
messages: [
|
|
251
|
+
{ role: 'system', content: systemPrompt },
|
|
252
|
+
{ role: 'user', content: userMessage },
|
|
253
|
+
],
|
|
254
|
+
stream,
|
|
255
|
+
chat_template_kwargs: { enable_thinking: false }, // OFF by default for speed
|
|
256
|
+
};
|
|
257
|
+
const res = await fetch('https://liara.nothumanallowed.com/v1/chat/completions', {
|
|
258
|
+
method: 'POST',
|
|
259
|
+
headers: {
|
|
260
|
+
'Content-Type': 'application/json',
|
|
261
|
+
},
|
|
262
|
+
body: JSON.stringify(body),
|
|
263
|
+
});
|
|
264
|
+
if (!res.ok) {
|
|
265
|
+
const err = await res.text();
|
|
266
|
+
throw new Error(`NHA Free ${res.status}: ${err}`);
|
|
267
|
+
}
|
|
268
|
+
if (stream) return streamSSE(res, 'openai');
|
|
269
|
+
const data = await res.json();
|
|
270
|
+
let content = data.choices?.[0]?.message?.content || '';
|
|
271
|
+
// Strip thinking tags if present
|
|
272
|
+
content = content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
|
273
|
+
return content;
|
|
274
|
+
}
|
|
275
|
+
|
|
235
276
|
const PROVIDERS = {
|
|
277
|
+
nha: callNHA,
|
|
236
278
|
anthropic: callAnthropic,
|
|
237
279
|
openai: callOpenAI,
|
|
238
280
|
gemini: callGemini,
|
|
@@ -247,6 +289,9 @@ export function getProviderCall(provider) {
|
|
|
247
289
|
}
|
|
248
290
|
|
|
249
291
|
export function getApiKey(config, provider) {
|
|
292
|
+
// NHA Free (Liara) doesn't need an API key
|
|
293
|
+
if (provider === 'nha') return 'nha-free-tier';
|
|
294
|
+
|
|
250
295
|
const keyMap = {
|
|
251
296
|
anthropic: config.llm.apiKey,
|
|
252
297
|
openai: config.llm.openaiKey || config.llm.apiKey,
|
|
@@ -417,6 +462,7 @@ function buildRequestBody(provider, model, systemPrompt, userMessage, stream) {
|
|
|
417
462
|
}
|
|
418
463
|
// OpenAI-compatible format (OpenAI, DeepSeek, Grok, Mistral)
|
|
419
464
|
const modelDefaults = {
|
|
465
|
+
nha: '/opt/models/qwen3-32b',
|
|
420
466
|
openai: 'gpt-4o',
|
|
421
467
|
deepseek: 'deepseek-chat',
|
|
422
468
|
grok: 'grok-3-latest',
|
|
@@ -424,7 +470,7 @@ function buildRequestBody(provider, model, systemPrompt, userMessage, stream) {
|
|
|
424
470
|
};
|
|
425
471
|
return {
|
|
426
472
|
model: model || modelDefaults[provider] || 'gpt-4o',
|
|
427
|
-
max_tokens: 8192,
|
|
473
|
+
max_tokens: provider === 'nha' ? 4096 : 8192,
|
|
428
474
|
messages: [
|
|
429
475
|
{ role: 'system', content: systemPrompt },
|
|
430
476
|
{ role: 'user', content: userMessage },
|
|
@@ -436,6 +482,7 @@ function buildRequestBody(provider, model, systemPrompt, userMessage, stream) {
|
|
|
436
482
|
/** Get provider API URL */
|
|
437
483
|
function getProviderUrl(provider, model, apiKey) {
|
|
438
484
|
const urls = {
|
|
485
|
+
nha: 'https://liara.nothumanallowed.com/v1/chat/completions',
|
|
439
486
|
anthropic: 'https://api.anthropic.com/v1/messages',
|
|
440
487
|
openai: 'https://api.openai.com/v1/chat/completions',
|
|
441
488
|
deepseek: 'https://api.deepseek.com/v1/chat/completions',
|
|
@@ -454,6 +501,9 @@ function getProviderHeaders(provider, apiKey) {
|
|
|
454
501
|
'anthropic-version': '2023-06-01',
|
|
455
502
|
};
|
|
456
503
|
}
|
|
504
|
+
if (provider === 'nha') {
|
|
505
|
+
return { 'Content-Type': 'application/json' }; // No auth needed for free tier
|
|
506
|
+
}
|
|
457
507
|
return {
|
|
458
508
|
'Content-Type': 'application/json',
|
|
459
509
|
'Authorization': `Bearer ${apiKey}`,
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -1979,9 +1979,10 @@ function renderSettings(el) {
|
|
|
1979
1979
|
['role', 'Role', 'e.g. Software Engineer'],
|
|
1980
1980
|
['profile-notes', 'Notes', 'Anything else agents should know about you'],
|
|
1981
1981
|
]) +
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
['
|
|
1982
|
+
'<div style="padding:12px 16px;margin-bottom:16px;background:var(--amberdim);border:1px solid var(--amber3);border-radius:8px"><span style="font-family:var(--term);color:var(--amber);font-size:13px;font-weight:700">NHA Free (Liara)</span><div style="font-size:11px;color:var(--dim);margin:4px 0 8px">Powered by Qwen3 32B. Free, no API key needed. Slower (5-15s).</div><button onclick="apiPost(\\x27/api/config\\x27,{key:\\x27provider\\x27,value:\\x27nha\\x27}).then(function(){location.reload()})" style="padding:6px 16px;background:var(--amber3);color:var(--bg);border:none;border-radius:6px;cursor:pointer;font-family:var(--mono);font-size:11px;font-weight:700">Use NHA Free</button></div>' +
|
|
1983
|
+
settingsSection('llm', 'LLM Provider', 'Or use your own API key for faster, more capable responses.', [
|
|
1984
|
+
['provider', 'Provider', 'nha (free) / anthropic / openai / gemini / deepseek / grok / mistral'],
|
|
1985
|
+
['key', 'API Key', 'Not needed for NHA Free', true],
|
|
1985
1986
|
['model', 'Model', 'Leave empty for default'],
|
|
1986
1987
|
]) +
|
|
1987
1988
|
settingsSection('responder', 'Message Responder', 'Auto-reply to Telegram and Discord messages.', [
|