nothumanallowed 16.0.55 → 16.0.56

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": "16.0.55",
3
+ "version": "16.0.56",
4
4
  "description": "Local AI assistant: 80 tools (Gmail, Calendar, Drive, GitHub, Slack, browser, code, files), 38 agents, visual workflows (Studio, AWF, WebCraft). Install with `npm i -g nothumanallowed`, run with `nha ui`. Free tier built-in (Liara), no API key required. Your data stays on your PC — OAuth tokens local, no cloud. Open-source MIT.",
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 = '16.0.55';
8
+ export const VERSION = '16.0.56';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -563,6 +563,41 @@ export async function callGrok(apiKey, model, systemPrompt, userMessage, stream
563
563
  return data.choices?.[0]?.message?.content || '';
564
564
  }
565
565
 
566
+ /**
567
+ * Auto-prefix a model name for OpenRouter. OpenRouter requires `vendor/model`
568
+ * format (e.g. `anthropic/claude-sonnet-4.5`). Agent cards in NHA often have
569
+ * bare model names like `claude-sonnet-4-20250514` or `gpt-4o`. Without the
570
+ * prefix, OpenRouter falls back to an OpenAI-like endpoint that returns a
571
+ * misleading "Incorrect API key provided" error (it's actually a model
572
+ * routing issue). We auto-prefix by inspecting the bare model name.
573
+ */
574
+ export function _autoPrefixOpenRouterModel(model) {
575
+ if (!model || typeof model !== 'string') return 'anthropic/claude-sonnet-4.5';
576
+ // Already in vendor/model format — leave alone
577
+ if (model.includes('/')) return model;
578
+ const lower = model.toLowerCase();
579
+ // Anthropic Claude family
580
+ if (lower.startsWith('claude')) return 'anthropic/' + model;
581
+ // OpenAI GPT family
582
+ if (lower.startsWith('gpt') || lower.startsWith('o1') || lower.startsWith('o3') || lower.startsWith('o4') || lower.startsWith('chatgpt') || lower === 'davinci' || lower === 'curie') return 'openai/' + model;
583
+ // Google Gemini family
584
+ if (lower.startsWith('gemini') || lower.startsWith('palm')) return 'google/' + model;
585
+ // Meta Llama family
586
+ if (lower.startsWith('llama') || lower.startsWith('codellama')) return 'meta-llama/' + model;
587
+ // DeepSeek
588
+ if (lower.startsWith('deepseek')) return 'deepseek/' + model;
589
+ // Mistral / Mixtral
590
+ if (lower.startsWith('mistral') || lower.startsWith('mixtral') || lower.startsWith('codestral')) return 'mistralai/' + model;
591
+ // Qwen
592
+ if (lower.startsWith('qwen')) return 'qwen/' + model;
593
+ // xAI Grok
594
+ if (lower.startsWith('grok')) return 'x-ai/' + model;
595
+ // Cohere
596
+ if (lower.startsWith('command') || lower.startsWith('cohere')) return 'cohere/' + model;
597
+ // Unknown vendor — default to anthropic prefix (most likely sandbox use case)
598
+ return 'anthropic/' + model;
599
+ }
600
+
566
601
  /**
567
602
  * OpenRouter — aggregator that exposes 100+ models (Claude, GPT, Gemini,
568
603
  * Mistral, Llama, Qwen, DeepSeek, etc.) via a single OpenAI-compatible API.
@@ -570,6 +605,7 @@ export async function callGrok(apiKey, model, systemPrompt, userMessage, stream
570
605
  * Model names: "anthropic/claude-sonnet-4.5", "openai/gpt-4o", "google/gemini-2.5-pro"...
571
606
  */
572
607
  export async function callOpenRouter(apiKey, model, systemPrompt, userMessage, stream = false, opts = {}) {
608
+ model = _autoPrefixOpenRouterModel(model);
573
609
  const body = {
574
610
  model: model || 'anthropic/claude-sonnet-4.5',
575
611
  max_tokens: opts.max_tokens || 8192,
@@ -594,7 +630,18 @@ export async function callOpenRouter(apiKey, model, systemPrompt, userMessage, s
594
630
  });
595
631
  if (!res.ok) {
596
632
  const err = await res.text();
597
- throw new Error(`OpenRouter ${res.status}: ${err}`);
633
+ // OpenRouter often passes through misleading "platform.openai.com" key errors
634
+ // when the real cause is (a) invalid OpenRouter key, (b) model name without
635
+ // vendor prefix, (c) model requires BYOK. Provide an actionable hint.
636
+ let hint = '';
637
+ if (res.status === 401) {
638
+ hint = '\n → 401 from OpenRouter usually means: (1) your sk-or-v1-... key is invalid/expired (regenerate at openrouter.ai/keys), or (2) the model name "' + model + '" needs a vendor prefix like "anthropic/' + model.replace(/^[a-z-]+\//, '') + '". This call auto-prefixed to "' + model + '".';
639
+ } else if (res.status === 404) {
640
+ hint = '\n → 404 from OpenRouter usually means the model "' + model + '" does not exist. See openrouter.ai/models for valid IDs.';
641
+ } else if (res.status === 402) {
642
+ hint = '\n → 402 from OpenRouter means insufficient credits. Top up at openrouter.ai/credits.';
643
+ }
644
+ throw new Error(`OpenRouter ${res.status}: ${err}${hint}`);
598
645
  }
599
646
  if (stream) return streamSSE(res, 'openai');
600
647
  const data = await res.json();
@@ -828,9 +875,12 @@ export async function callLLMWithTools(config, systemPrompt, messages, tools, on
828
875
  }
829
876
 
830
877
  // OpenRouter — uses OpenAI-compatible function calling schema. We reuse the
831
- // OpenAI tool-call implementation but point to OpenRouter's endpoint.
878
+ // OpenAI tool-call implementation but point to OpenRouter's endpoint and
879
+ // auto-prefix the model (anthropic/, openai/, etc) so bare names from agent
880
+ // cards work without manual edit.
832
881
  if (provider === 'openrouter') {
833
- return _callOpenAIWithTools(apiKey, model || 'anthropic/claude-sonnet-4.5', systemPrompt, messages, tools, onText, onToolCall, { ...opts, baseUrl: 'https://openrouter.ai/api/v1', referer: 'https://nothumanallowed.com', xTitle: 'NotHumanAllowed CLI' });
882
+ const orModel = _autoPrefixOpenRouterModel(model);
883
+ return _callOpenAIWithTools(apiKey, orModel, systemPrompt, messages, tools, onText, onToolCall, { ...opts, baseUrl: 'https://openrouter.ai/api/v1', referer: 'https://nothumanallowed.com', xTitle: 'NotHumanAllowed CLI' });
834
884
  }
835
885
 
836
886
  // Other providers: fallback to text-based tool calling (old system)