nothumanallowed 11.4.0 → 11.5.1

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": "11.4.0",
3
+ "version": "11.5.1",
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/config.mjs CHANGED
@@ -283,6 +283,9 @@ export function setConfigValue(key, value) {
283
283
  'my-role': 'profile.role',
284
284
  'role': 'profile.role',
285
285
  'profile-notes': 'profile.notes',
286
+ 'thinking': 'thinking',
287
+ 'extended-thinking': 'thinking',
288
+ 'language': 'language',
286
289
  };
287
290
 
288
291
  const resolved = aliases[key] || key;
@@ -295,7 +298,14 @@ export function setConfigValue(key, value) {
295
298
  }
296
299
 
297
300
  const lastKey = resolvedParts[resolvedParts.length - 1];
298
- if (obj[lastKey] === undefined) return false;
301
+ // Allow creating new keys (don't reject undefined)
302
+
303
+ // Empty value = clear the field
304
+ if (value === '' || value === null || value === undefined) {
305
+ obj[lastKey] = '';
306
+ saveConfig(config);
307
+ return true;
308
+ }
299
309
 
300
310
  // Type coercion based on existing type
301
311
  const existing = obj[lastKey];
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.4.0';
8
+ export const VERSION = '11.5.1';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -234,25 +234,33 @@ export async function streamSSE(res, format) {
234
234
 
235
235
  /**
236
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).
237
+ * Qwen3 32B on Hetzner RTX 6000 Pro 96GB. Supports thinking mode.
245
238
  */
246
239
  export async function callNHA(apiKey, model, systemPrompt, userMessage, stream = false) {
240
+ // Read thinking preference from config
241
+ let thinkingEnabled = false; // OFF by default for speed
242
+ try {
243
+ const fs = await import('fs');
244
+ const path = await import('path');
245
+ const os = await import('os');
246
+ const cfgFile = path.default.join(os.default.homedir(), '.nha', 'config.json');
247
+ if (fs.default.existsSync(cfgFile)) {
248
+ const cfg = JSON.parse(fs.default.readFileSync(cfgFile, 'utf-8'));
249
+ if (cfg.thinking === true || cfg.thinking === 'on' || cfg.thinking === 'true') {
250
+ thinkingEnabled = true;
251
+ }
252
+ }
253
+ } catch {}
254
+
247
255
  const body = {
248
256
  model: model || '/opt/models/qwen3-32b',
249
- max_tokens: 4096,
257
+ max_tokens: thinkingEnabled ? 8192 : 4096,
250
258
  messages: [
251
259
  { role: 'system', content: systemPrompt },
252
260
  { role: 'user', content: userMessage },
253
261
  ],
254
262
  stream,
255
- chat_template_kwargs: { enable_thinking: false }, // OFF by default for speed
263
+ chat_template_kwargs: { enable_thinking: thinkingEnabled },
256
264
  };
257
265
  const res = await fetch('https://liara.nothumanallowed.com/v1/chat/completions', {
258
266
  method: 'POST',
@@ -424,6 +432,22 @@ export async function callLLMStream(config, systemPrompt, userMessage, onToken,
424
432
  const callFn = getProviderCall(provider);
425
433
  if (!callFn) throw new Error(`Unknown provider: ${provider}`);
426
434
 
435
+ // NHA Free: add thinking config to streaming request
436
+ if (provider === 'nha') {
437
+ try {
438
+ const fs2 = await import('fs');
439
+ const path2 = await import('path');
440
+ const os2 = await import('os');
441
+ const cfgFile2 = path2.default.join(os2.default.homedir(), '.nha', 'config.json');
442
+ if (fs2.default.existsSync(cfgFile2)) {
443
+ const cfg2 = JSON.parse(fs2.default.readFileSync(cfgFile2, 'utf-8'));
444
+ const thinkOn = cfg2.thinking === true || cfg2.thinking === 'on' || cfg2.thinking === 'true';
445
+ // Will be added to body below via buildRequestBody override
446
+ opts._thinkingEnabled = thinkOn;
447
+ }
448
+ } catch {}
449
+ }
450
+
427
451
  // Gemini and Cohere don't support streaming — fall back to non-streaming
428
452
  if (provider === 'gemini' || provider === 'cohere') {
429
453
  const text = await callFn(apiKey, model, systemPrompt, userMessage, false);
@@ -468,7 +492,7 @@ function buildRequestBody(provider, model, systemPrompt, userMessage, stream) {
468
492
  grok: 'grok-3-latest',
469
493
  mistral: 'mistral-large-latest',
470
494
  };
471
- return {
495
+ const req = {
472
496
  model: model || modelDefaults[provider] || 'gpt-4o',
473
497
  max_tokens: provider === 'nha' ? 4096 : 8192,
474
498
  messages: [
@@ -477,6 +501,11 @@ function buildRequestBody(provider, model, systemPrompt, userMessage, stream) {
477
501
  ],
478
502
  stream,
479
503
  };
504
+ // NHA: add thinking control
505
+ if (provider === 'nha') {
506
+ req.chat_template_kwargs = { enable_thinking: false };
507
+ }
508
+ return req;
480
509
  }
481
510
 
482
511
  /** Get provider API URL */
@@ -1984,6 +1984,7 @@ function renderSettings(el) {
1984
1984
  ['provider', 'Provider', 'nha (free) / anthropic / openai / gemini / deepseek / grok / mistral'],
1985
1985
  ['key', 'API Key', 'Not needed for NHA Free', true],
1986
1986
  ['model', 'Model', 'Leave empty for default'],
1987
+ ['thinking', 'Extended Thinking', 'on / off — Qwen3 reasoning mode (NHA Free only)'],
1987
1988
  ]) +
1988
1989
  settingsSection('responder', 'Message Responder', 'Auto-reply to Telegram and Discord messages.', [
1989
1990
  ['telegram-bot-token', 'Telegram Bot Token', 'Get from @BotFather', true],